Crealloc()

realloc()

realloc() lets you resize a block of memory that was previously obtained from malloc(), calloc(), or an earlier realloc() call. This is essential for building data structures like dynamic arrays, where you do not know the final size up front and need to grow the allocation as more data arrives.

C
void *realloc(void *ptr, size_t new_size);
You pass it the pointer to the existing block and the new total size you want, in bytes. If it succeeds, it returns a pointer to a block of at least new_size bytes, with the contents of the original block preserved (up to the smaller of the old and new sizes). If it fails, it returns NULL and the original block is left completely untouched.
The Critical Gotcha: The Address May Change
realloc() does not necessarily resize memory in place. If there is not enough contiguous free space right after the existing block, it will allocate a brand-new block elsewhere, copy your data over, and free the old block — all internally. The pointer it returns can therefore be a completely different address from the one you passed in.
Never overwrite your only pointer directly
This means the following pattern is dangerous:

C
// WRONG: if realloc() fails, it returns NULL, and this line
// overwrites 'ptr' with NULL -- losing your only reference to the
// original block. That block is now leaked forever; you cannot free it.
ptr = realloc(ptr, new_size);
If realloc() fails, this statement assigns NULL straight into ptr, destroying the only pointer you had to the still-valid original block. You have now both failed to grow the memory and leaked the original allocation, with no way to free it.
The safe pattern is to assign the result to a temporary pointer first, check that for NULL, and only then update your real pointer:

C
// CORRECT: use a temporary variable
int *temp = realloc(ptr, new_size);

if (temp == NULL) {
    // realloc() failed -- 'ptr' is still valid and still points
    // to the original, unmodified block. Handle the error here,
    // e.g. by freeing 'ptr' and returning an error code.
    fprintf(stderr, "realloc failed\n");
    // ptr is still safe to use or free
} else {
    // Success -- it is now safe to overwrite ptr
    ptr = temp;
}
Growing a Dynamic Array: A Worked Example
Here is a small but complete program that starts with a small array and grows it with realloc() as more elements are added:

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

int main(void) {
    int capacity = 2;
    int count = 0;
    int *arr = malloc(capacity * sizeof(int));

    if (arr == NULL) {
        fprintf(stderr, "Initial allocation failed\n");
        return 1;
    }

    for (int i = 0; i < 6; i++) {
        if (count == capacity) {
            int new_capacity = capacity * 2; // double the capacity
            int *temp = realloc(arr, new_capacity * sizeof(int));

            if (temp == NULL) {
                fprintf(stderr, "realloc failed\n");
                free(arr); // arr is still valid -- clean it up
                return 1;
            }

            arr = temp;
            capacity = new_capacity;
        }

        arr[count] = i * i;
        count++;
    }

    for (int i = 0; i < count; i++) {
        printf("%d\n", arr[i]);
    }

    free(arr);
    return 0;
}
0
1
4
9
16
25
Correct vs Incorrect Pattern, Side by Side

Incorrect

Correct

ptr = realloc(ptr, size);

int *tmp = realloc(ptr, size); if (tmp) ptr = tmp;

On failure: original block leaked, ptr is now NULL

On failure: ptr untouched, still points to valid memory

Other realloc() Behaviors Worth Knowing
  • Calling realloc(ptr, 0) has historically been used to free the block, but its behavior is subtle and implementation-defined in newer standards -- prefer calling free() explicitly instead

  • Calling realloc(NULL, size) behaves exactly like malloc(size) -- useful if you want one code path that handles both the first allocation and later growth

  • Shrinking with realloc (new_size smaller than the current size) is allowed and typically succeeds, preserving the retained portion of the data

Growing by doubling, not by a fixed amount
In the example above, capacity is doubled each time it runs out rather than growing by a fixed number of elements. This amortized growth strategy is far more efficient for large arrays -- it is covered in detail on the Dynamic Arrays page.
  • realloc(ptr, new_size) resizes a block previously obtained from malloc/calloc/realloc

  • It may return a different address than the one you passed in -- never assume the block stayed in place

  • Always assign its result to a temporary pointer and check for NULL before overwriting your original pointer

  • On failure, the original block is untouched and still must eventually be freed