转移表
目录
- 一般实现
- 函数指针数组实现
- 回调函数实现
1、一般实现
让我们先来看下计算器的一般实现:
1、构建框架
int main()
{
int x,y;//初始化两个操作数
int ret = 0;
int input = 1;
do
{
scanf("%d", &input);
switch(input)
{
}
} while ( );
return 0;
}
2、打印菜单
可以构建一个menu函数,在之前扫雷的案例中已经涉及。
void menu()
{
printf("***********************\n");
printf("**** 1.add 2.sub ****\n");
printf("**** 3.mul 4.div ****\n");
printf("**** 0.exit ****\n");
printf("***********************\n");
printf("请选择\n");
}
3、完善分支
首先,需要输入一个input,根据input不同的值来判断应该进入switch的哪一个分支。
- 当input的值为1时,做加法运算。
- 当input的值为2时,做减法运算。
- 当input的值为3时,做乘法运算。
- 当input的值为4时,做除法运算。
- 当input的值为0时,退出计算器。
- 当input的值不为以上值时,需要重新输入。
4、补齐对应函数
随后我们以加法为例:
int add(int a, int b)
{
return a + b;
}
switch(input)//input非0时为真,进入switch内部
{
case 1:
printf("输⼊操作数:");
scanf("%d %d", &x, &y);
ret = add(x, y);//调用对应函数
printf("ret = %d\n", ret);
break;
}
5、代码呈现
#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");
printf("请选择\n");
}
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 x, y;
int input = 1;
int ret = 0;
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 1:
printf("输⼊操作数:");
scanf("%d %d", &x, &y);
ret = add(x, y);
printf("ret = %d\n", ret);
break;
case 2:
printf("输⼊操作数:");
scanf("%d %d", &x, &y);
ret = sub(x, y);
printf("ret = %d\n", ret);
break;
case 3:
printf("输⼊操作数:");
scanf("%d %d", &x, &y);
ret = mul(x, y);
printf("ret = %d\n", ret);
break;
case 4:
printf("输⼊操作数:");
scanf("%d %d", &x, &y);
ret = div(x, y);
printf("ret = %d\n", ret);
break;
case 0:
printf("退出程序\n");
break;
default:
printf("选择错误\n");
break;
}
} while (input);//以input作为控制循环的条件十分巧妙,当input的值为0时,正好不再循环
return 0;
}
但是我们不难发现,这种写法十分的复杂且出现了许多段相似的代码,能不能使它们精简一些呢?
这时我们就可以使用函数指针数组,将函数指针放到一个数组中,当我们需要调用其中的函数时,只要访问这个函数指针数组,取出所需函数的地址,对其进行调用,可以大幅精简代码。
2、函数指针实现
首先,我们可以创建一个函数指针数组,把可能需要使用的函数地址存入其中。
int (*pf[5])(int x, int y) = {0, add, sub, mul, div};
这里在开头放入0,是为了保证函数地址在数组中的下标与对应input值相同,方便后面我们调用对应函数。
这时,我们就可以摒弃复杂的switch语句,而使用if-else语句来实现转移表。代码如下(if-else语句部分):
if (input >= 1 && input <= 4)
{
int a, b = 0;
printf("请输入两个操作数\n");
scanf("%d %d", &a, &b);
ret = (*p[input])(a, b);//input对应数组下标,调用对应函数
printf("%d\n", ret);
}
else if (input == 0)
{
printf("退出计算器\n");
}
else
{
printf("输入错误,重新输入\n");
}
3、回调函数实现
那么,我们可不可以不使用函数指针数组,而起到简化代码的效果呢?
答案是:可以。
我们可以通过回调函数来达到这个效果。
回调函数就是⼀个通过函数指针调用的函数。
如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被用来调用其所指向的函数
时,被调用的函数就是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条
件发生时由另外的⼀方调用的,用于对该事件或条件进行响应。
**我们可以构建一个无返回值的calc函数,接收一个函数指针,通过该指针调用对应函数,达到化繁为简的效果。**代码如下(calc函数+主函数部分):
void calc(int(*pf)(int x,int y))
{
int ret = 0;
int x,y;
printf("输入操作数:");
scanf("%d %d",&x,&y);
ret = pf(x,y);
printf("ret = %d\n",ret);
}
int main()
{
menu();
int input = 1;
do
{
scanf("%d", &input);
switch (input)
{
case 1:
calc(add);
break;
case 2:
calc(sub);
break;
case 3:
calc(mul);
break;
case 4:
calc(div);
break;
case 0:
printf("退出程序\n");
break;
default:
printf("选择错误\n");
break;
}
} while (input);
return 0;
}