realloc(3)
C library function
Resizes a heap block and keeps its contents up to the smaller of the two sizes. On failure it returns NULL and leaves the old block allocated.
#include <stdlib.h>
void *realloc(void *ptr, size_t size);Description
realloc changes the size of a block that is already allocated. It can grow the block in place when there is room after it, or allocate a new one, copy the data over and free the old one. Either way, the C23 standard guarantees that the contents are preserved “up to the lesser of the new and old sizes”: if you grow the block, your old bytes are still there and the added bytes have indeterminate values; if you shrink it, the beginning is kept and the end is lost.
Two shortcuts are built into the function. realloc(NULL, size) behaves exactly like malloc(size). And, up to and including C17, realloc(ptr, 0) freed the block; C23 makes it undefined behavior, so stop using it to free memory and write free(3).
The address changes when the block moves. Every pointer that targeted the old location, including pointers into the block, is dead after a successful realloc.
Return value
The address of the resized block (sometimes the same as before, sometimes a new one), or NULL if the allocation fails. The key point: on failure, “the original block is left untouched; it is not freed or moved”. The old block is still valid, and still yours to free.
Pitfalls
p = realloc(p, n);loses the block ifreallocreturnsNULL: you have overwritten the only pointer to the old block, which is still allocated and now unreachable. Go through a temporary pointer.
p = realloc(p, n);if (p == NULL) return 1; /* the old block is lost */tmp = realloc(p, n);if (tmp == NULL) { free(p); /* p is still valid */ return 1;}p = tmp;Keeping an old pointer to the block after it moved: it points to freed memory.
Using
realloc(p, 0)to free: undefined behavior since C23, writefree(p).Forgetting that the bytes added when the block grows are not initialized.
mem_resize
Rewrite realloc as mem_resize, which is given the old size, moves the block to a buffer of the new size and keeps the bytes that fit.