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 问题的其他人的变体编写了类似的函数。它不需要比这更复杂。