Search code examples
cstringpointersmallocrealloc

realloc seems to not be reallocating memory


I need to dynamically append a char to a string, so I'm using realloc() to add more memory as I need it.

I'm new to C (coming from Python) so I've been reading a lot and this was the best I could do:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void append_to(char *array, char value) {
    size_t buffer = (strlen(array) * sizeof(char)) + sizeof(char);
    char *new_array = realloc(array, buffer);
    if (new_array == NULL) {
        printf("CRITICAL ERROR\n");
        exit(-1);
    }
    array = new_array;
    int position = strlen(array);
    array[position] = value;
}

int main() {
    char *list = malloc(sizeof(char));
    for (int i = 1; i < 26; i++){
        append_to(list, 'a');
        printf("%d -> %s\n", i, list);
    }
}

This is just an example to showcase the issue. The code runs flawlessly until iteration 24, see below:

1 -> a
2 -> aa
[...] //omitted
23 -> aaaaaaaaaaaaaaaaaaaaaaa
24 -> aaaaaaaaaaaaaaaaaaaaaaaa
25 -> 

What am I missing?


Solution

  • First you forget to add another NUL char at the end of your c-string.

    Second, realloc may change the memory location of the data, but you passed the list as value, so the relocation is not visible in the case of data relocation.

    That should lokks like:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void append_to(char **array, char value) { // pass pointer's address
        size_t buffer = (strlen(*array) * sizeof(char)) + sizeof(char) + sizeof(char); // one more to tackle the end of the string
        char *new_array = realloc(*array, buffer);
        if (new_array == NULL) {
            printf("CRITICAL ERROR\n");
            exit(-1);
        }
        *array = new_array;
        int position = strlen(*array);
        (*array)[position] = value;
        (*array)[position+1] = 0; // end of string
    }
    
    int main() {
        char *list = malloc(sizeof(char));
        list[0] = 0; // end of string
        for (int i = 1; i < 26; i++){
            append_to(&list, 'a'); // pass address of array so that it can be changed by the call
            printf("%d -> %s\n", i, list);
        }
        free(list); // always explicitly free unused resources
    }