2.12 指向函数的指针
C和C++代码精粹
一个指针可以指向函数也可以指向存储的对象。下面的语句声明fp是一个指向返回值为整型(int)的函数的指针:
int(*fp)( );
*ftp的圆括号是必需的,没有它的语句
int *fp( );
将fp声明为一个返回指向整型(int)指针的函数。这就是将星号与类型声明紧密相连的方式成为逐渐受人们欢迎的方式的原因之一。
int fp(); //方式说明fp()返回一个指向整型的指针(int )
当然,这种方式建议你通常应该每条语句只声明一个实体,否则,以下的语句将会使人感到迷惑:
int *ip, jp; //jp不是一个指针!
如果想具体说明fp指向的函数就必须带有一定的参数,如果是一个浮点型(float)和一个字符串型,那么可以这样写:
int (fp) (float, char );
然后可以在fp中存储这样一个函数的地址:
extern int g(float,char*);
fp=g;
表达式中函数的名字解析地址可以认为是指向那个函数代码区的开始的地址。下面的“hello,world”程序说明如何通过指针来执行一个函数。
/hello.c: 通过函数的指针来说hello /
#include <stdio.h>
main()
{
void ( * fp )( )=printf;
fp("hello, world\n");
}
要通过指针来执行一个函数,你可能认为得这样写:
(*fp)("hello world\n");
来复引用指针。事实上,在ANSI C出现以前必须这样做,但是ANSI C 委员会决定容许像我在hello.c中那样使用的普通函数调用句法。由于编译器知道它是一个指向函数的指针,并且它还知道在该环境下所能做的惟一的一件事就是调用函数,因此这里没有任何模糊不清的表达。
当把函数名作为一个参数传递给另一个函数时,编译器实际上给这个函数传递了一个指针(与数组名类似)。但是你为什么曾经想过给另一个函数传递函数指针呢?C标准库中的排序函数qsort 的使用就是一个例子,采用简单和复合的排序关键字,它可以对由任何类型的元素所组成的数组排序。程序清单2.17中的程序说明怎样排序命令行参数字符串,在这种情况下所需要做的全部事情就是传递给qsort一个知道如何比较字符串的函数。一个函数(像qsort)通过由运行时决定的指针来调用另一个函数(像 comp)的行为叫做返调(callback)。
函数指针的数组在菜单驱动应用程序中很容易见到,假设想将以下的目录展现给用户:
1.返回
2.插入
3.更新
4.退出
程序清单2.18的程序直接把键盘输入作为索引放到指向处理每一个菜单选择函数的指针的数组中。
程序清单2.17 用qsort函数将命令行参数排序
// sortargs.cpp: 排序命令行参数
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
int comp(const void, const void);
main(int argc, char *argv[])
{
qsort(argv+1, argc-1, sizeof argv[0], comp);
while (--argc)
cout << *++argv << endl;
}
int comp(const void p1, const void p2)
{
const char ps1 = (const char**) p1;
const char ps2 = (char**) p2;
return strcmp(ps1,ps2);
}
//从"sortargs *.cpp"命令输出:
address.cpp
arith.cpp
array1.cpp
array2.cpp
array3.cpp
array4.cpp
array5.cpp
array6.cpp
array7.cpp
array8.cpp
array9.cpp
bit1.cpp
bit2.cpp
convert.cpp
inspect.cpp
pointer.cpp
ptr2ptr.cpp
sortargs.cpp
swap1.cpp
swap2.cpp
程序清单2.18 用函数指针数组来处理菜单选择
/ menu.c: 举例说明函数数组/
#include <stdio.h>
/你一定要给这些提供定义/
extern void retrieve(void);
extern void insert(void);
extern void update(void);
extern int show_menu(void); /返回keypress /
main()
{
int choice;
void (*farray[])(void) = {retrieve,insert,update};
for (;;)
{
choice = show_menu();
if (choice >= 1 && choice <= 3)
farray[choice-1](); / 进程的需要 /
else if (choice == 4)
break;
}
return 0;
}
本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。