At the beginning of the previous chapter we stated that a pointer can point to any object present in memory at run time. Since functions themselves are located in memory, you can assign the address of a function to a pointer, creating a “function pointer.”
Summary: A function pointer makes it possible to pass a function as a function argument.
Function pointers provide a way—in fact, the only practical way—to pass a function as an argument to another function. This permits the second function to call the first function indirectly through the pointer.
While function pointers may sound rather obscure, they have some common practical uses:
Function pointers are used extensively in Windows and OS/2 Presentation Manager programs.
Some QuickC run-time library functions, such as qsort, expect to receive a pointer to a user-defined function in your program. (Online help includes an example program that uses qsort.)
Using an array of function pointers, you can create a “dispatch table.” A dispatch table is a list of related functions that can be called based on some choice made at run time. It is similar to an ON GOSUB statement in Basic or a call table in assembly language.
The syntax for function pointers is a bit complex, so let's start with a simple example. The FUNCPTR.C program creates a pointer to our old friend, printf, and calls printf through the pointer:
/* FUNCPTR.C: Demonstrate function pointers. */
#include <stdio.h>
main()
{
int (*func_ptr) ();
func_ptr = printf;
(*func_ptr) ( "Curiouser and curiouser...\n" );
}
Here is the output from FUNCPTR.C:
Curiouser and curiouser...
This line from FUNCPTR.C declares func_ptr as a pointer to a function:
int (*func_ptr) ();
The declaration of a function pointer must use the same type specifier as the function it references. If the function returns a float value, the pointer uses type float, and so on. Since the printf function returns an int value showing how many characters it displays, the declaration of func_ptr uses the type int.
Summary: A function-pointer declaration must have two pairs of parentheses.
Function-pointer declarations may look complex, but all the parentheses are essential. The empty parentheses at the end of the declaration are needed to show the pointer points to a function.
The parentheses enclosing the function name itself are mandatory, too. Notice what happens if you omit them:
void *func_ptr(); /* Error! Not a function pointer. */
Instead of declaring a pointer to a function, this statement declares a function that returns a pointer—not at all what we want in FUNCPTR.C.
The next program line initializes the function pointer, assigning it the address of the printf function:
func_ptr = printf;
This line has two important features. First, notice the name printf isn't followed by parentheses, as it would be when you call printf directly. We want to obtain the address of printf, not call it.
Second, note that it's not necessary to place the address-of operator before the name printf. Because func_ptr was declared as a function pointer, the compiler knows it should use the address of printf here. If you like, however, you can add the address-of operator to make the statement a little more readable:
func_ptr = &printf;
The next line calls the printf function indirectly through the pointer func_ptr:
(*func_ptr) ( "Curiouser and curiouser...\n" );
Note the similarity between this statement and a normal call to printf. It's equivalent to this line:
printf( "Curiouser and curiouser...\n" );
To call printf indirectly through func_ptr, you supply the same arguments as when you call printf directly.