← Back to C Course | Chapter 12: Advanced Topics | Lesson 7 of 20

C Callback Functions

A callback is a function you hand to another function so it can call yours later, like leaving your phone number to be called back. It lets one piece of code customize another.
Syntax
c
void function_name(return_type (*callback)(parameter_types)) {
  callback(arguments);
}

function_name(callback_function);

What is a Callback?

A callback is a function you hand to another function as an argument, so that receiving function can call it back at the appropriate moment during its own execution, rather than the caller controlling exactly when it runs.

This inversion of control is what lets library code stay generic while still letting your specific logic run at the right point.

Example: What is a Callback?

c
// Include standard input/output (printf, scanf)
#include <stdio.h>
void sayHello() {
	// Print formatted text to the screen
	printf("Hello");
}
void runCallback(void (*callback)()) {
	callback();
}
// Program execution starts in main()
int main() {
	runCallback(sayHello);
	// Return 0 to signal that the program finished successfully
	return 0;
}

Creating a Simple Callback

To accept a callback, a function declares one of its parameters as a function pointer type, then invokes that parameter like a normal function call wherever the customizable behavior should happen.

This separates the fixed control-flow logic (like iterating over a list) from the variable part (what to do with each element), which the caller supplies.

Example: Creating a Simple Callback

c
// Include standard input/output (printf, scanf)
#include <stdio.h>
void greet() {
	// Print formatted text to the screen
	printf("Hi there");
}
void doAction(void (*action)()) {
	action();
}
// Program execution starts in main()
int main() {
	doAction(greet);
	// Return 0 to signal that the program finished successfully
	return 0;
}

Callbacks with Parameters

A callback's own signature can include parameters, letting the calling function pass computed values — like the current array element or an index — directly into your custom logic each time it's invoked.

This lets one generic driver function support many different callbacks that each need different pieces of context to do their job.

Example: Callbacks with Parameters

c
// Include standard input/output (printf, scanf)
#include <stdio.h>
void printSquare(int x) {
	// Print formatted text to the screen
	printf("%d", x * x);
}
void process(int value, void (*callback)(int)) {
	callback(value);
}
// Program execution starts in main()
int main() {
	process(5, printSquare);
	// Return 0 to signal that the program finished successfully
	return 0;
}

Filtering Arrays with Callbacks

Passing a callback into a generic array-processing function lets that same function filter, transform, or inspect elements differently depending only on which callback was supplied, without duplicating the loop logic for each use case.

This is the same pattern behind functions like a custom filterArray(arr, n, predicateFn).

Example: Filtering Arrays with Callbacks

c
// Include standard input/output (printf, scanf)
#include <stdio.h>
int isEven(int n) {
	// Send n % 2 == 0 back to the caller
	return n % 2 == 0;
}
void filterPrint(int arr[], int size, int (*test)(int)) {
	// Loop: repeat while the condition holds
	for (int i = 0; i < size; i++) {
		// Check whether test(arr[i])
		if (test(arr[i])) {
			// Print formatted text to the screen
			printf("%d ", arr[i]);
		}
	}
}
// Program execution starts in main()
int main() {
	int nums[4] = {1, 2, 3, 4};
	filterPrint(nums, 4, isEven);
	// Return 0 to signal that the program finished successfully
	return 0;
}

Benefits and Use Cases of Callbacks

Callbacks are what make library functions like qsort() genuinely general-purpose: qsort() itself has no idea how to compare your specific data, so it delegates that decision entirely to the comparison callback you pass in.

This lets a single sorting implementation work correctly on integers, strings, structs, or anything else you define a comparator for.

Example: Benefits and Use Cases of Callbacks

c
// Include standard input/output (printf, scanf)
#include <stdio.h>
// Include general utilities (malloc, free, exit)
#include <stdlib.h>
int compareInts(const void *a, const void *b) {
	// Send (*(int*)a - *(int*)b) back to the caller
	return (*(int*)a - *(int*)b);
}
// Program execution starts in main()
int main() {
	int arr[3] = {3, 1, 2};
	qsort(arr, 3, sizeof(int), compareInts);
	// Print formatted text to the screen
	printf("%d %d %d", arr[0], arr[1], arr[2]);
	// Return 0 to signal that the program finished successfully
	return 0;
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Passing a callback whose signature does not match what the receiving function expects.
  2. Calling a callback pointer that is NULL without checking it first.
  3. Writing the function name with parentheses when passing it, which calls it instead of passing the address.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.