概述:
函数指针和函数指针数组是C 语言中相对比较绕的概念,对于初学者来说很不友好。在我刚刚接触C语言中这两个概念的时候也是一头雾水,萌生退意。尤其是当指针数组,数组指针,函数指针,函数指针数组这些东西结合到一块的时候。我们更要知难而进,逐步拆分,细细品味。
函数指针:
从名字上理解,就是指向函数的指针,本质上是一个指针,存放函数的地址。
其形式如下所示:
int add(int x, int y)
{
return x + y;
}
int main()
{
int (*pf)(int, int) = &add;
//此时的pf就是一个函数指针变量
return 0;
}
与数组指针相类似,(*pf)说明他是一个指针,往后走看见(int,int)说明他指向一个函数,函数的两个参数为int int,返回值也为int。
对于初始化这块:函数名就是他的地址。
&add == add
所以我们可以写为:
int (*pf)(int, int) = add;
我们应该如何对函数指针进行调用呢,以下代码就能很好的进行说明。
因为pf里面存放的是函数的地址,对pf进行解引用就找到了函数的地址,参数部分我们把3和5传进 去,返回值用ret进行保存。
int add(int x, int y)
{
return x + y;
}
int main()
{
int (*pf)(int, int) = add;
int ret = (*pf)(3, 4);
printf("%d\n", ret);
return 0;
}
结合以上的信息我们就可以分析如下两段代码:
(*(void(*)())0)();
这段代码的作用其实是调用0地址处的函数,我们如下进行初步分析:
1.void (*)() : 函数指针类型。
2.(void(*)())0 :把0强制类型转换为一个函数地址。
3.*(void(*)())0 :对0地址处进行解引用。
4.(*(void(*)())0)() :调用0地址处的函数。
void (*signal(int, void(*)(int)))(int);
对这段代码我们也可以进行如下分析:
1.signal首先和()结合,说明signal是一个函数名
2.signal函数第一个参数为int,第二个参数为函数指针类型(参数为int,返回类型为void的函数)
3.剩下的 void(* )(int) 便是signal的返回类型,类型为一个函数指针(参数为int ,返回类型为void)。
以上表达式出自《c和陷阱》这本书中,我们在刚刚接触这类表达式第一感觉就是头大懵逼,但是如果我们连这个的代码都能读懂,都其他的代码应该不会有太大的问题。
函数指针数组:存放函数指针的数组。
对于函数指针数组的应用与实现,以下这个例子就可以体现。
比如我们要写一个计算器,实现加减乘除的运算,一般的方式来写我们可以写为这样:
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;
}
void menu()
{
printf("****************************\n");
printf("**** 1.add 2.sub ****\n");
printf("**** 3.mul 4.div ****\n");
printf("**** 0.退出 ****\n");
printf("****************************\n");
}
int main()
{
int input = 0;
int ret = 0;
int x = 0;
int y = 0;
do
{
menu();
printf("请选择\n");
scanf("%d", &input);
switch (input)
{
case 1:
printf("请输入两个操作数:\n");
scanf("%d %d", &x, &y);
ret=add(x, y);
break;
case 2:
printf("请输入两个操作数:\n");
scanf("%d %d", &x, &y);
ret=sub(x, y);
break;
case 3:
printf("请输入两个操作数:\n");
scanf("%d %d", &x, &y);
ret=mul(x, y);
break;
case 4:
printf("请输入两个操作数:\n");
scanf("%d %d", &x, &y);
ret=div(x, y);
break;
case 0:
printf("退出程序");
break;
default:
printf("xuanzecuowu");
break;
}
printf("%d\n", ret);
} while (input);
return 0;
}
可以看到以上代码过于繁琐,但是,在引如函数指针数组的概念后,我们就可以对这段代码做出如下更改:
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;
}
void menu()
{
printf("****************************\n");
printf("**** 1.add 2.sub ****\n");
printf("**** 3.mul 4.div ****\n");
printf("**** 0.退出 ****\n");
printf("****************************\n");
}
int main()
{
int input = 0;
do
{
menu();
//pfarr就是函数指针数组
int (*pfarr[5])(int, int) = { NULL,add,sub,mul,div };
int x = 0;
int y = 0;
int ret = 0;
printf("请选择: \n");
scanf("%d", &input);
printf("请输入要操作的数字: \n");
scanf("%d %d", &x, &y);
ret=(pfarr[input])(x, y);
printf("ret = %d\n", ret);
} while (input);
}
这样看起来我们的代码就简短方便的多了,这其实就是函数指针数组的一个应用,但这样写的前提的add sub mul div他们的参数和返回类型都相同。