C指针进阶(2)----函数指针数组

在一篇文章中,我在末尾提出了一个问题,就是,小明的老师给他布置了一个作业

小明一时被难住了,思绪全无,就让我们来帮帮他吧!

首先,说起计算器,我相信大家都写过,很多都是下面这种形式:

#define _CRT_SCURE_NO_WARINGS 1
#include<stdio.h>

/*杰哥の作业*/
void menu()
{
	printf("****************************\n");
	printf("******1.add  2.sub********\n");
	printf("******3.mul  4.div********\n");
	printf("******     0.exit   *******\n");
	printf("****************************\n");
}
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 = 0;
	do
	{
		int x, y;
		int result;
		menu();
		printf("请选择一个功能\n");
		scanf("%d", &input);
		switch (input)
		{
			case 1:
			{
				printf("请输入两个数");
				scanf("%d%d", &x, &y);
				result = add(x, y);
				break;
			}

			case 2:
			{
				printf("请输入两个数");
				scanf("%d%d", &x, &y);
				result = sub(x, y);
				break;
			}

			case 3:
			{
				printf("请输入两个数");
				scanf("%d%d", &x, &y);
				result = mul(x, y);
				break;
			}
			case 4:
			{
				printf("请输入两个数");
				scanf("%d%d", &x, &y);
				result = div(x, y);
				break;
			}
			case 0:
			{
				printf("程序结束!\n");
				break;
			}
			default:
			{
				printf("输入错误,请重新输入!");
				break;
			}
		}
		printf("%d\n", result);

	} while(input);
	return 0;
}

 可以发现上面的代码虽然能实现案例的加减乘除,但代码出现了大量冗余,杰哥看过之后很容易生气,小明极有可能被登dur郎,那么有没有一种方式即可以实现计算器的功能,有大量减少的重复的代码呢?

当然有,那么这就是我即将为大家介绍的-----函数指针数组

首先,什么是函数指针数组?

非常简单,我们都知道数组用来存储一系列数据,但它往往被认为是一系列相同类型的变量。

我们也知道了函数指针是什么,那么,将它们结合起来就是,函数指针数组,

所以,函数指针数组其实就是将多个函数指针存放到数组中

我们来看一个函数指针数组的定义

int (*ptrarray[5])(int, int) = { NULL,add,sub,mul,div };

我们来简单地解析以下这个语句

首先语句中出现了多个括号,又因为括号是左结合性,所以,优先执行(*ptrarray[5]),又因为[]的优先级高于*,所以,ptrarray会先和[]结合,形成一维数组。

那么,注意,这个时候我们一旦将ptrarray[5]提出,我们就会发现,语句就只剩下

int (*)(int, int) 

我们惊讶的发现,这个剩下的语句刚刚好是一个函数指针。所以,array[0]的位置存放了一个函数指针,array[1]的位置也存放了一个函数指针,同理可得,array[2],array[3],array[4]的位置都存放了一个函数指针,那么,我不就实现了将多个函数指针放到一个数组里了吗?当我们需要某一个位置的函数指针的时候,只需要进行数组取值即可。

我相信,这个时候一定有小明要问了,

为什么将ptrarra[5]提出去?而且int (*)(int, int) 为啥是函数指针?

首先第一个问题,为什么将ptrarra[5]提出去?

        我们都知道,如何去定义一个一维数组,假设我有以下定义

        int array[5];

      我们都知道,这定义了一个具有5个整形元素的一维数组。

但现在我对,int array[5];这么解释:

array标识符和[]结合,形成一维数组,剩下的部分即是对array数组中5个元素类型说明。

因为剩下的部分是int,所以,array数组中5个元素的类型说明是int,所以

array是一个具有5个整形元素的一维数组。通过我上面的说明,我们就知道了,数据类型是对数组元素的类型说明。

所以,当我们再回头去看这个语句

int (*ptrarray[5])(int, int)

我将ptrarray[5]提出来后,剩下的部分就是对ptrarray数组的元素类型说明。

