After this lesson, you will be able to: Manage memory: stack vs heap, malloc/calloc/realloc/free, detect leaks + use-after-free with Valgrind / ASan.
Memory management is C's superpower + biggest pitfall. Master it or every program is a future CVE.
Stack: function-local variables, automatic; allocated on call, freed on return. Fast; size-limited (~MB). Heap: malloc/calloc/realloc; you decide lifetime. Slower; size = virtual memory. Rule of thumb: small + short-lived = stack; large or shared-across-functions = heap.
The four heap primitives.
#include <stdlib.h>int *arr = malloc(100 * sizeof(int)); // 100 ints, UNINITIALIZEDif (arr == NULL) { perror("malloc"); exit(1); }int *zeros = calloc(100, sizeof(int)); // 100 ints, ZERO-INITIALIZEDif (zeros == NULL) { perror("calloc"); exit(1); }// Grow / shrinkint *bigger = realloc(arr, 200 * sizeof(int));if (bigger == NULL) { free(arr); exit(1); } // realloc may return NULL; original still validarr = bigger;// Always free what you allocatedfree(arr);free(zeros);arr = NULL; // optional but good practice, prevents use-after-free
Memory leak: allocated but never freed. Memory grows over time. Use-after-free: free a pointer; then read/write through it. May appear to work; data corruption later. Double free: free the same pointer twice. Heap corruption. Mitigations: free + set to NULL; pair each malloc with a free in the function; use ASan or Valgrind.
Mandatory tools for C devs.
# Valgrind (Linux; brew works on macOS)valgrind --leak-check=full --show-leak-kinds=all ./myprogram# Reports leaks + invalid reads/writes + uninitialized reads# AddressSanitizer (built into gcc + clang)gcc -fsanitize=address -g main.c -o main./main# Crashes the program at the bug site with a clear report# For undefined behavior: -fsanitize=undefined# For threading bugs: -fsanitize=thread# RULE: always run your test suite under -fsanitize=address,undefined.# Catches 90% of memory bugs before users see them.
malloc + not checking for NULL. Out-of-memory = crash on next deref. free a pointer not returned by malloc (e.g. an offset into an array). Heap corruption. Forgetting realloc returns a NEW pointer (or NULL). Always assign the result. Mixing malloc/free with C++'s new/delete. Each manages its own pool.
Pick the cleanest answer.
Sign in and purchase access to unlock this lesson.