Function Pointers
As with Scheme, C allows variables to refer to functions, and functions can be passed as parameters. However, since C requires the type of each variable or parameter be declared, variables that may refer to functions must indicate the function's signature (number and type of parameters, return type).
The remainder of this reading presents an extended example that illustrates:
Initial Example
Suppose you are asked to write a program to compute a circle's circumference and area for radii between 0 and 9. The desired output might be:
radius circumference area 0.0000 0.0000 0.0000 1.0000 6.2832 3.1416 2.0000 12.5664 12.5664 3.0000 18.8496 28.2743 4.0000 25.1327 50.2655 5.0000 31.4159 78.5398 6.0000 37.6991 113.0973 7.0000 43.9823 153.9380 8.0000 50.2655 201.0619 9.0000 56.5487 254.4690
One simple approach for writing this type of program might utilize these features:
- Separate functions are defined for the circumference and the area of a circle.
-
The first line of the
mainprogram prints a header. -
A main loop iterates through the desired
radiusvalues. -
The loop itself contains three
printfstates, one for each value to be printed on a given line.
The resulting C program follows:
/* program to compute a circle's circumference and area
*/
#include <stdio.h>
const double pi = 3.1415926535;
/* circumference function */
double circum (double radius)
{
return 2 * pi * radius;
}
/* area function */
double area (double radius)
{
return pi * radius * radius;
}
int main ()
{
printf (" radius circumference area\n");
double radius;
for (radius = 0; radius < 10; radius++)
{
printf ("%12.4lf", radius);
printf ("%12.4lf", circum(radius));
printf ("%12.4lf", area(radius));
printf ("\n");
}
return 0;
}
Function Parameters
The above C program works fine and likely is completely satisfactory for the simple problem given. However, several elements in the program contain some common elements. For example,
-
The first three
printfstatements all use the same format string, and they each print just one value. -
The second and third
printfstatements call a function, the function requires one parameter, andradiusis used in the function call. -
Arguably, the first
printfstatement also has this format, where the function called is the identify functionx = iden(x)
Although these common elements are hardly earth shaking, it can be helpful to take advantage of such common elements in more complicated programs.
Printing Function
In exploiting the similarities in the printf statements,
we might write a function that takes a radius and a function as parameters
and then performs the required printing. The following code is an example:
/* printing function */
double myPrint (double x, double f (double))
{
printf ("%12.4lf", f(x));
}
This function has two formal parameters, the
number x and a function f.
Further, f is identified as a function that
will utilize one double value as an input
parameter, and f will return
a double when it completes execution.
The function myPrint utilizes the
function f when it performs its printing.
Full Program
The following program replaces the printf statements in
the main loop by calls to myPrint.
Note that myPrint is also used for printing the
value of radius by using an identify function.
The code observes, however, that a
simple printf for radius could be
used as a reasonable alternative.
/* program to compute a circle's circumference and area
example using function with a function parameter
*/
#include <stdio.h>
const double pi = 3.1415926535;
/* identity function */
double iden (double radius)
{
return radius;
}
/* circumference function */
double circum (double radius)
{
return 2 * pi * radius;
}
/* area function */
double area (double radius)
{
return pi * radius * radius;
}
/* printing function */
void myPrint (double x, double f (double))
{
printf ("%12.4lf", f(x));
}
int main ()
{
printf (" radius circumference area\n");
double radius;
for (radius = 0; radius < 10; radius++)
{
myPrint (radius, iden);
/* could also be
printf ("%12.4lf", radius);
*/
myPrint (radius, circum);
myPrint (radius, area);
printf ("\n");
}
return 0;
}
Arrays of Functions
As noted earlier in this lab, functions as parameters provide one mechanism to take advantage of common elements within an algorithm. A second approach involves utilizing an array of functions.
Declaration
Already, we have observed that the main loop in our example
utilizes the same printf statement — with different
functions being called. This suggests that we might declare an array of
the relevant functions:
double (*funcarr[3]) (double)= {iden, circum, area};
Let's unpack this syntax:
-
We can declare a simple variable as a pointer to a function with the
statement:
This states thatdouble (*f) (double)fwill refer to a function that has one parameter (adouble) and it will return adouble. (The*means thatfwill be a function pointer—a reference to a function.) -
With this declaration,
fcan be assigned a function:
so the statementf = area;
will cause theprintf ("%5.2", f(3.5));areafunction to be called, executed with the value 3.5, and used as the value to be printed. -
As with many C declarations, a variable can be defined and initialized in a
single statement. The following declaration initializes
fas a reference to theareafunction.double (*f) (double) = area; -
Arrays are declared by placing
[]within the declaration:
Heredouble (*funcarr[3]) (double);funcarris declared as an array of 3 function pointers. -
Arrays can be initialized by placing desired values within braces
{ }:double (*funcarr[3]) (double)= {iden, circum, area}; -
With this declaration, we can refer to the
circumfunction as
and we can call this function with the parameter 3.5 by writingfuncarr[1]funcarr[1] (3.5)
Full Program
The following program uses this declaration of funcarr in
the main loop by iterating through the three functions of interest
for printing.
/* program to compute a circle's circumference and area
example using an array of functions
*/
#include <stdio.h>
const double pi = 3.1415926535;
/* identity function */
double iden (double radius)
{
return radius;
}
/* circumference function */
double circum (double radius)
{
return 2 * pi * radius;
}
/* area function */
double area (double radius)
{
return pi * radius * radius;
}
int main ()
{
double (*funcarr[3]) (double) = {iden, circum, area};
printf (" radius circumference area\n");
double radius;
for (radius = 0; radius < 10; radius++)
{
int i;
for (i = 0; i < 3; i++)
{
printf ("%12.4lf", funcarr[i](radius));
}
printf ("\n");
}
return 0;
}
