Skills101

C Programming · Lesson 4 of 10 · Updated ·

Functions and Recursion in C — Prototypes, Call by Value, Storage Classes

A function is a named block of code that does one job. C programs are built from many small functions.

1. Declare, define, call

#include <stdio.h>

int square(int n);              /* prototype (declaration) */

int main(void) {
    printf("%d %d\n", square(4), square(square(2)));
    return 0;
}

int square(int n) {             /* definition */
    return n * n;
}
16 16
  • The prototype tells the compiler the function's name, return type and parameters before it's used.
  • A function that returns nothing has return type void.

2. Call by value (C's only way)

Calling swap(a, b) copies the values into x and y, so swapping the copies leaves a and b unchanged; calling swap(&a, &b) passes addresses, so the function changes the originals through pointers

C copies each argument into the parameter. Changing the parameter doesn't change the caller's variable:

#include <stdio.h>

void broken_swap(int x, int y) { int t = x; x = y; y = t; }
void swap(int *x, int *y) { int t = *x; *x = *y; *y = t; }

int main(void) {
    int a = 5, b = 9;
    broken_swap(a, b);
    printf("after broken_swap: %d %d\n", a, b);
    swap(&a, &b);
    printf("after swap:        %d %d\n", a, b);
    return 0;
}
after broken_swap: 5 9
after swap:        9 5

To let a function change the caller's variable, pass its address (a pointer). This is often called "call by reference", but technically C copies the pointer — still pass-by-value.

3. Recursion

A recursive function calls itself. It needs:

  1. a base case that stops, and
  2. a smaller step towards it.
#include <stdio.h>

long long factorial(int n) {
    if (n <= 1) return 1;            /* base case */
    return n * factorial(n - 1);     /* smaller step */
}

int fib(int n) {
    if (n < 2) return n;
    return fib(n - 1) + fib(n - 2);
}

int sum_digits(int n) {
    if (n == 0) return 0;
    return n % 10 + sum_digits(n / 10);
}

int main(void) {
    printf("%lld %d %d\n", factorial(10), fib(10), sum_digits(9875));
    return 0;
}
3628800 55 29

Each call gets its own stack frame. Too deep recursion → stack overflow (crash). Plain recursive fib is slow (exponential) — fine for learning, use a loop for big n.

4. Storage classes

ClassWhere it livesLifetimeDefault valueExample use
auto (default for locals)stackthe function callgarbagenormal local variables
static (local)data segmentwhole program0counting calls
externdata segmentwhole program0a global defined in another file
registerCPU register (a hint)the blockgarbageloop counters (compilers ignore it today)

static keeps its value between calls

#include <stdio.h>

void visit(void) {
    static int count = 0;   /* initialised once */
    int normal = 0;         /* reset every call */
    count++; normal++;
    printf("count=%d normal=%d\n", count, normal);
}

int main(void) {
    visit(); visit(); visit();
    return 0;
}
count=1 normal=1
count=2 normal=1
count=3 normal=1

5. Scope

  • Local variables exist only inside their block { }.
  • Global variables (outside all functions) are visible everywhere in the file — use sparingly.
  • An inner variable with the same name hides the outer one.

Common mistakes

  • Calling a function before declaring it (add a prototype).
  • Recursion without a base case → infinite recursion → crash.
  • Expecting a normal (non-pointer) parameter to change the caller's variable.

Quick recap

  • Prototype → definition → call; void for no return value.
  • C copies arguments; pass addresses (pointers) to modify the caller's data.
  • Recursion = base case + smaller step.
  • static locals keep their value across calls and start at 0.

Practice what you learned

📝 Quiz: C Functions and Recursion5 questions · instant answers & explanations · +10 XP · counts towards your free certificateTake the quiz →