🧮 Foundations — Before C
Where data lives: stack, heap & friends
▶ Open the interactive lesson — free, no signupThe most famous programming site on the internet is named after a crash — Stack Overflow — and you're about to find out precisely what that crash is. Your program's memory is split into a few neighborhoods with different rules, and the classic C disasters (leaks, overflows, using memory that's already gone) are simply those rules being broken. Learn the map now, and those bugs will make sense before you ever hit one.
To master C — a language famous for letting you touch memory directly — you first need a map of that memory. When your program runs, the OS hands it one big private stretch of memory — its address space — divided into segments, regions that each play by different rules:
▶ This spot has an interactive memmap widget — open the interactive lesson to play with it.
The stack: fast, automatic, small
Every function call pushes a stack frame holding its local variables and where to return to. When the function returns, the frame is popped — locals die automatically. It's blazingly fast (just moving one pointer) but limited (typically ~8 MB).
#include <stdio.h>
int square(int n) { /* n lives in square's frame */
int result = n * n; /* result too */
return result; /* frame destroyed on return */
}
int main(void) {
int x = 7; /* x lives in main's frame */
printf("%d\n", square(x));
return 0;
}Each call to square gets a fresh n. Recursion works because each level has its own frame — and infinite recursion gives the segment its famous crash: stack overflow.
🧠 Checkpoint: What happens to a function’s local variables when it returns?
- They are freed by the garbage collector
- Their stack frame is popped — they cease to exist
- They move to the heap
- They keep their values for the next call
Show answer
Their stack frame is popped — they cease to exist — The stack pointer simply moves back — the memory isn’t even wiped, it’s just up for grabs by the next call. C has no garbage collector.
The heap: big, manual, yours to manage
Need memory that outlives the function that made it, or whose size you only know at runtime? That's the heap: you ask with malloc, you give back with free. Nothing is automatic — forget to free and you leak; free twice and you corrupt. (Full lesson in Part 2.)
Static storage: there the whole time
Globals and static variables live in .data (if initialized) or .bss (zero-initialized — costs nothing in the executable file!). They exist from before main starts until the program exits.
#include <stdio.h>
#include <stdlib.h>
int counter = 42; /* .data — initialized global */
int zeros[1000]; /* .bss — auto zero-filled */
int main(void) {
int local = 1; /* stack */
int *dyn = malloc(4); /* dyn on stack, target on heap */
static int calls = 0; /* .data — survives across calls */
printf("global: %p\n", (void *)&counter);
printf("stack : %p\n", (void *)&local);
printf("heap : %p\n", (void *)dyn);
free(dyn);
return 0;
}$ gcc segments.c -o segments && ./segments global: 0x55d1c9e0a010 stack : 0x7ffd4a1b2a94 heap : 0x55d1cb2426b0 # stack addresses are way up high; globals & heap much lower
🧠 Checkpoint: Where does static int hits = 0; inside a function live?
- On the stack, like other locals
- On the heap
- In static storage (.data/.bss) — it survives between calls
- In the CPU cache
Show answer
In static storage (.data/.bss) — it survives between calls — static changes the storage, not the visibility: it’s still only nameable inside the function, but it lives in static storage for the whole program lifetime.
The #1 beginner crash: returning a pointer to a local variable. The variable's stack frame is gone the moment the function returns — the pointer now points at a ghost. Compilers warn about this; never ignore that warning.
int *broken(void) {
int x = 42;
return &x; /* ⚠ warning: address of local returned */
} /* x dies here — the pointer dangles! */🧠 Checkpoint: Why is return &x; (x being a local) broken?
- You can’t take addresses of ints
- x’s memory is reclaimed when the function returns
- The compiler deletes unused variables
- Pointers can’t leave functions
Show answer
x’s memory is reclaimed when the function returns — The frame is popped; the address now points into dead stack space that the very next function call will overwrite. Reading it is undefined behavior.
🎉 That's the foundations done! You now know how machines count, store, and execute. Time to actually write some C.
▶ Practice this lesson interactively (with live gcc)