转移表的使用

本文通过实例介绍了如何使用转移表优化计算器代码,避免case过多的问题,提高代码维护性和扩展性。通过定义运算符号表和对应的函数指针,实现了动态调用不同运算功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转移表的使用

当许多处理函数的函数原型一样时,使用转移表,可以让代码更清晰,维护更方便。

大学时看过一本书《C和指针》,里面有一小节关于转移表的介绍,当时就觉得很有意思。现在在工作中又看到了,随手记录一下。

还是以《C和指针》中的例子说起吧。

需要实现一个简易计算器,能对两个数进行各种运算。现有以下代码,代码读入一个式子,在Switch-case语句中进行相应的运算。

/*声明一些运算符号*/
typedef enum{
	ADD = '+',
	SUB = '-',
	MUL = '*',
	DIV = '/',
	//...其他运算法则
}ALG;
/*定义一些运算函数*/
double add(double a,double b){
	return a+b;	
}
double sub(double a,double b){
	return a-b;	
}
double mul(double a,double b){
	return a*b;	
}
double div_(double a,double b){
	return a/b;	
}
/*开始运算*/
int main(int argc, char *argv[]) {
	double a;
	double b;
	double result = 0;
	char c;
	printf("input:");
	scanf("%lf %c %lf",&a,&c,&b);
	switch(c){
		case ADD:
			result = add(a,b);break;
		case SUB:
			result = sub(a,b);break;
		case MUL:
			result = mul(a,b);break;
		case DIV:
			result = div_(a,b);break;
		//...其他case
		default:break;
	}
	printf("result:%0.2lf",result);
	return 0;
}

这里只有4种运算,且处理内容比较简单,所以这样处理也还好,但是如果要将其扩展为一个复杂计算器,处理几十种运算,这样做就不妥了,case会很多,这个处理函数会变得很长,非常不利于维护。

所以我们使用转移表的知识,将代码改成下面的的样子。

/*声明一些运算符号*/
typedef enum{
	ADD = '+',
	SUB = '-',
	MUL = '*',
	DIV = '/',
}ALG;
/*定义一些运算函数*/
double add(double a,double b){
	return a+b;	
}
double sub(double a,double b){
	return a-b;	
}
double mul(double a,double b){
	return a*b;	
}
double div_(double a,double b){
	return a/b;	
}
/*声明函数指针类型OPERFUN*/
typedef double (*OPERFUN)(double ,double);

/*定义运算符号列表 algorithm,定义运算函数列表 oper_fun */
ALG    algorithm[] = {ADD,SUB,MUL,DIV};		
OPERFUN oper_fun[] = {add,sub,mul,div_};
/*写一个处理函数,能够检查运算符号并调用相应的函数*/
double oper_handle(char c,double a, double b){
	int i ;
	int len = sizeof(algorithm)/sizeof(ALG);
	for( i = 0; i < len; i ++ ){
		if(c == algorithm[i]){
			if(oper_fun[i] != NULL){
				return oper_fun[i](a,b);
			}
		}
	}
	return 0;
}

int main(int argc, char *argv[]) {
	double a;
	double b;
	double result = 0;
	char c;
	printf("input:");
	scanf("%lf %c %lf",&a,&c,&b);
	result = oper_handle(c,a,b);		//在这里调用函数进行运算
	printf("result:%0.2lf",result);
	return 0;
}

代码改成这样就好多了,以后有了新的需求,就往algorithm和oper_fun列表里添加就好,代码长度基本不会增长多少。可能还有点小瑕疵,就是algorithm和oper_fun列表是分开的,一旦对应顺序出错了就糟糕了。

再改改。

/*声明一些运算符号*/
typedef enum{
	ADD = '+',
	SUB = '-',
	MUL = '*',
	DIV = '/',
}ALG;
/*定义一些运算函数*/
double add(double a,double b){
	return a+b;	
}
double sub(double a,double b){
	return a-b;	
}
double mul(double a,double b){
	return a*b;	
}
double div_(double a,double b){
	return a/b;	
}
/*声明函数指针类型OPERFUN*/
typedef double (*OPERFUN)(double ,double);

/*定义运算服务类型*/
typedef struct {
	ALG 	algorithm;
	OPERFUN oper_fun;
}OPER_SERVER;

/*运算服务列表,所有的运算符号和运算函数都添加在这个表里*/
OPER_SERVER oper_server[] = {
	{ADD,	add},
	{SUB,	sub},
	{MUL,	mul},
	{DIV,	div_},
};

double oper_handle(char c,double a, double b){
	int i ;
	int len = sizeof(oper_server)/sizeof(OPER_SERVER);
	for( i = 0; i < len; i ++ ){
		if(c == oper_server[i].algorithm){
			if(oper_server[i].oper_fun != NULL){
				return oper_server[i].oper_fun(a,b);
			}
		}
	}
	return 0;
}

int main(int argc, char *argv[]) {
	double a;
	double b;
	double result = 0;
	char c;
	printf("input:");
	scanf("%lf %c %lf",&a,&c,&b);
	result = oper_handle(c,a,b);		//调用函数进行运算
	printf("result:%0.2lf",result);
	return 0;
}

每次有新需求的时候,只需要oper_server中进行变动,algorithm和oper_fun一一对应,这样就不会把顺序搞乱了。

以上 用一个简单的例子演示了转移表的用法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值