Function pointer in C

The function pointer in C provides the execution link of a function.
In fact, the function pointer is sometimes disliked and not used enough. However, it is a very useful tool for introducing polymorphism or simplifying some complex structures.

Function pointer in C

How to use the function pointer in C

Declaration

The declaration of a function pointer in C is similar to the declaration of a function. You have to declare the return type, the argument list and the name of the function pointer.

Function_return_type (*Function_Pointer_name)(Function argument list);

Examples :

//It can point to function which takes an int as an argument and return nothing.
void (*fpData)(int);

//It can point to function which takes a const char * as an argument and return nothing.
void (*pfDisplayMessage)(const char *);

//It can point to function which takes an int as an argument and return int.
int  (*fpData)(int);

Initialization

A function pointer in C is similar to a common pointer, it must be initialized. Anyway, you have to respect the signature of the pointer. Indeed the pointed function must have the same return type and the same argument type.

//declaration of function pointer
int (* pfAddTwoNumber) (int, int);
//function with same signature
int AddTwoNumber(int a, int b)
{
    return (a + b);
}

Two syntaxes are possible to initialize a function pointer:*

pfAddTwoNumber = &AddTwoNumber;
    or
pfAddTwoNumber = AddTwoNumber;

Moreover, it is possible to initialize a function pointer with the declaration :

int (* pfAddTwoNumber) (int, int) = AddTwoNumber;

Be careful, a function pointer must always be initialized. Otherwise, calling a non-initialized function pointer will cause an application crash or a system crash.
It is recommended to initialize to NULL at the same time of declaration. Then check the validity of a function pointer before using it.

void (*fpData)(int) = NULL;

int program(int data)
{
    if( fpData != NULL)
    {
        (*fpData)(data); 
        return Valid;
    }
    else
    {
        return Invalid;
    }
}

Calling a function using the function pointer

A function using a function pointer is called as follows:

//Function pointer which has argument list
(*Function_Name)(ArgumentList);
    or
//Function pointer without argument list
(*Function_Name)();

It’s possible to ignore the indirection operator when calling the function by using the function pointer :

//Calling the function using the function pointer
iRetValue = (*pfAddTwoNumber)(10,20);
        or
//Calling the function using the function pointer        
iRetValue = pfAddTwoNumber(10,20);

Use of typedef with the function pointer

With typedef, we can make the function pointer declaration easier and more readable.
Indeed, using typedef for a pointer is very useful when creating an array of function pointers. Moreover, it is also very useful when using a function pointer as an argument or as a function return.

Example :

typedef  int (*pfunctPtr)(int, int); /* function pointer */

//Function pointer declaration
pfunctPtr pSomeFunction = NULL;

Example of a function pointer array :

//typedef of array of function pointers
typedef int (*apfArithmatics[3])(int,int);

apfArithmatics aArithmaticOperation = { AddTwoNumber,SubTwoNumber,MulTwoNumber };

In the same way, a typedef can be used to make a cast :

void *pvHandle = NULL;

typedef int (*pf)(int);
pf JumptoApp  =  (pf)pvHandle;

Function pointer as argument

It is possible to give a function pointer as argument.
So the same function can make use of different functions by using the function pointer.

Example :

typedef  int (*pfunctPtr)(int, int); /* function pointer */

//function pointer as arguments
int functionWithPointerArgument(int iData1,int iData2, pfunctPtr functPtr)
{
    int iRet =0;
    iRet = functPtr(iData1,iData2);
    return iRet;
}

/*function add two number*/
int AddTwoNumber(int iData1,int iData2)
{
    return (iData1 + iData2);
}
/*function subtract two number*/
int SubTwoNumber(int iData1,int iData2)
{
    return (iData1 - iData2);
}

int main()
{
    int iData1 = 10;
    int iData2 = 3;
    int Result = 0;

    Result = functionWithPointerArgument(iData1,iData2,AddTwoNumber);
    printf("\n\nResult  = %d\n\n",Result);

    Result = functionWithPointerArgument(iData1,iData2,SubTwoNumber);
    printf("\n\nResult  = %d\n\n",Result);

    return 0;
}

Return of a function pointer by a function

Example :

typedef  int (*pfunctPtr)(int, int); /* function pointer */
        
