The confusion
You declare a variable and it works. You call malloc() and it works.
Both give you memory. So why are they different things?
Because they have completely different lifetimes, sizes, and ownership rules. Confuse them and you get memory leaks, dangling pointers, and stack overflows. Understand them and the rest of C becomes predictable.
The stack
Every local variable you declare lives on the stack. When you call a function, the CPU pushes a new frame onto the stack. When that function returns, the frame is popped and the memory is automatically reclaimed. You never free it. You can't forget to free it. It's not your job.
The trade-off: the stack is fixed-size. On most Linux systems, 8 MB by default. Declare a 10 MB array on the stack and your program crashes immediately — a stack overflow.
The heap
The heap is where you go when you need memory that outlives the current function,
or when you don't know the size at compile time.
You request it with malloc().
You release it with free().
If you forget the free(), that memory is gone for the lifetime of
your program — a memory leak.
free(ptr),
the pointer variable still holds the old address. Reading from it is
undefined behavior. Set it to NULL immediately after freeing.
Watch it happen
Step through the visualization below. Watch the heap blocks appear and disappear. Notice what happens to the stack pointer variable when the heap block is freed.
The rules
- Automatic — no malloc, no free
- Limited size (~8 MB)
- Fast allocation (move a register)
- Lifetime = function scope
- Local variables, function args
- Manual — you malloc, you free
- Limited only by RAM
- Slower (syscall, bookkeeping)
- Lifetime = until you free it
- Dynamic sizes, long-lived data
Stack memory manages itself. Heap memory does exactly what you tell it — nothing more.