Question

How Function Pointers Work in C: Syntax, Examples, and Practical Use

cfunction-pointers

Question

I have recently been working with function pointers in C and want a clear summary of the basics.

How do function pointers work in C, what is their syntax, and how are they used in practice? A beginner-friendly explanation with simple examples would be helpful.

Short Answer

By the end of this page, you will understand what a function pointer is in C, how to declare and use one, how to pass it to other functions, and where it appears in real programs such as callbacks, sorting functions, and menu dispatch systems.

Concept

A function pointer is a variable that stores the address of a function.

In C, functions live at memory addresses just like data does. Normally, you call a function directly by its name:

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

int result = add(2, 3);

But you can also store the function's address in a pointer and call it indirectly:

int (*operation)(int, int) = add;
int result = operation(2, 3);

This matters because it lets your code become more flexible. Instead of hardcoding one behavior, you can choose a function at runtime.

Common reasons function pointers matter:

  • Callbacks: one function lets another function decide what action to perform
  • Custom behavior: pass different logic into reusable code
  • Dispatch tables: map commands or options to functions
  • Library APIs: many C libraries expect callback functions

The important rule is this:

  • A function pointer must match the function's return type and parameter types

For example, if a function returns int and takes two int arguments, the pointer must be declared to match that exact signature:

int (*ptr)(int, int);

Function pointers are powerful, but the syntax looks unusual at first because C must distinguish between:

  • a function declaration
  • a pointer declaration
  • a pointer to a function declaration

Once you learn to read the declaration from the variable name outward, the syntax becomes much easier.

Mental Model

Think of a function pointer as a remote control button.

  • The function is the device that performs the action
  • The function name is like knowing the device directly
  • The function pointer is a programmable button that can be set to trigger different devices

For example, suppose you have these functions:

  • add
  • subtract
  • multiply

A function pointer lets you say:

  • "Right now, this button means add"
  • "Later, change it so the same button means multiply"

Your code can call the same pointer variable, but the actual function that runs can change.

That is the core idea: the call site stays the same, but the behavior can be swapped.

Take Quiz

Syntax and Examples

Basic syntax

Here is a normal function:

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

A pointer to a function with the same signature looks like this:

int (*ptr)(int, int);

Read it as:

  • ptr is a pointer
  • *ptr is grouped with parentheses
  • it points to a function
  • that takes (int, int)
  • and returns int

Assigning a function to a pointer

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

You can also write:

int (*ptr)(int, int) = &add;

Both work in C for this use.

Calling through a function pointer

int result1 = ptr(4, 5);
int result2 = (*ptr)(4, 5);

Both calls are valid. The first form is more common.

Complete beginner example

#include <stdio.h>

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

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

int main(void) {
    int (*operation)(int, int);

    operation = add;
    printf("add: %d\n", operation(10, 3));

    operation = subtract;
    printf("subtract: %d\n", operation(10, 3));

    return 0;
}

What this shows

  • operation can point to any function with signature int (int, int)
  • first it points to add
  • then it points to subtract
  • the same variable is used to call different behavior

Passing a function pointer to another function

#include <stdio.h>

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

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

int calculate(int x, int y, int (*op)(int, int)) {
    return op(x, y);
}

int main(void) {
    printf("%d\n", calculate(2, 3, add));
    printf("%d\n", calculate(2, 3, multiply));
    return 0;
}

This is a classic callback-style pattern.

Step by Step Execution

Consider this example:

#include <stdio.h>

int square(int x) {
    return x * x;
}

int main(void) {
    int (*func)(int) = square;
    int result = func(6);
    printf("%d\n", result);
    return 0;
}

Step by step:

  1. The program defines square, a function that takes one int and returns one int.
  2. In main, func is declared as a pointer to a function with signature int (int).
  3. func = square; stores the address of square in func.
  4. func(6) calls the function that func points to.
  5. Since func points to square, the call becomes effectively square(6).
  6. square(6) returns 36.
  7. result receives 36.
  8. printf prints 36.

You can think of the call flow like this:

func --> square
func(6) --> square(6) --> 36

Now imagine changing the assignment:

func = some_other_function;

If some_other_function has the same signature, the call func(6) still works, but it runs different code.

Real World Use Cases

Function pointers appear in many practical C programs.

1. Callbacks in libraries

A library may let you provide your own function to handle events or data.

Examples:

  • comparison functions for sorting
  • signal handlers
  • iteration callbacks
  • GUI or embedded event handlers

2. Sorting with custom logic

The C standard library function qsort uses a function pointer so you can decide how elements should be compared.

int compare_ints(const void *a, const void *b) {
    int x = *(const int *)a;
    int y = *(const int *)b;
    return x - y;
}

3. Menu systems

A command-line tool can map user choices to functions.

void show_help(void);
void run_backup(void);
void exit_program(void);

Then a table of function pointers can be used to dispatch actions.

4. State machines

Embedded systems often use function pointers to represent state handlers.

Each state can be implemented as a function, and the current state's function pointer decides what code runs next.

5. Plugin-like behavior

A program can choose different implementations at runtime, such as:

  • different validation rules
  • different processing algorithms
  • different output formats
Take Quiz

Real Codebase Usage

In real codebases, developers usually use function pointers in structured ways rather than declaring them casually everywhere.

Common patterns

Callbacks

A function receives another function to customize behavior.

void process_items(int *items, int count, void (*handler)(int)) {
    for (int i = 0; i < count; i++) {
        handler(items[i]);
    }
}

This keeps process_items reusable.

Dispatch tables

Instead of a long chain of if or switch, developers sometimes store functions in an array.

