Function Pointers

A function is the address of the entry point to a group of instructions bundled together into the function construct. A function pointer stores the entry-point address of a function. If we dereference a function pointer, it is the same as calling the function.

When declaring a function pointer we need to separate the pointer declaration from the type of the return value. To separate the two we wrap the pointer declaration in a set of parentheses.

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

long addNums(int a, int b);
long subNums(int a, int b);
long multNums(int a, int b);

char *reverseStr(char *str);

int main()
{
    char *strOrig = "Greetings, Professor Falken";
    char *str = NULL;

    int i = 0;
    long answer = 0;
    int iVarOne = 42;
    int iVarTwo = 73;

    long (*mathFunction)(int a, int b);

    long (*mathArray[3])(int a, int b);

    char *(*stringFunction)(char *str);

    stringFunction = reverseStr;

    printf("Address of string reverse function is %p\n", reverseStr);
    str = (*stringFunction)(strOrig);

    printf("%s backwards is %s\n", strOrig, str);

    mathArray[0] = addNums;
    mathArray[1] = subNums;
    mathArray[2] = multNums;

    for(i = 0; i < 3; i++){
        answer = (*mathArray[i])(iVarOne, iVarTwo);
        printf("%ld\n", answer);
    }

    return 0;
}

long addNums(int a, int b){
    return a + b;
}

long subNums(int a, int b){
    return a - b;
}

long multNums(int a, int b){
    return a * b;
}

char *reverseStr(char *str){
    int i, j, strLength;

    char *returnString = NULL;

    if(str != NULL){
        strLength = strlen(str);
        returnString = (char *)malloc(sizeof(char) * (strLength  + 1));
        if(returnString != NULL){
            for(i = 0, j = strLength - 1; i < strLength; i++, j--){
                returnString[i] = str[j];
            }
            returnString[strLength] = '\0';
        }
    }
    return returnString;
}

The function names act as address tags in the same way that array names act as address tags.

Advertisements

Function Pointers in C

A function is not really a separate, isolated block of code so much as it is the address of the entry point to a series of instructions that are organized logically as a function. At the level of assembly language, a function is simply a sequence of instructions with a known starting point, which is the memory address of the first instruction.

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

int addThree(int a, int b, int c);
int subThree(int a, int b, int c);

int main()
{
 printf("Location of addThree() function %p\n", addThree);
 printf("Location of subThree() function %p\n", subThree);

 return 0;
}


int addThree(int a, int b, int c) {
 return a + b + c;
}

int subThree(int a, int b, int c) {
 return a - b - c;
}

A function pointer is therefore nothing more than a pointer that stores the entry point address of a function.

When declaring a function pointer, we should take care to separate the pointer declaration from the type of the return value by enclosing the pointer declaration in a set of parentheses.

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

//same param list and return values

//returns long long
long long addNum(int x, int y) { return x + y; }
long long subtractNum(int x, int y) { return x - y; }

//returns double
double divideNum(int x, int y) { return (double)x / y; }
double multiplyNum(int x, int y) { return (double)x * y; }


int main()
{
 long long (*iAction)(int x, int y);
 double(*dAction)(int x, int y);
 
 iAction = addNum;
 dAction = divideNum;

 //dereference the function pointer to call the function
 printf("%lld\n", (*addNum)(1138, 1701));
 printf("%f\n", (*dAction)(47, 7));

 dAction = multiplyNum;

 printf("%lld\n", (*subtractNum)(1138, 1701));
 printf("%f\n", (*dAction)(100, 11));

 return 0;
}

Note that function names function in the same as array names, in that they both devolve to a memory address.

We can use function pointers to increase the flexibility of the flow of our program. For example, by using function pointers we can alter the order in which we call functions depending on either compile time or run time data.

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

const int Num_Functions = 4;

void funcOne(void) {
 printf("Executing function one.\n");
}

void funcTwo(void) {
 printf("Executing function two.\n");
}

void funcThree(void) {
 printf("Executing function three.\n");
}

void funcFour(void) {
 printf("Executing function four.\n");
}

void(*funcArray[Num_Functions])(void) { funcOne, funcTwo, funcThree, funcFour };

int main()
{
 int i = 0;

 while (i < Num_Functions) {
 //using pointer arithmetic
 (*(funcArray + i++))();
 }

 printf("Now backwards!\n");

 //remember i is at 4
 //so we must decrement it before using it
 //as an index value
 while (i-- > 0) {
 //using indexers
 (*funcArray[i])();
 }
 return 0;
}

Another interesting thing we can do with function pointers is create a function dispatcher.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//note we are including time.h for the srand() function


const int Num_Functions = 4;

void functionW(const char *szArg) {
 printf("Function W acting on parameter '%s'\n\n", szArg);
}

void functionX(const char *szArg) {
 printf("Function X acting on parameter '%s'\n\n", szArg);
}

void functionY(const char *szArg) {
 printf("Function Y acting on parameter '%s'\n\n", szArg);
}

void functionZ(const char *szArg) {
 printf("Function Z acting on parameter '%s'\n\n", szArg);
}


