Recursive Factorial in C – How fact(5) Unwinds to 120

A function that calls itself, a one-line ternary, and five stack frames deep of multiplication — recursive factorial is the “hello world” of recursion, and this question from our C Programming Quiz App checks that you can actually trace it, because every wrong option is a factorial of something — just not the right thing.

The Quiz Question

int fact(int n) {
    return n <= 1 ? 1 : n * fact(n - 1);
}
printf("%d", fact(5));

What is printed by this code?

  1. 60
  2. 120
  3. 24
  4. Compile error

The Correct Answer: 120

Each call either hits the base case (n <= 1 returns 1) or multiplies n by the factorial of n - 1. The calls descend to the base case and the multiplications happen on the way back up:

fact(5) = 5 * fact(4)
        = 5 * (4 * fact(3))
        = 5 * (4 * (3 * fact(2)))
        = 5 * (4 * (3 * (2 * fact(1))))
        = 5 * (4 * (3 * (2 * 1)))
        = 5 * 4 * 3 * 2 * 1 = 120

Verified on gcc 13.3 and Apple clang 21, clean under -ansi -Wall -Wextra:

$ gcc -ansi -Wall -Wextra fact.c && ./a.out
fact(1) = 1
fact(2) = 2
fact(3) = 6
fact(4) = 24
fact(5) = 120

Why Each Wrong Answer Is Wrong

Why not 60?

60 is 5 × 4 × 3 — the trace cut off two levels early, as if the base case fired at n = 2. But n <= 1 is false for 2, so fact(2) still recurses: 2 * fact(1) = 2. Miscounting where the recursion bottoms out is the most common tracing slip.

Why not 24?

24 is fact(4) — an off-by-one at the top instead of the bottom, treating fact(5) as “multiply the numbers below 5”. The first frame contributes its own n: five frames, factors 5·4·3·2·1.

Why not a compile error?

Two suspicions might drive this pick, and both are unfounded. A function may call itself with no special ceremony — by the time the body is compiled, fact is already declared (its own definition’s declarator does that). And the ternary operator is an expression, so it’s perfectly at home in a return. Both compilers accept it silently with all warnings on.

How the Recursion Actually Executes

Each call gets its own stack frame with its own n — that’s why the five simultaneous ns (5, 4, 3, 2, 1) don’t interfere. This is also the flip side of the pass-by-value rule: fact(n - 1) passes a fresh copy downward and leaves the current frame’s n intact for the multiplication that happens after the recursive call returns.

Two limits are worth knowing before using this in real code. Overflow comes shockingly early: factorials grow faster than exponentials, and a 32-bit int holds only up to fact(12):

fact(12) = 479001600      /* fits            */
fact(13) = 1932053504     /* overflowed! (UB) */

(13! is actually 6,227,020,800 — the printed value is wraparound garbage, and signed overflow is undefined behavior, so even the garbage isn’t guaranteed.) Stack depth is the other limit — linear in n here, which is harmless for fact(5) but the reason deep recursions get rewritten as loops. For factorial specifically, the iterative version is a three-line for loop — see our full factorial program and the recursion guide for when each style wins.

Frequently Asked Questions

How does fact(5) compute 120?

Five stacked calls descend to the base case fact(1) = 1, then the returns multiply back up: 2·1, 3·2, 4·6, 5·24 = 120.

Can a C function call itself?

Yes — recursion needs no special syntax or declaration. Each call gets an independent stack frame with its own copies of the parameters and locals.

What is the largest factorial that fits in an int?

fact(12) = 479,001,600. fact(13) exceeds 2³¹−1 and overflows — and since signed overflow is undefined behavior in C, the result isn’t merely wrong but unreliable. Use unsigned long long (up to 20!) or a big-number library beyond that.

Related Reading

Recommended Books

This question is #152 in the C Programming Quiz App — 155 questions with explanations covering functions, pointers, memory, and more.
Download on Google Play →

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>