引言
- 本文主要内容围绕运用函数指针数组以及回调函数部分的内容,实现一种能够进行整数四则运算以及指定保留小数位的计算器。同时分析该计算器的缺点与不足,并分享学习心得。
-
目录
课上所学计算器
本节主要回忆课上所讲的内容,整理思路。首先实现最简单的四则运算函数Add Sub Div Mul ,后搭建do while 加 switch框架,再通过转移表或者回调函数进行函数的调用。同时为了简化代码,后在switch语句的各个case部分使用一个封装函数,实现用户输入操作操作数的功能。
-
普通计算器
#include<stdio.h>; 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 menu() { printf("#####################\n"); printf("### 1 sum 2 sub ###\n"); printf("### 3 mul 4 div ###\n"); printf("### 0 exit ###\n"); printf("#####################\n"); } int main() { int input = 0; do { menu(); printf("请选择:>"); scanf("%d", &input); int x=0,y=0,ret=0; switch (input) { case 1: printf("请输入两个操作数:>"); scanf("%d%*c%d", &x, &y); int ret = Add(x, y); printf("结果为%d\n", ret); break; case 2: printf("请输入两个操作数:>"); scanf("%d%*c%d", &x, &y); int ret = Sub(x, y); printf("结果为%d\n", ret); break; case 3: printf("请输入两个操作数:>"); scanf("%d%*c%d", &x, &y); int ret = Mul(x, y); printf("结果为%d\n", ret);; break; case 4: printf("请输入两个操作数:>"); scanf("%d%*c%d", &x, &y); int ret = Div(x, y); printf("结果为%d\n", ret); break; case: printf("计算结束\n"); break; default: printf("您的输入有误,请重新输入\n"); break; } } while (input); return 0; }
可以看到,在case后面的代码及其冗余,从而改进使用回调函数结合函数指针如下。
-
使用回调将函数实现
//回调函数
void Fuc(int(*calcul)(int a, int b))
{
int x = 0;
int y = 0;
printf("请输入两个操作数:>");
scanf("%d%*c%d", &x, &y);
int ret = calcul(x, y);
printf("结果为%d\n", ret);
}
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
Fuc(Add);
break;
case 2:
Fuc(Sub);
break;
case 3:
Fuc(Mul);
break;
case 4:
Fuc(Div);
break;
case:
printf("计算结束\n");
break;
default:
printf("您的输入有误,请重新输入\n");
break;
}
} while (input);
在使用回调函数后代码do while部分得到了简化。当一个函数的参数是另一个函数的地址,并且在特定的场景通过指针调用该函数时,这个被调用的函数叫回调函数,回调函数不是由该函数的实现直接调用,而是由另外的一方调用,用于该事件或条件进行相应。
-
使用转移表实现
(为重点突出,只展示封装函数),该处也可以把函数指针数组设置为5个元素,将第一个元素设为0,从而可以方便主函数的相关书写。
小结
简单回忆了上课所学,并实践回调函数以及转移表的相关代码。
课后改进与实践
本节基于上课所学,实践了一种可以进行带小数的乘除,并可以指定保留几位小数位的计算器
代码如下
基于回调函数
//回调函数实现计算器(可实现小数运算,以及指定输出的小数位)
#include<stdio.h>
float Add(int a, int b,int c)
{
return a + b;
}
float Sub(int a, int b,int c)
{
return a - b;
}
float Div(int a, int b, int c)
{
if (c == 0)
return a / b;
else
return (a * 1.0) / b;
}
float Mul(int a, int b,int c)
{
if (c == 0)
return a * b;
else
return (a * 1.0) * b;
}
void calcu(float(* fuc)(int a, int b, int c))
{
int decimal = 0;
int a=0, b=0;
printf("需要保留几位小数:>");
scanf("%d", &decimal);
printf("请输入操作数:>");
scanf("%d%*c%d", &a, &b);
float ret = fuc(a, b, decimal);
printf("结果为%.*f\n", decimal, ret);
}
void menu()
{
printf("**********************\n");
printf("*** 1-Add 2-Sub ***\n");
printf("*** 3-Div 4-Mul ***\n");
printf("****** 0-exit ******\n");
}
int main()
{
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
calcu(Add);
break;
case 2:
calcu(Sub);
break;
case 3:
calcu(Div);
break;
case 4:
calcu(Mul);
break;
case 0:
printf("计算结束\n");
break;
default:
printf("您的输入有误,请重新输入\n");
break;
}
} while (input);
return 0;
}
基于回调函数改进了封装函数,增加了指定小数位,通过printf函数占位符的相关知识限制输出的小数位。对加减法函数,改变了其返回类型,以及增设int c 变量用以匹配回调函数参数的指针。同时当decimal取零时,乘除函数也通过加设分支进行解决。
基于转移表
void calcul(int input)
{
int decimal = 0;
int a = 0, b = 0;
//转移表
double(*fuc[5])(int a, int b, int c) = { 0,Add ,Sub ,Div,Mul };
printf("请输入要保留的小数位:>");
scanf("%d", & decimal);
printf("请输入两个操作数:>");
scanf("%d%*c%d", &a, &b);
double ret = (*fuc[input])(a, b, decimal);
printf("答案为%*.f\n", decimal, ret);
}
总结
缺点,反思
- 只能进行整数运算,不能进行小数与小数,或者小数和整数的运算
- 不能根据要求自动保留小数位
- 不能实现连续计算
- 不能进行特殊数学计算
- 不能对每个环节的输入进行查错并反馈,该问题的具体尝试过程如下
如:
无法达到想要的效果,即在输入wps时判断有误并重新运行。后尝试更改else if 和else的顺序,并验证能正常工作后,在第二次运行计算时进行非法输入如图:
可见,非法输入后出现死循环,未达到目标。而后在do while中加input = 0;进行尝试如图:
可见,未进行死循环但,仍未能达到预期结果。后将位于do while循环中input赋值为一个难以出现的值,进行部分屏蔽如图:
可见,部分达到期望效果,后欲改变else代码块中的break为continue,同样出现死循环的情况。
可能通过后续对库函数的学习,以及对C编程学习的深入能有机会解决该问题。
幸甚至哉,歌以咏志