C/C++ Function Pointer

Introduction

Function pointers are used to pass functions as arguments to other functions in C and C++. The usages are universal in C and C++.

In this blog post, I would like to briefly cover the usages of function pointers.

Examples

To define a function pointer, we have to declare its type. The type of function pointer has the following signature.

1
T0 (*f)(T1, T2, T3, ...)

where f is the function pointer, T0 is the function output type, T1, T2, T3, etc, represents the type for argument 1, argument 2, and argument 3, etc.

When calling the function using function pointer, (*f) is just equivalent to f because the function name is just the function address.

function_ptr.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <iostream>

template <typename T>
T add(T x, T y)
{
return x + y;
}

template <typename T>
T minus(T x, T y)
{
return x - y;
}

template <typename T>
T runBinaryFunction1(T x, T y, T (*f)(T, T))
{
return (*f)(x, y);
}

template <typename T>
T runBinaryFunction2(T x, T y, T (*f)(T, T))
{
return f(x, y);
}

int main()
{
int x = 1;
int y = 2;

// fpAdd1 is a pointer for function which takes two inputs of type int and generates a output of type int
int (*fpAdd1)(int, int) = &add<int>;
// fpAdd1 is both function name and function address
// The following two are equivalent
std::cout << fpAdd1(x, y) << std::endl;
std::cout << (*fpAdd1)(x, y) << std::endl;

// add<int> is both function name and function address
// So assigning &add<int> and add<int> are equivalent
int (*fpAdd2)(int, int) = add<int>;
std::cout << fpAdd2(x, y) << std::endl;
std::cout << (*fpAdd2)(x, y) << std::endl;

// Lambda expression also works
// C does not have lambda expression
int (*fpAdd3)(int, int) = [](int x, int y){return x + y;};
std::cout << fpAdd3(x, 2) << std::endl;
std::cout << (*fpAdd3)(x, 2) << std::endl;

std::cout << runBinaryFunction1(x, y, fpAdd1) << std::endl;
std::cout << runBinaryFunction1(x, y, *fpAdd1) << std::endl;
std::cout << runBinaryFunction1(x, y, fpAdd2) << std::endl;
std::cout << runBinaryFunction1(x, y, *fpAdd2) << std::endl;
std::cout << runBinaryFunction1(x, y, fpAdd3) << std::endl;
std::cout << runBinaryFunction1(x, y, *fpAdd3) << std::endl;

std::cout << runBinaryFunction2(x, y, fpAdd1) << std::endl;
std::cout << runBinaryFunction2(x, y, *fpAdd1) << std::endl;
std::cout << runBinaryFunction2(x, y, fpAdd2) << std::endl;
std::cout << runBinaryFunction2(x, y, *fpAdd2) << std::endl;
std::cout << runBinaryFunction2(x, y, fpAdd3) << std::endl;
std::cout << runBinaryFunction2(x, y, *fpAdd3) << std::endl;
}

To compile the program, please run the following command in the terminal.

1
$ g++ function_ptr.cpp -o function_ptr -std=c++11

Conclusions

Just memorize the function pointer signature and in most of the scenarios we would not make mistake.

Author

Lei Mao

Posted on

02-09-2020

Updated on

02-09-2020

Licensed under


Comments