Function Pointers in C/C++ and Function Callbacks

In this useful tutorial, we will learn about function pointers. Firstly, we will see the introduction of function pointers. After that, we will discuss some real use cases of function pointers and call-backs.

If you have little or no knowledge of pointers, you should read this:

Function Pointer in C and C++

A function pointer is a pointer that points to a function. In other words, a function pointer holds the address of first instruction of a function or executable code. Unlike data pointers, dereferencing a function pointer invokes the reference function or calls the reference function.

A function pointer can be used to select a function from multiple options to be executed during run time based on some variables. For example, we have different functions that we want to execute for different types of interrupts. But we don’t know when a particular interrupt will occur on runtime. By using a function pointer, we can call a function related to each interrupt during runtime.

Function pointers provide us a way to call function during program execution when we do not know during compile time in which order to execute a function.

How to Declare a Function Pointer? 

The declaration of a function pointer depends on the function to which it will point to. For example, we have this function definition that accepts two integer variables as an argument and returns an integer variable:

int sum(int a, int b);

A function pointer for the above function can be declared like this:

int (*sumfunPtr)(int x, int y);

The important point to note here is that the input arguments and return type function pointer should be the same as of function definition.

Function Pointers as Function Arguments

Function pointers can be passed as arguments to functions then a function that would receive a function pointer as an argument can call-back the function that this pointer will point to. We will explain it with a simple C code below:

#include<stdio.h>
void message(){
printf("Welcome!");
}

void func(void (*ptr1)()){ 
ptr1();
}

int main(){
void (*ptr2)()=message;
func(ptr2);
}

We have two user defined functions in this code. The first function message() is a void function and takes in no arguments. It prints a “Welcome!” message as an output.

void message(){
printf("Welcome!");
}

The next user defined function func() is also a void function but this function takes a function pointer as an argument instead. In this case ‘ptr1’ should point to a void function that should take in no arguments. In func() we will use the function pointer ‘ptr1’ to call whatever function it is pointing to. The ptr1() is the call-back function that ‘ptr1’ points to.

void func(void (*ptr1)())
{ ptr1();
}

In the main() function, we will declare a function pointer and this function pointer will also point to a void function that takes in no arguments. We will initialize this function pointer ‘ptr2’ with the address of message. Then, we will call the function func() and pass this function pointer ‘ptr2’ as an argument.

int main(){
void (*ptr2)()=message;
func(ptr2);
}

Code Output

Now let’s see the code output. After the compilation of the above code, you will get this output.

Function Poinetrs and Callbacks output demo 1

You will notice that Welcome! is getting printed. This shows that the function message() is getting executing through the ptr1() call-back function.

To make this code more compact let us modify the main() function. We will replace the two statements with a single one as shown below.

int main(){
func(message);
}

As the name of a function returns a pointer, so this one statement (func(message)) is the same as the previous two statements which we were using in the main() method.

Note: When reference to a function is passed to another function, then that particular function is called a call-back function.

In this case, message() is the call-back function. Basically, it can be called back by func through the reference in this case which is the function pointer. The ptr1() statement where we are calling the function through a function pointer is a call-back. However, this example is not very purposeful as there is no point in calling message indirectly through func in this code (func(message)). Thus, we will look at a better example for function pointer and call-backs in the section below.

Callback Functions Using Function Pointers In C

The previous code did not provide us with a good example of function pointers and callbacks and made it look unreasonable. However, in this section, we will look at an example that will help you understand this concept in a clear and simpler manner.

Sorting List in Ascending Order

For demonstration let’s take an example of a bubble sort sorting algorithm. This C program sorts a list of integers in an array in ascending order. We will create our own user-defined sort function.

#include<stdio.h>
void BubbleSort(int array[],int elements){
int i,j,temp;
for(i=0;i<elements;i++)
    for(j=0;j<elements-1;j++){
        if (array[j]>array[j+1]){
          temp=array[j];
          array[j]=array[j+1];
          array[j+1]=temp;
       }
    }
}

int main(){
int i, array[]={15,10,8,4,7,3,34,0};
BubbleSort(array,8);
printf("Sorted List =");
for (i=0;i<8;i++){
printf(" %d", array[i]);}
}

