调用 std::stack::top() 或 pop() 前必须检查非空,否则触发未定义行为;数字解析需按完整 token 处理而非逐字符扫描,避免误拆多位数或负号。

遇到 std::stack 弹出空栈会崩溃怎么办
直接调用 top() 或 pop() 前不检查是否为空,程序大概率触发未定义行为,常见表现是段错误或 Windows 下的 std::logic_error(如 MSVC 报 “vector subscript out of range”)。这不是“运气不好”,而是 C++ 标准明确要求调用者保证非空。
- 每次
top()/pop()前必须加if (!stk.empty())判断 - 别依赖
try-catch捕获——std::stack::top()在空时根本不会抛异常,它只是读取无效内存 - 如果逻辑上“不该为空”,用
assert(!stk.empty())辅助调试,但发布版要禁用
数字字符转整数时忽略多位数和负号
后缀表达式里 "123" 是一个数,不是三个单独的 '1''2''3';"-5" 也不是操作符 '-' 加数字 '5'。按字符逐个扫会把 "123" 算成 1、2、3 三次入栈,结果全错。
- 用
std::isdigit()或c >= '0' && c 判断是否为数字字符 - 遇到数字字符,循环累加:
num = num * 10 + (c - '0'),直到下一个字符不是数字 - 若前一位是
'-'且当前是数字开头(比如"-123"),则最终给num加负号;注意区分减法操作符和负号——后者只出现在表达式开头或紧邻操作符之后
std::stack<int> 处理除法和减法顺序反了
后缀表达式中 "a b -" 表示 a - b,但如果你写成 stk.top(); stk.pop(); int b = ...; int a = ...; result = a - b;,实际顺序就对了;反过来先取 a 再取 b 就变成 b - a,除法同理。这是最常被抄错的点。
- 务必先弹出第二个操作数:
int b = stk.top(); stk.pop(); - 再弹出第一个操作数:
int a = stk.top(); stk.pop(); - 然后计算:
stk.push(a - b)或stk.push(a / b) - 特别注意除零:在
push前加if (b == 0) throw std::runtime_error("division by zero");
字符串分割用 std::istringstream 还是手写空格跳过
输入可能是空格分隔的单个字符串(如 "3 4 + 2 *"),也可能是带多个空格甚至制表符的(如 "3\t\t4 +\n2 *")。用 std::string::find_first_of(" \t\n") 手动切容易漏边界;而 std::istringstream 自动跳过所有空白符,更稳。
立即学习“C++免费学习笔记(深入)”;
- 推荐做法:构造
std::istringstream iss(expr);,然后while (iss >> token) { /* 处理 token */ } -
token是std::string,再判断它是数字(std::all_of(token.begin(), token.end(), ::isdigit)或支持负号的自定义判断)还是操作符 - 不用
getline()或substr()手动切——除非你明确需要保留原始分隔符位置
实际跑通的关键不在“用没用栈”,而在于数字解析是否完整、操作数弹出顺序是否颠倒、空栈访问是否防御。这些地方一错,整个结果就偏了,而且很难通过简单测试发现。











