Unload() 递归 C 段错误(TRIE 类数据库)CS50 pset5
Unload() recursion C Segfault (TRIE like data base) CS50 pset5
编辑 1
正如 Jonathan Leffler 所建议的,我现在不使用以下划线开头的名称,并且还删除了 ->
.
周围的空格
________________________________________________________________________________
尝试使用递归函数释放结构时出现段错误。
这是我的结构:
//creating new trie data ctructure
typedef struct dict
{
bool is_word;
struct dict *children[ALPHABET+1];
}
node;
用于存放词典,用于拼写检查。在程序结束时,我需要释放所有分配的内存。
这是我编写的函数。它应该一个接一个地调用自己和 free trie。然而,它在多次调用自身后给了我段错误。
bool unload(void)
{
// Check if root
if (temp == root)
{
for (int i = 0; i < ALPHABET+1; i++)
{
if (!temp->children[i] && i != ALPHABET)
{
}
else if (!temp->children[i] && i == ALPHABET)
{
free(temp);
return true;
}
else if(temp->children[i])
{
temp = temp->children[i];
unload();
}
}
}
else
{
for (int i = 0; i < ALPHABET+1; i++)
{
if (!temp->children[i] && i != ALPHABET)
{
}
else if (!temp->children[i] && i == ALPHABET)
{
temp1 = temp;
temp->children[i] = temp;
free(temp1);
return true;
}
else if (temp->children[i])
{
temp = temp->children[i];
unload();
}
}
}
return false;
}
假设 root 、 temp 、 temp1 是全局的。它们都是struct _dict。并且当函数第一次被调用时 temp == root.
您的代码证明了为什么全局变量不是一个好主意,而且会适得其反。您应该将要释放的节点传递给函数;初始调用传递根节点。该函数不需要访问任何全局变量。
另请注意,点 .
和箭头 ->
运算符绑定非常紧密,不应在其周围书写任何空格。此外,以下划线开头的名称基本上保留供实现使用。 The full details are more nuanced 比那个,但不多。最简单的方法是避免在您发明的名称中使用前导下划线。仅将它们用于访问系统提供的设施。
此代码执行必要的操作,假设分配 node
的代码确保所有指针都为空。
#include <stdlib.h>
#include <stdbool.h>
enum { ALPHABET = 26 };
typedef struct dict
{
bool is_word;
struct dict *children[ALPHABET+1];
} node;
void unload(node *item);
void unload(node *item)
{
for (int i = 0; i < ALPHABET+1; i++)
{
if (item->children[i] != 0)
unload(item->children[i]);
}
free(item);
}
可以修改代码以在使用之前测试 item
是否为 NULL。循环中的条件并不是绝对必要的,但如果在分配任何节点之前调用它,则整个函数更具弹性。
如图所示,它使用这些相当严格的警告选项(GCC 6.3.0 on a Mac 运行ning macOS Sierra 10.12.3)编译干净:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
> -Wstrict-prototypes -Wold-style-definition -c tr47.c
$
此代码尚未 运行。我已经为这个 CS50 问题的其他人的变体编写了类似的函数。它不需要比这更复杂。
编辑 1
正如 Jonathan Leffler 所建议的,我现在不使用以下划线开头的名称,并且还删除了 ->
.
周围的空格
________________________________________________________________________________
尝试使用递归函数释放结构时出现段错误。
这是我的结构:
//creating new trie data ctructure
typedef struct dict
{
bool is_word;
struct dict *children[ALPHABET+1];
}
node;
用于存放词典,用于拼写检查。在程序结束时,我需要释放所有分配的内存。
这是我编写的函数。它应该一个接一个地调用自己和 free trie。然而,它在多次调用自身后给了我段错误。
bool unload(void)
{
// Check if root
if (temp == root)
{
for (int i = 0; i < ALPHABET+1; i++)
{
if (!temp->children[i] && i != ALPHABET)
{
}
else if (!temp->children[i] && i == ALPHABET)
{
free(temp);
return true;
}
else if(temp->children[i])
{
temp = temp->children[i];
unload();
}
}
}
else
{
for (int i = 0; i < ALPHABET+1; i++)
{
if (!temp->children[i] && i != ALPHABET)
{
}
else if (!temp->children[i] && i == ALPHABET)
{
temp1 = temp;
temp->children[i] = temp;
free(temp1);
return true;
}
else if (temp->children[i])
{
temp = temp->children[i];
unload();
}
}
}
return false;
}
假设 root 、 temp 、 temp1 是全局的。它们都是struct _dict。并且当函数第一次被调用时 temp == root.
您的代码证明了为什么全局变量不是一个好主意,而且会适得其反。您应该将要释放的节点传递给函数;初始调用传递根节点。该函数不需要访问任何全局变量。
另请注意,点 .
和箭头 ->
运算符绑定非常紧密,不应在其周围书写任何空格。此外,以下划线开头的名称基本上保留供实现使用。 The full details are more nuanced 比那个,但不多。最简单的方法是避免在您发明的名称中使用前导下划线。仅将它们用于访问系统提供的设施。
此代码执行必要的操作,假设分配 node
的代码确保所有指针都为空。
#include <stdlib.h>
#include <stdbool.h>
enum { ALPHABET = 26 };
typedef struct dict
{
bool is_word;
struct dict *children[ALPHABET+1];
} node;
void unload(node *item);
void unload(node *item)
{
for (int i = 0; i < ALPHABET+1; i++)
{
if (item->children[i] != 0)
unload(item->children[i]);
}
free(item);
}
可以修改代码以在使用之前测试 item
是否为 NULL。循环中的条件并不是绝对必要的,但如果在分配任何节点之前调用它,则整个函数更具弹性。
如图所示,它使用这些相当严格的警告选项(GCC 6.3.0 on a Mac 运行ning macOS Sierra 10.12.3)编译干净:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
> -Wstrict-prototypes -Wold-style-definition -c tr47.c
$
此代码尚未 运行。我已经为这个 CS50 问题的其他人的变体编写了类似的函数。它不需要比这更复杂。