函数指针&&函数指针数组

函数指针&&函数指针数组,第1张

概述:

       函数指针和函数指针数组是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他们的参数和返回类型都相同。


 

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/584822.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-12
下一篇 2022-04-12

发表评论

登录后才能评论

评论列表(0条)

保存