Pointers & Memory · intermediate · ~12 min
Allocate memory whose size is only known at runtime.
malloc(n) asks the operating system for n bytes of heap memory and returns a pointer to it (or NULL if the allocation failed). The memory's contents are uninitialised. When you're done, you must call free(p) exactly once. Forget, and you have a memory leak; do it twice, and you have a double-free crash.
Stack variables are fixed in size at compile time. The moment your program needs a variable-sized buffer — a string of user-typed length, an array of N items where N is read at runtime, a tree of unknown shape — you need heap allocation. Every dynamic data structure in C builds on malloc and free.
Heap vs stack. The stack is per-function, automatic, fast, fixed-size; the heap is process-wide, manual, slower, grown by syscalls. Ownership. Every malloc must have exactly one matching free. Document who owns each pointer — comments like // caller frees save lives. Alignment. malloc returns a pointer suitable for any type's alignment; you can cast it to whatever you need.
int *a = malloc(100 * sizeof(int)); // 100 ints, uninitialised
if (!a) { /* allocation failed */ } // always check
a[0] = 42;
free(a); // exactly once
a = NULL; // belt-and-braces — prevents UAF later
void *malloc(size_t n) returns a pointer to n bytes of uninitialized memory on the heap, or NULL on failure. You must free it later or you leak.
Always check the return value, multiply correctly (malloc(n * sizeof(T))), and remember that the contents are garbage until you write to them.
int *a = malloc(10 * sizeof(int));
if (!a) return -1;
for (int i = 0; i < 10; i++) a[i] = i;
free(a);
sizeof(T) — allocates way too little.(int*)malloc(...) is unnecessary in C and can mask #include mistakes.Run under valgrind ./a.out to find leaks (memory you never freed) and invalid reads/writes. Compile with -fsanitize=address for a faster but slightly less detailed leak detector. If your program seems to slow down over time, you probably have a leak — every malloc that never gets freed permanently grows your process's footprint.
(1) Always check malloc's return for NULL — out-of-memory is rare but real. (2) Track ownership: who must free this pointer? Comment it. (3) Free exactly once: a double-free corrupts the allocator's bookkeeping and crashes (or worse, silently overlaps two allocations). (4) Treat the buffer as uninitialised — use calloc(n, sz) if you want zeroed memory.
Dynamic arrays, linked lists, trees, strings of unknown length, parsed JSON / XML trees, hash tables, every game engine's per-frame object pool.
malloc(strlen(src)+1) and strcpy into it. 3. Make a function that returns a malloc'd buffer the caller must free; document ownership in a comment.malloc gives you variable-size memory; free returns it. Every malloc has exactly one free. Check the return value, set freed pointers to NULL, and document ownership. Master these habits and the heap is a tool, not a trap.