Valgrind + C:条件跳转或移动取决于未初始化的值

Valgrind + C: conditional jump or move depends on uninitialised value(s)

我收到这个错误:

Conditional jump or move depends on uninitialised value(s)

我的意思是,我用于条件语句的值未初始化。但是,我相信要初始化的值。我不确定到底是什么问题。帮助将不胜感激。

该代码用于 CS50 的第 5 周作业,用于存储可以添加值的字典,以及用于检查文本是否存在拼写错误的字典。我正在尝试存储字典条目。

编辑

多亏了我在这里收到的帮助,我才能够解决之前出现的错误。我现在已经将最小示例更改为更接近真实情况(现在它从名为 'dictionary/small' 的文件而不是硬编码数组中获取单词值),我现在遇到了另一个问题。 Valgrind指向行

if (word == NULL || strcmp(word, "") == 0)

bool add_word(char *word) 中。它给出了这个错误:

==5452== Use of uninitialised value of size 8
==5452==    at 0x4C2F1B1: strcmp (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5452==    by 0x400B4C: add_word (test.c:81)
==5452==    by 0x400AA3: load (test.c:64)
==5452==    by 0x4008C6: main (test.c:26)
==5452==  Uninitialised value was created by a stack allocation
==5452==    at 0x4008E4: load (test.c:30)

代码如下:

#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>

#define LINES 45
#define LENGTH 143092

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

bool load(const char *dictionary);
bool unload(void);
bool add_word(char *word);
int char_to_child(char c);
char *strdup(const char *s);

node *root;

int main(void)
{
    load("dictionaries/small");
}

bool load(const char *dictionary)
{
    char *words[LINES];

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

    char buffer[LENGTH + 1];
    for (int i = 0; i < LINES && fgets(buffer, LENGTH * sizeof(char), fp); i++)
    {
        words[i] = NULL;
        if (strlen(buffer) <= LENGTH)
        {
            words[i] = strdup(buffer);
        }
    }  
    fclose(fp);     

    // create a try and add the words
    root = malloc(sizeof(node));
    if (!root)
    {
        return false;
    }
    root->is_word = NULL;
    for (int i = 0; i < 27; i++)
    {
        root->children[i] = NULL; 
    }

    for (int i = 0; i < LINES; i++)
    {
        if (add_word(words[i]) == false)
        {
            return false;
        }
        free(words[i]);
    }

    return true;
}

bool add_word(char *word) {
    node *ptr = root;

    if (ptr == NULL)
    {
        return false;
    }
    if (word == NULL || strcmp(word, "") == 0)
    {
        return false;
    }

    for (size_t i = 0; i < strlen(word); i++)
    {
        int letter = char_to_child(word[i]);

        if (letter < 27)
        {
            if (ptr->children[letter] == NULL)
            {
                node *new_node;
                new_node = malloc(sizeof(node));
                if (!new_node)
                {
                    return false;
                }
                new_node->is_word = false;
                for (int j = 0; j < 27; j++)
                {
                    new_node->children[j] = NULL;
                }

                ptr->children[letter] = new_node;
            }
            else
            {
                if (ptr->children[letter]->is_word != true)
                {
                    ptr->children[letter]->is_word = false;
                }
            }
            ptr = ptr->children[letter];
        }
    }
    ptr->is_word = true;


    return true;
}

int char_to_child(char c)
{
    if (c >= 'A' && c <= 'Z')
    {
        return c - 'A';
    }
    else if (c >= 'a' && c <= 'z')
    {
        return c - 'a';
    }
    else if (c == '\'')
    {
        return 26;
    }
    else 
    {
        return 27;
    }
}

问题是因为这段代码:

for (int i = 0; i < LINES; i++)
{
    if (add_word(words[i]) == false)

最终将阅读 words 中所有前 LINES 个条目。然而在这个早期的代码中:

for (int i = 0; i < LINES && fgets(buffer, LENGTH * sizeof(char), fp); i++)

你在fgets失败时停止,如果i < LINES-1在那一点,这意味着words中的一些指针保持未初始化。然后你的 valgrind 错误来自 add_word(words[i]) 和未初始化的指针。

要解决此问题,您可以先初始化所有指针,或者记住第一个循环结束时 i 的值,并使用相同的值结束第二个循环。

顺便说一句 if (strlen(buffer) <= LENGTH) 是多余的。 fgets 调用已经保证了这一点,因为您指定了 LENGTH.

的缓冲区大小