1#include <iostream>2int square(int x) {3 int y = x * x;4 return y;5}6int main() {7 int a = 3;8 int b = square(a);9 std::cout << b << '\n';10}main()a?b?square()x?y?933999SP
Violet card: the program (square.cpp)Sand slabs: stack frames, one per running call; slate blocks: the slots for local variablesKhaki tokens: a value being written or copiedPink SP flag (step 9): the stack pointer, which marks the top of the stackLeft: the program square.cpp. Middle: the call stack, a pile of frames. Front right: the output. main's frame holds the slots for a and b. Calling square pushes a second frame on top, with slots for x and y; the argument is copied into x, and the return value is copied back into b. When square returns its frame is popped, and x and y are gone. The C++ standard does not use the word stack: it says local variables have automatic storage duration, created when their block starts and destroyed when it ends. Every mainstream compiler keeps them in a call stack, though the optimiser may keep some only in CPU registers.

main's frame

  1. The program starts in main. First, main gets a frame: a block of memory on the stack with one slot for each local variable, a and b. Nothing has been stored in them yet.

Calling square

Returning

What happens

;; step 1/10 · main-frame
the stack: memory for the functions that are running
a frame:   one function call's local variables
push main's frame   slots for a and b
a = ?   b = ?   no value written yet: never read them

stack (top first)
  main   a = ?   b = ?

The C++ standard does not use the word stack: it says local variables have automatic storage duration, created when their block starts and destroyed when it ends. Every mainstream compiler keeps them in a call stack, though the optimiser may keep some only in CPU registers. The figure piles frames upward, like plates. In real memory the stack on x86-64 and ARM grows toward lower addresses, and a frame also holds the return address and saved registers.