Functions have addresses just like variables do, and C lets you store that address in a function pointer — a variable that can hold, pass around, and call a function indirectly.
#include <stdio.h>
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
typedef int (*Operation)(int, int); // named type for "function taking (int,int), returning int"
int compute(Operation op, int a, int b) {
return op(a, b); // calls whichever function was passed in
}
int main(void) {
printf("%d\n", compute(add, 5, 3)); // 8
printf("%d\n", compute(subtract, 5, 3)); // 2
return 0;
}
The syntax int (*Operation)(int, int) reads as "a pointer to a function taking two ints and returning int" — the parentheses around *Operation are required, since without them it would declare a function returning int* instead of a pointer to a function. A typedef like this makes function pointer types far more readable wherever they're used repeatedly.
Function pointers are the classic C mechanism for callbacks — passing behavior, not just data, into another function. The standard library's own qsort function uses exactly this pattern, taking a comparator function pointer so it can sort any data type according to caller-supplied logic:
int compareInts(const void *a, const void *b) {
return (*(const int*)a - *(const int*)b);
}
int nums[] = {5, 2, 8, 1};
qsort(nums, 4, sizeof(int), compareInts);