void(*actions[Num_Functions])(const char *szArg) = { functionW, functionX, functionY, functionZ };

//this function calls the other functions we have defined. 
void dispatchFunction(int iType, char * szInstruction) {
 if ((iType > -1) && (iType < Num_Functions)) {
 (*actions[iType])(szInstruction);
 }
}

int main()
{
 const int num_arguments = 6;
 srand(time(NULL));
 

 char *szArgs[num_arguments] = { 
 "Nice boat!", 
 "That is mahogany!", 
 "Don't Panic",
 "Greetings, Professor Falken",
 "You are likely to be eaten by a grue.",
 "El Psy Congroo."
 };

 for (int i = 0; i < num_arguments; i++) {
 dispatchFunction(rand() % Num_Functions, szArgs[i]);
 }
 return 0;
}

Fun with Function Pointers

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.

Function Pointers in C

A function pointer is a pointer that holds the address of a function, thereby giving our programs greater flexibility. This flexibility might (or might not, depending) come at the cost of increased use of system resources. 

The simplest function pointer we can have is a pointer to a function that accepts no parameters and doesn’t return a value. Such a pointer would look like void (*func)(); – we note here that the function pointer’s identifier, func, is preceded by an asterisk and enclosed in parentheses. 

Let’s look at an example.

#include <stdio.h>

void functionOne(void);
void functionTwo(void);

int main(void){

void (*funcA)();
void (*funcB)();

funcA = functionOne;
funcB = functionTwo;

funcA();
funcB();

return 0;

}

void functionOne(void){
printf("Function One called.\n");
}

void functionTwo(void){
printf("Function Two called.\n");
}

Assigning the function addresses to a function pointer is easy, just use the assignment operator use the function name as the rvalue. There’s no need to place the address-of operator before the function name. Just as with array names, the function name by itself returns the function’s address in memory. 

#include <stdio.h>

void printInt(int n);
void addDoubles(double dX, double dY);
int factorial(int n);

int main(void){

void (*funcOne)(int);
void (*funcTwo)(double, double);
int (*funcThree)(int);


funcOne = printInt;
funcTwo = addDoubles;
funcThree = factorial;

funcOne(73);
funcTwo(68.803, 18.0025);
printf("4! = %d\n", funcThree(4));

return 0;

}

void printInt(int n){
printf("Function received the integer %d\n", n);
}

void addDoubles(double dX, double dY){
printf("%f + %f = %f\n", dX, dY, dX + dY);
}

int factorial(int n){
int total = 1;
while(n>1){
total *= n--;
}
return total;
}

Passing a function as an argument to another function is not difficult. We must simply define a function pointer declaration as the parameter in the target function’s definition.

#include <stdio.h>

int divide(int x, int y);
int subtract(int x, int y);
int add(int x, int y);
void compute(int x, int y, int (*operation(int,int)));


int main(void){

int (*func)(int, int) = subtract;

compute(10, 20, func);

func = add;

compute(13, 191, func);

func = divide;

compute(17, 3, func);

return 0;

}

int divide(int x, int y){
if(x % y == 0){
return x / y;
} else {
printf("warning: remainder omitted.\n");
return x / y;
}
}

int subtract(int x, int y){
return x - y;
}

int add(int x, int y){
return x + y;
}

void compute(int x, int y, int (*operation(int,int))){
printf("performing an operation on %d and %d\n", x, y);
printf("the result is %d\n", operation(x, y));
}

Using typedef, we can make our function parameter lists a little clearer. The typedef keyword enables us to create new, more complex types out of simpler types.

#include <stdio.h>

#define ARRAY_SIZE 7

typedef int (*funcPtr)(int);

int makeEven(int n);
int makeOdd(int n);
void modifyArray(int array[], funcPtr fPtr);

int main(void){

int array1[ARRAY_SIZE] = {2161, 400, 25, 636, 18, 338, 41};
int array2[ARRAY_SIZE] = {47, 3, 424, 7, 33, 1999, 8};
int i;

funcPtr fPtrOne = makeEven;
funcPtr fPtrTwo = makeOdd;

for(i = 0; i < ARRAY_SIZE; i++){
printf("%d\t", array1[i]);
}

modifyArray(array1, fPtrOne);

for(i = 0; i < ARRAY_SIZE; i++){
printf("%d\t", array1[i]);
}

printf("\nNow for the second array.\n");

for(i = 0; i < ARRAY_SIZE; i++){
printf("%d\t", array2[i]);
}

modifyArray(array2, fPtrTwo);

for(i = 0; i < ARRAY_SIZE; i++){
printf("%d\t", array2[i]);
}

}


int makeEven(int n){
if(n % 2 == 0){
return n;
} else {
return n * 2;
}
}

int makeOdd(int n){
if(n % 2 == 0){
return n * 2 - 1;
} else {
return n;
}
}

void modifyArray(int array[], funcPtr fPtr){

printf("\nmodifying array\n");
for(int i = 0; i < ARRAY_SIZE; i++){
array[i] = fPtr(array[i]);
}

}