You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

递归读取二叉树时delete触发SIGTRAP错误,如何避免内存泄漏?

二叉树文件读取时delete触发SIGTRAP异常的解决

问题背景

我编写了从文件读取二叉树的方法,代码如下:

BinaryTree * FileService::read(BinaryTree * node) {
    basic_string<char> np = "nullptr";
    char * val = new char ();

    if (!fscanf(this->filePtr, "%s ", val)) {
        delete val;
        return node;
    }
    string str(val);
    if (str == np) {
        delete val;
        return node;
    }

    node = new BinaryTree();
    if (Helper::isFloatNumber(val)) {
        node->setNumericValue(stof(val));
    } else {
        node->setStrValue(val);
    }
    delete val; <----HERE SIGTRAP (Trace/breakpoint trap)
    node->setLeft(this->read(&node->getLeftReference()));
    node->setRight(this->read(&node->getRightReference()));

    return node;
}

执行时出现错误:Process finished with exit code -1073740940 (0xC0000374),调试时在标注的delete val;处触发SIGTRAP (Trace/breakpoint trap)陷阱。注释该行后代码可正常运行,但担心内存泄漏。我尝试过将delete val;移至return之前,也尝试用非空判断包裹delete操作:

if (val != nullptr) {
    delete val;
    val = nullptr;
}

但问题均未解决。请问哪里出错了?如何修改才能同时避免内存泄漏和异常?

问题根源

核心问题出在char * val = new char ();这一行:你只分配了1个字节的内存,但fscanf("%s ", val)会读取整个空白分隔的字符串,当输入的字符串长度大于0时,必然会越界写入,破坏堆内存结构。后续的delete val操作访问了被破坏的堆空间,就会触发SIGTRAP或堆损坏异常。

解决方法

方案1:使用固定大小的字符数组(简单直接)

把动态分配的单个char换成足够大的字符数组,避免越界:

BinaryTree * FileService::read(BinaryTree * node) {
    const basic_string<char> np = "nullptr";
    char val[256]; // 假设输入的单个节点值不超过255字节

    if (!fscanf(this->filePtr, "%255s ", val)) { // 限制读取长度,防止越界
        return node;
    }
    const string str(val);
    if (str == np) {
        return node;
    }

    node = new BinaryTree();
    if (Helper::isFloatNumber(val)) {
        node->setNumericValue(stof(val));
    } else {
        node->setStrValue(val);
    }
    // 数组在栈上,无需手动释放,不存在内存泄漏
    node->setLeft(this->read(&node->getLeftReference()));
    node->setRight(this->read(&node->getRightReference()));

    return node;
}

方案2:使用C++风格的字符串读取(更安全)

完全抛弃C风格的字符数组和fscanf,用C++的std::string和流操作来读取,从根源避免内存管理问题:

#include <string>
#include <fstream>

BinaryTree * FileService::read(BinaryTree * node) {
    const std::string np = "nullptr";
    std::string val;

    // 假设fileStream是std::ifstream类型,若原filePtr是FILE*可转为ifstream使用
    if (!(this->fileStream >> val)) { // >>自动按空白分隔读取字符串
        return node;
    }
    if (val == np) {
        return node;
    }

    node = new BinaryTree();
    if (Helper::isFloatNumber(val)) {
        node->setNumericValue(std::stof(val));
    } else {
        node->setStrValue(val);
    }
    // std::string自动管理内存,无需手动释放
    node->setLeft(this->read(&node->getLeftReference()));
    node->setRight(this->read(&node->getRightReference()));

    return node;
}

关键注意点

  • 绝对不要用new char()分配单个字符来存储字符串,%s需要足够空间容纳整个字符串(包括末尾的'\0')。
  • 用C风格函数读取字符串时,必须限制读取长度(比如%255s),防止缓冲区溢出。
  • 优先使用C++标准库的字符串和流操作,它们自带内存管理,能大幅减少内存泄漏和越界问题。

内容的提问来源于stack exchange,提问作者Deadpool

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 03:41:29