Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 不可修复内存泄漏_C_Memory_Memory Management_Memory Leaks_Trie - Fatal编程技术网

C 不可修复内存泄漏

C 不可修复内存泄漏,c,memory,memory-management,memory-leaks,trie,C,Memory,Memory Management,Memory Leaks,Trie,很抱歉前面有这么长的代码片段,但是我花了很长时间在这里查看,我觉得到目前为止我所看到的任何东西都不能帮助我解决这个问题。我在课程论坛上提出了问题,得到了助教的帮助,也从朋友那里得到了建议,但没有任何东西能够锁定我问题的根源 在这个程序中,我使用一棵树来创建拼写检查器。我的代码中有很多东西需要修复,但内存泄漏是我唯一真正需要帮助解决的问题 问题是,我相当确定我为节点分配了正确的空间量,我认为Valgrind证实了这一点,因为我只有2个未释放的块(365371个alloc中) 无论如何,我将发布整个

很抱歉前面有这么长的代码片段,但是我花了很长时间在这里查看,我觉得到目前为止我所看到的任何东西都不能帮助我解决这个问题。我在课程论坛上提出了问题,得到了助教的帮助,也从朋友那里得到了建议,但没有任何东西能够锁定我问题的根源

在这个程序中,我使用一棵树来创建拼写检查器。我的代码中有很多东西需要修复,但内存泄漏是我唯一真正需要帮助解决的问题

问题是,我相当确定我为节点分配了正确的空间量,我认为Valgrind证实了这一点,因为我只有2个未释放的块(365371个alloc中)

无论如何,我将发布整个代码(以防任何人需要完整的上下文),但我认为相关的部分是load函数和clear函数,在这里我分别分配和释放内存

/**
c* Implements a dictionary's functionality.
*/
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "dictionary.h"

// number of characters we are using (a-z and ')
#define LETTERS 27

// max guaranteed number of nonnegative char values that exist
#define CHARVALUES 128

// create node structure for trie
typedef struct node
{
    struct node *children[LETTERS];
    bool is_word;
}
node;

// create root node for trie
node *root;

// stores the size of our dictionary
unsigned int dict_size = 0;

/**
 * Returns true if word is in dictionary else false.
 */
bool check(const char *word)
{
    // keeps track of where we are; starts with root for each new word
    node *current_node = root;

    while (*word != '\0')
    {

        // indices: 'a' -> 0, ..., 'z' -> 25, '\' -> 26
        int index = (tolower(*word) - 'a') % CHARVALUES;
        if (index >= LETTERS - 1)
        {
            // by assumption, the char must be '\'' if not '\n' or a letter
            index = LETTERS - 1;
        }

        // if the node we need to go to is NULL, the word is not here
        if (current_node->children[index] == NULL)
        {
            return false;
        }

        // go to the next logical node, and look at the next letter of the word
        current_node = current_node->children[index];
        word++;
    }
    return current_node->is_word;
}

/**
 * Loads dictionary into memory. Returns true if successful else false.
 */
bool load(const char *dictionary)
{

    FILE *inptr = fopen(dictionary, "r");
    if (inptr == NULL)
    {
        return false;
    }

    // allocate memory for the root node
    root = malloc(sizeof(node));

    // store first letter (by assumption, it must be a lowercase letter)
    char letter = fgetc(inptr);

    // stores indices corresponding to letters
    int index = 0;

    /**
     * we can assume that there is at least one word; we will execute the loop
     * and assign letter a new value at the end. at the end of each loop, due
     * to the inside loop, letter will be a newline; we know the EOF in the
     * dictionary follows a newline, so the loop will terminate appropriately
     */
    do
    {
        // keeps track of where we are; starts with root for each new word
        node *current_node = root; 

        // this loop will only execute if our character is a letter or '\''
        while (letter != '\n')
        {
            // indices: 'a' -> 0, ..., 'z' -> 25, '\' -> 26
            index = (letter - 'a') % CHARVALUES;
            if (index >= LETTERS - 1)
            {
                // by assumption, the char must be '\'' if not '\n' or a letter
                index = LETTERS - 1;
            }

            // allocate memory for a node if we have not done so already
            if (current_node->children[index] == NULL)
            {
                current_node->children[index] = malloc(sizeof(node));

                // if we cannot allocate the memory, unload and return false
                if (current_node->children[index] == NULL)
                {
                    unload();
                    return false;
                }

            }

            // go to the appropriate node for the next letter in our word
            current_node = current_node->children[index];

            // get the next letter
            letter = fgetc(inptr);
        }

        // after each linefeed, our current node represents a dictionary word
        current_node->is_word = true;
        dict_size++;

        // get the next letter
        letter = fgetc(inptr);
    }
    while (letter != EOF);

    fclose(inptr);

    // if we haven't returned false yet, then loading the trie must have worked
    return true;
}

/**
 * Returns number of words in dictionary if loaded else 0 if not yet loaded.
 */
unsigned int size(void)
{
    return dict_size;
}

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

    /**
     * Unloads dictionary from memory. Returns true if successful else false.
     */
    bool unload(void)
    {
        clear(root);
        return true;
    }
