通过上一节对复杂声明的分析接触到了函数指针这个东西,实际上函数指针和其他的指针一样,在使用时也是要先进行初始化的,函数指针的初始化方法例如下:
int f( int value );
int (*pf)( int va ) = &f;
注意这里的&f前面的&符号是可选的,因为函数名被使用时总是由编译器把它转换为函数指针,&操作符只是显示地说明了编译器将隐式执行的任务。
在函数完成初始化之后,我们就可以使用一种方式调用函数:
int ans;
ans = f( 25 );
ans = (*pf)( 25 );
ans = pf( 25 );
分析:第一条语句简单的调用函数f,但是它的执行过长确实和实际想象的不一样,函数名f首先被转换为一个函数指针,该指针指定函数在内存中的位置,然后,函数调用操作符调用该函数,执行开始于这个地址的代码。
第二条语句对pf执行间接访问操作,它把函数指针转换为一个函数名,但是这个转换并不是真正需要的,因为编译器在执行函数调用操作符之前又会把它转换函数指针,不过这条语句的效果和第一条语句是完全一样的。第三条语句效果也是一样的,只是它更加的直接。
使用函数指针的实例:
1、回调函数
简单点儿说就是用户把一个函数指针作为参数传递给其他函数,后者将“回调”用户函数,窗口系统常常使用这个技巧来连接多个动作,任何时候,如果需要编写的函数能够在不同的时刻执行不同类型的工作或者执行只能由函数调用者定义的工作都可以使用这个技巧。
2、转移表
这个应用使用一个例子来说明是非常好的方式,例如下面的代码是一个袖珍式计算器程序的一部分,其他部分已经读入两个数(藕op1和op2)和一个操作符(oper),下面的代码对操作符进行测试,决定使用哪个函数。
switch ( oper )
{
case ADD:
result = add( op1, op2 );
break;
case SUB:
result = sub( op1, op2 );
break;
case MUL:
result = mul( op1, op2 );
break;
case DIV:
result = div( op1, op2 );
break;
......
}
对于一个具有上百个操作符的计算器,这条switch语句将会非常的长。使用转换表的方式可以很好的解决这个问题,转换表是一个函数指针数组。创建一个转换表有两个步骤,首先声明并初始化一个函数指针数组,在这里需要注意的是确保这些函数的原型出现在这个数组的声明之前。以上一个例子为例:
double add( double op1, double op2 );
double sub( double op1, double op2);
double mul( double op1, double op2 );
double div( double op1, double op2 );
......
double ( *oper_func[] )( double op1, double op2 ) = { add, sub, mul, div ......};
初始化列表中的各个函数名的正确顺序取决于程序中用于表示每个操作数的整型代码。在这个例子中假定add是0,sub是1,mul是2,接下去以此类推。
第二步就是替换上面的整条switch语句。
result = oper_func[ oper ]( op1, op2 );
oper从数组中选择正确的函数指针,函数调用操作符将执行这个函数。