Back to C Programming
2025-12-207 min read

22.5.3 Calling Function Pointers

Learn 22.5.3 Calling Function Pointers step by step with clear examples and exercises.

Why This Matters

Function pointers play a crucial role in C programming as they allow for dynamic function calls and the ability to pass functions as arguments to other functions or store them in data structures. This flexibility is essential for developing complex programs that can dynamically adapt to various situations, such as event-driven programming and system programming. Additionally, understanding function pointers will help you tackle real-world bugs, prepare for job interviews, and delve deeper into advanced topics like dynamic memory allocation and callback functions.

Prerequisites

To fully grasp the concept of calling function pointers, you should have a solid foundation in C programming basics:

  1. Variables, constants, and data types
  2. Control structures (if-else, switch-case, loops)
  3. Functions and their parameters
  4. Arrays and pointers
  5. Structures and unions
  6. File I/O
  7. Understanding of function prototypes and how to declare functions
  8. Knowledge of static variables and storage classes
  9. Familiarity with the concept of recursion
  10. Comprehension of pointer arithmetic and dereferencing

Core Concept

A function pointer is a variable that stores the memory address of a function. To call a function pointed to by a function pointer, you simply write the function pointer value in a function call. Here's an example:

void binary_op(double x, double y, void (*func)(double, double)) {
func(x, y); // Call the function pointed to by func
}

void add(double a, double b) {
printf("%.2f + %.2f = %.2f\n", a, b, a + b);
}

void subtract(double a, double b) {
printf("%.2f - %.2f = %.2f\n", a, b, a - b);
}

int main() {
void (*operation)(double, double) = add; // Initialize function pointer with the address of add function
binary_op(5.0, 3.0, operation); // Call the add function using the function pointer

operation = subtract; // Change the function pointed to by operation
binary_op(10.0, 5.0, operation); // Call the subtract function using the function pointer

return 0;
}

In this example, binary_op is a function that takes two double values and a function pointer as arguments. It calls the function pointed to by the function pointer with the given arguments. The add and subtract functions are examples of functions that can be pointed to by the operation variable in main.

Function Pointers and Function Prototypes

It is essential to understand function prototypes when working with function pointers. A function prototype declares a function's return type, name, and parameters. This information is crucial for the compiler to correctly interpret the function pointer and call the appropriate function.

void add(double a, double b); // Function prototype for the add function
void (*operation)(double, double) = add; // Initialize function pointer with the address of add function (no need for explicit casting in C99 and later)

Worked Example

Let's create a simple program that uses function pointers to implement a calculator. The user will input an operation (addition, subtraction, or multiplication) and two numbers. The program will dynamically allocate memory for the appropriate function based on the user's input and call it using a function pointer.

#include <stdio.h>
#include <stdlib.h>

typedef void (*arithmetic_func)(double, double); // Define function pointer type

void add(double a, double b) {
printf("%.2f + %.2f = %.2f\n", a, b, a + b);
}

void subtract(double a, double b) {
printf("%.2f - %.2f = %.2f\n", a, b, a - b);
}

void multiply(double a, double b) {
printf("%.2f * %.2f = %.2f\n", a, b, a * b);
}

arithmetic_func get_operation() {
char operation[10];
printf("Enter the operation (add/subtract/multiply): ");
scanf("%s", operation);

if (strcmp(operation, "add") == 0)
return add;
else if (strcmp(operation, "subtract") == 0)
return subtract;
else if (strcmp(operation, "multiply") == 0)
return multiply;
else {
printf("Invalid operation.\n");
exit(1);
}
}

int main() {
double num1, num2;
arithmetic_func operation = get_operation(); // Get the function pointer for the user's chosen operation

printf("Enter two numbers: ");
scanf("%lf %lf", &num1, &num2);

operation(num1, num2); // Call the function pointed to by operation with the user's input numbers

return 0;
}

Common Mistakes

  1. Forgetting to cast the function pointer type when initializing it:
void (*operation)(double, double) = add; // Correct
arithmetic_func operation = add; // Incorrect (no need for explicit casting in C99 and later)
  1. Failing to dereference the function pointer when calling the function:
