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).
In this unit, we begin with a reading from your textbook, supplemented by a demonstration of passing functions as parameters to procedures, just as we did in Scheme.
Textbook reading
- King: Section 17.7, pages 439-445 OR
- K&R: 5.11
Function Pointers and Arrays
The remainder of this reading presents an extended example that illustrates:
- the use of functions as parameters
- the declaration and use of arrays of functions
- the use of arrays of functions as parameters
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 */
void 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 reading, 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;
}
Arrays of Functions as Parameters
What if you wanted to separate the action from the declaration of the array? How would you pass in an array of function pointers to a procedure as a parameter? The following example modifies the previous program to demonstrate such a variant.
/* program to compute a circle's circumference and area
example using an array of functions as a 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;
}
/* print the value of each function in an array applied to the given radius */
void printarr(double radius, double (*funcarr[])(double) )
{
int i;
for (i = 0; i < 3; i++)
{
printf ("%12.4lf", funcarr[i](radius));
}
printf ("\n");
}
/* print the values of a set of functions for 10 radii */
int main ()
{
double (*funcarr[3]) (double) = {iden, circum, area};
printf (" radius circumference area\n");
double radius;
for (radius = 0; radius < 10; radius++)
{
printarr(radius,funcarr);
}
return 0;
}
