在一篇文章中,我在末尾提出了一个问题,就是,小明的老师给他布置了一个作业
小明一时被难住了,思绪全无,就让我们来帮帮他吧!
首先,说起计算器,我相信大家都写过,很多都是下面这种形式:
#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指针,那是玩意思?
一会找博主问问!