Valgrind:条件跳转或移动取决于使用哈希函数时的未初始化值
Valgrind: Conditional jump or move depends on uninitialised value(s) when using hash function
我这样实现了 djb2 hash function:
unsigned int hash(const char *word)
{
unsigned int hash = 5381;
int c;
while ((c = *word++))
{
hash = ((hash << 5) + hash) + c;
}
return hash % N;
}
在其他地方,我通过这个函数使用散列函数:
bool check_word(const char *word)
{
const char *word_lower = strlwr(word); // need word_lower because hash function is case sensitive
node *iterator = table[hash(word_lower)];
free((void*) word_lower);
while (iterator != NULL) // traverse linked list, looking for the given word via strcasecmp
{
if (strcasecmp(iterator->word, word) == 0)
{
return true;
}
iterator = iterator->next;
}
return false;
}
还有这个函数:
void fill_hash_table(const char *dictionary)
{
FILE *dict_ptr = fopen(dictionary, "r");
if (dict_ptr == NULL)
{
return;
}
// prepare char array for every word with size LENGTH + 1 because LENGTH is the guaranteed max length
char curr_word[LENGTH + 1];
while (fscanf(dict_ptr, "%s", curr_word) != EOF)
{
[...]
unsigned int table_pos = hash(curr_word);
[...]
}
[...]
}
其中 dictionary
表示包含以行分隔的字符串的文本文件,如下所示:
a
ab
abc
运行 Valgrind 产生 Conditional jump or move depends on uninitialized value(s)
,更具体地说,指的是 while ((c = *word++))
或 word
。
有没有办法避免这种情况?
strlwr()
函数是这样实现的:
// returns same string but lower-cased
const char *strlwr(const char *string)
{
char *string_to_lower = malloc(LENGTH + 1);
for (int i = 0; string[i]; i++)
{
string_to_lower[i] = tolower(string[i]);
}
return string_to_lower;
}
这个:
while ((c = *word++))
仅当您传递的 word
未正确初始化且以 NUL 结尾的字符串时才会导致此类警告。
您的代码中的问题很可能是由您的 strlwr()
函数引起的,该函数未正确以 NUL 终止字符串。您在终止符处退出 for
循环,但未能将其添加到结果字符串中。
正确的代码是:
const char *strlwr(const char *string)
{
char *string_to_lower = malloc(LENGTH + 1);
unsigned i;
for (i = 0; string[i]; i++)
{
string_to_lower[i] = tolower(string[i]);
}
string_to_lower[i] = '[=11=]'; // Ensure NUL terminator!
return string_to_lower;
}
其次,我建议你修改这个:
while (fscanf(dict_ptr, "%s", curr_word) != EOF)
您正在使用 %s
作为格式说明符,这是自找麻烦。您不能保证正在读取的数据不会溢出缓冲区。
使用包含缓冲区长度的正确格式说明符,如下所示:
fscanf(dict_ptr, "%45s", curr_word);
或者,更好的是,使用 fgets()
,它专为以安全方式读取字符串而设计:
fgets(cur_word, LENGTH, dict_ptr);
最后:
- 您应该检查
malloc()
的 return 值。
- 您应该避免像这样转换传递给
free
的指针:free((void*) word_lower)
。任何指针自动转换from/tovoid*
。强制转换仅在变量不是指针的情况下隐藏潜在错误。
- 如果值变为负数没有意义,您应该使用
unsigned
(甚至 size_t
)而不是 int
。
我这样实现了 djb2 hash function:
unsigned int hash(const char *word)
{
unsigned int hash = 5381;
int c;
while ((c = *word++))
{
hash = ((hash << 5) + hash) + c;
}
return hash % N;
}
在其他地方,我通过这个函数使用散列函数:
bool check_word(const char *word)
{
const char *word_lower = strlwr(word); // need word_lower because hash function is case sensitive
node *iterator = table[hash(word_lower)];
free((void*) word_lower);
while (iterator != NULL) // traverse linked list, looking for the given word via strcasecmp
{
if (strcasecmp(iterator->word, word) == 0)
{
return true;
}
iterator = iterator->next;
}
return false;
}
还有这个函数:
void fill_hash_table(const char *dictionary)
{
FILE *dict_ptr = fopen(dictionary, "r");
if (dict_ptr == NULL)
{
return;
}
// prepare char array for every word with size LENGTH + 1 because LENGTH is the guaranteed max length
char curr_word[LENGTH + 1];
while (fscanf(dict_ptr, "%s", curr_word) != EOF)
{
[...]
unsigned int table_pos = hash(curr_word);
[...]
}
[...]
}
其中 dictionary
表示包含以行分隔的字符串的文本文件,如下所示:
a
ab
abc
运行 Valgrind 产生 Conditional jump or move depends on uninitialized value(s)
,更具体地说,指的是 while ((c = *word++))
或 word
。
有没有办法避免这种情况?
strlwr()
函数是这样实现的:
// returns same string but lower-cased
const char *strlwr(const char *string)
{
char *string_to_lower = malloc(LENGTH + 1);
for (int i = 0; string[i]; i++)
{
string_to_lower[i] = tolower(string[i]);
}
return string_to_lower;
}
这个:
while ((c = *word++))
仅当您传递的 word
未正确初始化且以 NUL 结尾的字符串时才会导致此类警告。
您的代码中的问题很可能是由您的 strlwr()
函数引起的,该函数未正确以 NUL 终止字符串。您在终止符处退出 for
循环,但未能将其添加到结果字符串中。
正确的代码是:
const char *strlwr(const char *string)
{
char *string_to_lower = malloc(LENGTH + 1);
unsigned i;
for (i = 0; string[i]; i++)
{
string_to_lower[i] = tolower(string[i]);
}
string_to_lower[i] = '[=11=]'; // Ensure NUL terminator!
return string_to_lower;
}
其次,我建议你修改这个:
while (fscanf(dict_ptr, "%s", curr_word) != EOF)
您正在使用 %s
作为格式说明符,这是自找麻烦。您不能保证正在读取的数据不会溢出缓冲区。
使用包含缓冲区长度的正确格式说明符,如下所示:
fscanf(dict_ptr, "%45s", curr_word);
或者,更好的是,使用 fgets()
,它专为以安全方式读取字符串而设计:
fgets(cur_word, LENGTH, dict_ptr);
最后:
- 您应该检查
malloc()
的 return 值。 - 您应该避免像这样转换传递给
free
的指针:free((void*) word_lower)
。任何指针自动转换from/tovoid*
。强制转换仅在变量不是指针的情况下隐藏潜在错误。 - 如果值变为负数没有意义,您应该使用
unsigned
(甚至size_t
)而不是int
。