Function Pointers
Passing behavior as data — C's version of callbacks and lambdas
Quick check before you start: In Java, you can pass a
ComparatortoCollections.sort(). That is a function pointer in disguise. Read on to see how C does it without objects.Practice this topic: Function Pointers skill drill
After this lesson, you will be able to:
- Declare a function pointer variable
- Use
typedefto create readable function pointer aliases - Write a comparator callback for sorting
- Use
qsortfrom the C standard library
Declaration Syntax
A function pointer stores the address of a function. The syntax is notoriously ugly:
int (*compare)(int, int);
Read it from the inside out: compare is a pointer to a function that takes two int parameters and returns an int.
The parentheses around *compare are critical. Without them, int *compare(int, int) declares a function that returns int* — a completely different thing.
Assigning and Calling
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int (*op)(int, int);
op = add;
printf("%d\n", op(3, 4)); // prints 7
op = sub;
printf("%d\n", op(3, 4)); // prints -1
The function name without parentheses gives you its address. Calling through the pointer looks identical to calling the function directly.
typedef Makes It Readable
The raw syntax is hard to read and easy to get wrong. Use typedef:
typedef int (*Comparator)(const void*, const void*);
Now Comparator is a type you can use for variables and parameters:
void sort(int *arr, int n, Comparator cmp);
Much cleaner than embedding the full pointer syntax in every parameter list.
Writing a Comparator
A comparator takes two elements and returns:
- Negative if the first should come before the second
- Zero if they are equal
- Positive if the first should come after the second
int compare_ints(const void *a, const void *b) {
int x = *(const int*)a;
int y = *(const int*)b;
return x - y; // ascending order
}
The const void* parameters are required by qsort. You cast them to the actual type inside the function.
Using qsort
qsort is the C standard library’s sorting function. It sorts any array if you give it a comparator:
#include <stdlib.h>
int arr[] = {5, 2, 8, 1, 9};
int n = sizeof(arr) / sizeof(arr[0]);
qsort(arr, n, sizeof(int), compare_ints);
// arr is now {1, 2, 5, 8, 9}
The four arguments:
- Pointer to the array
- Number of elements
- Size of each element
- Comparator function
qsort does not know what type your array holds. It uses the size to move bytes around and the comparator to decide ordering. This is generic programming in C.
Reverse Order
To sort descending, flip the comparison:
int compare_ints_desc(const void *a, const void *b) {
int x = *(const int*)a;
int y = *(const int*)b;
return y - x; // descending order
}
Or negate the result of the ascending comparator. Same data, different behavior — controlled by the function pointer you pass.
Sorting Structs
qsort works on any array, including arrays of structs. Here is a comparator that sorts students by GPA in ascending order:
typedef struct {
char name[50];
double gpa;
} Student;
int compare_by_gpa(const void *a, const void *b) {
const Student *s1 = (const Student*)a;
const Student *s2 = (const Student*)b;
if (s1->gpa < s2->gpa) return -1;
if (s1->gpa > s2->gpa) return 1;
return 0;
}
The comparator casts the void* pointers to Student*, then compares the gpa fields. Do not subtract doubles — floating-point subtraction truncates to int and produces wrong results for small differences. Use the explicit if/else pattern instead.
Student roster[] = {{"Alice", 3.7}, {"Bob", 2.9}, {"Carol", 3.4}};
qsort(roster, 3, sizeof(Student), compare_by_gpa);
// roster is now: Bob (2.9), Carol (3.4), Alice (3.7)
To sort by a string field like name, use strcmp inside the comparator:
int compare_by_name(const void *a, const void *b) {
const Student *s1 = (const Student*)a;
const Student *s2 = (const Student*)b;
return strcmp(s1->name, s2->name);
}
strcmp already returns negative, zero, or positive, so you can return its result directly.
fp that points to a function taking two ints and returning an int?*fp are what make it a pointer to a function rather than a function returning a pointer. Option A declares a function named fp that returns int*.
What Comes Next
Function pointers let you parameterize behavior. But qsort uses void* — a typeless pointer. Next, you will learn how void pointers work and why they are C’s mechanism for generic programming.