(*operation)(num1, num2); // Correct
operation(num1, num2); // Incorrect (no need for explicit dereferencing in C99 and later)
  1. Not handling invalid user input in get_operation:
arithmetic_func get_operation() {
char operation[10];
printf("Enter the operation (add/subtract/multiply): ");
scanf("%s", operation);

if (strcmp(operation, "add") == 0)
return add;
else if (strcmp(operation, "subtract") == 0)
return subtract;
else if (strcmp(operation, "multiply") == 0)
return multiply;
else {
printf("Invalid operation.\n");
exit(1); // Exit the program instead of returning a null pointer
}
}
  1. Not freeing dynamically allocated memory when it is no longer needed:
void* my_malloc(size_t size) {
void* ptr = malloc(size);
if (ptr == NULL) {
fprintf(stderr, "Memory allocation failed.\n");
exit(1);
}
return ptr;
}

// Later in the code
void (*operation)(double, double) = my_malloc(sizeof(arithmetic_func)); // Allocate memory for function pointer
*operation = add; // Initialize function pointer with the address of add function
// ...
free(operation); // Free dynamically allocated memory when it's no longer needed

Practice Questions

  1. Modify the calculator program to include division as well.
  2. Write a function that takes two function pointers and another double value as arguments, applies both functions to the double in sequence, and returns the result.
  3. Implement a function that sorts an array of integers using quicksort with a user-defined comparison function (function pointer).
  4. Create a program that uses function pointers to implement a simple game of rock-paper-scissors against the computer. The player can choose their move by inputting 'r' for rock, 'p' for paper, or 's' for scissors. The computer will randomly choose its move, and the winner will be determined based on the rules of the game (rock beats scissors, scissors beat paper, and paper beats rock).
  5. Write a function that takes a function pointer as an argument and returns another function pointer that multiplies its input by a specified constant. For example, if the input function is f(x) = x*x and the constant is 2, the returned function should be g(x) = 2 * (x*x).
  6. Implement a function that takes two function pointers as arguments, each representing a mathematical operation (addition, subtraction, multiplication, or division). The function should return another function pointer that performs the specified operations in sequence on its input. For example, if the first function is f(x) = x + 5 and the second function is g(x) = x - 3, the returned function should be h(x) = (x + 5) - 3.
  7. Write a program that uses function pointers to implement a simple command-line calculator. The user can input an expression consisting of numbers, operators, and parentheses. The program will parse the expression using a recursive descent parser and evaluate it using function pointers representing arithmetic operations.

FAQ

Q: Why can't I call a function directly through its memory address?

A: In C, functions are not just blocks of code; they also have a return type and parameters. Calling a function indirectly through a function pointer allows the compiler to check these details at compile time.

Q: Can I use function pointers with non-void returning functions?

A: Yes, you can use function pointers with functions that return values other than void. However, when calling such a function through a function pointer, you need to handle the returned value appropriately.

Q: Are function pointers thread-safe in C?

A: Function pointers themselves are thread-safe, but the functions they point to may not be. If you're working with multi-threaded programs, ensure that your functions are reentrant or use appropriate synchronization mechanisms.

Q: Can I pass function pointers as arguments to other functions?

A: Yes, you can pass function pointers as arguments to other functions. This is often used in callback functions, where a function passed as an argument is called by another function at a specific point during its execution.

Q: How do I check if a function pointer points to a valid function?

A: To check if a function pointer points to a valid function, you can compare it to NULL or use the sizeof operator on the function pointer. If the size of the function pointer is not zero, then it likely points to a valid function. However, keep in mind that this method does not guarantee that the pointed-to function will be valid at runtime due to issues like segmentation faults or uninitialized pointers.

Q: How can I store an array of function pointers?

A: To store an array of function pointers, you need to allocate memory for each element in the array and initialize them with the addresses of the functions you want to include. Here's an example:

#include <stdio.h>

void func1(void) { printf("func1\n"); }
void func2(void) { printf("func2\n"); }
void func3(void) { printf("func3\n"); }

int main() {
void (*functions[3])(void) = {func1, func2, func3}; // Initialize an array of function pointers

for (int i = 0; i < 3; ++i) {
functions[i](); // Call each function in the array
}

return 0;
}