You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

《The C++ Programming Language第4版》桌面计算器输入pi输出错误如何修复?

C++桌面计算器预定义常量读取错误问题修复方案

我在复制Bjarne Stroustrup所著《The C++ Programming Language Fourth Edition》中的桌面计算器代码运行时,发现输入代码中已预定义的常量pi时输出结果错误,耗时1天定位到问题根源,现将问题场景、完整代码及修复方案分享如下:

完整可运行代码

#include <iostream>
#include <map>
#include <string>
#include <sstream>
#include <cctype>

enum class Kind:char{
  name,number,end,
  plus='+',minus='-',mul='*',div='/',print=';',assign='=',lp='(',rp=')'
};

struct Token{
  Kind kind;
  std::string string_value;
  double number_value;
};

int no_of_errors;

double error(const std::string& s)
{
  no_of_errors++;
  std::cerr << "error: " << s << '\n';
  return 1;
}

std::map<std::string,double> table;

double expr(bool get);
double term(bool get);
double prim(bool get);

class Token_stream{
public:
  Token_stream(std::istream& s):ip{&s},owns{false}{}
  Token_stream(std::istream* p):ip{p},owns{true}{}

  ~Token_stream(){close();}

  Token get();
  Token& current(){return ct;}

  void set_input(std::istream& s){close();ip=&s;owns=false;}
  void set_input(std::istream* p){close();ip=p;owns=true;}

private:
  void close(){if(owns) delete ip;}

  std::istream* ip;
  bool owns;
  Token ct{Kind::end};
};

Token_stream ts{std::cin};

Token Token_stream::get()
{
  char ch;

  do{
    if(!ip->get(ch)){
      return ct={Kind::end};
    }
  }while(ch!='\n' && std::isspace(ch));

  switch(ch){
    case ';':
    case '\n':
      return ct={Kind::print};
    case '*':
    case '/':
    case '+':
    case '-':
    case '(':
    case ')':
    case '=':
      return ct={static_cast<Kind>(ch)};
    case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
    case '.':{
      ip->putback(ch);
      *ip >> ct.number_value;
      ct.kind=Kind::number;
      return ct;
    }
    default:
      if(std::isalpha(ch)){
        ct.string_value = ch;
        while(ip->get(ch) && std::isalnum(ch)){
          ct.string_value +=ch;
        }
        ip->putback(ch);
        return ct={Kind::name,ct.string_value};
      }
      error("bad token");
      return ct={Kind::print};
  }
}

double expr(bool get)
{
  double left=term(get);
  for(;;){
    switch(ts.current().kind){
      case Kind::plus:left += term(true);break;
      case Kind::minus:left -= term(true);break;
      default:return left;
    }
  }
}

double term(bool get)
{
  double left = prim(get);
  for(;;){
    switch(ts.current().kind){
      case Kind::mul:left *= prim(true);break;
      case Kind::div:
        if(auto d = prim(true)){left /= d;break;}
        return error("divide by 0");
      default:return left;
    }
  }
}

double prim(bool get)
{
  if(get) ts.get();
  switch(ts.current().kind){
    case Kind::number:{
      double v=ts.current().number_value;
      ts.get();
      return v;
    }
    case Kind::name:{
      double& v=table[ts.current().string_value];
      if(ts.get().kind == Kind::assign) v=expr(true);
      return v;
    }
    case Kind::lp:{
      auto e = expr(true);
      if(ts.current().kind!=Kind::rp) return error("')' expected");
      ts.get();
      return e;
    }
    default:return error("primary expected");
  }
}

void calculate()
{
  for(;;){
    ts.get();
    if(ts.current().kind == Kind::end)break;
    if(ts.current().kind == Kind::print)continue;
    std::cout << expr(false) << '\n';
  }
}

int main(int arg,char* argv[])
{
  switch(arg){
    case 1:break;
    case 2:ts.set_input(new std::istringstream{argv[1]});break;
    default:error("too many arguments");return 1;
  }
  table["pi"] = 3.1415926535897932385;
  table["e"] = 2.7182818284590452354;
  calculate();
  return no_of_errors;
}

问题修复方案

问题出在Token_stream::get()成员函数的name类型Token构造逻辑中:

  • 错误代码:
// 位于Token_stream::get()成员函数内
return ct={Kind::name};

错误原因:构造name类型Token时未传入已经解析完成的字符串值,导致后续从预定义常量表中查找时匹配不到对应的key,返回默认值0而非预设的常量值

  • 修复后代码:
// 位于Token_stream::get()成员函数内
return ct={Kind::name, ct.string_value};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 01:24:03