应使用 std::getline 读整行再用 std::stringstream 解析,避免 cin >> 跳过运算符或因无空格导致读取错误;仅支持单二元运算,多运算需两遍扫描处理优先级;须用 try-catch 处理 stod 异常,检查除零时用 abs(b)用
std::stringstream和std::getline解析单行表达式用户输入形如
"3 + 5 * 2"的字符串时,不能直接用cin >>拆分——它会把"+"当作分隔符跳过,且无法处理空格不规范的输入(比如"3+5 *2")。稳妥做法是读整行,再用std::stringstream逐词提取:std::string line; std::getline(std::cin, line);std::stringstream ss(line); double a; char op; double b; if (ss >> a >> op >> b) { // 成功读到两个数和一个运算符 }
注意:这仅适用于**单个二元运算**(如
"10 - 3"),不支持多运算符或括号。若用户输"1 + 2 + 3",ss >> a >> op >> b只取前三个 token(即1、'+'、2),末尾的"+ 3"被忽略。手写简易运算符优先级处理(无括号)
要支持
"3 + 5 * 2"正确算出13而非16,必须先识别乘除,再做加减。可采用“两遍扫描”策略:
- 第一遍:把输入按空格切分(或用
std::stringstream提取所有 token),存入std::vector<:string>- 第二遍:遍历 token,遇到
"*"或"/"就立即计算其左右数字,并用结果替换这三个元素(如{"3", "+", "5", "*", "2"}→ 合并"5", "*", "2"为"10",得到{"3", "+", "10"})- 第三遍:对剩余
"+"和"-"从左到右计算关键点:
std::stod()转数字时抛异常(如输入"abc"),务必用try-catch包裹;"-"既作减号也作负号,简单计算器通常只支持二元减法,不处理"-5 + 3"这类前缀负号。避免
std::cin >>导致输入阻塞的典型错误常见错误写法:
double a, b; char op; std::cin >> a >> op >> b; // 若用户输 "3+5"(无空格),op 会读成 '3',b 读失败,流进入 failbit后果:
std::cin状态卡住,后续所有输入都被跳过。修复方式只有两种:
- 改用
std::getline+std::stringstream(推荐,见第一个副标题)- 若坚持用
>>,每次读后检查状态:if (!std::cin) { std::cin.clear(); std::cin.ignore(1000, '\n'); }另外,
std::cin >>对"3.14e2"这类科学计数法能正确解析,但对"3,14"(逗号小数点)直接失败——C++ 默认 locale 是英文格式,不支持千位分隔符或本地化小数点。除零和浮点精度问题怎么处理
除法必须显式检查:
if (b == 0.0)不可靠,因为浮点数比较需容忍误差。应写成:const double EPS = 1e-9; if (std::abs(b) < EPS) { std::cout << "Error: division by zero\n"; return; }但注意:这只能捕获真正接近零的除数,无法区分
0.0和-0.0(它们在 IEEE 754 中不同,但std::abs(-0.0)仍是0.0)。实际中,简单计算器可直接用b == 0.0判断,因为用户不会手动输-0.0。更隐蔽的问题是std::pow(0, 0)或开方负数——四则运算不涉及这些,但若后续扩展函数功能,必须单独拦截。浮点误差本身无法消除,例如
0.1 + 0.2输出0.30000000000000004。显示时可用std::setprecision(10) 控制小数位,但底层值不变。