Function Pointers in C
Function pointers in C language are an advanced concept that allows storing the address of a function in a pointer variable.
This enables calling functions dynamically, passing functions as arguments to other functions, and creating complex data structures such as function tables. Although it may seem complicated initially, understanding function pointers is fundamental to fully exploit the power and flexibility of the C language.
In this lesson we will focus on the syntax and basic operations we can perform with function pointers in C language.
Function Pointers
In C language, we have seen that a pointer can point to various data types: variables, arrays, strings, data structures, and dynamically allocated memory portions.
In C, moreover, it is also possible to create pointers that point to functions. At first glance this concept may seem strange, but actually, if we think about it carefully, functions in C also have a memory address. Therefore, we can create a pointer that points to such an address.
After all, if we recall the memory layout of a C program, we can see that functions are stored in a dedicated memory area, called Text segment:
Functions are stored in the Text segment, have their own address, and occupy a certain space in memory. Therefore, we can create a pointer that points to such an address.
The syntax for creating a function pointer is slightly more complex compared to that for creating a variable pointer.
The first fundamental thing to keep in mind is that, just as a pointer can only point to a specific data type, function pointers can only point to functions that have the same prototype. Therefore, when creating a function pointer, you need to know exactly two things:
- The return type of the function;
- The type and number of parameters that the function accepts.
For example, suppose we want to create a pointer that points to functions that take two integers as input and return an integer. The declaration of a function pointer of this type will be as follows:
int (*function_pointer)(int a, int b);
At first glance it seems we have defined a function prototype. What changes is the presence of parentheses around the name and the asterisk. This is necessary to indicate that function_pointer is a function pointer.
For the rest, the definition of a function pointer is similar to a function prototype. Parameter names are not necessary, but can be included to make the code more readable. Moreover, they do not necessarily have to correspond to the parameter names of the function to which the pointer points.
Function Pointers
A Function Pointer in C language is a special pointer variable that is capable of pointing to the memory address of a function.
To declare a function pointer, it is necessary to specify the return type of the function and the types of parameters that the function accepts. The syntax is as follows:
return_type (*pointer_name)(type1, type2, ..., typeN);
Where:
return_typeis the data type returned by the function;pointer_nameis the name of the pointer;type1,type2, ...,typeNare the types of parameters that the function accepts.
The syntax also allows specifying placeholder names for the parameters, but it is not mandatory.
The constraint on using a function pointer is that it can only point to functions that have the same prototype.
Once declared, let's see how to use this pointer. On it we can perform the following operations.
Assigning a function address to the pointer
Returning to the previous example, suppose we have two functions:
int sum(int a, int b) {
return a + b;
}
int product(int a, int b) {
return a * b;
}
These two functions respect the prototype required by the pointer function_pointer. Therefore we can assign the address of one of these functions to the pointer:
function_pointer = sum;
Now function_pointer points to the function sum.
A small detail to keep in mind is that, when assigning a function address to a pointer, it is not necessary to use the & operator before the function name. This is because, as we said, the name of a function already represents the memory address of the function.
In this, the situation is analogous to the case of arrays where the name is itself a pointer to the address of the first element.
Assignment of a Function Address to a Pointer
The syntax for assigning a function address to a pointer is as follows:
function_pointer = function_name;
Where function_pointer is the function pointer and function_name is the name of the function to which you want to assign the address.
It is not necessary to use the & operator before the function name, since the name of a function already represents the memory address of the function.
A function pointer, just like a variable pointer, can also be initialized at the time of declaration:
int (*function_pointer)(int a, int b) = sum;
Furthermore, we can also initialize the function pointer to NULL to indicate that it does not point to any function:
int (*function_pointer)(int a, int b) = NULL;
Calling the function to which the pointer points
Once the address of a function has been assigned to the pointer, we can call the function through the pointer. To do this, we can use the same syntax we use to call a function:
int a = 10;
int b = 20;
int result1;
int result2;
function_pointer = sum;
/* Call to the sum function via the pointer */
result1 = function_pointer(a, b);
printf("Result of sum: %d\n", result1);
function_pointer = product;
/* Call to the product function via the pointer */
result2 = function_pointer(a, b);
printf("Result of product: %d\n", result2);
In this example, we called the function sum and product through the pointer function_pointer.
Therefore, result1 will contain the value 30 and result2 will contain the value 200.
There is also a second syntax for calling a function through a pointer and it is often used for consistency with the syntax used for using data pointers:
result1 = (*function_pointer)(a, b);
In practice, the pointer is enclosed in parentheses and the dereferencing operator * is used.
Choosing between the two syntaxes is mostly a matter of style. Many developers prefer the second one to highlight the fact that a function is being called through a pointer.
Calling a Function through a Pointer
To call a function through a pointer, we can use the following syntax:
result = function_pointer(parameter1, parameter2, ..., parameterN);
Or, alternatively:
result = (*function_pointer)(parameter1, parameter2, ..., parameterN);
Where function_pointer is the function pointer and parameter1, parameter2, ..., parameterN are the parameters that the function requires.
Ensure that the Function Pointer is Initialized before Calling the Function
Just as for normal pointer variables, the same precautions apply to function pointers.
In particular, we must ensure that the function pointer is initialized before calling the function to which it points. If we try to call a function through an uninitialized pointer, the behavior of the program will be undefined.
Comparing two function pointers
As with variable pointers, we can compare two function pointers. Two function pointers are equal if they point to the same function. For example:
if (function_pointer == sum) {
printf("The pointer points to the sum function\n");
} else {
printf("The pointer does not point to the sum function\n");
}
In this case, the message printed will be The pointer points to the sum function.
On function pointers no other operations are possible. We cannot, for example, apply pointer arithmetic or increment or decrement a function pointer.
Comparing two Function Pointers
To compare two function pointers, we can use the comparison operators ==, !=.
Two function pointers are equal if they point to the same function:
if (function_pointer == function_name) {
// The two pointers point to the same function
}
Other relational operators can also be used to compare two function pointers, <, >, <=, >=, but their use does not make much sense in this context.
In Summary
In this lesson we have explored a fundamental construct of the C language: function pointers.
We have seen that:
- A function pointer is a pointer variable that can point to the memory address of a function;
- To declare a function pointer, it is necessary to specify the return type of the function and the types of parameters that the function accepts;
- Function addresses that respect the required prototype can be assigned to a function pointer;
- Once the address of a function has been assigned to the pointer, we can call the function through the pointer;
- Two function pointers are equal if they point to the same function.
Function pointers are a powerful tool that allows us to write more flexible and generic code. In the next lesson we will see a first fundamental application: passing functions as arguments to other functions.