RPN计算器异常求助:多位数运算结果仅显示最后一位
问题分析与修复方案
你遇到的核心问题是代码没有处理多位数的情况——不管是中缀转后缀还是后缀计算环节,都把每个数字字符当成了单独的操作数,导致多位数被拆成单个数字计算,最终结果完全偏离预期。比如输入13时,代码会把它当成1和3两个独立的数,而不是整数13。
具体问题点
- 中缀转后缀阶段:遇到数字字符时直接逐个写入后缀字符串,没有将连续的数字组合成完整的数,也没有添加分隔符区分不同操作数/运算符。比如
1+1生成的后缀是11+,而13生成的后缀是13,两者无法区分是两个单数字还是一个多位数。 - 后缀计算阶段:逐个字符处理后缀字符串,每个数字字符单独转成整数入栈,导致多位数被拆分成多个单数字计算,完全不符合预期逻辑。
修复步骤
1. 修改中缀转后缀函数,支持多位数并添加分隔符
修改infix_to_postfix方法,处理连续数字并在每个token(操作数/运算符)后添加空格分隔,这样后续计算时能清晰区分每个元素:
void infix2postfix :: infix_to_postfix() { int i,p=0; char next; char symbol; int len = strlen(infix); for(i=0; i<len; i++) { symbol=infix[i]; if(!white_space(symbol)) { switch(symbol) { case '(': push(symbol); break; case ')': while((next=pop())!='(') { postfix[p++] = next; postfix[p++] = ' '; // 运算符后加空格分隔 } break; case '+': case '-': case '*': case '/': case '%': case '^': while( !isEmpty() && priority(stack[top])>= priority(symbol) ) { postfix[p++]=pop(); postfix[p++] = ' '; // 弹出的运算符后加空格分隔 } push(symbol); break; default: /*处理多位数操作数*/ // 读取所有连续的数字字符 while(i < len && isdigit(infix[i])) { postfix[p++] = infix[i]; i++; } i--; // 外层循环会自动i++,这里回退一步避免跳过字符 postfix[p++] = ' '; // 操作数后加空格分隔 break; } } } while(!isEmpty()) { postfix[p++]=pop(); postfix[p++] = ' '; // 剩余运算符后加空格分隔 } // 去掉最后多余的空格,添加字符串结束符 if(p > 0) p--; postfix[p]='\0'; }
2. 修改后缀计算函数,按分隔的token处理
修改eval_post方法,按空格分割后缀字符串的每个token,区分数字和运算符,正确处理多位数:
int infix2postfix :: eval_post() { int a,b,temp,result; char token[20]; // 存储单个token,支持最大19位数字 int token_idx = 0; int len = strlen(postfix); for(int i=0; i<=len; i++) { // 遇到空格或字符串结束时,处理当前token if(postfix[i] == ' ' || postfix[i] == '\0') { if(token_idx == 0) continue; // 跳过空token(比如连续空格) token[token_idx] = '\0'; token_idx = 0; if(isdigit(token[0])) { // 数字token转成整数入栈 int num = atoi(token); push(num); } else { // 运算符token,弹出两个数计算 a=pop(); b=pop(); switch(token[0]) { case '+': temp=b+a; break; case '-': temp=b-a; break; case '*': temp=b*a; break; case '/': temp=b/a; break; case '%': temp=b%a; break; case '^': temp=pow(b,a); break; default: cout << "Unknown operator: " << token[0] << endl; exit(1); } push(temp); } } else { // 收集当前token的字符 token[token_idx++] = postfix[i]; if(token_idx >= 20) { cout << "Error: Too long number" << endl; exit(1); } } } result=pop(); return result; }
3. 替换不安全的gets函数
原代码中gets(infix)存在缓冲区溢出风险,建议换成更安全的fgets:
int main() { infix2postfix ip; top=-1; cout<<"Enter infix : "; // 使用fgets读取输入,避免缓冲区溢出 fgets(infix, sizeof(infix), stdin); // 去掉输入末尾的换行符 infix[strcspn(infix, "\n")] = '\0'; ip.infix_to_postfix(); cout<<"Postfix : "<<postfix<<endl; cout<<"Result is : "<<ip.eval_post()<<endl; return 0; }
测试验证
修复后测试你的例子:
- 输入中缀:
(1+1)*13+10/2
后缀:1 1 + 13 * 10 2 / +
结果为:31 - 输入中缀:
2*13+10/2
后缀:2 13 * 10 2 / +
结果为:31 - 输入中缀:
3*2+5
后缀:3 2 * 5 +
结果为:11
所有案例都能得到正确结果。
内容的提问来源于stack exchange,提问作者Victoria
相关产品推荐
相关产品推荐

