← Pointers and MemoryC PROGRAMMING 1.2.F

Dynamic Memory

Stack vs heap, malloc/free, NULL checks, leaks, use-after-free, double free, calloc, realloc.

StatusCollected
NotesChapter test: 5/5

Eleven pieces, and this is the chapter where memory management stops being automatic. Everything before this lived on the stack and cleaned itself up; from here on, anything malloc'd is my responsibility to free, exactly once, at the right time.

Stack vs heap

  • Stack — automatic, fast, and small. Local variables live here and vanish the instant their scope ends.
  • Heap — manual, larger, and persists until explicitly freed. Anything that needs to outlive the function that created it, or whose size isn't known until runtime, goes here.

malloc, NULL checks, and free

int *arr = malloc(10 * sizeof(int));
if (arr == NULL) {
    return -1;            /* allocation failed — never assume it succeeded */
}

arr[0] = 42;
free(arr);
arr = NULL;                /* set to NULL after freeing — see below */

malloc can fail and return NULL, and dereferencing that NULL is exactly as bad as any other NULL dereference. Every malloc gets checked before use, no exceptions.

The three ways to get this wrong

MistakeWhat happens
Leakfree() never called — the memory stays reserved for the life of the program, unreachable once the last pointer to it is gone.
Use-after-freethe memory is freed, then read or written anyway — it might still look fine by luck, or it might already belong to something else.
Double freefree() called twice on the same pointer — corrupts the allocator's internal bookkeeping, often crashes somewhere completely unrelated later.

Setting a pointer to NULL immediately after freeing it turns a potential use-after-free into a clean, checkable NULL dereference instead of silent corruption — cheap insurance.

calloc and realloc

  • calloc(n, size) — like malloc, but zero-initializes the memory and takes count and element size separately instead of one total.
  • realloc(ptr, new_size) — resizes an existing allocation, possibly moving it; the return value always gets reassigned, since the original pointer can become invalid.

Notes from readers

Comments — via GitHub