How the Code Works?

The BubbleSort() function will take an integer array and number of elements in the array as arguments. The function takes in two arguments. The first argument is ‘array[]’ of integer data type. The second argument is ‘elements’ of integer data type as well that depicts the number of elements in the array.

void BubbleSort(int array[],int elements)

We will use the bubble sort method to sort our list of numbers in ascending order. In bubble sort, we make multiple passes on an array and in each pass as we go from left to right as we go from lower indices to higher indices, we compare adjacent elements and if the element at lower index is greater than the element at higher index when comparing adjacent elements then we swap the elements.

The inner for loop is a pass on an array and the outer for loop is saying we will make passes equal to the number of elements. After the first pass the largest element in the list will ‘bubble up’ to the highest index. Likewise, in the next pass the second largest will ‘bubble up’ to its appropriate position. This will go on and finally when the passes equals the number of elements, the complete list will be sorted.

void BubbleSort(int array[],int elements){
int i,j,temp;
for(i=0;i<elements;i++)
    for(j=0;j<elements-1;j++){
        if (array[j]>array[j+1]){
          temp=array[j];
          array[j]=array[j+1];
          array[j+1]=temp;
       }
    }
}

In the main() function, we will call BubbleSort() function and pass the array of numbers and specify the number of elements as the two arguments. The number of elements in our case are 8. Lastly, we will print all the elements in the array.

int main(){
int i, array[]={15,10,8,4,7,3,34,0};
BubbleSort(array,8);
printf("Sorted List =");
for (i=0;i<8;i++){
printf(" %d", array[i]);}
}

Now let’s see the code output. After the compilation of the above code, you will get this output.

Function Poinetrs and Callbacks output demo 2

As you can see our array of integers got sorted in ascending order (increasing values).

Sorting List in Descending Order

Now let us see how we can modify the code given above to sort the list of integers in descending order (decreasing values).

The only change will be in the comparison logic in the if() statement as shown below:

if (array[j]<array[j+1])

While comparing the adjacent elements, now if the element at lower index is smaller then swap (then push it towards higher index). Comparing adjacent elements and swapping is just like pushing smallest/highest element towards higher indices. With this comparison we are pushing the smaller number towards higher index. Rest of the code remains the same.

#include<stdio.h>
void BubbleSort(int array[],int elements){
int i,j,temp;
for(i=0;i<elements;i++)
    for(j=0;j<elements-1;j++){
        if (array[j]<array[j+1]){
          temp=array[j];
          array[j]=array[j+1];
          array[j+1]=temp;
       }
    }
}

int main(){
int i, array[]={15,10,8,4,7,3,34,0};
BubbleSort(array,8);
printf("Sorted List =");
for (i=0;i<8;i++){
printf(" %d", array[i]);}
}

Now let’s see the code output. After the compilation of the above code, you will get this output.

Function Poinetrs and Callbacks output demo 3

As you can see our array of integers got sorted in descending order (decreasing values).

Now the question is how we can use the same bubble sort algorithm to sort an array of integers in both ascending and descending order? We can make use of function pointers as call-back functions by defining separate comparison functions for ascending and descending order sorting. But the bubble sort algorithm remains the same.

Including both Ascending & Descending orders

Now, what if we want to include both types of sorting orders for our integer list i.e. sorting numbers with increasing values and sorting numbers with decreasing values. Let us see how we can modify our program code now.

One way of handling this scenario is to create two functions for sorting. One function for ascending order and another one for descending order. The two functions will be almost identical except for the comparison statement in which we will change the sign (>/<) according to the sorting order. Therefore, this will lead to a lot of similar code that will make the project inconvenient.

Another solution to this scenario is to pass another argument to the BubbleSort() function to say whether we want the list sorted in ascending or descending order. This variable will be integer type and can be called ‘order’. If the value of the ‘order’ is 0 then we want the list of numbers sorted in descending order and when the ‘order’ is 1 then we want the list of numbers to be sorted in ascending order.

void BubbleSort(int array[],int elements, int order)

Using this approach, we can avoid writing a lot of identical code.

Using Function Pointers

However, the solution which we will use to sort the list with an option of sorting it in ascending/descending order in the same code will be to use function pointers instead.

