Function pointers

C makes some provisions for particular kinds of second-class values to be passed as function arguments by implicitly converting them to pointers. We’ve seen this in the case of arrays; strictly speaking, an array cannot be passed to a function in C, but using the name of an array as a value implicitly converts it to the array’s base address and pointers are first-class.

Functions in C are not first class. Function definitions cannot be nested, variables cannot store function values, functions cannot be assigned to or passed into or out of function calls. However, as with arrays, using the name of a function as a value implicitly converts to an address referring to the function (at the assembly level, this is the address you would use with the call instruction to jump to the function’s first instruction).

Function pointer types are notorious for being somewhat verbose, since the parameter and return types are included. For example, consider the strcmp function, which takes two strings as parameters, compares them, and returns an integer indicating their relative order (negative, zero, or positive, as the first argument is respectively less than, equal to, or greater than the second argument). Its declaration is this.

int strcmp(const char *s1, const char *s2);

The type corresponding to the address of strcmp is this.

int (*)(const char *, const char *)

In this code, a function pointer named cmp is declared and initialized to point at strcmp.

int (*cmp)(const char *, const char *) = strcmp;

Because such types get lengthy, they are very common candidates for typedef. If string comparison functions were going to come up much in a program, it is likely that something like this would be used instead of the previous version.

typedef int (*cmp_t)(const char *, const char *);

cmp_t cmp = strcmp;

There are other functions with the same parameter and return types, such as strcasecmp, which compares its arguments case-insensitively. Function pointers are often used to implement run-time polymorphism or a limited form of functional programming, as in the following example of a function which returns its minimum argument but allows the caller to specify what comparison function to use.

char *minstr(char *s1, char *s2, cmp_t cmp)
{
    return cmp(s1, s2) > 0 ? s2 : s1
}

This program demonstrates using function pointers to make a generic accumulate function which can be used to calculate sums and products of arrays of integers.

#include <stdio.h>
#include <stddef.h>
#include <stdint.h>

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

typedef int (*op_t)(int, int);

int accumulate(int *array, int size, int value, op_t op)
{
    int i;
    for (i = 0; i < size; i++)
        value = op(value, array[i]);
    return value;
}

int main()
{
    int nums[5] = {1, 2, 3, 4, 5};
    printf("Sum = %d\n", accumulate(nums, 5, 0, add));
    printf("Product = %d\n", accumulate(nums, 5, 1, multiply));
}
You have attempted of activities on this page