A function pointer is a pointer that holds the address of a function. Being able to create pointers to point to functions is awesome but also terrifying, in a way. The great thing about function pointers is that they provide us with a means for executing functions in an order that may not be known at compile time and without needing conditional statements. Function pointers provide support for alternate execution paths.
To declare a function pointer, we surround the function name with parentheses and add an asterisk to the front of the name. A rough outline of a function pointer follows the form return_type (*function_name)(parameters).The asterisk indicates that it is a pointer, and the parentheses make it a function pointer.
//returns void no parameters
void (*funcPtrOne)();
//returns int, passed an int
int (*funcPtrTwo)(int)
//returns double, passed two ints
double (*funcPtrThree)(int, int);
//returns char, passed string
char (*funcPtrFour)(const char *szText);
Be aware of the difference between functions that return a pointer versus function pointers. The parentheses around the function name prefixed by an asterisk indicates that it is a function pointer.
To use a function pointer, assign a function’s address to the function pointer. The function pointer and the actual function it is pointing to must have the same signature, i.e. the same return type and parameter types.
#include <stdio.h>
//func pointer
int (*fPtrIntCharChar)(char, char);
//function to compare two char parameters
//if first param is greater than second param
//or it is the only capital letter
//returns positive int
//if second param is greater than first param
//or it is the only capital letter
//returns negative int
int compareLetters(char cX, char cY);
int _tmain(int argc, _TCHAR* argv[])
{
int iRVal;
char cLetters[] = {'b', 'f', 'A', 'Q', 'u', 'Z', 'z', 'T', 'b', 'C', 'e', 'e', 'r', 'V', 'v'};
const int Array_Bounds = sizeof(cLetters) / sizeof(char);
fPtrIntCharChar = compareLetters;
for(int i = 1; i < Array_Bounds; i++){
iRVal = fPtrIntCharChar(cLetters[i-1], cLetters[i]);
if(iRVal==0){
printf("%c and %c are equal.\n", cLetters[i-1], cLetters[i]);
}
if(iRVal>0){
printf("%c comes before %c.\n", cLetters[i-1], cLetters[i]);
}
if(iRVal<0){
printf("%c comes before %c.\n", cLetters[i], cLetters[i-1]);
}
}
return 0;
}
//returns -1 if first character is after
//second character
//returns +1 if first character is before
//the second character
int compareLetters(char cX, char cY){
int iDiff = cX - cY;
//x is greater than y
//therefore x is after y in the alphabet
if(iDiff > 0){
return -1;
}
//y is greater than x numerically
//therefore y is after x in the alphabet
if(iDiff < 0){
return 1;
}
//two letters are equal
return iDiff;
}
As we can see above, just like with array names, when we use the name of a function by itself, it returns the function’s address. It is not necessary to use the address of operator. We can even use the comparison operator to verify this.
#include <stdio.h>
void (*funcPtrA)(int a);
double (*funcPtrB)(double a);
void functionOne(int a);
double functionTwo(double a);
int _tmain(int argc, _TCHAR* argv[])
{
printf("Address for functionOne %p.\n", functionOne);
printf("Address for functionTwo %p. \n", functionTwo);
//& operator unnecessary
funcPtrA = &functionOne;
funcPtrB = functionTwo;
if(funcPtrA == functionOne){
printf("Same address.\n");
}
if(funcPtrB == &functionTwo){
printf("Still same address.\n");
}
return 0;
}
void functionOne(int a){
printf("Hello %d.\n", a);
}
double functionTwo(double a){
return a * 19.99;
}
It’s simple enough to declare a type definition for function pointers.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef void (*fPtrVoidVoid)(void);
typedef char*(*fPtrCharCharPtr)(char *);
void functionPrintHello(void);
char * functionChangeString(char *);
int main(void){
fPtrVoidVoid fpOne = functionPrintHello;
fPtrCharCharPtr fpTwo = functionChangeString;
char * szString = fpTwo("Do you have stairs in your house?");
fpOne();
printf("%s\n", szString);
//clean up
free(szString);
return 0;
}
void functionPrintHello(void){
printf("Saluton Mundo! ");
}
char * functionChangeString(char * szParam){
char *rszVal = (char *)malloc((strlen(szParam) + 256)*sizeof(char));
strcpy(rszVal, szParam);
strcat(rszVal, " I am protected.");
return rszVal;
}
It is not difficult to pass a function pointer, we must simply use the function pointer declaration as a parameter of a function.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef int (*fptrInt)(int, int);
void doSomething(int iArray[], int bounds, fptrInt);
int sum(int x, int y);
int multiply(int x, int y);
int main(void){
int iArray[] = {80, 443, 25, 161, 143, 389, 156, 21};
const int iBounds = sizeof(iArray) / sizeof(int);
doSomething(iArray, iBounds, sum);
printf("And now for something completely different.\n");
doSomething(iArray, iBounds, multiply);
return 0;
}
void doSomething(int iArray[], int bounds, fptrInt func){
for(int i = 0; i < bounds - 1; i+=2){
printf("%d.\n", func(iArray[i], iArray[i+1]));
}
}
int sum(int x, int y){
printf("Adding %d and %d.\n", x, y);
return x + y;
}
We can see that function pointers can add a high degree of flexibility to code. There are performance considerations to be aware of – on the lower level, function pointers can disrupt the processor pipeline, which can negatively impact performance.