#include<stdio.h>
int compare(int x, int y){
    if (x > y) return 1;
    else return -1;
}
void BubbleSort(int array[],int elements, int (*compare)(int,int)){
int i,j,temp;
for(i=0;i<elements;i++)
    for(j=0;j<elements-1;j++){
        if (compare(array[j],array[j+1])>0){
          temp=array[j];
          array[j]=array[j+1];
          array[j+1]=temp;
       }
    }
}

int main(){
int i, array[]={15,10,8,4,7,3,34,0};
BubbleSort(array,8, compare);
printf("Sorted List =");
for (i=0;i<8;i++){
printf(" %d", array[i]);}
}

How the Code Works?

Sorting of a list is always done on some sort of ranking mechanism, so based on some property we should be able to compare elements and say that these elements should come first and the others should come later. The core logic in sorting will always be the same. Only the ranking mechanism or comparison logic will change. We will decide which element is greater in rank and which element is lesser through a function. Thus, we will perform the comparison through a function.

The BubbleSort() function will take a function pointer as an argument. The call-back function or the function that this pointer should point to must take two integers as arguments. It should compare the two integers and then it should return back an integer. It should return 1 if the first element has a higher rank and -1 if the second element has higher rank. The element that has the higher rank will get sorted at the end of list.

void BubbleSort(int array[],int elements, int (*compare)(int,int))

We will use the call-back function for comparison. If array[j] and array[j+1] are passed as arguments to the call-back function and we get 1 then the (>0) condition will be true. While this condition is true, we will swap, because array[j] will have to be in higher rank for this comparison function to return 1. Hence, we will try to push array[j] towards the higher indices.

if (compare(array[j],array[j+1])>0){
          temp=array[j];
          array[j]=array[j+1];
          array[j+1]=temp;
       }

This is the call-back function for the Bubble sort mechanism.

int compare(int x, int y){
    if (x > y) return 1;
    else return -1;
}

Inside the main(), we will use the name of the call-back function that will return the function pointer. We will pass it as an argument while calling BubbleSort() along with the array and the number of elements.

int main(){
int i, array[]={15,10,8,4,7,3,34,0};
BubbleSort(array,8,compare);
printf("Sorted List =");
for (i=0;i<8;i++){
printf(" %d", array[i]);}
}
Code Output

Now let’s see the code output. After the compilation of the above code, you will get this output.

Function Poinetrs and Callbacks output demo 2

As you can see our array of integers got sorted in ascending order (increasing values).

  • To sort the array of integers in descending order (decreasing values) we will have to modify the comparison logic a bit. The rest of the code will remain the same. Now, in the call-back function we will return -1 if (x > y) instead of 1. By doing this we have changed the ranking mechanism. The element with the lower value will now be ranked higher and thus will go towards the end of the array. This is the modified call-back function for sorting numbers in decreasing values.
int compare(int x, int y){
    if (x > y) return 1;
    else return -1;
}

Now let’s see the code output. After the compilation of the above code, you will get this output.

Function Poinetrs and Callbacks output demo 3

As you can see our array of integers got sorted in descending order (decreasing values).

Thus, we were able to sort the array of integers in both orders: ascending and descending by just changing the ranking mechanism. This BubbleSort() function can sort a list of integers based on any ranking mechanism. For each ranking mechanism, we can have a call-back function associated with it.

The following code can sort numbers in both ascending and descending order using function pointers as function callbacks.

#include<stdio.h>
int compare_ascending(int x, int y){
    if (x > y) return 1;
    else return -1;
}

int compare_decending(int x, int y){
    if (x < y) return 1;
    else return -1;
}
void BubbleSort(int array[],int elements, int (*compare)(int,int)){
int i,j,temp;
for(i=0;i<elements;i++)
    for(j=0;j<elements-1;j++){
        if (compare(array[j],array[j+1])>0){
          temp=array[j];
          array[j]=array[j+1];
          array[j+1]=temp;
       }
    }
}

