递归函数调用子函数时出现'double free or corruption'内存错误求助
分析并解决
double free or corruption错误 你说得完全没错——栈上的std::vector确实会在离开作用域时自动调用析构函数释放内存,那为什么还会出现这个内存错误呢?问题出在你的代码在处理逆波兰表达式时,对vector栈进行了非法操作,破坏了它的内部内存管理结构,导致析构时触发了double free。
核心问题:栈操作越界(未定义行为)
看一下你回溯里的输入"4 6 5 * + +",我们一步步走一遍执行流程:
- 依次入栈4、6、5,栈状态:
[4,6,5] - 遇到
*:弹出5和6,计算6*5=30入栈,栈状态:[4,30] - 遇到
+:弹出30和4,计算4+30=34入栈,栈状态:[34] - 遇到第二个
+:此时栈里只有1个元素,但你的代码直接执行两次pop_back()——第一次弹出34后栈已经空了,第二次调用stack.back()和stack.pop_back()都是未定义行为!
这种非法操作会篡改vector内部的元数据(比如容量、内存指针、元素计数),当函数结束vector析构时,它会尝试释放已经被破坏的内存结构,最终触发double free or corruption错误。
另外,你的代码还有两个潜在的漏洞会导致同类问题:
- 循环结束后没有处理剩余的
token:如果RPN字符串最后没有空格(比如"4 5+"),最后一个数字5会留在token里,不会被入栈,后续处理+时同样会出现栈元素不足的情况。 - 没有校验
stod的输入合法性:如果token不是合法数字,stod会抛出异常,可能中途终止函数,但此时vector的状态也可能异常。
修复方案
1. 添加栈操作的边界检查
在处理运算符之前,必须确保栈里至少有2个元素:
if (find(arithOperators.begin(), arithOperators.end(), rpnIn[i]) != arithOperators.end()) { // 先检查栈元素数量是否足够 if (stack.size() < 2) { cerr << "Error: Insufficient operands for operator " << rpnIn[i] << endl; return NAN; // 或者抛出异常终止程序 } // 后续的弹出和运算逻辑... }
2. 处理循环结束后的剩余token
在for循环结束后,检查token是否为空,确保最后一个数字被入栈:
// 循环结束后处理未被空格分隔的最后一个token if (!token.empty()) { try { stack.push_back(stod(token)); } catch (const std::exception& e) { cerr << "Error: Invalid number token: " << token << endl; return NAN; } token.clear(); }
3. 捕获stod的异常
避免非法数字导致的异常破坏程序状态:
// 替换原来的stack.push_back(stod(token)); try { stack.push_back(stod(token)); } catch (const std::invalid_argument& e) { cerr << "Error: Invalid number format: " << token << endl; return NAN; } catch (const std::out_of_range& e) { cerr << "Error: Number out of range: " << token << endl; return NAN; }
修复后的完整代码示例
#include <vector> #include <string> #include <algorithm> #include <stdexcept> #include <iostream> #include <cmath> using namespace std; // 假设arithOperators是全局或局部定义的运算符集合 vector<char> arithOperators = {'+', '-', '*', '/'}; double evaluateCountdown(string rpnIn) { vector<double> stack; double a = 0, b = 0; string token = ""; char arithToken; for (int i = 0; i < rpnIn.size(); ++i) { if (rpnIn[i] == ' ') { if (token != "") { try { stack.push_back(stod(token)); // Push number to stack } catch (const std::invalid_argument& e) { cerr << "Error: Invalid number format: " << token << endl; return NAN; } catch (const std::out_of_range& e) { cerr << "Error: Number out of range: " << token << endl; return NAN; } token = ""; } } else { if (find(arithOperators.begin(), arithOperators.end(), rpnIn[i]) != arithOperators.end()) { // 检查栈元素是否足够 if (stack.size() < 2) { cerr << "Error: Insufficient operands for operator " << rpnIn[i] << endl; return NAN; } // Pop two numbers of stack and perform operation arithToken = rpnIn[i]; a = stack.back(); stack.pop_back(); b = stack.back(); stack.pop_back(); if (arithToken == '+') { stack.push_back(b+a); } else if (arithToken == '-'){ stack.push_back(b-a); } else if (arithToken == '/') { // 额外添加除零检查 if (a == 0) { cerr << "Error: Division by zero" << endl; return NAN; } stack.push_back(b/a); } else if (arithToken == '*') { stack.push_back(b*a); } } else { token += rpnIn[i]; //add chars to string } } } // 处理最后一个token if (!token.empty()) { try { stack.push_back(stod(token)); } catch (const std::exception& e) { cerr << "Error: Invalid number token: " << token << endl; return NAN; } } // 最后检查栈里是否只剩一个结果 if (stack.size() != 1) { cerr << "Error: Invalid RPN expression, final stack size is " << stack.size() << endl; return NAN; } return stack.back(); }
总结
你的内存错误本质是未定义行为导致的vector内部结构破坏——当你对空栈执行back()或pop_back()时,vector的内存管理信息被篡改,析构时就会触发double free。通过添加边界检查、处理剩余token和异常捕获,可以彻底解决这个问题。
内容的提问来源于stack exchange,提问作者jonikvir
相关产品推荐
相关产品推荐

