πŸ‡―πŸ‡΅ ζ—₯本θͺž | πŸ‡ΊπŸ‡Έ English

Function Pointers in C

Pass functions as data. Essential for qsort, callbacks, and dispatch tables.

πŸ’ͺ It's normal not to get it on the first try
Function-pointer declaration syntax is some of the thorniest in C. It's fine to learn it when you need it, rather than up front.
How to come back to it
  1. Get comfortable with functions and pointers first
  2. Start by using typedef to give the type a readable name
  3. Just knowing how to call qsort covers most real-world needs
  4. Lock in one fact: functions have addresses too
πŸ’‘ Tip: read the declaration outward from the name β€” int (*fp)(int) means "fp is a pointer to a function that takes an int and returns an int."

What is a function pointer?

Every function has an address in memory, and a function pointer simply stores that address. Once you have one, you can hold functions in variables, pass them as arguments, and put them into arrays.
#include <stdio.h>

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

int main(void) {
    // fp points to "a function taking int, returning int"
    int (*fp)(int) = square;  // function name decays to its address

    printf("%d\n", fp(5));   // 25
    printf("%d\n", (*fp)(5)); // 25, older style
    return 0;
}
Rule: a function name used as an expression automatically decays to its address. So fp = square and fp = &square are equivalent, and so are fp(5) and (*fp)(5).

Reading the declaration / typedef

How to read it

int (*fp)(int, int);
β‘  the name is fp
β‘‘ (*fp) β€” fp is a pointer
β‘’ (int, int) β€” to a function that takes two ints
β‘£ the outer int β€” and returns an int
β†’ "a pointer to a function that takes two ints and returns an int"

Mind the parentheses

int *fp(int);       // ❌ NOT a function pointer
                    // it's the prototype of a function returning int*

int (*fp)(int);     // βœ… function pointer

Cleaner with typedef

typedef int (*CmpFn)(const void *, const void *);

void sort(int *a, int n, CmpFn cmp) {
    /* ... */
}
Trick: typedef turns the whole messy type into a single name. Once CmpFn is defined, CmpFn x; declares a function pointer.

Callbacks

Here's a generic "do X to each element" routine where the caller supplies what X is:
#include <stdio.h>

void for_each(int *a, int n, void (*fn)(int)) {
    for (int i = 0; i < n; i++) fn(a[i]);
}

void print_int(int v)    { printf("%d ", v); }
void print_square(int v) { printf("%d ", v * v); }

int main(void) {
    int a[] = {1, 2, 3, 4, 5};
    for_each(a, 5, print_int);    printf("\n");
    for_each(a, 5, print_square); printf("\n");
    return 0;
}
Separating how to iterate from what to do is a fundamental pattern in event-driven systems, GUIs, async APIs, and sorting.

Sorting anything with qsort

The standard qsort takes a comparison function as a function pointer, which means it can sort any type β€” ints, strings, structs, you name it.

Signature

void qsort(void *base,
           size_t nmemb,
           size_t size,
           int (*compar)(const void *, const void *));

int ascending

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

int cmp_int_asc(const void *p1, const void *p2) {
    int a = *(const int *)p1;
    int b = *(const int *)p2;
    if (a < b) return -1;
    if (a > b) return 1;
    return 0;
}

int main(void) {
    int a[] = {5, 2, 8, 1, 9, 3};
    qsort(a, 6, sizeof(int), cmp_int_asc);
    for (int i = 0; i < 6; i++) printf("%d ", a[i]);
    // 1 2 3 5 8 9
}
Gotcha: return a - b; looks like it works, but it can overflow for large or negative values. Always compare and return -1, 0, or 1.

Struct with two-key sort

struct Student {
    char name[32];
    int score;
};

// higher score first, ties broken by name
int cmp_student(const void *p1, const void *p2) {
    const struct Student *a = p1;
    const struct Student *b = p2;
    if (a->score != b->score)
        return (b->score > a->score) ? 1 : -1;
    return strcmp(a->name, b->name);
}
qsort(students, n, sizeof(struct Student), cmp_student);

Dispatch tables

Instead of a big switch, use an array of function pointers for clean, data-driven code:
#include <stdio.h>

double op_add(double a, double b) { return a + b; }
double op_sub(double a, double b) { return a - b; }
double op_mul(double a, double b) { return a * b; }
double op_div(double a, double b) { return b != 0 ? a / b : 0; }

struct OpEntry {
    char sym;
    double (*fn)(double, double);
};

static const struct OpEntry ops[] = {
    {'+', op_add}, {'-', op_sub},
    {'*', op_mul}, {'/', op_div},
};

double calc(char op, double a, double b) {
    for (int i = 0; i < sizeof(ops) / sizeof(ops[0]); i++) {
        if (ops[i].sym == op) return ops[i].fn(a, b);
    }
    return 0;
}

int main(void) {
    printf("%.2f\n", calc('+', 3, 4));
    printf("%.2f\n", calc('*', 6, 7));
}
Adding a new operator is as simple as adding one row to the table β€” no logic changes needed anywhere else.

Challenges

Challenge 1: Descending sort
Write a comparator that sorts an int array in descending order.
Challenge 2: Sort strings
Sort char *words[] = {"banana","apple","cherry"}; alphabetically. Note that the comparator receives const char **.
Challenge 3: a filter function
Implement int filter(int *a, int n, int *out, int (*pred)(int)). It should copy every element for which pred returns non-zero. Test it with an even-number predicate.
Challenge 4: traffic-light state machine
Implement red β†’ green β†’ yellow β†’ red as an array of state-handler function pointers.

Review Quiz

Check your understanding of this lesson!

Q1. What does int (*fp)(int) declare?

A pointer to a function that takes an int and returns an int
A function that returns an int pointer
A function that takes an int array

The parentheses group *fp together, so it reads as "fp is a pointer to a function." Without them, int *fp(int) means something entirely different.

Q2. Which is the correct prototype for a qsort comparison function?

int cmp(const void *a, const void *b)
int cmp(int a, int b)
int cmp(void *a, void *b, size_t n)

qsort has to handle arbitrary types, so the arguments come in as const void *. Cast them back to the actual type inside the comparison function.

Q3. Which is the correct way to call a function through a function pointer fp?

fp(10) or (*fp)(10)
&fp(10)
*fp[10]

In C, you can call a function pointer just like a regular function name, using (). The older explicit-dereference style (*fp)(...) is equivalent.