- 函数指针的定义格式
- <返回类型> (*<指针变量>)(<形参表>) 例如:
int f(int); int (*pf)(int) = &f;
pf是一个函数指针,它能够指向的是参数为int类型并且返回值为int类型的函数
2. 也可以用typedef为函数指针类型取一个名字,然后再用该函数指针类型来定义指针变量:
typedef <返回类型> (*<函数指针类型名>)(<形参表>)。
typedef double (*PF)(double); PF pf;
第一行是对一个函数指针进行了定义声明,声明了一个具有double返回值,并且参数是double类型的函数指针。以后就可以用PF来声明其它的相同类型的函数指针。
- 函数指针的用途
- 转换表(jump table)
- 作为参数传递给另一个函数
作为参数传递给另一个函数 用法主要是回调函数(callback function),也就是用户把一个函数指针作为参数传递给其它函数,后者将“回调”用户的函数。一个很常用的例子就是c函数库的qsort函数, qsort并不知道进行比较的值的类型,这是我们就可以传入一个比较函数的函数指针,对于不同类型的比较,我们可以让这个函数指针绑定到不同的函数上。这里就不详细说了。
转换表 对于用户的不同输入,我们要调用不同的函数实现不同的功能,这时候也许我们可以用switch语句来实现。但是当每次我要增加一些操作的时候,就必须修改switch,也就是修改main函数里面的代码,这样是非常不方便的。那我们就可以用跳转表来实现,跳转表其实就是一函数指针数组。一般的用法如下[1]:
代码实现如下:
#include <stdio.h> typedef void (*PF)(void); struct jump_table{ char ch; PF pf; }; void pf_a(void) { printf("CALL pf_a "); } void pf_b(void) { printf("CALL pf_b "); } void pf_w(void) { printf("CALL pf_w "); } struct jump_table table[100] = { //跳转表 {'a',pf_a}, {'b',pf_b}, {'w',pf_w}, {0,NULL} }; int main() { char ch; int i; while( (ch = getchar()) != 'x') { i = 0; while ((table[i].ch != 0)) { if (ch == table[i].ch) { table[i].pf(); break; } i++; } } } 2013/10/16 22:33
我们可以看到用户输入的key值是不连续的,所以我们必须每次都扫描一遍数组,同时我们在定义数组的时候要设置结束标志,这样能方便判断结束。
但是如果用户输入的是从零开始的连续整数,或者是一些诸如连续字符a-z之类的,那么我们就可以直接跳转到相应的项,而不需扫描数组。比如我们在做计算器的时候,我们把ADD定义为0,SUB定义为1....[2],那么就可以如下的定义:
double add(double, double); double sub(double, double); double mul(double, double); double div(double, double); .... double (*oper_func[])(double,double) = { add,sub,mul,div,..... };
然后通过下面来调用相应的操作函数,oper为输入的值:
result = oper_func[oper](op1, op2);
oper_func从数组中选择正确的函数指针,而函数调用操作符将执行这个函数。当然,我们这里还需要的注意的是数组越界问题,为了保证所使用的下标位于合法的范围内,在一开始的时候我们可以先检查下标的合法性,然后再进行调用操作。
- 参考资料
- [1] 我们老师上课的课件,具体解释权归老师所以;
- [2] 《C和指针》
复杂函数指针的应用
来看下下面这个代码:
void (* pf(void (*fun)()))()
咋第一眼看上去有点头晕呢!那么多括号,那么多嵌套。莫急莫急!我们来把它细分一下,首先看 void (*fun)(),这就是我们前面看到的函数指针,这个没问题。然后再看看
pf(void (*fun)()),pf不也是一个函数嘛,只不过它的参数是一个函数指针罢了。那么如果我们令pf(void (*fun)())为X,那么那一整个式子可以表示成:void(*X)(),这就是函数指针的定义。说明X又是一个函数指针,也就是说函数pf的返回值又是一个函数指针。这样就都清楚啦,再来屡一下:pf这样一个函数:接受参数为函数指针,而且pf的返回值也是个参数为void返回值为void的函数指针。
而且我们还可以用下面这两个定义来表示上面这个函数定义,这样看起来就明了多了:
typedef void (*PF)(); PF pf(PF fun);
typedef void PF(); PF *pf(PF *fun);
从下面这个定义方式,我们就可以很明确的看到pf函数的参数是一个PF*类型,返回值也是一个PF*类型的函数。
下面用一个程序来看看这个应用的例子:
#include <stdio.h> void fun_a(int a,int b) { printf("This is function A. "); } void fun_b(int a) { printf("This is function B. "); } void (*pf(void (*fun)(int,int)))(int) { void (*p)(int); printf("This is function pf. "); fun(1,1); p = fun_b; return p; } int main() { pf(fun_a)(1); return 0; }
输出结果是:
参考资料: