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.

Advertisements

One thought on “Fun with Function Pointers

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s