Back to C Programming
2026-07-126 min read

C - Callback Function in C

Learn C - Callback Function in C step by step with clear examples and exercises.

Why This Matters

Callback functions are a crucial concept in C programming, especially when working with libraries and APIs that require you to handle events or perform specific actions at certain points during program execution. They allow you to pass functions as arguments to other functions, enabling modularity and flexibility in your code. Understanding callbacks can help you write more efficient and versatile programs, making you better prepared for real-world programming challenges and job interviews.

Prerequisites

Before diving into callback functions, it's essential to have a good understanding of the following topics:

  1. Functions in C
  2. Pointers in C
  3. Basic data structures like arrays and structs
  4. Recursion
  5. File I/O (standard input and output)
  6. Basic memory management (allocation and deallocation)

Core Concept

A callback function is a function that is passed as an argument to another function. The called function, often referred to as the higher-order function or container function, invokes the callback function at some point during its execution. This allows for modular programming, where you can write separate functions to handle specific tasks and then integrate them into your main program using callbacks.

Callback Function Definition

To define a callback function, you simply create a regular function with a specific signature. The most important aspect is that the function takes no arguments or has a specific set of arguments that are known at the time of defining the higher-order function. Here's an example of a simple callback function:

void myCallback(int num) {
printf("The number passed to the callback is: %d\n", num);
}

Callback Function Usage in Higher-Order Functions

Now let's create a higher-order function that takes a callback function as an argument and invokes it when needed.

void callMyCallback(int num, void(*callback)(int)) {
callback(num);
}

In this example, callMyCallback is the higher-order function that takes two arguments: an integer and a pointer to a function that accepts an integer. The pointer to the function (void (*callback)(int)) is used to pass the callback function as an argument. Inside the callMyCallback function, we invoke the callback by dereferencing the pointer and calling it with the provided integer argument.

Registering Callbacks

To register a callback for use in higher-order functions, you simply pass the address of your callback function to the higher-order function as an argument. Here's how you can call callMyCallback with our example callback:

int main() {
void (*callback)(int) = myCallback; // Assign the address of myCallback to a pointer
callMyCallback(10, callback); // Pass the callback function as an argument to callMyCallback
return 0;
}

In this example, we assign the address of myCallback to a pointer variable, and then pass that pointer to callMyCallback. When you run this program, it will output: "The number passed to the callback is: 10".

Worked Example

Let's create an example that demonstrates the use of callback functions in handling events. We'll write a simple event-driven program where we register multiple callback functions for different events and invoke them when those events occur.

#include <stdio.h>

// Function prototypes
void onEvent1(int event);
void onEvent2(char* message);
void registerEventCallback(int event, void (*callback)(...));
void triggerEvent(int event, ...);

int main() {
// Register callback functions for events 1 and 2
registerEventCallback(1, &onEvent1);
registerEventCallback('a', &onEvent2);

// Trigger an event with arguments specific to onEvent1
triggerEvent(1, 42);

// Trigger an event with arguments specific to onEvent2
triggerEvent('b', "Hello, world!");

return 0;
}

void onEvent1(int event) {
printf("onEvent1 was triggered with argument %d\n", event);
}

void onEvent2(char* message) {
printf("onEvent2 received the following message: %s\n", message);
}

// Higher-order function to register callback functions for events
void registerEventCallback(int event, void (*callback)(...)) {
// Store the callback function for the specified event
// You could use a hash map or similar data structure here in a real application
if (event == 1) {
onEvent1_callback = callback;
} else if (event == 'a') {
onEvent2_callback = callback;
}
}

// Higher-order function to trigger events and invoke registered callbacks
void triggerEvent(int event, ...) {
va_list args;
va_start(args, event);

if (event == 1) {
onEvent1_callback(va_arg(args, int));
} else if (event == 'a') {
char* message = va_arg(args, char*);
onEvent2_callback(message);
}

va_end(args);
}

In this example, we have two callback functions onEvent1 and onEvent2. We also have a higher-order function registerEventCallback that stores the registered callbacks for different events. The triggerEvent function invokes the appropriate callback based on the event that is being triggered. When you run this program, it will output:

onEvent1 was triggered with argument 42
onEvent2 received the following message: Hello, world!

Common Mistakes

Forgetting to dereference callback pointers

When working with callback functions, it's essential to remember that you need to dereference the pointer to the function before calling it. Failing to do so will result in a segmentation fault or other runtime errors.

// Incorrect: callMyCallback(callback, 10);
callMyCallback(callback, 10); // Correct: (*callback)(10)

Passing the wrong number of arguments to callbacks

Make sure that you pass the correct number and types of arguments to your callback functions. If a callback function expects more or fewer arguments than it receives, unexpected behavior can occur.

// Incorrect: void myCallback(int num);
void myCallback(int num, char* str); // Correct: with an additional argument

callMyCallback(10, "Hello"); // Incorrect: passing a string to a function expecting an integer

Not handling null or undefined callbacks

When registering and triggering events, it's essential to handle cases where the callback may be null or undefined. This can help prevent crashes and ensure that your program behaves correctly in all situations.

void onEvent1(int event) {
if (event_callback != NULL) {
(*event_callback)(event);
} else {
printf("No callback registered for event %d\n", event);
}
}

Practice Questions

  1. Write a higher-order function that takes a callback function and an array of integers as arguments. The higher-order function should iterate through the array, invoking the callback function on each element.
  2. Modify the event-driven example to support multiple callbacks for the same event. When triggering an event, invoke all registered callbacks for that event.
  3. Create a callback function that sorts an array of integers using a specified sorting algorithm (e.g., bubble sort or quicksort). Register this callback with a higher-order function that triggers the sorting on an array of integers.

FAQ

  1. Why are callback functions useful in C programming?

Callback functions help promote modularity and flexibility by allowing you to write separate functions for specific tasks and integrate them into your main program using callbacks. This can make your code more reusable, easier to maintain, and better suited for event-driven or asynchronous programming.

  1. How do I pass a callback function as an argument to another function in C?

To pass a callback function as an argument to another function in C, you need to declare a pointer to the function type and assign the address of your callback function to that pointer. You can then pass this pointer as an argument to the higher-order function.

  1. What happens if I forget to dereference the pointer to a callback function before calling it?

If you forget to dereference the pointer to a callback function before calling it, you will likely encounter a segmentation fault or other runtime errors because you are trying to call a function at an incorrect memory address.

  1. What should I do when triggering an event and there is no registered callback for that event?

When triggering an event and there is no registered callback for that event, it's essential to handle this case gracefully to prevent crashes or unexpected behavior in your program. You can print an error message or take other appropriate actions based on the requirements of your application.