应使用 std::getline 读整行再用 std::stringstream 解析,避免 cin >> 跳过运算符或因无空格导致读取错误;仅支持单二元运算,多运算需两遍扫描处理优先级;须用 try-catch 处理 stod 异常,检查除零时用 abs(b) < EPS。

用 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></:string> - 第二遍:遍历 token,遇到
"*"或"/"就立即计算其左右数字,并用结果替换这三个元素(如{"3", "+", "5", "*", "2"}→ 合并"5", "*", "2"为"10",得到{"3", "+", "10"}) - 第三遍:对剩余
"+"和"-"从左到右计算
关键点:std::stod() 转数字时抛异常(如输入 "abc"),务必用 try-catch 包裹;"-" 既作减号也作负号,简单计算器通常只支持二元减法,不处理 "-5 + 3" 这类前缀负号。
立即学习“C++免费学习笔记(深入)”;
避免 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) 控制小数位,但底层值不变。











