Trace factorial(5) — what actually happens on the call stack?
Five calls descend to factorial(0), which returns 1 without recursing; then the results are multiplied back up on the way out: 1, 1, 2, 6, 24, 120.
* The descent only stacks frames — every multiplication happens on the way back up. *
static int factorial(int n) {
if (n == 0) return 1; // base case
else return n * factorial(n-1); // recursive case
}
Descent — each call suspends itself mid-expression and waits: factorial(5) needs factorial(4), which needs factorial(3) … down to factorial(0). At the bottom, five frames are stacked up, each holding its own n and each parked at the same multiplication.
Ascent — factorial(0) returns 1 outright, and every suspended frame resumes, multiplies and returns:
| Frame | computes | returns |
|---|---|---|
factorial(0) |
base case | 1 |
factorial(1) |
$1 \times 1$ | 1 |
factorial(2) |
$2 \times 1$ | 2 |
factorial(3) |
$3 \times 2$ | 6 |
factorial(4) |
$4 \times 6$ | 24 |
factorial(5) |
$5 \times 24$ | 120 |
The point worth internalising is that the multiplications happen on the way back up, not on the way down. Nothing is computed during the descent — it only builds the stack of pending work. That is why a deep recursion consumes memory proportional to its depth: all $n$ frames are alive at once, each one holding a multiplication it has not yet been able to perform.
Go deeper:
Python Tutor — step through the call stack — run the recursion and watch the frames pile up and unwind, in Python or Java.
Factorial — why 0! = 1 — the empty-product argument behind the base case.