未初始化的值由堆分配创建

时间:2014-12-21 23:47:07

标签: c malloc hashtable valgrind

我试图使用哈希表来实现单词词典,所以我需要将它全局化,并在我的一个头文件中声明它

extern node** dictionary;

节点在哪里

typedef struct node
{
    char* word;
    struct node* next;
} node;

然后在另一个定义了函数的文件中,我包含了包含字典声明的标题,并且我在顶部添加了

node** dictionary;

然后在实际加载字典的函数中,我首先为链接列表分配内存,这将创建哈希表

bool load(const char* dict_file)
{
    dictionary = malloc(sizeof(node*) * LISTS);

    FILE* dict = fopen(dict_file, "r");

    if(dict == NULL)
        return false;

    char buffer[MAX_LEN + 2];

    size_dict = 0;

    while(fgets(buffer, MAX_LEN + 2, dict) != NULL)
    {
        node* new_node = malloc(sizeof(node));

        int len = strlen(buffer);

        new_node->word = malloc(sizeof(char) * (len));

        //avoid \n
        for(int i = 0; i < len - 1; i++)
            new_node->word[i] = buffer[i];

        new_node->word[len - 1] = '\0';

        new_node->next = NULL;

        int index = hash(buffer);

        new_node->next = dictionary[index];

        dictionary[index] = new_node;

        size_dict++;
    }

    if (ferror(dict))
    {
        fclose(dict);
        return false;
    }

    fclose(dict);
    return true;
}

所以程序工作正常,然后释放所有分配的内存用于字符串和节点,当我运行valgrind(一个检测内存泄漏的调试器)时,它表示没有内存泄漏是可能的,但它表示存在错误< i>未分配的值是由堆分配创建的,并将我重定向到确切的行,我在那里为dictionary分配了我已编写的加载函数的确切第一行的内存上面。
我做错了什么?我想全局使用dictionary的方式是错误的,那么有人可以提出一些其他方法来保持全局并避免这种错误吗?

2 个答案:

答案 0 :(得分:7)

在更新的代码中,您使用未初始化的指针:

dictionary = malloc(sizeof(node*) * LISTS);

// .... code that does not change dictionary[i] for any i

new_node->next = dictionary[index];   // use uninitialized pointer

正如人们已经猜到的那样,只有在进入此循环之前预先设置了所有指针NULL之后,这才有效:

dictionary = malloc(sizeof(node*) * LISTS);
if ( !dictionary )
    return false;

for (size_t i = 0; i < LISTS; ++i)
    dictionary[i] = NULL;

答案 1 :(得分:4)

您分配给dictionary的堆分配使用malloc,它不会初始化返回的字节。因此,您发布的代码中的dictionary最终会成为一个未初始化的指针数组。大概你继续以某种方式使用那些指针,valgrind知道这是一个错误。

解决此问题的一种简单方法是使用calloc而不是malloc,因为它会为您返回返回的字节。或者,使用memset自己将字节归零。