【问题标题】:Freeing TRIE structure in C recursively递归地释放 C 中的 TRIE 结构
【发布时间】:2018-01-17 15:38:54
【问题描述】:

我目前正在尝试使用 recursive function 成功释放 TRIE structure,但无济于事,但我发现内存丢失。

trie结构定义为:

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

并且我在全局范围内声明了以下 Node*:

node* trie = NULL;
node* root = NULL;

第二个仅用于跟踪根节点,第一个用于从文件中接收单词。到目前为止,在不释放堆内存的情况下编译程序时,除了内存丢失之外,我没有收到任何错误。

在实现了一个 unload( ) 函数后,我开始遇到Segmentation Fault 错误。

查看我的代码的 sn-p:

/*
Frees node by node recursively
*/

bool freeSpace(node* child)
{   
    for (int i = 0; i < 27; i++)
    {
        if(trie->children[i] != NULL)
        {
            freeSpace(trie->children[i]);
        }
    }
    free(trie);
    return true;
}

/**
 * Unloads dictionary from memory. Returns true if successful else false.
 */ 
bool unload()
{

    if(root != NULL)
    {
        trie = root;
        freeSpace(trie);

        if(freeSpace(trie))
            return true;
        else
            return false;
    }
    else
    {
        return false;
    }

}

也许我的代码在返回值和验证方面不是很聪明,但我现在的主要问题是保证递归按预期工作并且没有内存泄漏或发生分段错误。有什么建议吗?

提前致谢!

【问题讨论】:

  • 为什么要释放两次? freeSpace(trie); if(freeSpace(trie))...
  • 为什么在unload 函数中调用freeSpace 两次?第二次,您当然会收到段错误
  • 应该bool freeSpace(node* child)bool freeSpace(node* trie) 吗?否则,它似乎没有意义。
  • 为什么freeSpace 需要返回一个值?
  • @IanAbbott trie 是全局变量,所以child 是这里的冗余变量。

标签: c recursion trie


【解决方案1】:

这是你的代码 sn-p 的修改版本,它更有意义:

/*
Frees node by node recursively
*/

void freeSpace(node* t)
{   
    for (int i = 0; i < 27; i++)
    {
        if(t->children[i] != NULL)
        {
            freeSpace(t->children[i]);
        }
    }
    free(t);
}

/**
 * Unloads dictionary from memory. Returns true if successful else false.
 */ 
bool unload()
{

    if(root != NULL)
    {
        trie = root;
        freeSpace(trie);
        return true;
    }
    else
    {
        return false;
    }

}

freeSpace 函数已更改为使用参数作为要释放的 trie 的基础。您的原始版本有一个未使用的参数child,而是使用了全局变量trie,这没有意义。

freeSpace 不需要返回值,因为它所做的只是免费的东西,它只返回一个固定值true。我将其返回类型更改为void

您的 unload 函数在同一个对象上调用了两次 freeSpace,因此我删除了其中一个调用。

【讨论】:

  • 这看起来好多了!我会试一试,看看效果如何! Thx 我的主要问题是参数和变量名称超载并将它们混合在一起。现在我看到了我正在做的菜鸟错误。根据真/假问题,是的,这是一团糟。再次感谢!
【解决方案2】:

我认为你的 freeSpace() 函数应该使用 child 参数 而不是 trie。这就是它应该的样子。

bool freeSpace(node* child){   
    for (int i = 0; i < 27; i++)
    {
        if(child->children[i] != NULL)
        {
            freeSpace(child->children[i]);
        }
    }
    free(child);
    return true;
}

【讨论】:

  • 哦...我花了很长时间研究这个并实现我的整个程序,但我没有注意到我没有在函数内部调用我想要的结构,而是调用我的值路过。
  • 没问题。它发生了。只是一个快速的建议,如果您对特定的变量名称感到满意,请尝试将其用于参数,否则会发生这种情况。一切顺利。
【解决方案3】:

仔细查看您的代码。你真的在任何地方使用函数的参数吗?实际上,您总是在每次迭代时查看全局 trie 指针,这是您不想做的。

要解决此问题,请更改代码,以便查看作为参数传入的节点及其子节点,而不是全局 trie 指针。

还有一个问题需要注意,那就是处理空指针的方式。现在,您假设参数指针不为空,然后在重复之前检查每个子项以查看它是否为非空。但是如果 trie 本身一开始就为 null 怎么办?我会考虑创建一个基本案例来检查 trie 是否为空,如果是,则不执行任何操作。然后,您可以在进行递归调用之前消除检查,现在可以适当地防范另一种极端情况。

【讨论】:

    猜你喜欢
    • 2016-04-13
    • 1970-01-01
    • 1970-01-01
    • 2015-01-05
    • 2012-11-15
    • 1970-01-01
    • 2023-02-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多