说明:函数指针,顾名思义就是指向函数的指针。C/C++中函数名的本质其实就是一段代码段空间的首地址。
1.定义
如下的 pf 就是一个函数指针,指向所有返回类型为 int,并带有两个 const int 参数的函数。需要注意的是 *pf 两边的括号不能少,否则下面定义就变成声明一个函数 pf,其返回类型为 int *, 带有两个 const int 参数。
1 int (*pf)(const int, const int);
2.取别名
如果每次都像上面那样来声明一个函数指针,那样就显得太复杂了,我们可以通过取别名的方式来简化声明复杂程度,如下:
1 typedef int (*cmpFun)(const int, const int);
这样,cmpFun 就成了一种数据类型,可以用它来声明和定义形如上面 pf 那样的函数指针,比如:
1 cmpFun pf = someFunction; 2 cmpFun pf = &someFunction;
下面是一个测试代码:
1 #include <stdio.h> 2 3 void myCmp(int a,int b) 4 { 5 printf("%d\t%d\n",a,b); 6 } 7 8 typedef void (*PF)(int a, int b); 9 PF pf = myCmp; 10 11 int main(void) 12 { 13 (*pf)(1,2); 14 pf(1,2); 15 //两种访问方式都没问题 16 return 0; 17 }
3.函数名作为地址的用法
上面提到了,函数名的本质是一个地址,那如果我们拿到这个地址,是否可以直接调用相应的函数呢?答案是肯定的!如下代码,先打印出函数名所代表的地址,然后将其强转成 PF 函数指针类型,然后在对其进行函数的调用。
1 #include <stdio.h> 2 3 void myCmp(int a,int b) 4 { 5 printf("%d\t%d\n",a,b); 6 } 7 8 typedef void (*PF)(int a, int b); 9 PF pf = myCmp; 10 11 int main(void) 12 { 13 pf(1,2); 14 printf("%p\t%p\n",myCmp,&myCmp); 15 ((PF)(0x00401610))(1,2); 16 return 0; 17 }
上面代码的打印结果为:
1 1 2 2 00401610 00401610 3 1 2
4.回调函数
当函数作为参数而发起的调用函数的过程,就叫作函数的回调。函数的回调其实也是利用了函数指针这一概念。下面是一个回调示例:
1 #include <stdio.h> 2 3 void myCmp(int a,int b) 4 { 5 printf("%d\t%d\n",a,b); 6 } 7 void prin(void (*p)(int a,int b)) 8 { 9 p(1,2); 10 } 11 12 int main(void) 13 { 14 prin(myCmp); 15 return 0; 16 }
5.函数指针数组
如下定义一个返回值和参数皆为 void 的函数指针数组:
1 void (*funcArray[N])(void);
函数指针的一个用法出现在菜单驱动系统中。例如程序可以提示用户输入一个整数值来选择菜单中的一个选项。用户的选择可以做函数指针数组的下标,而数组中的指针可以用来调用函数。下面是一个程序示例:
1 #include <stdio.h> 2 void func1() 3 { 4 printf("void func1()\n"); 5 } 6 void func2() 7 { 8 printf("void func2()\n"); 9 } 10 void func3() 11 { 12 printf("void func3()\n"); 13 } 14 15 int main(void) 16 { 17 int i = 0; 18 void (*p[3])(void) = {func1,func2,func3}; 19 for(;i<3;i++) 20 (p[i])(); 21 return 0; 22 } 23 24
6.拓展
1 (*(void(*) ()) 0)()
思考以上代码的意义!