Introduction to Function Pointers
17 Jul 2021
This post is my notes while going through LLVM tutorials [1]. I do not own any of these materials.
Creating and Assigning Function Pointers
Function pointers are pointers to functions. To create a non-const function pointer:
// fcnPtr is a pointer to a function that takes no arguments and returns an integer
int (*fcnPtr)();
Here, fcnPtr can point to any function that takes no arguments and returns an int. Note that the parenthesis around *fcnPtr is required.
To create a const function pointer:
int (*const fcnPtr)();
Similar to normal pointers, function pointers can be initialized or assigned after the definition:
int foo() {
return 5;
}
int goo(){
return 6;
}
int main() {
int (*fcnPtr)(){ &foo }; // fcnPtr points to function foo
fcnPtr = &goo; // fcnPtr now points to function goo
return 0;
}
The type of the function pointer and the assigned function must match:
// function prototypes
int foo();
double goo();
int hoo(int x);
// function pointer assignments
int (*fcnPtr1)(){ &foo }; // okay
int (*fcnPtr2)(){ &goo }; // not okay. goo returns double
double (*fcnPtr4)(){ &goo }; // okay
fcnPtr1 = &hoo; // not okay. hoo takes one int input
int (*fcnPtr3)(int){ &hoo }; // okay
Calling Functions Using Function Pointers
Two ways to do this: explicit and implicit dereference.
Explicit dererefence:
int foo(int x) {
return x;
}
int main() {
int (*fcnPtr)(int){ &foo };
(*fcnPtr)(5); // call foo(5) explicitly
return 0;
}
Implicit dererefence:
int main() {
int (*fcnPtr)(int){ &foo };
fcnPtr(5); // call foo(5) implicitly
return 0;
}
Passing Function Pointers as Arguments
Common use case. Functions used as arguments to other functions are sometimes called callback functionss. For example, I can create a function to perform sort but let the caller provide the specifc comparison function as a function pointer:
// the user-defined comparison is the third parameter
void selectionSort(int *array, int size, bool (*comparisonFcn)(int, int)) {
for (int startIndex{ 0 }; startIndex < (size - 1); ++startIndex) {
int bestIndex{ startIndex };
for (int currentIndex{ startIndex + 1 }; currentIndex < size; ++currentIndex) {
// Use the function pointer implicitly
if (comparisonFcn(array[bestIndex], array[currentIndex])) {
bestIndex = currentIndex;
}
}
std::swap(array[startIndex], array[bestIndex]);
}
}
bool ascending(int x, int y) {
return x > y;
}
bool descending(int x, int y) {
return x < y;
}
int main() {
int array[9]{ 3, 7, 9, 5, 6, 1, 8, 2, 4 };
selectionSort(array, 9, descending); // pass in different comparison functions
selectionSort(array, 9, ascending);
return 0;
}
Note that as a function parameter, function pointer type is equivalent to function type. Thus, the below two lines are the equivalent:
void selectionSort(int *array, int size, bool (*comparisonFcn)(int, int))
void selectionSort(int *array, int size, bool comparisonFcn(int, int))
We can provide default functions:
void selectionSort(int *array, int size, bool (*comparisonFcn)(int, int) = ascending);
Using Type Aliases to Make Function Pointers Prettier
using ValidateFunction = bool(*)(int, int);
bool validate(int x, int y, bool (*fcnPtr)(int, int)); // ugly
bool validate(int x, int y, ValidateFunction pfcn) // clean
Type Inference
We can use the auto keyword to infer the type of a function pointer:
int foo(int x) {
return x;
}
int main() {
auto fcnPtr{ &foo };
std::cout << fcnPtr(5) << '\n';
return 0;
}
Sources
[1] https://www.learncpp.com/cpp-tutorial/function-pointers/