We saw earlier that functions have a storage class and scope, similar to variables. In C, it is also possible to define and use function pointers, i.e. pointer variables which point to functions. Function pointers can be declared, assigned values and then used to access the functions they point to. Function pointers are declared as follows:
int (*fp)(); double (*fptr)();
Here, fp is declared as a pointer to a function that returns int type, and fptr is a pointer to a function that returns double. The interpretation is as follows for the first declaration: the dereferenced value of fp, i.e. (*fp) followed by () indicates a function, which returns integer type. The parentheses are essential in the declarations. The declaration without the parentheses:
int *fp();
declares a function fp that returns an integer pointer.
We can assign values to function pointer variables by making use of the fact that, in C, the name of a function, used in an expression by itself, is a pointer to that function. For example, if isquare() and square() are declared as follows:
int isquare(int n); double square(double x);
the names of these functions, isquare and square, are pointers to those functions. We can assign them to pointer variables:
fp = isquare; fptr = square;
The functions can now be accessed, i.e. called, by dereferencing the function pointers:
m = (*fp)(n); /* calls isquare() with n as argument */ y = (*fptr)(x); /* calls square() with x as argument */
Function pointers can be passed as parameters in function calls and can be returned as function values. Use of function pointers as parameters makes for flexible functions and programs. An example will illustrate the approach. Suppose we wish to sum integers in a specified range from x to y. We can easily implement a function to do so:
/* File: sumutil.h */ int sum_int(int x, int y);/* File: sumutil.c */ #include <stdio.h> #include "sumutil.h" /* Function sums integers from x to y. */ int sum_int(int x, int y) { int i, cumsum = 0;
for (i = x; i <= y; i++) cumsum += i; return cumsum; }
The file sumutil.h contains prototypes for all the functions written in sumutil.c. Next, suppose we wish to sum squares of integers from x to y. We must write another function to do so:
/* File: sumutil.h - continued */ int sum_squares(int x, int y); int isquare(int x);/* File: sumutil.c - continued */ /* Function sums squares of integers form x to y. */ int sum_squares(int x, int y) { int i, cumsum = 0;
for (i = x; i <= y; i++) cumsum += isquare(i); return cumsum; }
/* Function returns the square of x. */ int isquare(int x) { return x * x; }
Function isquare() returns the integer square of i. The constructions of the two functions sum_int() and sum_squares() are identical. In both cases, we cumulatively add either the integers themselves or squares of the integers. A function iself(), which returns the value of the integer argument, can be used in sum_int() to make the functions truly identical. Here is a modified function that uses iself():
/* File: sumutil.h - continued */ int sum_integers(int x, int y); int iself(int x);/* File: sumutil.c - continued */ /* Function sums integers from x to y. */ int sum_integers(int x, int y) { int i, cumsum = 0;
for (i = x; i <= y; i++) cumsum += iself(i); return cumsum; }
/* Function returns the argument x. */ int iself(int x) { return x; }
The two sum functions, sum_integers() and sum_squares(), are now identical except for the functions used in the cumulative sum expressions. In one case, we use iself(), in the other case, isquare(). It is clear that a single more flexible generic sum function can be written by passing a function pointer, fp, as an argument with a value pointing to the appropriate function to use. The cumulative sum expression would then take the form:
cumsum += (*fp)(i);
Here is the implementation:
/* File: sumutil.h - continued */ int sum_gen(int (*fp)(), int x, int y);/* File: sumutil.c - continued */ /* Function sums values of *fp applied to integers from x to y. */ int sum_gen(int (*fp)(), int x, int y) { int i, cumsum = 0;
for (i = x; i <= y; i++) cumsum += (*fp)(i); return cumsum; }
Finally, we can improve the generic sum function by using a pointer to a function that updates the integer using a specified step size:
/* File: sumutil.h - continued */ int sum(int (*fp)(), int x, int (*up)(), int step, int y);/* File: sumutil.c - continued */ /* Function returns the sum of function *fp applied to integers from x to y, incremented by *up in step size. */ int sum(int (*fp)(), int x, int (*up)(), int step, int y) { int i, cumsum = 0;
for (i = x; i <= y; i = (*up)(i, step)) cumsum += (*fp)(i); return cumsum; }
The function pointed to by (*up) takes two arguments, an integer to be updated and the step size. The generic function sum() can now be used to sum (*fp)(i) applied to integers i, which are updated by (*up)(i, step). The pointer variable, fp can point to any function that processes an integer and returns an integer. Similarly, up can point to any function that returns an updated integer value.
Let us now write a program that reads starting and ending integers as well as step size until EOF. For each set of data read, the program first computes and prints the sum of integers using sum_int, and sum of squares using sum_squares(). These two sums are in steps of one, since that is how the functions are written. Next, the program uses the above generic sum function sum() to compute sums of integers and squares in specified step sizes. Figure 14.17 shows the program.
/* File: sums.c
Other Source Files: sumutil.c
Header Files: sumutil.h
This program illustrates the use of function pointers to define a
single function sum() that sums powers of integers between specified
limits. The function is then applied to sum integers and squares.
Individual functions to sum integers and squares are also implemented.
The results are printed out for both approaches.
*/
#include <stdio .h>
#include "sumutil.h"
main()
{
int x, y, step, isquare(), iself(), iincr();
printf("***Function Pointers – Sums of Function Values***/n/n");
printf("Type starting, ending limits, and step size, EOF to quit/n");
while (scanf("%d %d %d", &x, &y, &step) != EOF) {
printf("Sum of integers from %d to %d in steps of 1 = %d/n" ,
x, y, sum_int(x, y));
printf("Sum of squares from %d to %d in steps of 1 = %d/n",
x, y, sum_squares(x, y));
printf("Sum of integers from %d to %d in steps of %d is %d/n" ,
x, y, step, sum(iself, x, iincr, step, y));
printf("Sum of squares from %d to %d in steps of %d is %d/n",
x, y, step, sum(isquare, x, iincr, step, y));
}
}
/* File: sumutil.h - continued */
int iincr(int x, int step);
/* File: sumutil.c - continued */
/* Increments x by size of step. */
int iincr(int x, int step)
{
return x + step;
}