CS50 PSET5 无法释放内存,段错误
CS50 PSET5 cannot free memory, seg fault
似乎我的程序虽然编译并开始 运行,但根据 valgrind 的内存泄漏导致段错误:
==4602== HEAP SUMMARY:
==4602== in use at exit: 4,007,248 bytes in 71,558 blocks
==4602== total heap usage: 71,564 allocs, 6 frees, 4,017,464 bytes allocated
==4602==
==4602== 336 bytes in 6 blocks are still reachable in loss record 1 of 4
==4602== at 0x307307F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4602== by 0x4019C1: check (dictionary.c:37)
==4602== by 0x40160B: main (speller.c:113)
==4602==
==4602== 336 bytes in 6 blocks are definitely lost in loss record 2 of 4
==4602== at 0x307307F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4602== by 0x4019F5: check (dictionary.c:44)
==4602== by 0x40160B: main (speller.c:113)
==4602==
==4602== 510,048 bytes in 9,108 blocks are definitely lost in loss record 3 of 4
==4602== at 0x307307F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4602== by 0x401BFA: load (dictionary.c:144)
==4602== by 0x4012CE: main (speller.c:40)
==4602==
==4602== 3,496,528 bytes in 62,438 blocks are still reachable in loss record 4 of 4
==4602== at 0x307307F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4602== by 0x401BFA: load (dictionary.c:144)
==4602== by 0x4012CE: main (speller.c:40)
==4602==
==4602== LEAK SUMMARY:
==4602== definitely lost: 510,384 bytes in 9,114 blocks
==4602== indirectly lost: 0 bytes in 0 blocks
==4602== possibly lost: 0 bytes in 0 blocks
==4602== still reachable: 3,496,864 bytes in 62,444 blocks
==4602== suppressed: 0 bytes in 0 blocks
这里是检查和加载函数,其中似乎发生了泄漏,特别是在分配内存的行:
bool check(const char *word)
{
// Hash word to check
unsigned int h = hash(word);
table[h] = malloc(sizeof(node));
if (table[h] == NULL)
{
return false;
}
// Set up cursor
node *cursor = malloc(sizeof(node));
if (cursor == NULL)
{
return false;
}
// Copy word to be checked into cursor
strcpy(cursor->word, word);
// Set cursor to point at first element of the linked list
cursor = table[h];
// Traverse linked list to check for word's presence
while (cursor->next != NULL)
{
if (strcasecmp(cursor->word, table[h]->next->word) == 0)
{
return true;
// Free allocated memory
while (cursor != NULL || table[h] != NULL)
{
node *tmp = cursor->next;
free(cursor);
cursor = tmp;
node *tmp2 = table[h]->next;
free(table[h]);
table[h] = tmp2;
}
}
else
{
// Move cursor to next node
cursor = cursor->next;
}
}
return false;
}
bool load(const char *dictionary)
{
// Open dictionary file
FILE *file = fopen(dictionary, "r");
// Check if opening was successful
if (file == NULL)
{
return false;
}
// Malloc new node
node *string = malloc(sizeof(node));
// Set up buffer, remember to initialize it, otherwise the compiler won't know what it points at
char read_file[LENGTH + 1];
//Read every word
while (fscanf(file, "%s", read_file) != EOF)
{
// Scan word into read_file
fscanf(file, "%s", read_file);
// Check if memory was allocated correctly
if (string == NULL)
{
return false;
}
// Copy string from read file to node
strcpy(string->word, read_file);
// Hash the word and malloc
unsigned int h = hash(string->word);
table[h] = malloc(sizeof(node));
// Insert node into hash table
string->next = table[h]->next;
table[h]->next = string;
counter++;
}
// Close file
fclose(file);
// Free memory
free(string);
return true;
}
// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
return counter;
}
// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
// TODO
for (int i = 0; i < N; i++)
{
node *cursor = NULL;
while (cursor != NULL)
{
cursor = table[i]->next;
node *tmp = cursor;
cursor = cursor->next;
free(tmp);
}
}
return true;
}
如果需要,我很乐意提供更多信息。
仅考虑分配和分配:
table[h] = malloc();
cursor = malloc();
cursor = table[h]; // here you lose the only link to the newly allocated node!
// -> memory leak
另外你不检查 table[h]
中是否已经有一个节点然后你丢失了 link 因为你只是覆盖而不检查。
我个人的做法是先寻找插入点,然后创建新节点:
node** cursor = &table[h];
while(*cursor)
{
cursor = &(*cursor)->next;
}
*cursor = malloc(sizeof(**cursor));
似乎我的程序虽然编译并开始 运行,但根据 valgrind 的内存泄漏导致段错误:
==4602== HEAP SUMMARY:
==4602== in use at exit: 4,007,248 bytes in 71,558 blocks
==4602== total heap usage: 71,564 allocs, 6 frees, 4,017,464 bytes allocated
==4602==
==4602== 336 bytes in 6 blocks are still reachable in loss record 1 of 4
==4602== at 0x307307F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4602== by 0x4019C1: check (dictionary.c:37)
==4602== by 0x40160B: main (speller.c:113)
==4602==
==4602== 336 bytes in 6 blocks are definitely lost in loss record 2 of 4
==4602== at 0x307307F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4602== by 0x4019F5: check (dictionary.c:44)
==4602== by 0x40160B: main (speller.c:113)
==4602==
==4602== 510,048 bytes in 9,108 blocks are definitely lost in loss record 3 of 4
==4602== at 0x307307F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4602== by 0x401BFA: load (dictionary.c:144)
==4602== by 0x4012CE: main (speller.c:40)
==4602==
==4602== 3,496,528 bytes in 62,438 blocks are still reachable in loss record 4 of 4
==4602== at 0x307307F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4602== by 0x401BFA: load (dictionary.c:144)
==4602== by 0x4012CE: main (speller.c:40)
==4602==
==4602== LEAK SUMMARY:
==4602== definitely lost: 510,384 bytes in 9,114 blocks
==4602== indirectly lost: 0 bytes in 0 blocks
==4602== possibly lost: 0 bytes in 0 blocks
==4602== still reachable: 3,496,864 bytes in 62,444 blocks
==4602== suppressed: 0 bytes in 0 blocks
这里是检查和加载函数,其中似乎发生了泄漏,特别是在分配内存的行:
bool check(const char *word)
{
// Hash word to check
unsigned int h = hash(word);
table[h] = malloc(sizeof(node));
if (table[h] == NULL)
{
return false;
}
// Set up cursor
node *cursor = malloc(sizeof(node));
if (cursor == NULL)
{
return false;
}
// Copy word to be checked into cursor
strcpy(cursor->word, word);
// Set cursor to point at first element of the linked list
cursor = table[h];
// Traverse linked list to check for word's presence
while (cursor->next != NULL)
{
if (strcasecmp(cursor->word, table[h]->next->word) == 0)
{
return true;
// Free allocated memory
while (cursor != NULL || table[h] != NULL)
{
node *tmp = cursor->next;
free(cursor);
cursor = tmp;
node *tmp2 = table[h]->next;
free(table[h]);
table[h] = tmp2;
}
}
else
{
// Move cursor to next node
cursor = cursor->next;
}
}
return false;
}
bool load(const char *dictionary)
{
// Open dictionary file
FILE *file = fopen(dictionary, "r");
// Check if opening was successful
if (file == NULL)
{
return false;
}
// Malloc new node
node *string = malloc(sizeof(node));
// Set up buffer, remember to initialize it, otherwise the compiler won't know what it points at
char read_file[LENGTH + 1];
//Read every word
while (fscanf(file, "%s", read_file) != EOF)
{
// Scan word into read_file
fscanf(file, "%s", read_file);
// Check if memory was allocated correctly
if (string == NULL)
{
return false;
}
// Copy string from read file to node
strcpy(string->word, read_file);
// Hash the word and malloc
unsigned int h = hash(string->word);
table[h] = malloc(sizeof(node));
// Insert node into hash table
string->next = table[h]->next;
table[h]->next = string;
counter++;
}
// Close file
fclose(file);
// Free memory
free(string);
return true;
}
// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
return counter;
}
// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
// TODO
for (int i = 0; i < N; i++)
{
node *cursor = NULL;
while (cursor != NULL)
{
cursor = table[i]->next;
node *tmp = cursor;
cursor = cursor->next;
free(tmp);
}
}
return true;
}
如果需要,我很乐意提供更多信息。
仅考虑分配和分配:
table[h] = malloc();
cursor = malloc();
cursor = table[h]; // here you lose the only link to the newly allocated node!
// -> memory leak
另外你不检查 table[h]
中是否已经有一个节点然后你丢失了 link 因为你只是覆盖而不检查。
我个人的做法是先寻找插入点,然后创建新节点:
node** cursor = &table[h];
while(*cursor)
{
cursor = &(*cursor)->next;
}
*cursor = malloc(sizeof(**cursor));