You need to enable JavaScript to run this app. 如何为K&R教材的C语言RPN计算器添加负数处理能力
优惠活动
大模型
产品
解决方案
定价
更多

如何为K&R教材的C语言RPN计算器添加负数处理能力

RPN计算器负数支持实现方案

你之前的修改方向不对:首先ggetch本身不会跳过空格,跳空格的是ggetop开头专门写的跳过空格、制表符的循环。你在主函数的case '-'分支处理的话,所有'-'已经被ggetop判定为运算符返回了,根本拿不到后面的数字内容,自然实现不了负数识别。
核心思路:把负号的判断逻辑放到ggetop函数里处理,而不是在switch分支里——需要在ggetop读到'-'的瞬间,结合上下文判断它是二元减号,还是属于数字的负号位。

前置说明

如果要在'-'和后面的数字之间加空格,会天然产生歧义:输入1 - 2到底是计算1减2,还是输入1和-2两个数?所以常规RPN计算器的负数规则是负号和后面的数字之间不能有空格,这样歧义自然消除,也不需要在跳完空格后反复回退判断。
你之前以为“ggetop和ggetch会自动跳过空格”导致失败,本质是ggetop读到'-'就直接当成运算符返回了,根本没有继续读取后面跟的数字内容。

具体修改步骤

1. 新增上下文标记

加一个全局变量记录上一次读到的token类型,用来判断当前位置是不是应该读新操作数的场景:

// 初始值为-1,代表程序刚启动,还没读过任何token
int last_type = -1;

2. 重构ggetop的负号判断逻辑

原来的ggetop读到非数字/非小数点的字符就直接返回,现在调整为读到'-'时先做判断:

  • 先读下一个字符,如果下一个字符是数字、或者小数点,再检查当前是否处于“读操作数”的上下文(程序刚启动、上一个token是运算符/换行符)
  • 满足条件的话,把'-'连同后面的数字部分一起存入字符串,最终返回NUMBER标记,走数字入栈逻辑
  • 不满足条件的话,把刚才多读的字符通过unggetch放回缓冲区,直接返回'-'作为减号运算符

3. 修正原有bug

你之前在case '-'分支的写法存在明显错误:

  • 连续调用两次ggetch(),等于读走了两个字符,根本不是只判断'-'后面的第一个字符
  • ggetop返回'-'的时候,传入的字符串s只存了'-'本身,没有存后面的数字,调用aatof(s)得到的是-0,完全不符合预期
  • 代码里写的printf("%s",6)是严重错误,%s格式符要求传入字符串指针,传整数6会直接触发内存访问错误导致程序崩溃

参考核心修改代码

修改后的ggetop函数完整实现:

int ggetop(char s[])
{
    int i, c;
    // 保留原有跳过空格、制表符的逻辑
    while ((s[0] = c = ggetch()) == ' ' || c == '\t')
        ;

    s[1] = '\0';
    // 新增:读到'-'时先判断是不是负号
    if (c == '-') {
        int next_c = ggetch();
        // 满足负号条件:下一个是数字/小数点,且当前是该读操作数的上下文
        if ( (isdigit(next_c) || next_c == '.') && 
             (last_type == -1 || last_type == '+' || last_type == '-' || 
              last_type == '*' || last_type == '/' || last_type == '%' || last_type == '\n') ) {
            i = 0;
            s[i++] = c;
            c = next_c;
            // 沿用原有逻辑读取后面的数字、小数部分
            while (isdigit(s[i++] = c = ggetch()))
                ;
            if (c == '.')
                while (isdigit(s[i++] = c = ggetch()))
                    ;
            s[--i] = '\0';
            if (c != EOF)
                unggetch(c);
            last_type = NUMBER;
            return NUMBER;
        } else {
            // 不是负号,把多读的字符放回缓冲区,返回'-'作为减号
            unggetch(next_c);
            last_type = '-';
            return '-';
        }
    }

    // 保留原有非数字字符的返回逻辑
    if (!isdigit(c) && c != '.') {
        last_type = c;
        return c;
    }
    // 保留原有数字读取逻辑
    i = 0;
    if (isdigit(c))
        while (isdigit(s[++i] = c = ggetch()))
            ;
    if (c == '.')
        while (isdigit(s[++i] = c = ggetch()))
            ;
    s[i] = '\0';
    if (c != EOF)
        unggetch(c);
    last_type = NUMBER;
    return NUMBER;
}

主循环里的case '-'分支改回标准的二元减号逻辑即可,不需要额外处理:

case '-':
    op2 = pop();
    push(pop() - op2);
    break;

运行验证

修改完成后,以下输入均可正常计算:

  • 输入-123 4 + → 输出-119
  • 输入3 -4 * → 输出-12
  • 输入10 -3 % → 输出1
  • 输入5 3 - → 输出2

内容的提问来源于stack exchange,提问作者Autumn Exp1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.02 10:45:01