Function Pointer in C

  1. Use void (*func)() Notation to Define Function Pointer in C
  2. Use Function Pointer Array to Implement Type-Generic Programming Feature

This article will introduce how to use a function pointer in C.

Use void (*func)() Notation to Define Function Pointer in C

Function pointers are yet another construct in C programming that implement advanced features like dynamic function calling, structures that include their own methods similar to object-oriented design, type-generic programming and etc. Note that function pointer declaration can have complicated syntax, namely, void (*func)(void) notation declares the pointer to void function that takes no parameters. Although we assign the address of printInt function, that takes a single int argument to the void (*func)(void) type function pointer in the following example. Once the function pointer named func is defined, it can be called with the usual function call notation func(arg) or with dereferencing operator (*func)(arg).

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

void printInt(int x)
{
    printf("printed from printInt: %d\n", x);
}

int main() {
    int input1 = 10233;

    void (*func)(int) = printInt;

    func(input1);
    (*func)(input1);

    exit(EXIT_SUCCESS);
}

Output:

printed from printInt: 10233
printed from printDouble: 11.234000

Alternatively, we can define a new type alias of a function pointer using typedef to make code more readable. Note that different function types would need separate typedef statements. In the following code sample, we define a pointer to a void function without any arguments; nonetheless, both printInt and printDouble function addresses are stored in the variable of type FuncPtr. It should be noted out that the address of the specific function can be taken with explicit & operator or with the implicit assignment of function name itself, as demonstrated in the next example.

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

typedef void (*FuncPtr)();

void printInt(int x)
{
    printf("printed from printInt: %d\n", x);
}

void printDouble(double x)
{
    printf("printed from printDouble: %f\n", x);
}

int main() {
    int input1 = 10233;
    double input2 = 11.234;

    FuncPtr func1 = printInt;
    FuncPtr func2 = printDouble;

    func1(input1);
    func2(input2);

    exit(EXIT_SUCCESS);
}

Output:

printed from printInt: 10233
printed from printDouble: 11.234000

Use Function Pointer Array to Implement Type-Generic Programming Feature

Like other objects, one can define an array of function pointers with brackets [] notation. This array can be utilized to choose and call specific functions during run-time easily. Notice that we are using the keyword _Generic, which is switch like an expression that lets the user choose the specific case base on the type evaluation of the controlling expression. Consequently, we implement the following code example, where the corresponding print function is called based on the type of the variable passed in the switch condition. Note that, enum type is also utilized to define constant values for different cases.

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

enum TYPE {INTEGER, DOUBLE, INVALID};

#define typename(x) _Generic((x), \
          int: INTEGER, \
        double: DOUBLE, \
      default: INVALID)

typedef void (*FuncPtr)();

void printInt(int x)
{
    printf("printed from printInt: %d\n", x);
}

void printDouble(double x)
{
    printf("printed from printDouble: %f\n", x);
}

int main() {
    int input1 = 10233;
    double input2 = 11.234;

    FuncPtr func_ptrs[] = {printInt, printDouble};

    switch (typename(input1)) {
        case INTEGER: func_ptrs[INTEGER](input1); break;
        case DOUBLE: func_ptrs[DOUBLE](input1); break;
        case INVALID: printf("No corresponding type found!\n");
        default: break;
    }

    switch (typename(input2)) {
        case INTEGER: func_ptrs[INTEGER](input2); break;
        case DOUBLE: func_ptrs[DOUBLE](input2); break;
        case INVALID: printf("No corresponding type found!\n");
        default: break;
    }

    exit(EXIT_SUCCESS);
}

Output:

printed from printInt: 10233
printed from printDouble: 11.234000
Contribute
DelftStack is a collective effort contributed by software geeks like you. If you like the article and would like to contribute to DelftStack by writing paid articles, you can check the write for us page.