0
void replace(char *str) {
    unsigned int len = 0;
    unsigned int no_of_spaces = 0;
    while (*str) {
        if ((char)*str == SPACE)
            no_of_spaces++;
        str++;
        len++;
    }

    unsigned int new_len = len + 2 * no_of_spaces;
    str = (char*) realloc(str, new_len * sizeof(char));
    str[new_len] = '\0';
}

I use function like replace("random string");.

Here I am trying to increase the size of the string so that spaces can be replaced with another string. For this I need to count the no of spaces and also get the length of the original string. I have been able to do that.

For resizing I am using realloc but when I run it, it gives Aborted (core dumped)?

Animesh Pandey
  • 5,900
  • 13
  • 64
  • 130

4 Answers4

7

Was your original string allocated using malloc? or realloc? Perhaps you are trying to increase the size of a static string (a string literal):

char sStatic[256];   // cannot realloc

char *sNonStatic = NULL;   // can / must realloc

replace("random string") // cannot realloc within replace

EDIT: after reading your comment, you should take a copy of your incoming string, increase the size, then output a copy/ new string. You cannot increase the size of a constant string (a string literal).

Grantly
  • 2,546
  • 2
  • 21
  • 31
  • 1
    Good guess - hadn't thought of that one ! – Paul R Aug 20 '15 at 09:07
  • I am directly passing a string as an argument like `replace("random string")`. – Animesh Pandey Aug 20 '15 at 09:08
  • 2
    Answer amended. You cannot increase this kind of constant string – Grantly Aug 20 '15 at 09:09
  • Glad it helped. Thats why replace functions normally have an Input and Output parameter (or return the Output) - always as a copy of the original string – Grantly Aug 20 '15 at 09:12
  • This means that all the operations that manipulate the length of an array are not on the original string? – Animesh Pandey Aug 20 '15 at 09:14
  • 2
    Your compiler should have given you a warning when you tried to pass a string literal to a function taking `char *` - either you do not have warnings enabled (in which case enable them !) or you chose to ignore the warning (why ?). – Paul R Aug 20 '15 at 09:15
  • 1
    @AnimeshPandey Not at all. You can easily use 'allocated' strings throughout your application which can be realloc'd. But in this case you are accepting raw user input as a string constant. Good practice is ALWAYS to do sanity checks on the string and copy it into a dynamic buffer. (Sanity checks - not too long, no bad characters, etc) – Grantly Aug 20 '15 at 09:18
  • @PaulR I compile the file with ` cc -Wall -g prog.c -o prog.o`. – Animesh Pandey Aug 20 '15 at 09:19
  • 2
    @AnimeshPandey: OK - so you should have seen a warning then ? – Paul R Aug 20 '15 at 09:20
5

The only pointers that can be passed to realloc are null pointers and those that have been returned by calloc, malloc or realloc previously!

This is important because you mentioned that you've called your function like replace("random string")... Is "random string" a null pointer, or returned by one of those *alloc functions? No. Perhaps you meant to use strdup or something (e.g. char *foo = strdup("random string"); replace(foo); free(foo);)? strdup is a POSIX function (e.g. not C-standard like the *alloc functions) but it should return something returned by the *alloc functions.


Following this code:

unsigned int new_len = len + 2 * no_of_spaces;
str = (char*) realloc(str, new_len * sizeof(char)); /* NOTE there's a potential memory leak
                                                     * when realloc returns NULL here, though
                                                     * that's the least of your problems */

... you must check str to ensure realloc succeeded, and only then the only valid indexes for str are between 0 and new_len - 1. This is either a null pointer dereference or a buffer overflow:

str[new_len] = '\0';

Perhaps you meant the following:

size_t new_len = len + 2 * no_of_spaces;
void *temp = realloc(str, new_len + 1); /* <--- NOTE +1 HERE! */
if (temp == NULL) {
    /* XXX: Bomb out due to allocation failure */
}
str = temp;

... and now the valid indexes are between 0 and new_len + 1 - 1, so this is valid:

str[new_len] = '\0';
autistic
  • 1
  • 3
  • 35
  • 80
1

This line is incorrect, since valid indices range from 0 .. new_len - 1:

str[new_len] = '\0';

It should probably be:

str[new_len - 1] = '\0';

You also have a couple of other potential problems:

  • realloc can return NULL - you should check for this

  • in the case that realloc fails you lose your original str pointer and get a memory leak - you should use a temp pointer for the result, test this for NULL, and then only if realloc has succeeded should you set str equal to temp:


char * temp = realloc(str, new_len);
if (temp == NULL)
{
    // handle error here...
}
else
{
    str = temp; // success...
    str[new_len - 1] = '\0';
}

  • not a bug as such, but you have a lot of unnecessary casts which are potentially dangerous as they can masks bugs that would otherwise generate compiler errors or warnings. You can safely remove all the casts in your code above.
Paul R
  • 208,748
  • 37
  • 389
  • 560
0

You also move the pointer

while (*str) {
    if ((char)*str == SPACE)
        no_of_spaces++;
    str++;
    len++;
}

and when you are at the end you try to reallocate it. But you are already away from where the array is. Use a temp variable here. And as the others said. The string is hopefully created with malloc and not as an array.

And str[new_len] = '\0'; is out of bounds.

Kami Kaze
  • 2,069
  • 15
  • 27