C语言入门学习——指针进阶2

指针进阶2

  • 函数指针
  • 函数指针数组
  • 指向函数指针数组的指针
  • 回调函数
  • 总结

函数指针

请先看一段代码:

int ADD(int a,int b)
{
	return a + b;
}
int main()
{
	int ret = 0;
	printf("%p\n",ADD);
	printf("%p\n",&ADD);

	return 0;
}

C语言入门学习——指针进阶2_第1张图片
由输出结果可知:
数组的首地址与总地址,值一样,但意义不同;而函数的地址,虽然方式不一样,但是意义一样
函数也是有自己的地址的

既然每个函数都有他自己的地址,那么函数指针是指向函数地址的
函数指针定义

函数返回值类型 (*函数名)(参数)
例如: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)

C语言入门学习——指针进阶2_第2张图片
相比较申请多个函数指针来说,达到了简化结构和程序通用性
所以可通过利用函数指针数组来存入多个参数相同的函数的地址,使用对应的下标来调用出函数功能,只需要传入相关参数即可

指向函数指针数组的指针

既然有指向数组的数组指针,那也会有指向函数指针数组的指针
请看代码:

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)

总结

  1. 每个函数都是有自己的地址
  2. 数组的取地址(&)与数组名,值一样,但意义不同;而函数的函数名和取地址,虽然方式不一样,但是意义一样;所以在函数指针取函数地址时,&加不加都一样
  3. 在使用函数指针时,函数指针变量名前的 * 加和不加都对,但是加上 * 可以方便理解
  4. 函数指针数组与指针数组一样,数组里的每个元素都是指针,只不过函数指针数组是指向函数的
  5. 回调函数就是一个通过函数指针调用的函数
  6. 回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应
  7. 函数指针与调用的函数,参数类型必须相同

你可能感兴趣的:(c语言,学习,c++)