请先看一段代码:
int ADD(int a,int b)
{
return a + b;
}
int main()
{
int ret = 0;
printf("%p\n",ADD);
printf("%p\n",&ADD);
return 0;
}
由输出结果可知:
数组的首地址与总地址,值一样,但意义不同;而函数的地址,虽然方式不一样,但是意义一样
函数也是有自己的地址的
既然每个函数都有他自己的地址,那么函数指针是指向函数地址的
函数指针定义
函数返回值类型 (*函数名)(参数)
例如:int (*p)(int,int)
那么函数指针是如何调用函数的,请看代码:
#include
int ADD(int a,int b)
{
return a + b;
}
int main()
{
int ret = 0;
定义函数指针
int (*fp)(int,int) = ADD; &ADD和直接给ADD一样
函数指针使用方式1:
ret = (*fp)(2,3);
printf("%d\n",ret); //5
函数指针使用方式2:
ret = fp(2,3);
printf("%d\n",ret); //5
说明,*可以不加,但加上对于传统理解方便
return 0;
}
函数指针调用函数时,只需要把函数地址给函数指针,但函数指针与函数的参数必须相同
函数指针数组与指针数组一样,数组里每个元素都是指针,只不过函数指针数组是指向函数的地址
假如有这样一段代码,有加减乘除4个函数,现在想用函数指针调用他们
那么可以创建4个函数指针存他们的地址,代码如下:
//加
int Add(int a,int b)
{
return a + b;
}
//减
int Sub(int a,int b)
{
return a - b;
}
//乘
int Mul(int a,int b)
{
return a * b;
}
//除
int Div(int a,int b)
{
return a / b;
}
int main()
{
int i = 0;
int (*pf1)(int,int) = Add;
int (*pf2)(int,int) = Sub;
int (*pf3)(int,int) = Mul;
int (*pf4)(int,int) = Div;
return 0;
}
但是这样的方式又没什么效率,这时可以创建一个函数指针数组,代码如下:
int main()
{
int i = 0;
int (*p[4])(int,int) = {Add,Sub,Mul,Div};
for(i = 0;i < 4;i++)
{
printf("%d\n",p[i](2,3));
}
return 0;
}
指针数组,先是数组结合,数据类型是int* ————int* pf[];
函数指针数组, 变量名先跟数组结合,数据类型是 int(*)() ,所以是函数指针数组————int(*p[4])(int,int)
相比较申请多个函数指针来说,达到了简化结构和程序通用性
所以可通过利用函数指针数组来存入多个参数相同的函数的地址,使用对应的下标来调用出函数功能,只需要传入相关参数即可
既然有指向数组的数组指针,那也会有指向函数指针数组的指针
请看代码:
int main()
{
int (* pf[4])(int,int) = {Add,Sub,Mul,Div};
int (*(*ppf)[4])(int,int) = &pf; 这里传递的是函数指针数组的总地址
for(i = 0;i < 4;i++)
{
printf("%d\n",(*ppf)[i](3,3));
} 对函数指针数组的总地址解引用得到数组名,数组名就是数组的首地址
return 0; *ppf == pf
} == &pf[0]
( * ppf)[4]是一个数组指针,是 int( * )(int,int)的类型所以就是 int(*(ppf)[4])(int,int),也就是指向 函数指针数组 的指针
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。
回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
这里介绍一个简单的例子:
int Add(int a,int b)
{
return a + b;
}
//减
int Sub(int a,int b)
{
return a - b;
}
//乘
int Mul(int a,int b)
{
return a * b;
}
//除
int Div(int a,int b)
{
return a / b;
}
void clal(int(*p)(int,int))
{
int temp1 = 0,temp2 = 0;
int ret = 0;
printf("请输入两个操作数:\n");
scanf("%d %d",&temp1,&temp2);
ret = (*p)(temp1,temp2);
printf("ret = %d\n",ret);
}
int main()
{
printf("%d\n",clal(Add));
return 0;
}
把加法函数的地址作为参数传递给clal调用,这就是回调函数。
例如在回调中,主程序把回调函数像参数一样传入库函数。这样一来,只要我们改变传进库函数的参数,就可以实现不同的功能,就会变得很灵活
练习,分析下列数据类型:
//代码1
(*(void (*)())0)();
void (*)()是函数指针类型
(( void (*)() ) 0)()是强制转换
最外层的 * 是解引用*0() 加与不加都对
//代码2
void (*signal(int , void(*)(int)))(int);
signal是函数的声明
int , void(*)(int)是函数的两个参数
void (*)(int)是返回值类型
写成方便理解的形式就是:
void (*typedef)(int) pf_t
pf_t signal(int , pf_t)