如何释放递归结构(trie)

最终编辑

我释放内存的功能正常工作,正如Milevyo所说,问题在于我修复的节点创建问题。 我现在有一个单独的问题,程序在正常运行时发生段错误,但不能在gdbvalgrind重现。 但是,这完全是一个单独的问题。

后来我发现这段错误发生了,因为我没有正确检查EOF字符。 根据Cliff B在这个问题中的回答,EOF的检查只发生在文件中的最后一个字符之后。 因此,在加载字典文件的函数中,我已经将文件的最后一个字符赋给了某个i (在本例中,根据printf调用,它是-1),并尝试创建并访问子节点if索引-1。 这导致了一个分段错误,并且还导致了我的卸载函数的问题,它不会卸载我创建的最后一个节点。

至于为什么我在gdbvalgrind运行程序时没有出现分段错误,我不知道。

编辑3

在节点创建发生的地方逐步完成加载功能时,我注意到一个意外的行为。 我相信问题出现在这些嵌入在for循环中的代码行中。 铸造(node*)只是为了安全,尽管它不会影响我所知道的代码的运行。

// if node doesnt exist, calloc one, go to node
if (current_node->children[i] == NULL)
{
    current_node->children[i] = (node*) calloc(1, sizeof(node));
    nodes++;
}
current_node = current_node->children[i];

在加载函数的过程中,我看到我的current_node->children[i]似乎正确地被calloc (所有的孩子都设置为NULL ),但是当我进入current_node->children[i]并检查它的孩子(见下图),我发现地址被搞砸了。 特别是,由于某种原因,子节点中的第i个孩子被设置为0x0 。 虽然0x0应该等于NULL (纠正我,如果我错了),我的free_all函数似乎要进入0x0指针,这当然会导致段错误。 任何人都可以阐明如何发生这种情况?

儿童的价值[i]

编辑2 :我使用calloc来创建我的节点

root = calloc(1, sizeof(node));

对于我的子节点,它们是在for循环中创建的,我循环访问正在读取的字典文件的字符。

if (current_node->children[i] == NULL)
{
    current_node->children[i] = calloc(1, sizeof(node));
    nodes++;
}

c在这种情况下表示正在读入的单词的字符。我得到i使用以下内容:

if (c == ''')
    i = 26;
else if (isalpha(c))
    i = c - 97;

编辑 :我想我的节点创建中的东西是错误的,正如milevyo建议的。 这是因为如果我打印出地址,它会从0x6032500x6033400x6034300x603520 ,然后在段错误之前最终到达(nil) 。 我已经通过在gdb中打印出它的值来验证根节点是否正确传入。 我会试着弄明白。

原始问题

当我尝试释放递归结构时遇到了段错误,但找不到原因,并希望得到一些帮助。

我的结构定义如下:

typedef struct node
{
    bool is_word;
    struct node* children[27];
}
node;

这意味着实现一个为了拼写检查而将字典加载到字典中的trie结构。 拼写检查完成后,我需要释放我分配给trie的内存。

这是我当前的函数,它应该在传递根节点时释放trie,但是在这种情况下会发生段错误,尽管不是立即:

void free_all(node* curs)
{
    int i;

    // recursive case (go to end of trie)
    for (i = 0; i < 27; i++)
    {
        if (curs->children[i] != NULL)
        {
            free_all(curs->children[i]);
        }
    }

    // base case
    free(curs);
}

我可以在哪里出错? 如果需要更多信息,请告诉我。


我认为,根节点有问题(也许它是空的)。 如果没有,请看别处。 例如在节点创建中。

void free_all(node* curs)
{
    int i;
    if(!curs) return;   // safe guard including root node. 

    // recursive case (go to end of trie)
    for (i = 0; i < 27; i++)
       free_all(curs->children[i]);


    // base case
    free(curs);
}

free_all函数可以。 你必须检查你是否设置为NULL所有未分配的孩子。 这包括不是叶子的节点,但没有全部27个子节点。

如果没问题,或修复它并不能修复段错误,则必须进行调试。

链接地址: http://www.djcxy.com/p/89709.html

上一篇: How to free recursive struct (trie)

下一篇: Why Doesn't Visual Studio's Designer Match What I See At Runtime?