Function Pointers
| Since: | C89(1989) |
|---|
A function pointer is a pointer that stores the address of a function. You use it to switch which function to call at runtime, or to implement callbacks by passing a function as an argument.
Syntax
// Declare a function pointer type. // return_type (*pointer_name)(parameter_type, ...); int (*fp)(int, int); // Assign a function's address (the function name itself is the address). fp = function_name; // Call a function through the function pointer. fp(arg1, arg2); (*fp)(arg1, arg2); // Explicit dereference — works the same way. // Using typedef to give a function pointer type a readable name. typedef return_type (*TypeName)(parameter_type, ...); TypeName variable_name = function_name;
Uses of Function Pointers
| Use | Description |
|---|---|
| Callbacks | Inject part of the logic from the caller. Commonly used in sorting, filtering, and event handling. |
| Dispatch table | Create an array of function pointers and switch which function to call by index. Can serve as an alternative to switch statements. |
| Strategy pattern | Swap out algorithms via function pointers to give structs different behaviors. |
| qsort / bsearch | These standard library functions accept a comparison function as a function pointer to sort or search data of any type. |
Sample Code
sample_function_pointer.c
#include <stdio.h>
#include <stdlib.h>
// Define the functions to operate on.
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }
// A callback function that takes a function pointer as an argument.
void apply(int x, int y, int (*op)(int, int), const char *name) {
printf("%s(%d, %d) = %d\n", name, x, y, op(x, y));
}
// Use typedef for readability.
typedef int (*BinaryOp)(int, int);
// Comparison function for qsort (ascending order).
// 'void *' is a generic pointer that accepts any type. 'const' indicates the value pointed to will not be modified through this pointer.
int compare_asc(const void *a, const void *b) {
return (*(int *)a - *(int *)b);
}
// Comparison function for qsort (descending order).
int compare_desc(const void *a, const void *b) {
return (*(int *)b - *(int *)a);
}
int main(void) {
// Assign a function to a function pointer and call it.
int (*fp)(int, int) = add;
printf("add(3, 5) = %d\n", fp(3, 5)); // Prints: add(3, 5) = 8
fp = sub;
printf("sub(10, 3) = %d\n", fp(10, 3)); // Prints: sub(10, 3) = 7
// Pass functions as callbacks.
apply(6, 2, add, "add"); // Prints: add(6, 2) = 8
apply(6, 2, sub, "sub"); // Prints: sub(6, 2) = 4
apply(6, 2, mul, "mul"); // Prints: mul(6, 2) = 12
// Dispatch table (array of function pointers).
BinaryOp ops[] = {add, sub, mul};
const char *names[] = {"add", "sub", "mul"};
for (int i = 0; i < 3; i++) {
printf("%s(10, 4) = %d\n", names[i], ops[i](10, 4));
}
// Use function pointers with qsort.
int arr[] = {5, 1, 4, 2, 3};
qsort(arr, 5, sizeof(int), compare_asc);
printf("Ascending: ");
for (int i = 0; i < 5; i++) printf("%d ", arr[i]); // Prints: 1 2 3 4 5
printf("\n");
qsort(arr, 5, sizeof(int), compare_desc);
printf("Descending: ");
for (int i = 0; i < 5; i++) printf("%d ", arr[i]); // Prints: 5 4 3 2 1
printf("\n");
return 0;
}
Run the following command:
gcc function_pointer.c -o function_pointer ./function_pointer add(3, 5) = 8 sub(10, 3) = 7 add(6, 2) = 8 sub(6, 2) = 4 mul(6, 2) = 12 add(10, 4) = 14 sub(10, 4) = 6 mul(10, 4) = 40 Ascending: 1 2 3 4 5 Descending: 5 4 3 2 1
Common Mistakes
Common Mistake 1: Parenthesis Placement in the Declaration
Parenthesis placement in function pointer declarations is critical. Getting it wrong declares a "function that returns a pointer" rather than a "function pointer."
fp_declare_ng.c
#include <stdio.h>
/* NG: int *fp(int) declares "a function fp that returns int *" */
/* int *fp(int); */
/* OK: int (*fp)(int) declares "a function pointer that takes int and returns int" */
int double_val(int x) { return x * 2; }
int main(void) {
int (*fp)(int) = double_val;
printf("double_val(5) = %d\n", fp(5));
return 0;
}
Run the following command:
gcc fp_declare_ng.c -o fp_declare_ng ./fp_declare_ng double_val(5) = 10
Common Mistake 2: Calling a NULL Function Pointer
Calling an uninitialized function pointer causes a crash. Always check for NULL before calling.
fp_null_ng.c
#include <stdio.h>
typedef void (*Handler)(const char *);
int main(void) {
Handler h = NULL;
/* NG: calling h while it is NULL */
/* h("message"); */ /* Segmentation fault */
/* OK: check for NULL before calling */
if (h != NULL) {
h("message");
} else {
printf("No handler is registered.\n");
}
return 0;
}
Run the following command:
gcc fp_null_ng.c -o fp_null_ng ./fp_null_ng No handler is registered.
Notes
Function pointers are how C implements higher-order functions — the ability to pass functions as arguments or return values. The standard library functions qsort() and bsearch() accept a comparison function via a function pointer, which allows them to sort or search data of any type generically.
Using typedef to give a function pointer type a meaningful name improves code readability. Parentheses placement in function pointer declarations is critical: int *fp(int) declares a function that returns int *, while int (*fp)(int) declares a pointer to a function — they mean completely different things.
Embedding function pointers in structs enables object-oriented-style design in C. For more on structs, see struct. For type aliases, see typedef.
If you find any errors or copyright issues, please contact us.