Pass functions as data. Essential for qsort, callbacks, and dispatch tables.
typedef to give the type a readable nameqsort covers most real-world needsint (*fp)(int) means "fp is a pointer to a function that takes an int and returns an int."
#include <stdio.h> int square(int x) { return x * x; } int main(void) { // fp points to "a function taking int, returning int" int (*fp)(int) = square; // function name decays to its address printf("%d\n", fp(5)); // 25 printf("%d\n", (*fp)(5)); // 25, older style return 0; }
fp = square and fp = &square are equivalent, and so are fp(5) and (*fp)(5).fp(*fp) β fp is a pointer(int, int) β to a function that takes two intsint β and returns an intints and returns an int"
int *fp(int); // β NOT a function pointer // it's the prototype of a function returning int* int (*fp)(int); // β function pointer
typedef int (*CmpFn)(const void *, const void *); void sort(int *a, int n, CmpFn cmp) { /* ... */ }
typedef turns the whole messy type into a single name. Once CmpFn is defined, CmpFn x; declares a function pointer.#include <stdio.h> void for_each(int *a, int n, void (*fn)(int)) { for (int i = 0; i < n; i++) fn(a[i]); } void print_int(int v) { printf("%d ", v); } void print_square(int v) { printf("%d ", v * v); } int main(void) { int a[] = {1, 2, 3, 4, 5}; for_each(a, 5, print_int); printf("\n"); for_each(a, 5, print_square); printf("\n"); return 0; }
qsort takes a comparison function as a function pointer, which means it can sort any type β ints, strings, structs, you name it.void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
#include <stdio.h> #include <stdlib.h> int cmp_int_asc(const void *p1, const void *p2) { int a = *(const int *)p1; int b = *(const int *)p2; if (a < b) return -1; if (a > b) return 1; return 0; } int main(void) { int a[] = {5, 2, 8, 1, 9, 3}; qsort(a, 6, sizeof(int), cmp_int_asc); for (int i = 0; i < 6; i++) printf("%d ", a[i]); // 1 2 3 5 8 9 }
return a - b; looks like it works, but it can overflow for large or negative values. Always compare and return -1, 0, or 1.struct Student { char name[32]; int score; }; // higher score first, ties broken by name int cmp_student(const void *p1, const void *p2) { const struct Student *a = p1; const struct Student *b = p2; if (a->score != b->score) return (b->score > a->score) ? 1 : -1; return strcmp(a->name, b->name); } qsort(students, n, sizeof(struct Student), cmp_student);
switch, use an array of function pointers for clean, data-driven code:#include <stdio.h> double op_add(double a, double b) { return a + b; } double op_sub(double a, double b) { return a - b; } double op_mul(double a, double b) { return a * b; } double op_div(double a, double b) { return b != 0 ? a / b : 0; } struct OpEntry { char sym; double (*fn)(double, double); }; static const struct OpEntry ops[] = { {'+', op_add}, {'-', op_sub}, {'*', op_mul}, {'/', op_div}, }; double calc(char op, double a, double b) { for (int i = 0; i < sizeof(ops) / sizeof(ops[0]); i++) { if (ops[i].sym == op) return ops[i].fn(a, b); } return 0; } int main(void) { printf("%.2f\n", calc('+', 3, 4)); printf("%.2f\n", calc('*', 6, 7)); }
int array in descending order.char *words[] = {"banana","apple","cherry"}; alphabetically. Note that the comparator receives const char **.int filter(int *a, int n, int *out, int (*pred)(int)). It should copy every element for which pred returns non-zero. Test it with an even-number predicate.Check your understanding of this lesson!
int (*fp)(int) declare?The parentheses group *fp together, so it reads as "fp is a pointer to a function." Without them, int *fp(int) means something entirely different.
qsort comparison function?qsort has to handle arbitrary types, so the arguments come in as const void *. Cast them back to the actual type inside the comparison function.
fp?In C, you can call a function pointer just like a regular function name, using (). The older explicit-dereference style (*fp)(...) is equivalent.