函数指针数组的使用场景、局限和优点
原文地址:http://blog.csdn.net/qq_34861102/article/details/78085180
函数名
每个函数都有一个入口地址,该入口地址就是函数指针所指向的地址,函数名即为入口地址。
int foo(int x){ return x; }
foo
为函数名函数指针
函数指针是指向函数的指针变量,每个函数都有一个入口地址,指针变量中保存函数的入口地址,有了指向函数的指针变量后,可用该指针变量调用函数,就如同用指针变量可引用其他类型变量一样。
函数指针的声明方法为:
void(*fp)();
返回值类型 (指针变量名) ([形参列表]);*
函数指针数组的使用场景
函数指针数组即函数指针的数组。
在使用
C
语言构造解释器的过程中,对于词法分析得到的Token
在进行语法分析的过程中,对于不同的类别的Token
此处函数需要进行一个识别。输入参数假定为int* buffer
和void* value
,其中int* buffer
用来识别Token
的类型,如浮点数、整数等;void* value
为Token
的具体值。假设此处没有封装成一个类,仅仅是一个主函数需要对不同接受类型的Token
进行不同的函数调用,假设有100种不同的类型。若按通常做法,会写出如下代码:
void MyFuntion( int* buffer, void*value ){ switch(buffer[0]){ case 1 : function1(); break; case 2 : function2(); break; case 3 : ...... case 100: function100(); break; } }
按照这种写法,每一次对于不同的
Token
都要进行多次判断之后才能找到正确的函数处理函数,代码的执行效率较低,这里就可以适用函数指针数组的概念解决多次判断的问题。按函数指针数组的思路,会写出如下代码:
void funtion0(void); ...... void funtion100(void); void (*fun[100])(void) = {funtion0,......,funtion100}; void MyFuntion( int* buffer, void*length ){ (*fun[buffer[0]])(); }
只要2行代码,就完成了100条case语句要做的事,减少了编写代码时工作量,从代码执行效率上来说,直接调用函数指针,也比case语句高。
给一个可运行的实际案例:
#include <stdio.h> #include <stdbool.h> #define swap(x,y) {typeof(x) t = x; x = y; y = t;} bool rule1(int x, int y){ return x > y; } bool rule2(int x, int y){ return x < y; } bool rule3(int x, int y){ return x%3 < y%3; } void sort(int *a,int n, bool (*f)(int,int)){ for (int i = 0; i < n - 1;i ++){ for (int j = 0; j < n - 1;j ++){ if (f(a[j],a[j+1])) swap(a[j],a[j+1]); } } } void print(int *a,int n){ for (int i = 0; i < n; i ++){ printf("%d",a[i]); } printf("\n"); } int main(){ int a[10] = {2,1,3,8,0,4,6,5,7,9}; //定义函数指针数组 bool (*f[])(int,int) = {rule1,rule2,rule3}; sort(a,10,f[0]); print(a,10); return 0; }
使用场景的分析
局限性
无法对参数(
parameter
)和返回值(returnvalue
)的类型进行检查,因为函数已经退化成指针,指针是不带有这些类型信息的实际测试:
bool rule1(int x, int y){ return 'x > y'; }
将返回值修改为非
bool
类型的字符串,可以看到程序是可以运行的,但是运行结果出现与预期结果不相符合。可以看到这里的返回值(
returnvalue
)是没有检查的优点
优点从上面的应用实例中可以明显看出,减少代码的编写工作量、提高代码的运行效率,尤其是对未定函数的存在的场景适用。