用std::stringstream解析混合表达式最稳,需分两轮处理乘除与加减以保证运算符优先级,配合stod安全转换并校验末尾字符,括号用栈配对+递归调用处理。

用 std::stringstream 解析数字字符串最稳
用户输入一串“3+5*2”这种混合表达式时,不能靠 cin >> int 直接读——它遇到 + 就停了,后面全丢。用 std::stringstream 可以边读边判类型,比手写字符遍历容错高得多。
常见错误是把整个字符串当数字读:ss >> num 遇到非数字立即失败,后续流状态变 failbit,不 clear() 就再也读不出东西。
- 先读一个数:
ss >> num,成功则继续 - 再读一个字符:
ss.get(ch),检查是不是+、-、*、/ - 每次读完操作符后,记得确认
ss.good(),否则可能是末尾空格或非法字符
加减乘除优先级必须分两轮算
写成从左到右顺序计算(比如 3+5*2 算成 8*2=16)是初学者最常踩的坑。C++ 没有内置运算符优先级解析,得自己模拟:第一轮处理 * 和 /,把它们和前后数字合并成新值;第二轮再统一加减。
典型错误是只用一个循环+一个 switch,结果 1+2*3+4 算成 ((1+2)*3)+4 = 13,而正确结果是 1+(2*3)+4 = 11。
立即学习“C++免费学习笔记(深入)”;
- 用
std::vector<double>存所有数字,另一个std::vector<char>存对应操作符(跳过第一个) - 遍历操作符数组,遇到
*或/就立刻更新前一个数字:nums[i] = nums[i] * nums[i+1],然后删掉nums[i+1]和该操作符 - 最后只剩
+和-,从左到右累加即可
std::stod 比 atof 更安全,但要捕获异常
用户可能输“3.14+2e-1”或者“inf”,atof 遇到非法输入返回 0,你根本不知道是真为 0 还是解析失败。std::stod 会抛 std::invalid_argument 或 std::out_of_range,必须包在 try/catch 里。
容易忽略的是:stod 不吃开头空格,但吃结尾非数字字符——比如“123abc”会成功转出 123,不报错。所以得手动检查转换后位置是否到了字符串末尾。
- 调用
std::size_t pos; double x = std::stod(s, &pos); - 检查
pos == s.length(),否则说明后面还有没消化的字符 - 捕获
std::invalid_argument处理纯字母,std::out_of_range处理超大数如1e309
别硬写递归下降,入门够用就别碰语法树
看到“支持括号”就想上递归下降解析器?对入门项目来说太重了。真正卡住人的不是算法,而是括号嵌套时怎么把子表达式切出来——find_first_of(")") 找不到匹配的左括号,count 计数又容易漏掉转义或字符串字面量(虽然计算器不用管这个,但思维惯性会带偏)。
更实际的做法是:先扫一遍字符串,记录每对括号位置,用栈配对;找到最内层一对后,提取中间内容递归调用计算器函数,再把结果代回去。简单、可调试、不引入额外依赖。
- 用
std::stack<int>存'('下标,遇到')'就 pop 出对应左括号位置 - 找“最内层”就是最后一次 push 后紧跟着的
')',即栈顶配对完成时的区间 - 替换字符串时注意:原串长度变了,下标要动态调整,不如每次只处理一个最内层,递归调用自身
括号逻辑看着绕,其实核心就两点:配对必须用栈,替换必须用递归调用——少一个,就会在 2*(3+(4-1)) 这种地方崩掉。











