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

问题描述 投票:5回答:2

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

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(检测内存泄漏的调试器)时,它说不可能发生内存泄漏,但是它说有错误未初始化的值是由堆分配创建的,并将我重定向到确切的行,在这里我为dictionary分配的内存是我上面编写的加载函数的确切第一行。我究竟做错了什么?我想我在全局上使用dictionary的方法是错误的,所以有人可以建议将其保持在全局状态并避免此错误的其他方法吗?

c malloc hashtable valgrind
2个回答
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;
}

4
投票

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

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

© www.soinside.com 2019 - 2024. All rights reserved.