Dynamic Memory Management
This domain focuses on the contract of each allocation function, the four ways heap code goes wrong (leak, double free, use-after-free, out-of-bounds access), and how to handle allocation failure correctly.
The allocator interface
void *malloc(size_t n)returns uninitialized memory, suitably aligned for any type, orNULL.void *calloc(size_t n, size_t size)zeroes the block and performs the multiplication for you.void *realloc(void *p, size_t n)may move the block. On success the old pointer is invalid; on failure it returnsNULLand leavespuntouched.realloc(p, 0)is implementation-defined (it may free or return a minimal block).void free(void *p)acceptsNULLand does nothing; any other pointer must have come from an allocation function.freecannot set the caller's pointer toNULL.
Correct patterns
- Check every allocation for
NULL, and include<stdlib.h>so the prototype is visible - in C99 and later, a cast cannot rescue a missing declaration. - Write
p = malloc(n * sizeof *p)to keep the element type in one place, and guard the multiplication against overflow (or usecalloc). - Use a temporary for
realloc, and release resources on every error path.
Worked example
int *grow(int *a, size_t n) {
int *tmp = realloc(a, n * sizeof *a);
if (tmp == NULL) {
free(a); /* only if ownership passes to this function */
return NULL;
}
return tmp;
}
Assigning realloc(...) straight back to a would leak the original block when realloc returns NULL: a would be overwritten with NULL and the old pointer lost. Here the failure path is explicit and the caller can decide what to do. After a successful realloc, the old pointer must never be used again.
Traps
free(p); free(p);andfree(p); p->x = 1;are undefined; set the pointer toNULLafter freeing if it may be reused.- Freeing an address the allocator never returned (a local variable, or
p + 1). - Writing
sizeof(ptr)instead ofsizeof *ptrin the size expression. - Assuming
mallocor the new part of areallocblock is zeroed; onlycallocguarantees zeros. - Leaking the block when an early
returnskips thefree. - Depending on
strdup, which is POSIX rather than ISO C.