如何释放递归struct(trie)

时间:2016-01-09 08:01:39

标签: c recursion struct free trie

最终编辑

我释放内存的功能正常工作,正如milevyo所说,问题在于节点创建,我已经修复了。我现在有一个单独的问题,程序在正常运行时会出现段错误,但无法在gdbvalgrind中复制。但是,这完全是一个单独的问题。

我发现这个段错误是因为我没有正确检查EOF字符。 As per Cliff B's answer in this question,EOF检查仅在文件中的最后一个字符之后发生。因此,在我加载字典文件的函数中,我已经将文件的最后一个字符分配给某个i(在这种情况下根据printf调用为-1),然后尝试了如果索引为-1,则创建和访问子节点。这导致了分段错误,并且还导致我的卸载功能出现问题,卸载功能不会卸载我创建的最后一个节点。

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

编辑3

在逐步执行创建节点的load函数时,我注意到了一个意外的行为。我相信这个问题存在于这些代码行中,它们嵌入在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),但是当我踏入{{ 1}}并检查它的孩子(见下图),我看到地址搞砸了。具体来说,子节点中的current_node->children[i]'子节点由于某种原因设置为i。虽然0x0应该等于0x0(如果我错了,请纠正我),我的NULL函数似乎想要进入free_all指针,当然会导致段错误。任何人都可以了解这可能发生的原因吗?

Values of children[i]

编辑2 :我正在使用0x0来创建节点

calloc

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

root = calloc(1, sizeof(node));
在这种情况下,

if (current_node->children[i] == NULL) { current_node->children[i] = calloc(1, sizeof(node)); nodes++; } 表示正在读入的单词的字符。我使用以下内容获取c

i

编辑:我认为我的节点创建中的某些内容有问题,正如milevyo建议的那样。这是因为如果我打印出地址,它会从if (c == '\'') i = 26; else if (isalpha(c)) i = c - 97; 0x6032500x603340再到0x603430,最后到0x603520,然后才会出现段错误。我已经验证通过在gdb中打印出它的值来正确传递根节点。我会试着弄明白。

原始问题

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

我的结构定义如下:

(nil)

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

这是我当前的函数,它应该在传递根节点时释放trie,但是在执行此操作时会出现段错误,但不是立即执行:

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

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

2 个答案:

答案 0 :(得分:3)

我认为,根节点有问题(可能是null)。如果没有,看看其他地方。例如,在节点创建中。

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);
}

答案 1 :(得分:1)

free_all功能正常。你必须检查你设置为NULL所有未分配的孩子。这包括不是叶子但没有所有27子节点的节点。

如果可以,或者修复它不能修复段错误,则必须进行调试。