应使用双栈法解析四则运算表达式,而非std::stringstream或std::stod;维护nums和ops栈,按优先级计算,处理括号与负号,并严格校验输入合法性。
std::stringstream 和 std::stod 解析表达式太危险直接用字符串流或类型转换函数处理用户输入的四则运算表达式(比如 "3 + 4 * 2"),几乎必然出错。这些工具不理解运算符优先级,也不会递归解析括号,std::stod("3 + 4 * 2") 只会读到 3 就停,后面全被忽略。真要这么做,得自己拆分 token、建栈、模拟运算过程——相当于重写一个简易解释器。
这是教科书级解法,稳定、易懂、能覆盖常见需求。核心是维护两个栈:nums 存操作数,ops 存运算符。遇到数字就入 nums;遇到运算符时,先检查栈顶是否该立即计算(比如当前是 *,而栈顶是 +,那 + 不能等,得先算掉);遇到左括号无条件入栈,右括号则一路弹出直到左括号。
map:比如 {'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}
- 出现在开头或左括号后(如 "(-5 + 3)"),应视为一元负号,需补 0 入 nums
if (b == 0) throw std::runtime_error("division by zero");
double calc(double a, double b, char op) {
switch(op) {
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/': if (b == 0) throw std::runtime_error("division by zero"); return a / b;
}
return 0;
}
如果只要求用户输入带空格的格式(如 "3 + 4 * 或 
"10 / ( 2 - 1 )"),可以先用 std::istringstream 按空格切分 token,再逐个识别数字、运算符、括号。这样避免手写跳过空白、识别多位数、处理小数点等边界问题。
while (iss >> token),token 是 std::string
token == "(" 或 token == ")" 比判断单个字符更清晰std::stod(token) 安全转换,前提是已确认 token 不含非法字符真实场景下,用户可能输 "3++4"、"(5 + " 或 "abc * 2"。只靠双栈逻辑无法捕获所有异常,必须在解析前/中加校验:
0-9、+-*/()、空格;小数点需成对出现在数字中"3 * + 4"
nums 应只剩 1 个数,ops 应为空,否则说明表达式不完整这些检查点分散在词法分析和语法计算阶段,漏掉任意一个,程序就可能崩溃或返回错误结果。