I am using the below function to replace a sub-string in a given string
void ReplaceSubStr(char **inputString, const char *from, const char *to)
{
char *result = NULL;
int i, cnt = 0;
int tolen = strlen(to);
int fromlen = strlen(from);
if (*inputString == NULL)
return;
// Counting the number of times old word
// occur in the string
for (i = 0; (*inputString)[i] != '\0'; i++)
{
if (strstr((&(*inputString)[i]), from) == &(*inputString)[i])
{
cnt++;
// Jumping to index after the old word.
i += fromlen - 1;
}
}
// Making new string of enough length
result = (char *)malloc(i + cnt * (tolen - fromlen) + 1);
if (result == NULL)
return;
memset(result, 0, i + cnt * (tolen - fromlen) + 1);
i = 0;
while (&(*inputString))
{
// compare the substring with the result
if (strstr(*inputString, from) == *inputString)
{
strncpy(&result[i], to, strlen(to));
i += tolen;
*inputString += fromlen;
}
else
{
result[i++] = (*inputString)[0];
if ((*inputString)[1] == '\0')
break;
*inputString += 1;
}
}
result[i] = '\0';
*inputString = result;
return;
}
The problem with the above function is memory leak. Whatever memory is allocated for inputString will be lost after this line.
*inputString = result;
since I am using strstr and moving pointer of inputString *inputString += fromlen; inputString is pointing to NULL before the above line. So how to handle memory leak here.
Note: I dont want to return the new memory allocated inside the function. I need to alter the inputString memory based on new length.
You should use a local variable to iterate over the input string and avoid modifying *inputString before the final step where you free the previous string and replace it with the newly allocated pointer.
With the current API, ReplaceSubStr must be called with the address of a pointer to a block allocated with malloc() or similar. Passing a pointer to local storage or a string literal will have undefined behavior.
Here are a few ideas for improvement:
you could return the new string and leave it to the caller to free the previous one. In this case, you would take the input string by value instead of by address:
char *ReplaceSubStr(const char *inputString, const char *from, const char *to);
If the from string is empty, you should either insert the to string between each character of the input string or do nothing. As posted, your code has undefined behavior for this border case.
To check if the from string is present at offset i, use memcmp instead of strstr.
If cnt is 0, there is nothing to do.
You should return an error status for the caller to determine if memory could be allocated or not.
There is no need to initialize the result array.
avoid using strncpy(). This function has counter-intuitive semantics and is very often misused. Read this: https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/
Here is an improved version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int ReplaceSubStr(char **inputString, const char *from, const char *to) {
char *input = *inputString;
char *p, *q, *result;
size_t cnt;
size_t tolen = strlen(to);
size_t fromlen = strlen(from);
if (input == NULL || fromlen == 0)
return 0;
// Counting the number of times old word occurs in the string
for (cnt = 0, p = input; (p = strstr(p, from)) != NULL; cnt++) {
p += fromlen;
}
if (cnt == 0) // no occurrence, nothing to do.
return 0;
// Making new string of enough length
result = (char *)malloc(strlen(input) + cnt * (tolen - fromlen) + 1);
if (result == NULL)
return -1;
for (p = input, q = result;;) {
char *p0 = p;
p = strstr(p, from);
if (p == NULL) {
strcpy(q, p0);
break;
}
memcpy(q, p0, p - p0);
q += p - p0;
memcpy(q, to, tolen);
q += tolen;
p += fromlen;
}
free(*inputString);
*inputString = result;
return 0;
}
int main() {
char *p = strdup("Hello world!");
ReplaceSubStr(&p, "l", "");
printf("%s\n", p); // prints Heo word!
free(p);
return 0;
}
You cannot obviously free the input as it can be a literal, some memory you don't control. That would cripple your function even more than now.
You could return the old value of inputString so you'd be able to free it if needed.
char *ReplaceSubStr(char **inputString, const char *from, const char *to)
{
char *old_string = *inputString;
...
return old_string;
}
The caller is responsible to free the contents of old_string if needed.
If not needed (we have to workaround the char ** input by assigning a valid writable array to a pointer to be able to pass this pointer:
char input[]="hello world";
char *ptr = input;
ReplaceSubStr(&ptr, "hello", "hi");
// input is now "hi world" in a different location
free(ptr); // when replaced string isn't needed
if needed:
char *input = strdup("hello world");
char *old_input = ReplaceSubStr(&input, "hello", "hi");
free(old_input);
or just
free(ReplaceSubStr(&input, "hello", "hi"));
then always (when replaced string isn't needed):
free(input);
The only constraint is that you cannot use a constant string literal as input (const char *input = "hello world") because of the prototype & the possible return of a char * to pass to free.
Related
I am writing some functions for strings, and im having a problem with realloc. Why do i get the error realloc(): invalid pointer: 0x000...
This is my string structure:
typedef struct {
int length; /* Length of the String excluding '\0' */
char * string; /* pointer to string */
} string;
This is my string creating function:
string string_create(char content[]) {
string localString;
localString.length = 0;
while (content[localString.length] != '\0') {
localString.length++;
}
localString.string = (char *)calloc((localString.length + 1), sizeof(char));
localString.string = content;
return localString;
}
This is my string insertion function: (The function with the problems)
void string_insert(string * btstring, int index, char s[]) {
int stringLength = 0;
while (s[stringLength] != '\0') {
stringLength++;
}
if (stringLength > 0) {
btstring -> length += stringLength;
btstring -> string = (char *) realloc((btstring -> string), ((btstring -> length + 1) * sizeof(char)));
for (int i = 0; i < stringLength; i++) {
char c = s[i];
char temp[2] = {0, c};
int cindex = index + i;
while (btstring -> string[cindex] != '\0') {
temp[0] = btstring -> string[cindex];
btstring -> string[cindex] = temp[1];
temp[1] = temp[0];
cindex++;
}
temp[0] = btstring -> string[cindex];
btstring -> string[cindex] = temp[1];
temp[1] = temp[0];
cindex++;
btstring -> string[cindex] = temp[1];
}
}
}
realloc can return the requested amount of memory at a different address (and it can fail). Therefore, you should do:
char *tmp;
tmp = realloc(btstring->string, stringLength + 1);
if (!tmp) return; // could not allocate the memory
btstring->string = tmp; // assign the (new) memory to the string.
btstring->length = stringLength; // only now update the length
Notes:
realloc retains the data of the original memory if it has to allocate a different piece of memory to satisfy your request.
don't cast the return value of the malloc family of functions. A void pointer is compatible with all pointers.
the size of a char is always 1.
though a matter of style, it is common not to have spaces between the struct and members as in a->b and c.d.
Another error is in the create function:
localString.string = content;
This will assign the character pointer content to the character pointer localString.string, throwing away the memory you just allocated. You should do:
strcpy(localString.string, content);
This copies the content of the string content to the memory of localString.string.
I try to code my own concatenation function in C without library, but I have issue and I don't know where it comes from.
To do my function I use pointers of char.
This is my Code :
#include <stdio.h>
#include <stdlib.h>
int longueur(char *str)
{
int i =0;
while(str[i] != '\0')
{
i++;
}
return i;
}
void concat(char* source, char* dest)
{
int longStr1 = (longueur(source));
int longStr2 = (longueur(dest));
int i=0, j=0;
char* temp = dest;
free(dest);
dest = (char*) realloc(dest, ((longStr1 + longStr2)* sizeof(char)));
/*dest[0] = temp[0]; <------ If I do this it will generate issue, so the bellow code too*/
while(temp[i] != '\0')
{
dest[i] = temp[i];
i++;
}
while(source[j] != '\0')
{
dest[i] = source[j];
i++;
j++;
}
dest[i] = '\0';
}
int main()
{
char *str1 = "World";
char *str2 = "Hello";
concat(str1, str2);
printf("-------------\n%s", str2);
return 0;
}
EDIT
I read all your answer, so I changed my concat function to :
void concat(char* source, char* dest)
{
int longStr1 = (longueur(source));
int longStr2 = (longueur(dest));
int i=0, j=0;
dest = (char*) malloc((longStr1 + longStr2)* sizeof(char) + sizeof(char));
while(dest[i] != '\0')
{
dest[i] = dest[i];
i++;
}
while(source[j] != '\0')
{
dest[i] = source[j];
i++;
j++;
}
dest[i] = '\0';
}
Now I don't have issue but my code only display "Hello"
In addition to all the good comments and solutions: realloc can give you a different pointer and you must return that pointer. So your function signature should be:
void concat(char* source, char** dest)
{
int longStr1 = (longueur(source));
int longStr2 = (longueur(dest));
int i=0, j=0;
char* temp = *dest, *temp2;
if ((temp2 = realloc(dest, ((longStr1 + longStr2)+1))==NULL) return;
*dest= temp2;
while(temp[i] != '\0')
{
*dest[i] = temp[i];
i++;
}
while(source[j] != '\0')
{
*dest[i] = source[j];
i++;
j++;
}
*dest[i] = '\0';
}
..and this assumes the function will only be called with a dest that was allocated with malloc. And sizeof(char) is always 1. (This resulting function is not optimal.)
--EDIT--
Below the correct, optimized version:
void concat(char* source, char** dest)
{
int longSrc = longueur(source);
int longDst = longueur(dest);
char *pDst, *pSrc;
if ((pDst = realloc(*dest, longSrc + longDst + 1))==NULL) return;
if (pDst != *dest) *dest= pDst;
pDst += longSrc;
pSrc= source;
while(pSrc)
*pDst++ = *pSrc++;
*pDst = '\0';
}
In your code
free(dest);
and
dest = (char*) realloc(dest, ((longStr1 + longStr2)* sizeof(char)));
invokes undefined behavior as none of them use a pointer previously allocated by malloc() or family.
Mostly aligned with your approach, you need to make use of another pointer, allocate dynamic memory and return that pointer. Do not try to alter the pointers received as parameters as you've passed string literals.
That said, you need to have some basic concepts clear first.
You need not free() a memory unless it is allocated through malloc() family.
You need to have a char extra allocated to hold the terminating null.
Please see this discussion on why not to cast the return value of malloc() and family in C..
If your concatenation function allocates memory, then, the caller needs to take care of free()-ing the memory, otherwise it will result in memory leak.
After you have freed dest here:
free(dest);
You cannot use this pointer in following call to realloc:
dest = (char*) realloc(dest, ((longStr1 + longStr2)* sizeof(char)));
/*dest[0] = temp[0]; <------ If I do this it will generate issue, so the bellow code too*/
man realloc
void *realloc(void *ptr, size_t size);
The realloc() function changes the size of the memory block
pointed to by ptr to size bytes. (...)
But this pointer is invalid now and you cannot use it anymore. When you call free(dest), the memory dest points to is being freed, but the value of dest stays untouched, making the dest a dangling pointer. Accessing the memory that has already been freed produces undefined behavior.
NOTE:
Even if free(dest) is technically valid when called on pointer to memory allocated by malloc (it is not an error in your function to call free(dest) then), it is incorrect to use this on pointer to literal string as you do in your example (because str2 points to string literal it is an error to pass this pointer to function calling free on it).
Given your original use, perhaps you would find a variant like this useful
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
size_t longueur ( const char * str ) { /* correct type for string lengths */
size_t len = 0;
while (*str++ != '\0') ++len;
return len;
}
char * concat ( const char * first, const char * second ) {
const char * s1 = first ? first : ""; /* allow NULL input(s) to be */
const char * s2 = second ? second : ""; /* treated as empty strings */
size_t ls1 = longueur(s1);
size_t ls2 = longueur(s2);
char * result = malloc( ls1 + ls2 + 1 ); /* +1 for NUL at the end */
char * dst = result;
if (dst != NULL) {
while ((*dst = *s1++) != '\0') ++dst; /* copy s1\0 */
while ((*dst = *s2++) != '\0') ++dst; /* copy s2\0 starting on s1's \0 */
}
return result;
}
int main ( void ) {
const char *str1 = "Hello";
const char *str2 = " World";
char * greeting = concat(str1, str2);
printf("-------------\n%s\n-------------\n", greeting);
free(greeting);
return 0;
}
In this variant, the two inputs are concatenated and the result of the concatenation is returned. The two inputs are left untouched.
I'm implementing a shell in C, and I ran into some problems parsing command-line entries. I want my parser method to separate command-line entries that are delimited by the whitespace character, and return the result as a double char pointer. ie, say I have "ls -l >ls.txt", my parser should return a char **r with r[0]="ls", r[1]="-l", and r[2]=">ls.txt".
Here is the code for my current parse method, which is, by the way, segfaulting, and I'm out of ideas as to how to fix that:
char **parser(int *argc, char *s)
{
char **r;
char *t, *m;
int i,n,size;
t = malloc(strlen(s)); // firs i used this instead of *r, but i run
// into trouble when i have more than two
// argc. ( You see why, right?)
//strcpy(t,s);
i = 0;
size = 5;
r = malloc(size*sizeof(char *));
while (( m = strchr(s, ' '))) {
n = ((int)m) - ((int)s);
if (i==0) {
*r = malloc(n);
} else {
*r = realloc(*r, n);
}
strncpy(*r, s, n);
*r[n]= '\0';
s = (char*)(s+n+1);
if (i == size)
r = realloc(r, (size = 2*size)*sizeof(char*));
i++;
r = (char **)(r + sizeof(char*));
}
s[strlen(s)-1] = '\0';
if ((i<1) || (strlen(s)>1)) {
*r = s;
}
*argcp = ++i;
return r;
}
I know my code isn't ideal. It could be made better using strsep, but my main concer is how to manage memory for the double char pointer I want to return.
Thanks for the help!
This is a quick stab.
My C is so rusty, all of the hinges are stuck, so.
The premise is that you will end up with a pointer to an array of pointers. The key detail though, is at the end of that list of pointers, is the argument data itself. So when you're done, you simply need to free the returned pointer.
Untested. There may well be a one off error sneaking in here.
Edit, I compiled and quickly tested it.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char **parser(int *argc, char *s) {
char **r, **rp;
char *t, *p, *w;
void *vp;
int l;
l = strlen(s); // size of cmd line
vp = malloc(l + (*argc * sizeof(char *))); // total buffer size
t = (char *)(vp + (*argc * sizeof(char *))); // offset into buffer for argument copy
r = (char **)vp; // start of buffer, start of pointer array to arguments
strcpy(t, s); // copy arguments in to buffer
p = t; // parsing pointer
w = t; // word pointer for each argument
rp = r; // storage for first pointer
while(*p) { // while not at end of string
if (*p == ' ') { // if we find a space
if (w) { // if we have a word pointer assigned
*rp++ = w; // store the word pointer
w = NULL; // set word pointer to null
*p = '\0'; // terminate argument with a 0
} // else do nothing continue to skip spaces
} else {
if (w == NULL) { // If we haven't got a new arg yet
w = p; // set it
} // otherwise, just keep scanning
}
p++; // move along the string
}
if (w) { // clean up at the end if we have an arg
*rp++ = w;
w = NULL; // no reason to set 0 at the end, it's already there from strcpy
}
return r;
}
int main() {
char *cmd = "arg1 arg2";
int argc = 2;
char **r = parser(&argc, cmd);
printf("%s\n",r[0]);
printf("%s\n",r[1]);
}
Does anyone know why I keep getting this seg fault error?
I am trying to run a program that locates a substring "from" within "src" and replaces all non-overlapping occurrences of "from" in src with "to" in the output string "dest".
Also, could anyone provide me with the proper way to test this case? As I'm not too sure how I could display this with type "void"... (Trying this as an exercise)
void find_replace(char* src, char* from, char* to, char* dest)
{
int count = 0;
int diff = strlen(to) - strlen(from);
int destlength = strlen(src);
dest = malloc(destlength);
for (int i = 0; i < strlen(src); i++)
{
int index = 0;
while (src[i+index] == from[index] && index < strlen(from)){
index++;
}
if (index == strlen(from)) {
for (int j = 0; j < strlen(to); j++) {
dest[i+j+(count * diff)] = to[j];
}
i += strlen(from) - 1;
count++;
}
else {
dest[i + (count * diff)] = src[i];
}
}
return ;
}
Is it sufficient enough to do this for a test?
int main (int argc, char *argv[])
{
char* dest;
find_replace("hello my name is leeho lim", "leeho lim", "(insert name)" dest);
for (int i = 0; i < strlen(dest); i++)
{
printf("%c", dest[i]);
}
printf("\n");
}
The problems happens because you are trying to access an unallocated pointer with
strlen(dest)
In the for in your main program.
The reason for this is that you sent the value of the pointer dest to the function, not the pointer itself, so when you allocated the memory inside your function, so you didn't actually modify the memory address stored in the pointer outside of it.
When you send the pointer as a parameter of a function, what you are actually doing is sending the memory address stored in that pointer, you are sending the value stored in the pointer, not the pointer itself.
If you want to get the allocated memory address for the string, you either can make the function return it, or you can declare and send dest as a pointer to a pointer.
EDIT: As the other comment points out, you can also perform the allocation in main(), instead of doing it inside your function.
A few minor tweaks to your program is all you need.
Change the return value of find_replace to be the newly allocated memory for the changed string.
Instead of
void find_replace(char* src, char* from, char* to, char* dest)
Use
char* find_replace(char* src, char* from, char* to)
Change the implementation slightly.
Instead of
dest = malloc(destlength);
use
char* dest = malloc(destlength);
and
Instead of
return;
use
return dest;
Change the way you use the function.
Instead of
char* dest;
find_replace("hello my name is leeho lim", "leeho lim", "(insert name)", dest);
use
char* dest = find_replace("hello my name is leeho lim", "leeho lim", "(insert name)");
Make sure to deallocate memory returned by find_replace.
free(dest);
Here's a fully working program:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* find_replace(char* src, char* from, char* to)
{
int count = 0;
int diff = strlen(to) - strlen(from);
int destlength = strlen(src);
char* dest = malloc(destlength);
for (int i = 0; i < strlen(src); i++)
{
int index = 0;
while (src[i+index] == from[index] && index < strlen(from)){
index++;
}
if (index == strlen(from)) {
for (int j = 0; j < strlen(to); j++) {
dest[i+j+(count * diff)] = to[j];
}
i += strlen(from) - 1;
count++;
}
else {
dest[i + (count * diff)] = src[i];
}
}
return dest;
}
int main (int argc, char *argv[])
{
char* dest = find_replace("hello my name is leeho lim", "leeho lim", "r sahu");
for (int i = 0; i < strlen(dest); i++)
{
printf("%c", dest[i]);
}
free(dest);
printf("\n");
}
Update, in response to OP's comment
If the return type of find_replace must be void, there are couple of options on how to deal with the memory needed for dest.
Allocate memory for dest in the calling function.
char* dest = malloc(SUFFICIENT_SIZE);
find_replace("hello my name is leeho lim", "leeho lim", "(insert name)", dest);
free(dest);
Then, there is no need for the line
dest = malloc(...);
in find_replace.
Allocate memory for dest in find_replace. Then, you need to pass a pointer to a pointer.
void find_replace(char* src, char* from, char* to, char** dest)
and use *dest instead of just dest in the function.
void find_replace(char* src, char* from, char* to, char** dest)
{
int count = 0;
int diff = strlen(to) - strlen(from);
int destlength = strlen(src);
*dest = malloc(destlength);
for (int i = 0; i < strlen(src); i++)
{
int index = 0;
while (src[i+index] == from[index] && index < strlen(from)){
index++;
}
if (index == strlen(from)) {
for (int j = 0; j < strlen(to); j++) {
(*dest)[i+j+(count * diff)] = to[j];
}
i += strlen(from) - 1;
count++;
}
else {
(*dest)[i + (count * diff)] = src[i];
}
}
return;
}
and change the you call find_replace.
char* dest;
find_replace("hello my name is leeho lim", "leeho lim", "(insert name)", &dest);
There are two main problems with your (original) code:
it does not provide for your find_replace() function to return the allocated destination buffer to the caller, and
it does not reliably allocate enough space for the destination buffer.
In principle, issue (1) could be resolved in two ways. Either the space could be allocated by the caller and a pointer to it passed to the function, or the space could be allocated by the function and a pointer returned to the caller. Your original code allocates space in the function, but does not return a pointer to it to the caller.
It is preferable for the function to perform the allocation, because satisfying issue (2) requires a more thorough analysis of the inputs than makes sense to insist the caller perform. Consider what happens in your revised code when you do this:
char dest[4];
int canary = 0;
find_replace("aaa", "a", "longer string", dest);
assert(canary == 0);
Most likely you get a segfault, possibly you get an assertion failure, and perhaps you get who-knows-what, because find_replace() cannot perform its job without writing past the end of dest, the result of which is undefined.
Although you've said the exercise requires your function to have no return value (i.e. void), it can still return a pointer to the destination string via the argument list. You simply pass a pointer to the dest pointer instead of its value, so that the function can update that value. The signature would look like this:
void find_replace(const char *src, const char *from, const char *to,
char **dest_p);
(Note the const qualifers for src, from, and to, which are appropriate, if not necessary, if the function is meant to accept string literals.)
The amount of space needed for dest is the length of src plus one for the terminator plus, if to is longer than from, the difference between the lengths of the to and from strings times the number of appearances of the to string. You could, however, compute an upper bound on that length, and later shrink the allocation (if needed) after you find out how much space is actually used. For example:
void find_replace(const char *src, const char *from, const char *to,
char **dest_p) {
ssize_t src_size = strlen(src);
ssize_t from_size = strlen(from);
ssize_t to_size = strlen(to);
char *temp;
if (!from_size) {
/* special case: the 'from' string is empty ... */
/* whatever you do, set temp to something valid or NULL */
} else {
ssize_t size_diff = to_size - from_size;
if (size_diff < 0) size_diff = 0;
temp = malloc(1 + src_size + (src_size / from_size) * size_diff);
if (temp) {
/* use next to track the next unused position in temp */
char *next = temp;
/*
* perform the substitution, updating 'next' appropriately as
* you go along (INSERT CODE AFTER THIS COMMENT) ...
*/
/* be sure to terminate: */
*(next++) = '\0';
/* shrink the string to the actual space used (optional): */
next = realloc(temp, next - temp);
/*
* On (re)allocation error, next will be NULL and temp will still
* be a valid pointer. Otherwise, next will be a pointer to the
* space, not necessarily equal to temp, and temp might no longer
* be a valid pointer.
*
* An OK error recovery strategy is to just return a pointer
* to the full-size space.
*/
if (next) {
temp = next;
}
} /* else allocation failure; return NULL */
}
/*
* The caller gets a pointer to the allocated space (if any). It is his
* responsibility to free it when it is no longer needed.
*/
*dest = temp;
}
The actual substitution code is left as an exercise, since this is homework, after all.
EDIT: I should add how I have this all set up. The struct definition and prototypes are in mystring.h. The function definitions are in mystring.c. The main is in mystringtest.c. For mystring.c and mystringtest.c, I have #include "mystring.h" at the top. I'm compiling like gcc -o test.exe mystring.c mystringtest.c. Not sure if any of that matters, but I'm new with C so I'm just trying to include everything.
I have a good deal of experience with Java but am pretty new to C. I imagine this is related to pointers and memory but I'm totally at a loss here for what's going on. Here's my code:
typedef struct {
char *chars;
int length;
int maxSize;
} String;
int main() {
char *a;
a = readline();
String *s = newString(a);
int b = length(s);
printf("length is %d \n", b);
}
I run the program and enter "hello" (as prompted by readline()). I've stepped through the program and after length(s), s->chars is still a pointer to the array of chars 'hello'. After the print statement, s->chars becomes a pointer to the array of chars 'Length is %d \n'. I'm totally at a loss for what I'm doing wrong. I'm working on a virtual machine if that matters at all. Any help is greatly appreciated. I'll give the code for newString and length too.
int length(String *s) {
char *temp = s->chars;
char b = *temp;
int count;
if (b == '\0') { count = 0; }
else { count = 1; }
while (b != '\0') {
b = *(temp+count);
count++;
}
return count;
}
String *newString(char *s) {
String st;
st.length = 20;
st.maxSize = MAXCHAR;
char *temp = malloc(20 * sizeof(char));
char b = *s;
int count = 0;
while (b != '\0') {
*(temp + count) = b;
count++;
b = *(s+count);
if (count == st.maxSize) { break; }
if (count == st.length) {
st.length = st.length + 20;
temp = realloc(temp, st.length * sizeof(char));
}
}
st.chars = temp;
return &st;
}
String *newString(char *s) {
String st;
...
return &st;
}
You are returning a pointer to a local variable. After newString returns, the local variable no longer exists, so you have a dangling pointer.
Either allocate st with malloc, or return it by value.
you must null terminate the string after the while loop, you have not left space for the null terminator. Also I don't see why you need to realloc
//using strlen will eliminate the need for realloc, +1 is for the null terminator
int len = strlen(s)
char *temp = malloc((len * sizeof(char)) +1);
//null terminate
*(temp+count) = '\0';
st.chars = temp;