因此,我对这个输出的解释是,在下面的代码块中:

        if (current_node->children[index] == NULL)
        {
            current_node->children[index] = malloc(sizeof(node));

            // if we cannot allocate the memory, unload and return false
            if (current_node->children[index] == NULL)
            {
                unload();
                return false;
            }

        }
执行
malloc
语句(实际上是line dictionary.c:111)两次,这样分配的内存永远不会被释放。(这是正确的吗?)现在,这让我认为真正的问题在于我的clear函数,也就是说,它写得不好,不能清除trie的每个节点

然而,我已经盯着代码看了好几个小时,我真的看不出它有什么问题。(我相信很多人都是这样;我只是不太擅长这个。)

在此方面的任何帮助都将不胜感激

作为旁注:我有很多人(不是课程工作人员)告诉我应该将children数组中的所有指针初始化为NULL,但课程工作人员直接告诉我这是可选的,我已经用相同的结果对这两种方法进行了测试。我知道这可能是一个可移植性的东西,即使它在技术上“工作”像那样,但我只知道这不是我正在寻找的解决方案,因为我知道还有一些其他的根本原因(即,一个导致它在任何设备上都不工作的原因…)

同样,如果你能以任何方式帮助我解决我的逻辑问题,我将不胜感激。我花了几个小时试图弄明白这一点,但毫无结果

root = malloc(sizeof(node));
这会产生一块未初始化的内存

if (current_node->children[index] == NULL)
这里假设内存已经初始化,而实际上是垃圾

您需要在使用
root
之前初始化它们的内容,或者使用calloc将它们全部设置为零

这会产生一块未初始化的内存

if (current_node->children[index] == NULL)
这里假设内存已经初始化,而实际上是垃圾


在使用
root
之前,您需要初始化它们的内容,或者使用calloc将它们全部设置为零。

在使用calloc()切换malloc()语句后(如其他人所建议,这将删除大量valgrind错误),添加一个小样本字典和以下最小值main()

。。。您的代码运行更干净,没有任何内存泄漏:

==636== HEAP SUMMARY:
==636==     in use at exit: 0 bytes in 0 blocks
==636==   total heap usage: 15 allocs, 15 frees, 42,688 bytes allocated
==636==
==636== All heap blocks were freed -- no leaks are possible
==636==
==636== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 12 from 8)
不过,一个明显的漏洞是,如果从load()返回false,则无法释放文件指针


编辑:当你在字典中引入大写单词时,Valgrind开始(再次)抛出各种各样的错误。因此,请集中精力进行调试

在使用calloc()切换两个malloc()语句之后(正如其他人所建议的;这将删除大量valgrind错误),添加一个小样本字典,以及以下最小值main():

。。。您的代码运行更干净,没有任何内存泄漏:

==636== HEAP SUMMARY:
==636==     in use at exit: 0 bytes in 0 blocks
==636==   total heap usage: 15 allocs, 15 frees, 42,688 bytes allocated
==636==
==636== All heap blocks were freed -- no leaks are possible
==636==
==636== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 12 from 8)
不过,一个明显的漏洞是,如果从load()返回false,则无法释放文件指针


编辑:当你在字典中引入大写单词时,Valgrind开始(再次)抛出各种各样的错误。因此,请集中精力进行调试

故意的。正如我所提到的,我测试了这个程序,不管有没有指针初始化(对于根数组和所有子数组),结果都是一样的。实际上,我们是在运行时排名的,所以从技术上讲,只要它编译并“工作”而不泄漏内存,我们就被鼓励删减任何不必要的内容,所以我删减了它。我会承认,这是一种“错误”的发展方式,一般来说,是的,这正是这个问题,在我开始考虑它不固定之前,担心速度。记住优化的基本规则:(1)不要这样做!(2) (仅限专家)暂时不要这样做。代码中有明显的越界读取,而您的问题是关于泄漏的?故意的。正如我所提到的,我测试了这个程序,不管有没有指针初始化(对于根数组和所有子数组),结果都是一样的。实际上,我们是在运行时排名的,所以从技术上讲,只要它编译并“工作”而不泄漏内存,我们就被鼓励删减任何不必要的内容,所以我删减了它。我会承认,这是一种“错误”的发展方式,一般来说,是的,这正是这个问题,在我开始考虑它不固定之前,担心速度。记住优化的基本规则:(1)不要这样做!(2) (仅限专家使用)不要这样做。代码中存在明显的越界读取,而您的问题是关于泄漏的?正如我所说的,我已经测试了代码,包括是否将这些指针初始化为NULL。我还测试了使用和不使用calloc的情况。它除了可移植性之外什么都没有帮助,实际上这对于这个任务是不鼓励的,因为它不是必需的,并且会显著增加运行时间。这不是我的内存错误的根源(至少在代码编译的机器上,这是这里最重要的),考虑到我在采取这些预防措施时会遇到完全相同的错误。@mattstone
malloc
:ed内存的内容可以是任何垃圾。这不是一个po