student@ubuntu:~$
pointers-memory Lesson 7 9 min read

Stack, Heap & Memory Layout

How your program's memory is organized — and why it matters for every pointer you write

Reading: Hanly & Koffman: §13.2 (pp. 711–716)

Quick check before you start: Can you draw a box for “stack” and a box for “heap” and say which grows up vs. down? If yes, skip to Stack Frames. If not, read on.

Practice this topic: Memory Layout skill drill

After this lesson, you will be able to:

  • Name the five segments of a C program’s memory layout
  • Explain the difference between stack and heap lifetime
  • Describe what a stack frame contains
  • Distinguish where local, global, and dynamically allocated variables live

The Five Memory Segments

When the OS loads your compiled C program, it carves out five regions of virtual memory:

Segment Contents Lifetime
Text Machine code (your compiled instructions) Entire program
Data Initialized global/static variables Entire program
BSS Uninitialized global/static variables (zeroed) Entire program
Stack Local variables, function parameters, return addresses Per function call
Heap Dynamically allocated memory (calloc, realloc) Until you free it

The text segment is read-only. The data and BSS segments are fixed at load time. The stack and heap are where the action happens at runtime.

High address
┌──────────────┐
│    Stack      │  ← grows downward
│      ↓        │
│              │
│      ↑        │
│    Heap       │  ← grows upward
├──────────────┤
│    BSS        │
├──────────────┤
│    Data       │
├──────────────┤
│    Text       │
└──────────────┘
Low address

Stack Frames

Every time you call a function, the system pushes a stack frame onto the stack. That frame holds:

  1. The function’s local variables
  2. The parameters passed to the function
  3. The return address (where to go back after the function ends)

When the function returns, the frame is popped. The memory is gone. This is why returning a pointer to a local variable is a bug — the memory it points to no longer belongs to you.

int* broken(void) {
    int x = 42;
    return &x;  // WARNING: x dies when broken() returns
}

Your compiler will warn you about this. Listen to it.

Local vs. Global Variables

A local variable lives on the stack inside its function’s frame. It is created when the function is called and destroyed when the function returns.

A global variable lives in the data or BSS segment. It exists for the entire program. If you initialize it (int count = 10;), it goes in data. If you do not (int count;), it goes in BSS and is automatically zeroed.

Stack vs. Heap Lifetime

This is the core distinction:

  • Stack memory is automatic. You do not allocate it or free it. It disappears when the function returns.
  • Heap memory is manual. You allocate it with calloc and you must free it with free. It survives until you say otherwise.

In Java, the garbage collector handles heap cleanup. In C, you are the garbage collector.

void example(void) {
    int local = 5;            // stack — dies at }
    int *heap = calloc(1, sizeof(int));  // heap — lives until free()
    *heap = 5;
    free(heap);               // now it dies
}

If you forget free(heap), that memory leaks. The OS reclaims it when your program exits, but in a long-running program (a server, a game), leaks accumulate and eventually crash the process.


Check Your Understanding
Where are local variables stored in a C program's memory?
AIn the data segment
BIn the heap
COn the stack, inside the function's stack frame
DIn the BSS segment
Answer: C. Local variables are part of the function's stack frame. They are created when the function is called and destroyed when it returns. Global variables go in data or BSS. Heap memory is only created by explicit allocation calls like calloc.

What Comes Next

You know where memory lives. Next, you will learn how to allocate and free heap memory yourself using calloc, realloc, and free.

Next: calloc, realloc & free