Unlike some languages, C requires a function to be declared (its prototype known) before it's used — not necessarily fully defined yet.
int factorial(int n); // prototype: declares the signature, defined later
int main(void) {
printf("%d\n", factorial(5)); // 120 — legal because the prototype above is already known
return 0;
}
int factorial(int n) { // full definition
if (n <= 1) return 1; // base case — stops the recursion
return n * factorial(n - 1); // recursive case — calls itself with a smaller problem
}
A prototype tells the compiler a function's name, return type, and parameter types in advance, which is why main can call factorial even though the full definition appears later in the file — without it, the compiler wouldn't know if the call is valid. In multi-file projects, prototypes typically live in header (.h) files, shared across every .c file that needs to call the function.
Recursion — a function calling itself — always needs a base case that stops the recursion (n <= 1 above) and a recursive case that moves measurably closer to that base case; without both, the function recurses forever, eventually crashing with a stack overflow once it exhausts the call stack. Recursion often produces clearer code for naturally recursive problems (tree traversal, factorial, Fibonacci), but iterative loops are usually faster and more memory-efficient in C, since each recursive call consumes additional stack space.