/*function add two number*/
int AddTwoNumber(int iData1,int iData2)
{
    return (iData1 + iData2);
}
/*function subtract two number*/
int SubTwoNumber(int iData1,int iData2)
{
    return (iData1 - iData2);
}

//Return function pointer
pfunctPtr ArithMaticOperation(int iChoice)
{
    //function pointer
    pfunctPtr pArithmaticFunction = NULL;
    if(iChoice == 1)
    {
        pArithmaticFunction = AddTwoNumber;
    }
    if(iChoice == 2)
    {
        pArithmaticFunction = SubTwoNumber;
    }
    return pArithmaticFunction;
}
        
int main()
{
    int iData1 = 10;
    int iData2 = 3;
    int Result = 0;
    pfunctPtr pArithmaticFunction = NULL; //function pointer

    pArithmaticFunction = ArithMaticOperation(1);
    Result = (*pArithmaticFunction) (iData1,iData2);
    printf("Result  = %d\n\n",Result);

    pArithmaticFunction = ArithMaticOperation(2);
    Result = (*pArithmaticFunction) (iData1,iData2);
    printf("Result  = %d\n\n",Result);

    return 0;
}

Function pointers array

We may also create an array of function pointers.
So, the array of function pointers gives the possibility to access the functions using the array index.

Example :

/*function add two number*/
int AddTwoNumber(int iData1,int iData2)
{
    return (iData1 + iData2);
}
/*function subtract two number*/
int SubTwoNumber(int iData1,int iData2)
{
    return (iData1 - iData2);
}
                
int main()
{
    int iRetValue = 0;

    //Declaration of array of function pointer
    int (*apfArithmatics [2])(int,int) = {AddTwoNumber,SubTwoNumber};
        
    //Calling the Add function using index of array
    iRetValue = (*apfArithmatics [0])(20,10);
    printf("\n\nAddition of two number = %d\n\n",iRetValue);
    //Calling the subtract function using index of array
    iRetValue = (*apfArithmatics[1])(20,10);
    printf("\n\nsubtraction of two number = %d\n\n",iRetValue);
        
    return 0;
}

Function pointer in structures

C is not an object-oriented language. Consequently, it doesn’t contain member functions like C++. But using pointers in a structure allows to provide pointers to functions that are considered as member functions. This allows us to add a notion of polymorphism in C.

Example :

//function pointer to point display message
typedef void (*pfnMessage)(const char*,float fResult);
//function pointer to point arithmetic  function
typedef float (*pfnCalculator)(float,float);

//structure of function pointer
typedef struct S_sArithMaticOperation
{
    float iResult;
    pfnMessage DisplayMessage;
    pfnCalculator ArithmaticOperation;
} sArithMaticOperation;

Example program : Periodic alarm

This is a small program using function pointers.
The objective is to obtain a module that allows to implement periodic alarms (timer) that call callback functions. It’s possible to create as many instances of timer as necessary. In the end, the execution of callback functions takes place when a function is called periodically.

The source code is available on the GitHub repository Function-Pointer-in-C

Alarm module

alarm.h

//Callback Function signature 
typedef int (*fpCallback)(int);

//Structure for alarm data
typedef struct S_sPeriodicAlarm
{
    time_t period;
    int nbrOfAlarm;
    time_t lastTimeAlarm;
    fpCallback callback;
    void* next_sPeriodicAlarm;
}sPeriodicAlarm;
//Pointer to structure for alarm data
typedef sPeriodicAlarm* psPeriodicAlarm;

void initPerodicAlarm(sPeriodicAlarm *periodicAlarm_ptr, time_t period, fpCallback callback);
int checkPeriodicAlarm(sPeriodicAlarm *periodicAlarm_ptr);
void checkAllPeriodicAlarm(void);

First, a typedef defines the signature of callback functions.

Then, the sPeriodicAlarm structure contains several information :
The period and time value of the system during the last alarm determines when an alarm should be triggered.
Moreover, the structure contains the address of the callback function and the address of the next alarm structure (NULL if no other alarm). So we can browse all the alarms thanks to the storage of the pointer of the next alarm

alarm.c

Initialization :

#include <time.h> // or #include <sys/time.h>
#include "alarm.h"

volatile psPeriodicAlarm firstPeriodicAlarm_ptr = NULL;
volatile psPeriodicAlarm lastPeriodicAlarm_ptr = NULL;

