C语言作为一门面向过程的语言,那么他的代码块一般是以函数为最小单位的,我们了解过栈帧之后都知道,代码也是有地址的,那么存放代码地址的变量就叫做函数指针变量。
对于一个函数而言,函数名或者&函数名都代表的是这个函数的地址。
那么这个地址怎么保存呢?请看下面的代码:
void test()
{
printf("Hello\n");
}
int main()
{
void (*p)() = test;
p();
(*p)();
return 0;
}
这样我们就可以使用函数指针p来调用这个函数,在这里有一点比较特殊的地方,我们可以通过*解引用调用,也可以直接用指针名称来调用。
特别强调,函数指针不可以用来做加减运算,我们都知道,指针做加减时,会加上或者减去其指向类型的大小,但是函数的大小计算起来很不方便,而且这样的加减没有意义,所以C语言语法规定不能进行函数指针的加减运算,否则编译器会直接报错!
好了,讲清楚了基本概念,我们来看一点有意思的代码:
//代码1
(*(void (*)())0)();
//代码2
void(*signal(int, void(*)(int)))(int);
来看代码1,先看优先级最高的部分void(*)(),这是一个函数指针,那么给0前面加一个数据类型代表了什么意思呢?当然是把0强制转换成函数指针类型,然后在把他的外壳加上,可以得出结论,这是一个把0强制转换成函数指针的函数调用。
搞明白代码1之后来看代码2。依然是先看优先级,void(*)(int)
依然是一个函数指针,只是他现在被当成了signal函数的一个参数,另外一个参数当然是int,那么我们就搞清楚了signal(int,void(*)(int))
这一部分内容。然后我们省略这一部分去看剩下的,void(*)(int)
也是一个函数指针,这个类型自然是用来做函数返回值类型的类型了。所以,这是一个返回值为函数指针,参数为int和函数指针的函数调用。
好了,看了函数指针,你有没有兴趣了解一下函数指针数组呢?很容易可以想到,既然有函数指针,那当然有函数指针数组,那么函数指针数组是什么格式呢?
int (*p[10])(); //名称为p的函数指针数组
学以致用,我们拿这个小东西来写几行代码吧!下面用函数指针数组实现了一个简单的计算器,大家可以参考函数指针数组的基本使用:
int Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x - y;
}
int Mul(int x, int y)
{
return x * y;
}
int Div(int x, int y)
{
return x / y;
}
int main()
{
int input = 1;
int(*p[5])() = { 0, Add, Sub, Mul, Div };//转移表
while (input)
{
printf("请选择操作>:\n");
printf("******************************\n");
printf("*** 1. Add 2. Sub ***\n");
printf("*** 3. Mul 4. Div ***\n");
printf("*** 0. Exit ***\n");
printf("******************************\n");
scanf("%d", &input);
if (input >= 1 && input <= 4)
{
int x, y;
printf("请输入两个运算数据>:");
scanf("%d", &x);
scanf("%d", &y);
printf("resault:%d\n", (*p[input])(x, y));
}
else if (input != 0)
{
printf("操作非法,请重新操作\n");
}
}
system("pause");
return 0;
}