C Function Pointers, Callbacks & Event-Driven Architecture Masterclass
Welcome to Phase 10 (Chapter 26): C Function Pointers, Callbacks & Event-Driven Architecture Masterclass! In high-level computer science, higher-order functions (functions that accept other functions as arguments) form the backbone of modern event-driven architectures, GUI button listeners, network packet hooks, and sorting algorithms. In C, Function Pointers enable higher-order callback programming directly in hardware machine code. In this exhaustive textbook-grade guide, you will master the syntax of function pointer parameters, build generic callback filter engines, implement standard C library qsort comparators, and construct high-speed $O(1)$ Jump Table state machines.
A Callback is a function that is passed as an argument to another function, with the expectation that the receiving function will "call back" (execute) that logic at the appropriate time:
1. [ main() ] โโ Passes Pointer to isEven() Function โโโบ [ filterArray() ]
โ
2. [ filterArray() Loop ] โโ Calls isEven(element) โโโโโโโโโโ
โโโ Returns true/false
3. [ filterArray() ] โโโโโโ If true: Appends element to output buffer!
#include <stdio.h>
#include <stdbool.h>
// Predicate Callbacks
bool isEven(int n) { return n % 2 == 0; }
bool isPositive(int n) { return n > 0; }
// Generic Higher-Order Filter: accepts function pointer predicate!
void filterAndPrint(const int arr[], int size, bool (*predicate)(int), const char* label) {
printf("%s: [ ", label);
for (int i = 0; i < size; i++) {
if (predicate(arr[i])) {
printf("%d ", arr[i]);
}
}
printf("]\n");
}
int main(void) {
int numbers[] = {-10, 15, 22, -3, 40, 7, -8, 50};
int size = sizeof(numbers) / sizeof(numbers[0]);
// Passing isEven callback
filterAndPrint(numbers, size, isEven, "Even Numbers");
// Passing isPositive callback
filterAndPrint(numbers, size, isPositive, "Positive Numbers");
return 0;
}
Instead of using slow, lengthy if-else ladders or large switch blocks, high-performance operating systems (such as Linux syscall dispatchers) store function pointers inside an Array of Function Pointers (Jump Table) for instantaneous $O(1)$ constant-time execution:
โก Jump Table Blueprint:
int (*operationTable[4])(int, int) = {add, subtract, multiply, divide};
Calling operationTable[opcode](a, b) jumps directly to the target CPU instruction address in a single clock cycle!
Q1: How do we simplify complex function pointer syntax using typedef?
You can create a clean alias using: typedef bool (*Predicate)(int);. Now your function parameter simply becomes: void filter(const int arr[], int size, Predicate pred);, drastically improving code readability!
Q2: How does the standard C qsort() function use callbacks?
qsort is completely agnostic of what data type it sorts. It accepts a generic comparator callback: int (*compar)(const void*, const void*). By returning negative, zero, or positive integers, your callback tells qsort how to order custom structs, strings, or numbers.
Run this callback math engine in our live GCC compiler:
#include <stdio.h>
int doubleVal(int x) { return x * 2; }
int tripleVal(int x) { return x * 3; }
void transform(int *arr, int size, int (*func)(int)) {
for (int i = 0; i < size; i++) arr[i] = func(arr[i]);
}
int main(void) {
int data[] = {1, 2, 3, 4};
transform(data, 4, doubleVal);
for (int i = 0; i < 4; i++) printf("%d ", data[i]);
printf("\n");
return 0;
}