#include <stdio.h>

void say_hello(void) { printf("Hello\n"); }
void say_bye(void)   { printf("Bye\n"); }

int main(void) {
    void (*actions[2])(void) = { say_hello, say_bye };
    actions[0]();
    actions[1]();
    return 0;
}

Validation hooks

A shared function may accept a validation function pointer.

int is_even(int x) {
    return x % 2 == 0;
}

Then another function can call it on different values.

Guarding against null pointers

In production code, a function pointer may be optional, so developers check before calling it.

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

Using typedef for readability

Real code often hides complex declarations with typedef.

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

int apply(int a, int b, Operation op) {
    return op(a, b);
}

This improves maintainability, especially when the same signature is used repeatedly.

Common Mistakes

1. Forgetting parentheses in the declaration

This is one of the most common mistakes.

Broken code:

int *ptr(int, int);

This does not mean “pointer to function”. It means:

  • ptr is a function
  • it takes two int values
  • it returns int *

Correct code:

int (*ptr)(int, int);

The parentheses around *ptr are required.

2. Using the wrong function signature

Broken code:

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

void (*ptr)(int, int) = add;

Problem:

  • add returns int
  • ptr expects a function returning void

The signature must match.

Correct version:

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

3. Calling a null function pointer

Broken code:

void (*callback)(void) = NULL;
callback();

This causes undefined behavior and can crash.

Safer code:

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

4. Confusing a function pointer with a normal data pointer

A function pointer points to executable code, not ordinary data.

Do not treat it like an int * or char *.

5. Making the syntax harder than it needs to be

Beginners often avoid typedef, but it can help a lot.

Without typedef:

int run(int x, int y, int (*op)(int, int));

With typedef:

typedef int (*Operation)(int, int);
int run(int x, int y, Operation op);

6. Assuming *ptr() means the same thing as (*ptr)()

Operator precedence matters.

  • (*ptr)() means call the function pointed to by ptr
  • *ptr() means call ptr as a function first, then dereference its result

Use parentheses carefully.

Comparisons

Function pointer vs normal function call

ConceptNormal function callFunction pointer call
How function is chosenFixed at compile time in your codeCan be selected indirectly at runtime
Syntaxadd(2, 3)ptr(2, 3)
FlexibilityLowerHigher
ReadabilitySimplerSlightly harder at first

Function pointer declaration vs function declaration

SyntaxMeaning
int func(int, int);func is a function returning int
int (*func)(int, int);func is a pointer to a function returning int

Without typedef vs with typedef

StyleExampleBenefit
Without typedefint (*op)(int, int)Direct but noisy
With typedeftypedef int (*Operation)(int, int);Easier to read and reuse

if/else dispatch vs function pointer dispatch table

ApproachBest for
if/else or switchSmall number of fixed cases
Function pointer tableMany commands or swappable behaviors

Use function pointers when behavior needs to be passed around, selected dynamically, or organized cleanly.

Take Quiz

Cheat Sheet

Core syntax

Declare a function:

int add(int a, int b);

Declare a pointer to that kind of function:

int (*ptr)(int, int);

Assign a function:

ptr = add;

Call through the pointer:

ptr(2, 3);
(*ptr)(2, 3);

Reading the declaration

int (*ptr)(int, int);
  • ptr = variable name
  • *ptr = pointer
  • (int, int) = points to a function taking two int
  • int at the start = function returns int

Common pattern

Pass a function pointer as an argument:

int calculate(int a, int b, int (*op)(int, int));

Typedef version

typedef int (*Operation)(int, int);
Operation op = add;

Rules

  • Signature must match exactly
  • Parentheses around *name matter
  • Check for NULL before calling optional callbacks
  • func and &func are both commonly usable when assigning

Common mistakes

Broken:

int *ptr(int, int);

Correct:

int (*ptr)(int, int);

Quick example

#include <stdio.h>

int double_value(int x) {
    return x * 2;
}

int main(void) {
    int (*func)(int) = double_value;
    printf("%d\n", func(5));
    return 0;
}

FAQ

What is a function pointer in C?

A function pointer is a variable that stores the address of a function, allowing you to call that function indirectly.

Why are function pointers used in C?

They are used for callbacks, custom behavior, dispatch tables, event handling, and standard library functions such as qsort.

How do I declare a function pointer in C?

Match the function's return type and parameters:

int (*ptr)(int, int);

Do I need to use & when assigning a function to a function pointer?

Usually no. ptr = add; works. ptr = &add; also works in common C usage.

How do I call a function through a pointer?

You can write either:

ptr(1, 2);

or:

(*ptr)(1, 2);

What happens if the function signature does not match?

That is incorrect and may produce compiler warnings or undefined behavior. The pointer type must match the function type.

Are function pointers the same as normal pointers?

No. They are both pointers, but a function pointer points to executable code, while a normal pointer usually points to data.

Is typedef recommended for function pointers?

Yes, especially when the declaration appears in multiple places. It makes the code easier to read.

Take Quiz

Mini Project

Description

Build a small calculator program that uses a function pointer to choose an operation. This demonstrates the core value of function pointers: the same calling code can execute different functions depending on which function address is stored.

Goal

Create a calculator that can switch between addition, subtraction, and multiplication by assigning different functions to one function pointer.

Requirements

  • Define at least three functions with the same signature: add, subtract, and multiply.
  • Declare a function pointer that can point to any of those functions.
  • Assign different functions to the pointer and call it multiple times.
  • Print the operation results clearly.
  • Keep the program in one C source file with a main function.
Take Quiz

Keep learning

Related questions

View more