好,当我们解决完这个问题后,我们再来看一下下一个问题。

int (*)(int, int) 这个表达式不就是上一篇文章中的表达式吗?只是(*)标识符省去了而已,还是和上一篇文章所阐述的含义一样。

所以,文章写到这,我们已经很清楚了,什么是函数指针数组了

那么,我再来看一下这个表达式:

int (*ptrarray[5])(int, int) = { NULL,add,sub,mul,div };

那么其实,ptrarray[0]其实就是指针指向NULL指针,而NULL指针,我们都知道其实就是空指针(常量0),那么,ptrarray[1]就是令指针指向add函数,那么下面只需要调用不就可以了吗?

所以,文章到这,小明就又有问题了

那么,函数指针数组怎么调用呢?

其实非常的简单,我在上面的末尾部分其实也差不多写出来了,我相信有不少读者也看出来了,没错,就是:

result = (ptrarray[input])(x, y);

没错,就是这么简单,就是这么容易,你会发现这不就是C语言基础部分吗?

是的,相信你自己的判断,有的时候,有一些东西就是看起来那么简单,有的bug看起来很简单,,很好解决,但有的bug,你就是解决不了,对此你会感到无奈,就像生活中,你为了一个她(他)去送东西,你明明努力了那么久,准备了那么多,跑了2千多米,却在某个地方找不到去他(她)地方的关键车,你对此也会感到无奈,生活也如此,程序也如此罢了

言回正传,函数指针数组的调用和数组引用很像,也可以认为他们就是一样

此时,小明看到这后,脑中有了一丝思绪,但还不确定,好像还有个点没想到,于是,他继续提问

我既然知道了如何定义函数指针数组及调用,那么如何应用到我的题目中呢?

其实,非常简单,将函数指针数组应用到题目中,我们只需要修改主函数,在修改亿点点语句,即可得出以下代码

#define _CRT_SCURE_NO_WARINGS 1
#include<stdio.h>

/*杰哥の作业*/
void menu()
{
	printf("****************************\n");
	printf("******1.add  2.sub********\n");
	printf("******3.mul  4.div********\n");
	printf("******     0.exit   *******\n");
	printf("****************************\n");
}
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 = 0;
	do
	{
		int x, y;
		int result;
		menu();
		printf("请选择一个功能\n");
		scanf("%d", &input);
		int (*ptrarray[5])(int, int) = { NULL,add,sub,mul,div };
		if (input >= 0 && input <= 4)
		{
			if (input == 0)
			{
				printf("退出程序!\n");
				break;
			}
			printf("请输入两个数");
			scanf("%d%d", &x, &y);
			result = (ptrarray[input])(x, y);
			printf("结果为:%d\n", result);

		}
		else
		{
			printf("输入错误,请重新输入!\n");
		}
	} while (input);
	return 0;
}

我相信,我将函数指针数组及调用都讲明白了,上面的大部分程序大家也就能看懂了,但问题超多的小明又问了几个问题,我们来看一下

Q:ptrarray[0]要传入NULL指针?

这是一个好问题,虽然,这个问题不在函数指针数组的范围内,但这却是实现计算器功能的关键一步。

首先,这个计算器实现了一个输入0就退出计算器功能,既然,我输入0就是结束,那么就代表我不需要调用任何函数,输入0,那么也代表input拿到0这个值,正好走入if嵌套,break函数结束整个程序,并且,当ptrarray[0]时0的时候,也符合了我们输入习惯,输入1进行加法运算,正好ptrarray[1]是令指针指向了加法函数,输入0,指向NULL,正好结束整个程序,符合我们题意

所以,我们发现ptrarray[0] = NULL是一个不错的写法。

小明听后,恍然大悟,转手给博主点了一个赞,收藏加评论“有用!”,小明交了之后,杰哥看了看,满意的笑了笑,对小明说:“小明写的不错啊,给你打18分,剩下2分是不要骄傲,继续加油!”,小名了笑了笑。突然,又有了新疑问,既然,博主一直提NULL指针,那是玩意思?

一会找博主问问!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值