【问题标题】:How to free allocated memory in a binary tree in C如何在C中释放二叉树中分配的内存
【发布时间】:2015-02-24 19:59:14
【问题描述】:

我的 C 程序中的某个函数出现问题。该计划的目的是:

  • 将二进制文件中的整数读取到数组中
  • 使用二叉树对这些数字进行排序
  • 做一些其他的事情
  • 释放您使用 malloc() 分配的所有内存;

除了能够释放我的二叉树之外,我一切正常。这是我的树和节点(又名叶子)的结构。

typedef struct Node *NodeP;
typedef struct Tree *TreeP;

// Definition of a tree
    struct Tree
    {
        NodeP root;
    }Tree;

    // Definition of a node
    struct Node
    {
        int data;
        NodeP L, R;
    }Node;

在我的程序中,我使用 malloc 为我的树和每个单独的节点分配内存。所以我调用了一个函数来释放树及其所有节点。

/*
 * Frees the memory allocated for
 * each node
 */
void freeNode(NodeP p)
{
    if(p == NULL) return;
    freeNode(p->L);
    freeNode(p->R);
    free(p);
}

/*
 * Frees the memory allocated
 * for the tree
 */
TreeP freeTree(TreeP tree)
{
    if(tree->root == NULL)
        free(tree);
    else
    {
        freeNode(tree->root);
        free(tree);
    }

    return NULL;
}

当我运行这个程序时,我的调试器给了我这个错误。

EXC_BAD_ACCESS (code=EXC_I386_GPFLT)

我已经尝试过每次递归迭代,但我找不到它为什么给我一个错误。我在想它是在边缘情况下从树的边缘掉下来的?我不知道。非常感谢任何帮助!

编辑:

这里是下载完整程序的链接。我包含了一个自述文件和我正在使用的二进制文件。一个只有 10 个整数长度,另一个是 20000 长度。感谢您迄今为止的帮助!

https://copy.com/902v0bMv8DtIMUrc

【问题讨论】:

  • 为什么不看一下调用栈来实现,问题出在哪里? (至少,在什么级别)
  • 我可以看到两个不寻常的构造(freeNode 中的p = NULL 和从freeTree 返回的NULL),但这些都不应该是你问题的根源(但我会无论如何都要摆脱它们)。我怀疑您已经在其他地方浪费了您的堆,并且问题仅在您遍历树以释放节点时才显现出来。看看别处。
  • 我认为实现没有明显错误,因此您必须使用带有小树的调试器来查找问题。树可能格式不正确,例如多个父母指向同一个孩子,或者某些指针未正确初始化,但这些类型的问题不在您共享的代码中。旁注:freeNode 末尾的行 p = NULL; 什么都不做,应该删除。
  • 您是否真的为包含单个指针的根结构分配了内存,您free()?这是一种奇怪的做法:树根通常是指向第一个节点的指针。
  • $64:当您构建该树时,您是否确保所有叶节点的左右子树指针都为 NULL? freeTree 函数应该只需要 if (tree) { freeNode(tree->root); free(tree); } 顺便说一句。在您的链接代码中,malloc(sizeof(TreeP)); 不是您想要的。这正好为指针的大小分配内存,而不是Tree 节点的大小,如果您没有不明智地将指针类型隐藏在 typedef 中,您可能不会犯这个错误。

标签: c tree malloc binary-tree free


【解决方案1】:

这里有点混乱:

// Definition of a tree
struct Tree
{
    NodeP root;
}Tree;

// Definition of a node
struct Node
{
    int data;
    NodeP L, R;
}Node;

上面的定义定义了变量,而不是类型!

这里有个bug:

TreeP newTree()
{
    TreeP tree = (TreeP) malloc(sizeof(TreeP));
    tree->root = NULL;
    return tree;
}

它应该是TreeP tree = malloc(sizeof(struct Tree));。一个很好的例子说明为什么 typedef 结构指针是一个坏主意。由于 Tree 只保存一个指针,这不会造成任何问题,但应该修复它。

这里是 THE 错误:

/*
 * Creates a new node in the tree
 */
void insertTreeNode(TreeP tree, int data)
{
    NodeP p = tree->root;
    Boolean b = FALSE;

    /*  Creates a node and tests for errors  */
    NodeP node = (NodeP) malloc(sizeof(Node));
    if(node == NULL)
        fprintf(stderr, "Memory allocation failed! \n");
    else
    {
        node->data = data;
        node->L = NULL;
        node->R = NULL;

        /*  Inserts in empty tree case  */
        if(tree->root == NULL)
            tree->root = node;
        else
        {
            /*  Inserts in any other case  */
            while(p != NULL && b != TRUE)
            {
                if(node->data >= p->data)
                {
                    if(p->R == NULL)
                    {
                        p->R = node;
                        b = TRUE;
                    }
                    else p = p->R;
                }
                if(node->data <= p->data) // replace this line with else
                {
                    if(p->L == NULL)
                    {
                        p->L = node;
                        b = TRUE;
                    }
                    else p = p->L;
                }
            }
        }
    }
}

如果p-&gt;data == data,则必须将新节点链接到节点 p 的左侧或右侧,但不能在两个子树中。

可能还有其他错误,但这个会咬人!

【讨论】:

  • 非常感谢!这就是我做错了。我也修复了你提到的其他事情。 :)
  • @Hotsaucejalapeno struct Tree* tree = malloc(sizeof(*tree)); 将是一个合理的选择。或者只是Tree* tree = malloc(sizeof(*tree));,如果你修复你的结构decls 来实际声明类型TreeNode。祝你好运。
  • @WhozCraig:我更喜欢Tree *tree = malloc(sizeof(*tree)); 风格。将* 附加到该类型很容易出错,就像在经典的Tree* L,R; 中一样,TreeP L,R; 由于其他原因是一个不好的解决方案。
猜你喜欢
  • 2012-02-29
  • 2021-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-20
  • 2011-03-29
  • 2017-05-11
  • 1970-01-01
相关资源
最近更新 更多