Unload()递归C Segfault(类似TRIE的数据库)CS50 pset5

时间:2017-03-13 21:14:06

标签: c dictionary recursion trie cs50

编辑1
根据{{​​3}}的建议,我现在不使用以下划线开头的名称,也删除了->周围的空格。
------------------------------------------------------------------------

在尝试使用递归函数释放struct时,我遇到了段错误。

这是我的结构:

//creating new trie data ctructure
typedef struct dict
{
    bool is_word;
    struct dict *children[ALPHABET+1];
}
node;

它用于存储在拼写检查器中使用的字典。在程序结束时,我需要释放所有已分配的内存。

这是我写的功能。它应该自称并且一块一块地自由发送。然而,在多次调用自己之后,它给了我段错误。

 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。

1 个答案:

答案 0 :(得分:0)

您的代码正在证明为什么全局变量是一个坏主意,并且适得其反。您应该将要释放的节点传递给该函数;初始调用通过根节点。该函数不需要访问任何全局变量。

另请注意,点.和箭头->运算符绑定非常紧密,不应使用它们周围的任何空格。此外,以下划线开头的名称基本上保留供实现使用。 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。因此,循环中的条件并不是绝对必要的,但如果在分配任何节点之前调用它,则整体函数会更具弹性。

如图所示,它使用这些相当严格的警告选项(运行macOS Sierra 10.12.3的Mac上的GCC 6.3.0)完全编译:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
>     -Wstrict-prototypes -Wold-style-definition -c tr47.c
$

此代码尚未运行。我已就这个CS50问题为其他人的变种编写了类似的功能。它不需要比那更复杂。