/**
 * @brief Initialize a periodic alarm with the parameters in arguments
 * 
 * @param periodicAlarm_ptr     Pointer to alarm data structure
 * @param period                Trigger period
 * @param callback              Pointer to callback function
 */
void initPerodicAlarm(sPeriodicAlarm *periodicAlarm_ptr, time_t period, fpCallback callback)
{
    periodicAlarm_ptr->period = period;
    periodicAlarm_ptr->nbrOfAlarm = 0;
    periodicAlarm_ptr->lastTimeAlarm = time(NULL) * 1000;
    periodicAlarm_ptr->callback = callback;
    periodicAlarm_ptr->next_sPeriodicAlarm = NULL;
    
    //Check if is the first alarm
    if(lastPeriodicAlarm_ptr != NULL)
        lastPeriodicAlarm_ptr->next_sPeriodicAlarm = periodicAlarm_ptr;
    else
        firstPeriodicAlarm_ptr = periodicAlarm_ptr;
    
    lastPeriodicAlarm_ptr = periodicAlarm_ptr;
}

The pointers of the first and last alarm structure are stored in the global variables ‘firstPeriodicAlarm_ptr’ and ‘lastPeriodicAlarm_ptr’.
The initialization function allows to set the periodic alarm and to store the pointer of the current alarm in the previous one.
However, in the case of a first alarm, only the global pointer of the first alarm structure is initialized.

Checking for the occurrence of an alarm :

/**
 * @brief Check if an alarm is active and execute the associated callback function
 * 
 * @param periodicAlarm_ptr     Pointer to alarm data structure
 * @return int                  Status of callback function
 */
int checkPeriodicAlarm(sPeriodicAlarm *periodicAlarm_ptr)
{
    int ret = -1;
    time_t mnow = time(NULL) * 1000;
    
    if(mnow > (periodicAlarm_ptr->lastTimeAlarm  + periodicAlarm_ptr->period))
    {
        periodicAlarm_ptr->lastTimeAlarm = mnow;
        ++periodicAlarm_ptr->nbrOfAlarm;
        if(periodicAlarm_ptr->callback != NULL)
            ret = periodicAlarm_ptr->callback(periodicAlarm_ptr->nbrOfAlarm);
    }
    
    return ret;
}

This function checks if an alarm should be triggered. If true, the alarm counter is incremented and the ‘callback’ function is called.
If no alarm is triggered, the function returns “-1”. Otherwise, the function returns the return value of the ‘callback’ function.

Verification of the occurrence of all alarms :

/**
 * @brief Checks all the alarms and executes the associated callback functions
 */
void checkAllPeriodicAlarm(void)
{
    psPeriodicAlarm actualPeriodicAlarm_ptr = firstPeriodicAlarm_ptr;
    
    while(actualPeriodicAlarm_ptr != NULL)
    {
        checkPeriodicAlarm(actualPeriodicAlarm_ptr);
        actualPeriodicAlarm_ptr = actualPeriodicAlarm_ptr->next_sPeriodicAlarm;
    }
}

Finally, this function checks all the alarms. Indeed, a loop checks all the pointers of the alarm structure if not NULL.

Main program

main.c

#include <stdio.h>
#include <sys/time.h>
#include "alarm.h"

sPeriodicAlarm firstAlarm;
sPeriodicAlarm secondAlarm;

int firstAlarmCallback(int cnt)
{
    printf("First Alarm callback: %d\n\r", cnt);
    return 0;
}

int secondAlarmCallback(int cnt)
{
    printf("Second Alarm callback: %d\n\r", cnt);
    return 0;
}

int main() 
{
    initPerodicAlarm(&firstAlarm, 2000, &firstAlarmCallback);
    initPerodicAlarm(&secondAlarm, 1000, &secondAlarmCallback);
	
    while(1)
    {
        checkAllPeriodicAlarm();
        //Do some stuff
        Sleep(10); //Limit usage of CPU
    }
    return 0;
}

We use two periodic alarms in this program. First, they are declared with the structure ‘sPeriodicAlarm’.
Then the alarms are initialized with the ‘initPerodicAlarm’ function. Finally, the verification and the triggering of the alarms are managed by the periodic call of the function ‘checkAllPeriodicAlarm()’.
It is also possible to use a timer interrupt to call the ‘checkAllPeriodicAlarm()’ function.