Search code examples
arrayscmemory-management

What is the difference between these two implementations of push_front function for dynamically allocated array? (malloc vs realloc)


Can you explain why exactly the first function doesn't work correctly?

I wrote two identical functions:

bool push_front(int value, size_t *size, int **arr) {
    if (!*arr) return false;
    int *new_arr = realloc(*arr, sizeof(int[*size + 1]));
    if (!new_arr) return false;
    new_arr[0] = value;
    for (size_t i = 1, j = 0; j < *size; ++i, ++j)
        new_arr[i] = (*arr)[j];
    ++*size;
    *arr = new_arr;
    return true;
}

bool push_front(int value, size_t *size, int **arr) {
    if (!*arr) return false;
    int *new_arr = malloc(sizeof(int[*size + 1]));
    if (!new_arr) return false;
    new_arr[0] = value;
    for (size_t i = 1, j = 0; j < *size; ++i, ++j)
        new_arr[i] = (*arr)[j];
    ++*size;
    free(*arr);
    *arr = new_arr;
    return true;
}

The first one does add an element, but it's also rewriting all the array elements to 'value'. Any ideas why it happens?


Solution

  • The first approach using realloc has multiple problems:

    • if the array is empty, you might want to allocate a singleton even if *arr is null, hence you should only fail if *arr is null and if *size is not. As suggested by @Fe2O3, you can still use realloc if *arr is null because realloc(NULL, size) is equivalent to malloc(size) .
    • you overwrite the first element before shifting the elements one position to the right
    • you read (*arr)[i] after reallocating the array: *arr may be an invalid pointer if the block was reallocated to a different address, this has undefined behavior.
    • you copy the elements the first to the last one position to the right: each element is overwritten before it is copied, resulting in all elements receiving the same value value.

    Here is a modified version:

    bool push_front(int value, size_t *size, int **arr) {
        if (!*arr && *size)
            return false;
        int *new_arr = realloc(*arr, sizeof(int[*size + 1]));
        if (!new_arr)
            return false;
        for (size_t i = *size; i > 0; i--)
            new_arr[i] = new_arr[i - 1];
        new_arr[0] = value;
        ++*size;
        *arr = new_arr;
        return true;
    }