如何释放递归结构(trie)
最终编辑
我释放内存的功能正常工作,正如Milevyo所说,问题在于我修复的节点创建问题。 我现在有一个单独的问题,程序在正常运行时发生段错误,但不能在gdb
或valgrind
重现。 但是,这完全是一个单独的问题。
后来我发现这段错误发生了,因为我没有正确检查EOF字符。 根据Cliff B在这个问题中的回答,EOF的检查只发生在文件中的最后一个字符之后。 因此,在加载字典文件的函数中,我已经将文件的最后一个字符赋给了某个i
(在本例中,根据printf
调用,它是-1),并尝试创建并访问子节点if索引-1。 这导致了一个分段错误,并且还导致了我的卸载函数的问题,它不会卸载我创建的最后一个节点。
至于为什么我在gdb
或valgrind
运行程序时没有出现分段错误,我不知道。
编辑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建议的。 这是因为如果我打印出地址,它会从0x603250
到0x603340
到0x603430
到0x603520
,然后在段错误之前最终到达(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?