CFunction Prototypes

Function Prototypes

A function prototype is a declaration that tells the compiler a function's return type and the type of each parameter, without providing the function's body. Prototypes are how the compiler checks that every call to a function is consistent with how the function is actually defined.

Anatomy of a Prototype

A prototype

C
int add(int a, int b); // parameter names 'a' and 'b' are optional here

int add(int, int);     // this is equally valid — only the types matter

Parameter names in a prototype are purely documentation for whoever reads the code — the compiler only cares about the types and their order. Most style guides keep the names anyway, since int add(int, int); tells a reader far less than int add(int a, int b);.

Why Prototypes Matter

Without a prototype visible before a call, the compiler has nothing to check the call against. With one, it can catch real bugs the moment you compile, instead of letting them become runtime surprises.

A prototype catches a type mismatch

C
#include <stdio.h>

double area(double width, double height); // prototype

int main(void) {
    // Compiler knows area() expects two doubles, and warns/errors here:
    printf("%f\n", area("oops", 5));
    return 0;
}

double area(double width, double height) {
    return width * height;
}
Forward Declaring Within a File

If you want to call a function before its definition appears later in the same file — often to keep main near the top for readability — place a prototype above the first use.

Forward declaration in a single file

C
#include <stdio.h>

int factorial(int n); // forward declaration

int main(void) {
    printf("5! = %d\n", factorial(5)); // OK: prototype seen above
    return 0;
}

int factorial(int n) { // definition comes after main
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}
void Means "No Arguments"

Writing void inside the parentheses explicitly tells the compiler the function takes no parameters at all.

No parameters, correctly declared

C
int getRandomNumber(void); // takes no arguments — enforced by the compiler

int main(void) {
    int n = getRandomNumber();
    // getRandomNumber(5); // compiler error: too many arguments
    return 0;
}
int f() is NOT the same as int f(void)
This is a genuine, C-specific gotcha. In old-style (pre-ANSI) C, an empty parameter list like `int f()` meant "this function takes an unspecified number of arguments of unspecified types" — it disabled argument checking entirely. `int f()` is legal C even today for backward compatibility, but it gives up all the safety a prototype is supposed to provide: the compiler will happily let you call `f(1, 2, "three")` without complaint. `int f(void)` is the modern, explicit, and safe way to say "this function takes no arguments" — always prefer it.

Form

Meaning

Recommended?

int f(void)

Takes exactly zero arguments (checked by compiler)

Yes

int f()

Old-style: unspecified arguments, no checking

No

int f(int a, int b)

Takes exactly two ints (checked by compiler)

Yes

  • A prototype declares the return type and parameter types so the compiler can check calls.

  • Parameter names in a prototype are optional and purely documentation.

  • Use (void) for a function that intentionally takes no arguments.

  • Avoid empty () parameter lists in new code — they disable type checking.

Prototypes and headers
In multi-file programs, prototypes are typically written once in a header file and shared by every `.c` file that needs to call the function, which keeps every caller checked against the same signature.
Next: recursion
With declarations, definitions, parameters, and return values covered, the next page explores recursion — functions that call themselves.