(CS50/pset5/speller) 根据 check50 和 valgrind,我遇到了内存泄漏问题。我想我正在使用一个没有值的变量
(CS50/pset5/speller) I have a memory leak issue, according to check50 and valgrind. I think I'm using a variable that doesn't have a value
根据 check50 和 valgrind,我遇到了内存泄漏问题。看起来我正在尝试使用可能没有值的变量。根据 check50,其他一切正常,唯一的问题是内存。这是 valgrind 的错误消息:
==3243== Conditional jump or move depends on uninitialised value(s)
==3243== at 0x520A60F: tolower (ctype.c:46)
==3243== by 0x4010CD: check (dictionary.c:36)
==3243== by 0x400CD9: main (speller.c:112)
==3243== Uninitialised value was created by a stack allocation
==3243== at 0x4008E4: main (speller.c:21)
==3243==
==3243== Use of uninitialised value of size 8
==3243== at 0x520A623: tolower (ctype.c:46)
==3243== by 0x4010CD: check (dictionary.c:36)
==3243== by 0x400CD9: main (speller.c:112)
==3243== Uninitialised value was created by a stack allocation
==3243== at 0x4008E4: main (speller.c:21)
==3243==
WORDS MISSPELLED: 0
WORDS IN DICTIONARY: 143091
WORDS IN TEXT: 6
TIME IN load: 1.46
TIME IN check: 0.00
TIME IN size: 0.00
TIME IN unload: 0.21
TIME IN TOTAL: 1.67
==3243==
==3243== HEAP SUMMARY:
==3243== in use at exit: 0 bytes in 0 blocks
==3243== total heap usage: 143,097 allocs, 143,097 frees, 8,023,462 bytes allocated
==3243==
==3243== All heap blocks were freed -- no leaks are possible
==3243==
==3243== For counts of detected and suppressed errors, rerun with: -v
==3243== ERROR SUMMARY: 492 errors from 2 contexts (suppressed: 0 from 0)
Asking for help...
==3243== Conditional jump or move depends on uninitialised value(s)
Looks like you're trying to use a variable that might not have a value? Take a closer look at line 36 of dictionary.c.
这是我的代码(如果你能帮忙我会很高兴;))
// Implements a dictionary's functionality
#include <stdbool.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <strings.h>
#include <stdio.h>
#include "dictionary.h"
#define HASHTABLE_SIZE 65536
// 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 = HASHTABLE_SIZE;
// Hash table
node *table[N];
unsigned int totalWords = 0;
// Returns true if word is in dictionary else false
bool check(const char *word)
{
//Initialize lower case word
char lcword[LENGTH + 1];
for (int i = 0; i < LENGTH + 1; i++)
lcword[i] = tolower(word[i]);
node *cursor = table[hash(lcword)];
while (cursor != NULL)
{
if (strcasecmp(word, cursor->word) == 0)
{
return true;
}
cursor = cursor->next;
}
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
//https://www.reddit.com/r/cs50/comments/1x6vc8/pset6_trie_vs_hashtable/cf9nlkn/
unsigned int hash_value = 0;
for (int i = 0, n = strlen(word); i < n; i++)
hash_value = (hash_value << 2) ^ word[i];
return hash_value % HASHTABLE_SIZE;
}
// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
FILE *dicfile = fopen(dictionary, "r");
char *word = malloc(LENGTH + 1);
//Check if word is null
if (word == NULL)
return false;
//Check if the fopen function opened a not NULL file
if (dicfile == NULL)
return false;
//Iterate over dictionary until fscanf return EOF (meaning it's the end of the file)
while (fscanf(dicfile, "%s", word) != EOF)
{
//Create a node to store the current word
node *new_node = malloc(sizeof(node));
if (new_node == NULL)
return false;
//Copy the new_node's word into the current word
strcpy(new_node->word, word);
//Get the index (hash the current word and store it in n)
int n = hash(new_node->word);
//Insert the new_node into the linked list
new_node->next = table[n];
table[n] = new_node;
//Add to the total number of words in the text file
totalWords++;
}
fclose(dicfile);
free(word);
return true;
}
// Returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void)
{
return totalWords;
}
// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
for (int i = 0; i < HASHTABLE_SIZE; i++)
{
node* cursor = table[i];
node* tmp;
while (cursor != NULL)
{
tmp = cursor;
cursor = cursor->next;
free(tmp);
}
free(cursor);
}
return true;
}
如果你想知道,我的代码的第 36 行是这个:lcword[i] = tolower(word[i]);
谢谢!!!
关于:
for (int i = 0; i < LENGTH + 1; i++)
在 C 中,数组索引的有效范围是 0...(number of elements in array-1 )
注意 -1
注意:宏:LENGTH
未在发布的代码中的任何位置定义。
函数:check()
在发布的代码中实现,但从未调用过。
关于:
for ( int i = 0, n = strlen(word); i < n; i++)
函数:strlen()
returns一个size_t
,所以语句应该是:
for ( size_t i = 0, n = strlen(word); i < n; i++ )
函数:size()
已实现但从未调用。
包含未使用的头文件是一种非常糟糕的编程习惯。例如:
#include <strings.h>
关于;
if (dicfile == NULL)
return false;
这应该紧随其后;
FILE *dicfile = fopen(dictionary, "r");
并且应该包含声明:
perror( "fopen to read dictionary file failed" );
关于:
while (fscanf(dicfile, "%s", word) != EOF)
调用 fscanf()
失败还有其他原因。应该检查是否成功。
%s
输入格式转换说明符可以输入比数组 word()
中更多的字符。此外,该说明符始终将 NUL 字节附加到输入。为避免任何缓冲区溢出问题,请始终使用比缓冲区长度小 1 的修饰符。建议:
while (fscanf(dicfile, "%" LENGTH "s", word) == 1)
关于您关于内存泄漏的问题:
发布的代码修改了 table[]
中的指针(通过覆盖它们),而没有首先检查那里已经有一个活动条目。如果 'hashed' 索引处已经有一个活动条目进入 table,则新条目必须链接到(可以链接到之前)当前条目之后,在 [=27= 中的同一索引处]
当然,当一个活动条目被覆盖时,结果就是内存泄漏。
根据 check50 和 valgrind,我遇到了内存泄漏问题。看起来我正在尝试使用可能没有值的变量。根据 check50,其他一切正常,唯一的问题是内存。这是 valgrind 的错误消息:
==3243== Conditional jump or move depends on uninitialised value(s)
==3243== at 0x520A60F: tolower (ctype.c:46)
==3243== by 0x4010CD: check (dictionary.c:36)
==3243== by 0x400CD9: main (speller.c:112)
==3243== Uninitialised value was created by a stack allocation
==3243== at 0x4008E4: main (speller.c:21)
==3243==
==3243== Use of uninitialised value of size 8
==3243== at 0x520A623: tolower (ctype.c:46)
==3243== by 0x4010CD: check (dictionary.c:36)
==3243== by 0x400CD9: main (speller.c:112)
==3243== Uninitialised value was created by a stack allocation
==3243== at 0x4008E4: main (speller.c:21)
==3243==
WORDS MISSPELLED: 0
WORDS IN DICTIONARY: 143091
WORDS IN TEXT: 6
TIME IN load: 1.46
TIME IN check: 0.00
TIME IN size: 0.00
TIME IN unload: 0.21
TIME IN TOTAL: 1.67
==3243==
==3243== HEAP SUMMARY:
==3243== in use at exit: 0 bytes in 0 blocks
==3243== total heap usage: 143,097 allocs, 143,097 frees, 8,023,462 bytes allocated
==3243==
==3243== All heap blocks were freed -- no leaks are possible
==3243==
==3243== For counts of detected and suppressed errors, rerun with: -v
==3243== ERROR SUMMARY: 492 errors from 2 contexts (suppressed: 0 from 0)
Asking for help...
==3243== Conditional jump or move depends on uninitialised value(s)
Looks like you're trying to use a variable that might not have a value? Take a closer look at line 36 of dictionary.c.
这是我的代码(如果你能帮忙我会很高兴;))
// Implements a dictionary's functionality
#include <stdbool.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <strings.h>
#include <stdio.h>
#include "dictionary.h"
#define HASHTABLE_SIZE 65536
// 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 = HASHTABLE_SIZE;
// Hash table
node *table[N];
unsigned int totalWords = 0;
// Returns true if word is in dictionary else false
bool check(const char *word)
{
//Initialize lower case word
char lcword[LENGTH + 1];
for (int i = 0; i < LENGTH + 1; i++)
lcword[i] = tolower(word[i]);
node *cursor = table[hash(lcword)];
while (cursor != NULL)
{
if (strcasecmp(word, cursor->word) == 0)
{
return true;
}
cursor = cursor->next;
}
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
//https://www.reddit.com/r/cs50/comments/1x6vc8/pset6_trie_vs_hashtable/cf9nlkn/
unsigned int hash_value = 0;
for (int i = 0, n = strlen(word); i < n; i++)
hash_value = (hash_value << 2) ^ word[i];
return hash_value % HASHTABLE_SIZE;
}
// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
FILE *dicfile = fopen(dictionary, "r");
char *word = malloc(LENGTH + 1);
//Check if word is null
if (word == NULL)
return false;
//Check if the fopen function opened a not NULL file
if (dicfile == NULL)
return false;
//Iterate over dictionary until fscanf return EOF (meaning it's the end of the file)
while (fscanf(dicfile, "%s", word) != EOF)
{
//Create a node to store the current word
node *new_node = malloc(sizeof(node));
if (new_node == NULL)
return false;
//Copy the new_node's word into the current word
strcpy(new_node->word, word);
//Get the index (hash the current word and store it in n)
int n = hash(new_node->word);
//Insert the new_node into the linked list
new_node->next = table[n];
table[n] = new_node;
//Add to the total number of words in the text file
totalWords++;
}
fclose(dicfile);
free(word);
return true;
}
// Returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void)
{
return totalWords;
}
// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
for (int i = 0; i < HASHTABLE_SIZE; i++)
{
node* cursor = table[i];
node* tmp;
while (cursor != NULL)
{
tmp = cursor;
cursor = cursor->next;
free(tmp);
}
free(cursor);
}
return true;
}
如果你想知道,我的代码的第 36 行是这个:lcword[i] = tolower(word[i]);
谢谢!!!
关于:
for (int i = 0; i < LENGTH + 1; i++)
在 C 中,数组索引的有效范围是 0...(number of elements in array-1 )
注意 -1
注意:宏:LENGTH
未在发布的代码中的任何位置定义。
函数:check()
在发布的代码中实现,但从未调用过。
关于:
for ( int i = 0, n = strlen(word); i < n; i++)
函数:strlen()
returns一个size_t
,所以语句应该是:
for ( size_t i = 0, n = strlen(word); i < n; i++ )
函数:size()
已实现但从未调用。
包含未使用的头文件是一种非常糟糕的编程习惯。例如:
#include <strings.h>
关于;
if (dicfile == NULL)
return false;
这应该紧随其后;
FILE *dicfile = fopen(dictionary, "r");
并且应该包含声明:
perror( "fopen to read dictionary file failed" );
关于:
while (fscanf(dicfile, "%s", word) != EOF)
调用 fscanf()
失败还有其他原因。应该检查是否成功。
%s
输入格式转换说明符可以输入比数组 word()
中更多的字符。此外,该说明符始终将 NUL 字节附加到输入。为避免任何缓冲区溢出问题,请始终使用比缓冲区长度小 1 的修饰符。建议:
while (fscanf(dicfile, "%" LENGTH "s", word) == 1)
关于您关于内存泄漏的问题:
发布的代码修改了 table[]
中的指针(通过覆盖它们),而没有首先检查那里已经有一个活动条目。如果 'hashed' 索引处已经有一个活动条目进入 table,则新条目必须链接到(可以链接到之前)当前条目之后,在 [=27= 中的同一索引处]
当然,当一个活动条目被覆盖时,结果就是内存泄漏。