C Function Pointers Explained: Call Functions Through Pointers

Function pointers are a powerful feature of C that allows a program to store the address of a function and call that function indirectly. They are useful for callbacks, sorting, event handling, state machines, and configurable program behavior.

What is a Function Pointer?

A function pointer is a pointer that stores the address of a function. Its type describes the function's return type and parameter types.

C
int add(int a, int b)
{
    return a + b;
}

int (*operation)(int, int) = add;

printf("Result: %d\n", operation(10, 20));

Understanding Function Pointer Syntax

The syntax can look unusual at first. In int (*operation)(int, int), operation is a pointer to a function that accepts two int arguments and returns an int.

C
int (*operation)(int, int);

Calling a Function Through a Pointer

Once a function pointer points to a compatible function, the function can be called using the pointer.

C
int multiply(int a, int b)
{
    return a * b;
}

int (*operation)(int, int) = multiply;

int result = operation(5, 6);

printf("%d\n", result);

Using the Address-of Operator

A function name can be used in a context where a pointer to that function is expected. The address-of operator can also be used explicitly.

C
int subtract(int a, int b)
{
    return a - b;
}

int (*operation)(int, int) = &subtract;

printf("%d\n", operation(20, 8));

Function Pointers as Parameters

A function can receive another function as an argument through a function pointer. This is one of the main ways C implements callback behavior.

C
int add(int a, int b)
{
    return a + b;
}

int calculate(int a, int b, int (*operation)(int, int))
{
    return operation(a, b);
}

int result = calculate(10, 5, add);

printf("%d\n", result);

Creating a Callback

A callback is a function passed to another function so it can be invoked at an appropriate point in the program.

C
void process(int value, void (*callback)(int))
{
    callback(value);
}

void printValue(int value)
{
    printf("Value: %d\n", value);
}

process(42, printValue);

Using typedef for Function Pointers

typedef can make complex function pointer declarations easier to read and reuse.

C
typedef int (*Operation)(int, int);

int add(int a, int b)
{
    return a + b;
}

Operation operation = add;

printf("%d\n", operation(4, 7));

Function Pointer Arrays

An array of function pointers can associate different functions with indexes or commands. This is useful for menus and dispatch tables.

C
void optionOne(void)
{
    printf("Option One\n");
}

void optionTwo(void)
{
    printf("Option Two\n");
}

void optionThree(void)
{
    printf("Option Three\n");
}

void (*menu[])(void) = {
    optionOne,
    optionTwo,
    optionThree
};

int choice = 1;

menu[choice]();

Building a Calculator with Function Pointers

A calculator can select an operation dynamically by storing different arithmetic functions in function pointers.

C
#include <stdio.h>

typedef double (*Operation)(double, double);

double add(double a, double b)
{
    return a + b;
}

double subtract(double a, double b)
{
    return a - b;
}

double multiply(double a, double b)
{
    return a * b;
}

int main(void)
{
    Operation operation = multiply;

    printf("Result: %.2f\n", operation(6.0, 7.0));

    return 0;
}

Function Pointers and qsort

The standard library qsort function accepts a comparison function through a function pointer. This allows the caller to define how elements should be ordered.

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

int compareInts(const void *a, const void *b)
{
    int x = *(const int *)a;
    int y = *(const int *)b;

    return (x > y) - (x < y);
}

int main(void)
{
    int numbers[] = {40, 10, 30, 20};
    size_t count = sizeof numbers / sizeof numbers[0];

    qsort(numbers, count, sizeof numbers[0], compareInts);

    for (size_t i = 0; i < count; i++)
    {
        printf("%d ", numbers[i]);
    }

    return 0;
}

Function Pointer vs Data Pointer

FeatureData PointerFunction Pointer
Points ToAn object or dataA function
Exampleint *ptrint (*func)(int)
Typical UseAccess memory and dataCall functions dynamically
Common ApplicationArrays and structuresCallbacks and dispatch

Function Pointers and Callbacks

Callbacks are useful when a library or framework needs to call application-defined behavior without knowing the exact implementation in advance.

C
typedef void (*Handler)(const char *message);

void handleMessage(const char *message)
{
    printf("Message: %s\n", message);
}

void runTask(Handler handler)
{
    handler("Task completed");
}

int main(void)
{
    runTask(handleMessage);
    return 0;
}

Function Pointers and State Machines

Function pointers can represent different states in a program. Each state can have its own handler function.

C
void idle(void)
{
    printf("Idle state\n");
}

void running(void)
{
    printf("Running state\n");
}

void stopped(void)
{
    printf("Stopped state\n");
}

typedef void (*StateHandler)(void);

StateHandler state = running;

state();

Function Pointer Compatibility

A function pointer should point to a function with a compatible function type. The return type and parameter types are important when assigning and calling through a function pointer.

C
int add(int a, int b)
{
    return a + b;
}

typedef int (*Operation)(int, int);

Operation operation = add;

Checking a Function Pointer

A function pointer can be compared with a null pointer constant before calling it when the pointer may be optional.

C
void greet(void)
{
    printf("Hello!\n");
}

void (*callback)(void) = greet;

if (callback != NULL)
{
    callback();
}

Common Function Pointer Mistakes

  • Using an incompatible function pointer type
  • Calling through a NULL function pointer
  • Using an invalid function pointer
  • Creating unnecessarily complicated declarations
  • Forgetting the required function parameters
  • Using callbacks without clearly defining their ownership and lifetime

Function Pointer Best Practices

  • Use typedef for complex function pointer types
  • Keep callback signatures simple
  • Check optional function pointers before calling them
  • Use compatible function signatures
  • Document what a callback is expected to do
  • Prefer clear dispatch tables over deeply nested conditional logic when appropriate

Real-World Applications

  • Sorting with qsort
  • Event handlers
  • Callback APIs
  • Command dispatch tables
  • State machines
  • Embedded systems
  • Plugin-style architectures

Practice Exercises

  • Create a function pointer for an addition function
  • Build a calculator using function pointers
  • Create a callback that prints processed values
  • Build a menu using an array of function pointers
  • Sort an array using qsort
  • Create a simple state machine
  • Design a small callback-based event system

Conclusion

Function pointers allow C programs to select and invoke behavior dynamically. Once you understand their syntax and type compatibility, they become especially useful for callbacks, sorting, state machines, dispatch tables, and flexible system designs.

Note: Note: Always ensure that a function pointer refers to a compatible and valid function before calling it. Using typedef can make complex function pointer code much easier to understand.