int main(){
int i, array[]={15,10,8,4,7,3,34,0};
BubbleSort(array,8, compare_ascending);
printf("Sorted List =");
for (i=0;i<8;i++){
printf(" %d", array[i]);}
printf("\n");
BubbleSort(array,8, compare_decending);
printf("Sorted List =");
for (i=0;i<8;i++){
printf(" %d", array[i]);}
}

Sorting Absoute Value with Bubble Sort and Function Pointers

Now, let’s make this project a bit further and include both positive and negative numbers to be sorted.

Sorting in increasing order of the absolute value of integers

Our aim will be to sort the array of integers in increasing order of the absolute value of integers. This means that the negative signs will not matter. Note that now the integers values will include both negative and positive values. We will take the modulus of the value and then compare.

For example if our un sorted array is {2,9,-1,7,-4,3,-5,0} then the sorted array in increasing order of the absolute value of integers will be {0,-1,2,3,-4,-5,7,9}.

As you already know, to be able to sort the array of integers we will require a comparison function. We first include the math.h library which will be helpful as we will require the abs() function from this library. This function returns the absolute value of an integer. If absolute value of x is greater than the absolute value of y, then it will be ranked higher so it will return 1. Otherwise, it will return -1. We will use this function to sort our array.

#include<math.h>
int compare(int x, int y){
    if (abs(x) > abs(y)) return 1;
    else return -1;
}

Now let’s see the code output. After the compilation of the above code, you will get this output.

Function Poinetrs and Callbacks output demo 4

As you can see our array of integers got sorted in increasing order of the absolute value of integers.

Sorting in decreasing order of the absolute value of integers

If you want to sort the array of integers in decreasing order of absolute value of integers then we will use the following comparison function.

#include<math.h>
int compare(int x, int y){
    if (abs(x) > abs(y)) return -1;
    else return 1;
}

Now, in the call-back function we will return -1 if absolute value of x is greater than absolute value of y instead of 1. By doing this we have changed the ranking mechanism.

For example if our un sorted array is {2,9,-1,7,-4,3,-5,0} then the sorted array in decreasing order of the absolute value of integers will be {9,7,-5,-4,3,2,-1,0}.

Now let’s see the code output. After the compilation of the above code, you will get this output.

Function Poinetrs and Callbacks output demo 5

As you can see our array of integers got sorted in decreasing order of the absolute value of integers.

Notice that only the call-back function is being modified with the addition of the math.h library. The rest of the code is the same as before.

#include<stdio.h>
#include<math.h>
int abs_compare_ascending(int x, int y){
    if (abs(x) > abs(y)) return 1;
    else return -1;
}

#include<math.h>
int abs_compare_decending(int x, int y){
    if (abs(x) > abs(y)) return -1;
    else return 1;
}
void BubbleSort(int array[],int elements, int (*compare)(int,int)){
int i,j,temp;
for(i=0;i<elements;i++)
    for(j=0;j<elements-1;j++){
        if (compare(array[j],array[j+1])>0){
          temp=array[j];
          array[j]=array[j+1];
          array[j+1]=temp;
       }
    }
}

int main(){
int i, array[]= {0,-1,2,3,-4,-5,7,9};
BubbleSort(array,8, abs_compare_ascending);
printf("Sorted List =");
for (i=0;i<8;i++){
printf(" %d", array[i]);}
printf("\n");
BubbleSort(array,8, abs_compare_decending);
printf("Sorted List =");
for (i=0;i<8;i++){
printf(" %d", array[i]);}
}

Different CallBack function for qsort()

The BubbleSort() function that we created can only take an array of integers but we have a library function that can take any array. It is generic in nature. This library function is in stdlib.h library. This function is called qsort() and is named after quick sort.

Now let us use this function to make our code more broader in general. Below is the new program sketch which sorts an integer array in increasing values. Note the array consists of both positive and negative numbers.

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
int compare(const void* x,const void* y){
  int X = *((int*)x); 
  int Y = *((int*)y); 
  return X-Y; 
}

int main(){
int i, array[]={2,9,-1,7,-4,3,-5,0};
qsort(array,8,sizeof(int),compare);
printf("Sorted List =");
for (i=0;i<8;i++){
printf(" %d", array[i]);}
}

How the Code Works?

