Search code examples
cpointersmallocrealloc

Resizing a char* on the fly - why does this code *work*?


I'm experimenting with malloc & realloc and came up with some code for the following problem:

I want to create a string of unknown size, without setting any limit. I could ask the user for a nr of chars, but I rather resize the str as the user types each character.

So I was trying to do this with malloc + realloc and the idea was that everytime the user enters a new char, I use realloc to request +1 piece of memory to hold the char.

While trying to implement this, I did a mistake and ended up doing the following:

int main () {
    /* this simulates the source of the chars... */
    /* in reality I would do getch or getchar in the while loop below... */

    char source[10];
    int i, j;
    for (i=0, j=65; i<10; i++, j++) { 
            source[i] = j;
    }

    /* relevant code starts here */

    char *str = malloc(2 * sizeof(char)); /* space for 1 char + '\0' */
    int current_size = 1;

    i = 0;
    while(i<10) {
            char temp = source[i];
            str[current_size-1] = temp;
            str[current_size] = '\0';
            current_size++;
            printf("new str = '%s' | len = %d\n", str, strlen(str));
            i++;
    }

    printf("\nstr final = %s\n", str);

    return 0;

} 

Note that the realloc part is not implemented yet.

I compiled and executed this code and got the following output

new str = 'A' | len = 1
new str = 'AB' | len = 2
new str = 'ABC' | len = 3
new str = 'ABCD' | len = 4
new str = 'ABCDE' | len = 5
new str = 'ABCDEF' | len = 6
new str = 'ABCDEFG' | len = 7
new str = 'ABCDEFGH' | len = 8
new str = 'ABCDEFGHI' | len = 9
new str = 'ABCDEFGHIJ' | len = 10

I found these results weird, because I expected the program to crash: str has space for 2 chars, and the code is adding more than 2 chars to the str without requesting more memory. From my understanding, this means that I'm writing in memory which I don't own, so it should give a runtime error.

So... Why does this work?

(The compiler is GCC 4.3.4.)

Thanks in advance.

EDIT: One of the commenters suggesting that a call to free() could lead to the error being signaled. I tried calling free() with the above code and no error resulted from executing the code. However, after adding more items to the source array, and also calling free, the following error was obtained:

* glibc detected ./prog: free(): invalid next size (fast): 0x09d67008 **


Solution

  • Since you're writing past the allocated memory, your code has undefined behaviour.

    The fact that the code happened to not crash once (or even many times) does not change that.

    Undefined behaviour doesn't mean that the code has to crash. In your case, there happens to be some memory immediately following str, which you're overwriting. The actual effects of overwriting that memory are not known (you could be changing the value of some other variable, corrupting the heap, launching a nuclear strike etc).