如何让支持括号的C语言计算器处理含空格的表达式?
解决带空格表达式的计算器问题
你实现的计算器在处理带空格的表达式(如(2 + 3) * 2)时输出错误结果2,但无空格的表达式(如(2+3)*2)能得到正确结果10,问题出在输入读取不完整和未处理空格字符两个核心环节,以下是具体修复方案:
问题根源分析
- 输入截断:原代码使用
scanf("%s", str)读取输入,%s会在遇到空格时停止读取,因此输入(2 + 3) * 2时,str实际只存储了(2,后续内容完全未被处理,导致计算错误。 - 空格干扰逻辑:即使能读取完整带空格的字符串,原代码没有跳过空格,空格会被当作非数字、非运算符的特殊字符进入栈操作逻辑,破坏计算流程。
修正后的完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_SIZE 1024 int insert_operand(int *operand, int * top_num, int num) /* 数据入栈 */ { (*top_num) ++; operand[*top_num] = num; /* 存储数据 */ return 0; /* 正常退出 */ } int insert_oper (char * oper , int *top_oper , char ch) { (*top_oper)++; oper[*top_oper] = ch; /* 存储运算符 */ return 0; /* 正常退出 */ } int compare(char *oper , int *top_oper , char ch) /* 比较运算符优先级 */ { if((oper[*top_oper] == '-' || oper[*top_oper] == '+') && (ch == '*' || ch == '/')) { return 0; // 当前运算符优先级更高,直接入栈 } else if(*top_oper == -1 || ch == '(' || (oper[*top_oper] == '(' && ch != ')')) { return 0; // 栈空、左括号或左括号后非右括号,直接入栈 } else if (oper[*top_oper] =='(' && ch == ')') { (*top_oper)--; // 弹出左括号,不处理右括号 return 1; } else { return -1; // 当前运算符优先级更低,先计算栈顶运算 } } int deal_date(int *operand ,char *oper ,int *top_num, int *top_oper) /* 执行运算 */ { int num_1 = operand[*top_num]; /* 取出栈顶两个数据 */ int num_2 = operand[*top_num - 1]; int value = 0; if(oper[*top_oper] == '+') { value = num_1 + num_2; } else if(oper[*top_oper] == '-') { value = num_2 - num_1; } else if(oper[*top_oper] == '*') { value = num_2 * num_1; } else if(oper[*top_oper] == '/') { value = num_2 / num_1; } (*top_num) --; /* 数据栈栈顶下移 */ operand[*top_num] = value; /* 运算结果入栈 */ (*top_oper) --; /* 运算符栈栈顶下移 */ return 0; // 补充缺失的返回值 } int main() { int operand[MAX_SIZE] = {0}; /* 数据栈初始化 */ int top_num = -1; char oper[MAX_SIZE] = {0}; /* 运算符栈初始化 */ int top_oper = -1; // 修改1:用fgets读取整行输入,支持空格 char *str = (char *) malloc (sizeof(char) * 100); if (str == NULL) { perror("malloc failed"); return 1; } fgets(str, 100, stdin); // 修改2:去除fgets读取到的换行符(如果存在) size_t len = strlen(str); if (len > 0 && str[len-1] == '\n') { str[len-1] = '\0'; } char* temp; char dest[MAX_SIZE]; int num = 0; int i = 0; while(*str != '\0') { // 修改3:跳过所有空格字符 while (*str == ' ') { str++; if (*str == '\0') break; } if (*str == '\0') break; temp = dest; while(*str >= '0' && *str <= '9') /* 判断是否为数字 */ { *temp = *str; str++; temp++; } /* 遇到非数字退出 */ if(*str != '(' && temp != dest) /* 优化判断:只要读取到数字就处理 */ { *temp = '\0'; num = atoi(dest); /* 字符串转数字 */ insert_operand(operand, &top_num,num); /* 数字入栈 */ } while(1) { // 再次检查空格,防止处理完数字后遇到空格 if (*str == ' ') { str++; continue; } if (*str == '\0') break; i = compare(oper,&top_oper,*str); /* 判断运算符优先级 */ if(i == 0) { insert_oper(oper,&top_oper,*str); /* 运算符入栈 */ break; } else if(i == 1) /* 括号内表达式结束 */ { str++; break; // 处理完右括号后跳出循环 } else if(i == -1) /* 执行运算 */ { deal_date(operand,oper,&top_num,&top_oper); } } if (*str != '\0') { str ++; /* 指向表达式的下一个字符 */ } } printf("%d\n",operand[0]); /* 输出结果 */ free(str); // 释放malloc分配的内存 return 0; }
关键修改说明
- 输入读取优化:用
fgets替代scanf("%s"),支持读取包含空格的整行输入,同时处理fgets可能读取到的换行符,避免干扰后续字符串处理。 - 空格跳过逻辑:在进入数字读取和运算符处理前,先跳过所有空格字符,确保只有有效字符(数字、运算符、括号)进入核心计算逻辑。
- 边界判断优化:将原
*(temp - 1) != '\0'改为temp != dest,更准确判断是否读取到数字字符,避免边界错误。 - 健壮性修复:补充
deal_date函数的返回值,释放malloc分配的内存,避免内存泄漏。
内容的提问来源于stack exchange,提问作者p0vi3
相关产品推荐
相关产品推荐