The qsort() function takes in four arguments. The first argument is the array of any type e.g. integer array, char array etc. The second argument is the number of elements. The third argument is the size of the data type in bytes. The last argument is the function pointer which is the pointer to the comparison function.

qsort(array,8,sizeof(int),compare);

The comparison function should take two constant void arguments as pointers and return an integer. Void pointers are generic pointers. We typecast them to a pointer of any data type. This is the specification of the qsort() function. It should be passed a pointer to such a function so it will be able to call it back.

You can think of this as a reference of the first element passed as a void pointer. To get the element we will first have to typecast the void pointer to int pointer (considering we have an integer array). Then we will use the asterisk operator to de-reference and obtain the value. Likewise, the same operation will be performed for the second element as well. This function will return a positive integer if the element X is ranked higher and return -1 if X is ranked lower. This will be checked via the statement (X-Y). If X is higher in value (X-Y) will be positive. This comparison function will rank an integer with higher value as high. So, basically this comparison function can be used to sort the array in increasing order of value of integers.

Thus, if the function returns a positive value then it means element X is ranked higher and if the function returns a negative value then it means that element y is ranked higher.

int compare(const void* x,const void* y){
  int X = *((int*)x); 
  int Y = *((int*)y); 
  return X-Y; 
}

Inside the main() function, we will initialize our array with both positive and negative values. Then we will call the qsort() function with all its appropriate arguments that we discussed above. Lastly, we will print the array as an output.

int main(){
int i, array[]={2,9,-1,7,-4,3,-5,0};
qsort(array,8,sizeof(int),compare);
printf("Sorted List =");
for (i=0;i<8;i++){
printf(" %d", array[i]);}
}

Code Output

Now let’s see the code output. After the compilation of the above code, you will get this output.

Function Poinetrs and Callbacks output demo 6

As you can see our array of integers got sorted in increasing order of integer values keeping in view the negative values as well.

  • Moreover, if you want to sort an integer array in decreasing value just modify the comparison function as shown below. The rest of the code remains the same.
int compare(const void* x,const void* y){
  int X = *((int*)x); 
  int Y = *((int*)y); 
  return Y-X;  
}

In this function, we just modified the return statement. Instead of returning the value of (X-Y) we will return the value of (Y-X) instead. Thus, the element with the lesser value will be ranked higher, and hence the list will be sorted in decreasing order.

Now let’s see the code output. After the compilation of the above code, you will get this output.

Function Poinetrs and Callbacks output demo 7

As you can see our array of integers got sorted in decreasing order of integer values keeping in view the negative values as well.

  • We can also sort the array of integers in increasing order of the absolute value of integers. The comparison function will be modified as follows:
int compare(const void* x,const void* y){
  int X = *((int*)x); 
  int Y = *((int*)y); 
  return (abs(X)-abs(Y));
   
}

Now let’s see the code output. After the compilation of the above code, you will get this output.

Function Poinetrs and Callbacks output demo 4

As you can see our array of integers got sorted in increasing order of the absolute value of integers.

  • Likewise, we can also sort the array of integers in decreasing order of the absolute value of integers. The comparison function will be modified as follows:
int compare(const void* x,const void* y){
  int X = *((int*)x); 
  int Y = *((int*)y); 
  return (abs(Y)-abs(X));
}

Now let’s see the code output. After the compilation of the above code, you will get this output.

Function Poinetrs and Callbacks output demo 5

As you can see our array of integers got sorted in decreasing order of the absolute value of integers.

Array of Function Pointers

Similarly, we can define an array of function pointers to switch between different functions during runtime.

#include <stdio.h>
typedef int (*fptr)(int, int);
int sum(int num1, int num2);
int sub(int num1, int num2);
int mult(int num1, int num2);
int div(int num1, int num2);

int main()
{
	int x, y, choice, result;
	fptr ope[4];
	ope[0] = sum;
	ope[1] = sub;
	ope[2] = mult;
	ope[3] = div;
	result = ope[2](5, 10);
	printf("%d", result);
	return 0;
}

int sum(int x, int y) { return(x + y); }
int sub(int x, int y) { return(x - y); }
int mult(int x, int y) { return(x * y); }
int div(int x, int y) { if (y != 0) return (x / y); else  return 0; }

You may like to read:

Leave a Comment