Valgrind:有条件的跳跃或移动取决于未初始化的值。在较长的数组中用 '\0' 终止字符串不够吗?
Valgrind: Conditional jump or move depends on uninitialised value(s). Is not terminating a string inside a longer array with '\0' enough?
cs50的第5题,拼写,要求实现一些词典功能。
我用 valgrind 收到这个警告:
==393== Conditional jump or move depends on uninitialised value(s)
==393== at 0x49DB143: tolower (ctype.c:46)
==393== by 0x483F864: strcasecmp (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==393== by 0x4019CF: check (dictionary.c:42)
==393== by 0x401603: main (speller.c:114)
==393== Uninitialised value was created by a heap allocation
==393== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==393== by 0x401AF8: load (dictionary.c:82)
==393== by 0x40129E: main (speller.c:40).
这是我的 dictionary.c 文件,其中包含辅助函数。
// Implements a dictionary's functionality
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dictionary.h"
#include <strings.h>
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// Number of buckets in hash table
const unsigned int N = 1;
unsigned int siz = 0;
// Hash table
node *table[N];
/*
for (int i = 0; i < N; i++)
{
table[i]->next
}
*/
// Returns true if word is in dictionary, else false
bool check(const char *word)
{
// TODO
int h = hash(word);
node *ll = table[h];
while (ll != NULL)
{
if (strcasecmp(ll->word, word) == 0)
{
printf("len: %lu\n", strlen(ll->word));
return true;
}
ll = ll->next;
}
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
// TODO
return 0;
}
// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
printf("a\n");
// TODO
FILE *input = fopen(dictionary, "r");
if (input == NULL)
{
printf("Could not open file.\n");
return false;
}
printf("b\n");
char c;
int i = 0;
unsigned int h = 0;
char word[LENGTH + 1];
node *key = NULL;
while (fread(&c, sizeof(char), 1, input))
{
if (i == 0)
{
key = malloc(sizeof(node));
}
else if (c == '\n')
{
word[i] = '[=11=]';
i = 0;
h = hash(word);
key->next = table[h];
table[h] = key;
siz++;
continue;
}
key->word[i] = c;
i++;
}
fclose(input);
/*
for (int j = 0; j < N; j++)
{
while (table[j] != NULL)
{
printf("%s ->\n", table[j]->word);
table[j] = table[j]->next;
}
}
*/
return true;
}
// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
// TODO
return siz;
}
// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
// TODO
node *n = NULL;
node *tmp = NULL;
for (int i = 0; i < N; i++)
{
n = table[i];
while (n != NULL)
{
tmp = n;
n = n->next;
free(tmp);
}
}
return true;
}
我认为出现此警告是因为在第 42 行,函数 strcasecmp 试图将字符串 node->word 的某些字符小写,即使在 '\0' 之后也是如此。
事实上,如果我在 load() 中替换,警告就会消失,
key = malloc(sizeof(node));
与 key = calloc(1, sizeof(node));
因为 calloc allocate 并将内存设置为 0.
所以,我的问题是:strcasecmp 是如何工作的??
在 malloc 场景 ll->word 中,我传递给 strcasecmp 的参数是这样的字符数组“actual_valid_chars \0 垃圾字节直到数组长度:LENGTH”。
在 calloc 场景中,数组是“actual_valid_chars \0 000000...”。
因此,我认为在 malloc 的情况下,我正在将未初始化的内存传递给 strcasecmp,但在这两种情况下我也使用 \0 终止字符串。
strcasecmp() 不应该通过'\0'识别字符串的结尾,即使它在数组的中间?
有人可以向我澄清这些段落吗?
另外,我可以简单地忽略这些警告,还是有更好的做法可以使用?
key->word
在加载函数中不是空终止的。 char 数组 word
是,尽管它从未被填充。
cs50的第5题,拼写,要求实现一些词典功能。 我用 valgrind 收到这个警告:
==393== Conditional jump or move depends on uninitialised value(s)
==393== at 0x49DB143: tolower (ctype.c:46)
==393== by 0x483F864: strcasecmp (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==393== by 0x4019CF: check (dictionary.c:42)
==393== by 0x401603: main (speller.c:114)
==393== Uninitialised value was created by a heap allocation
==393== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==393== by 0x401AF8: load (dictionary.c:82)
==393== by 0x40129E: main (speller.c:40).
这是我的 dictionary.c 文件,其中包含辅助函数。
// Implements a dictionary's functionality
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dictionary.h"
#include <strings.h>
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// Number of buckets in hash table
const unsigned int N = 1;
unsigned int siz = 0;
// Hash table
node *table[N];
/*
for (int i = 0; i < N; i++)
{
table[i]->next
}
*/
// Returns true if word is in dictionary, else false
bool check(const char *word)
{
// TODO
int h = hash(word);
node *ll = table[h];
while (ll != NULL)
{
if (strcasecmp(ll->word, word) == 0)
{
printf("len: %lu\n", strlen(ll->word));
return true;
}
ll = ll->next;
}
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
// TODO
return 0;
}
// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
printf("a\n");
// TODO
FILE *input = fopen(dictionary, "r");
if (input == NULL)
{
printf("Could not open file.\n");
return false;
}
printf("b\n");
char c;
int i = 0;
unsigned int h = 0;
char word[LENGTH + 1];
node *key = NULL;
while (fread(&c, sizeof(char), 1, input))
{
if (i == 0)
{
key = malloc(sizeof(node));
}
else if (c == '\n')
{
word[i] = '[=11=]';
i = 0;
h = hash(word);
key->next = table[h];
table[h] = key;
siz++;
continue;
}
key->word[i] = c;
i++;
}
fclose(input);
/*
for (int j = 0; j < N; j++)
{
while (table[j] != NULL)
{
printf("%s ->\n", table[j]->word);
table[j] = table[j]->next;
}
}
*/
return true;
}
// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
// TODO
return siz;
}
// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
// TODO
node *n = NULL;
node *tmp = NULL;
for (int i = 0; i < N; i++)
{
n = table[i];
while (n != NULL)
{
tmp = n;
n = n->next;
free(tmp);
}
}
return true;
}
我认为出现此警告是因为在第 42 行,函数 strcasecmp 试图将字符串 node->word 的某些字符小写,即使在 '\0' 之后也是如此。
事实上,如果我在 load() 中替换,警告就会消失,
key = malloc(sizeof(node));
与 key = calloc(1, sizeof(node));
因为 calloc allocate 并将内存设置为 0.
所以,我的问题是:strcasecmp 是如何工作的?? 在 malloc 场景 ll->word 中,我传递给 strcasecmp 的参数是这样的字符数组“actual_valid_chars \0 垃圾字节直到数组长度:LENGTH”。 在 calloc 场景中,数组是“actual_valid_chars \0 000000...”。
因此,我认为在 malloc 的情况下,我正在将未初始化的内存传递给 strcasecmp,但在这两种情况下我也使用 \0 终止字符串。
strcasecmp() 不应该通过'\0'识别字符串的结尾,即使它在数组的中间? 有人可以向我澄清这些段落吗? 另外,我可以简单地忽略这些警告,还是有更好的做法可以使用?
key->word
在加载函数中不是空终止的。 char 数组 word
是,尽管它从未被填充。