【发布时间】:2022-06-16 14:37:10
【问题描述】:
所以我一直在尝试完成 cs50,问题集 5,拼写问题,并且我已经完成了整个代码,除了他们自己的网站上的演练视频之外没有任何参考。
我曾尝试查看其他人的代码,但我的代码存在一些问题,我只是不明白为什么会这样。 代码可以正常编译,但是会出现分段错误。
当我使用 valgrind 时,它告诉我有很多泄漏和需要关闭的文件,但我已经在需要的地方完成了所有这些更改,并且已经多次编译了我的代码。
这是我的代码
#include <cs50.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// TODO: Choose number of buckets in hash table
// LENGTH is a const int = 45
const unsigned int N = LENGTH;
// Hash table
node *table[N];
// Size no.
int size_number = 0;
// Returns true if word is in dictionary, else false
bool check(const char *word)
{
int n = hash(word);
for (node *cursor = table[n]; cursor->next != NULL; cursor = cursor->next)
{
if (strcasecmp(cursor->word, word) == 0)
{
return true;
}
}
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
int n = -1;
for (int i = 0; i < strlen(word); i++)
{
if (isalpha(word[i]) || word[i] == '\'')
{
n++;
}
}
return n;
}
// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
FILE *dict = fopen(dictionary, "r");
if (dict == NULL)
{
printf("Could not open dictionary\n");
return false;
}
char word[N];
while(fscanf(dict, "%s", word))
{
int n = fscanf(dict, "%s", word);
if (n == EOF)
{
break;
}
size_number++;
node *loaded_word = malloc(sizeof(node));
if (loaded_word == NULL)
{
fclose(dict);
return false;
}
strcpy(loaded_word->word, word);
int index = hash(loaded_word->word);
loaded_word->next = table[index];
table[index]->next = loaded_word;
}
fclose(dict);
return true;
}
// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
return size_number;
}
// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
for (int i = 0; i < N; i++)
{
while(table[i] != NULL)
{
node *tmp = table[i]->next;
free(table[i]);
table[i] = tmp;
}
}
return true;
}
我用过
valgrind ./speller texts/cat.txt
cat.txt 是
A cat is not a caterpillar.
这是 valgrind 的输出
==6031== Invalid write of size 8
==6031== at 0x401BDE: load (dictionary.c:90)
==6031== by 0x4012BE: main (speller.c:40)
==6031== Address 0x30 is not stack'd, malloc'd or (recently) free'd
==6031==
==6031==
==6031== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==6031== Access not within mapped region at address 0x30
==6031== at 0x401BDE: load (dictionary.c:90)
==6031== by 0x4012BE: main (speller.c:40)
==6031== If you believe this happened as a result of a stack
==6031== overflow in your program's main thread (unlikely but
==6031== possible), you can try to increase the size of the
==6031== main thread stack using the --main-stacksize= flag.
==6031== The main thread stack size used in this run was 8388608.
==6031==
==6031== HEAP SUMMARY:
==6031== in use at exit: 528 bytes in 2 blocks
==6031== total heap usage: 3 allocs, 1 frees, 4,624 bytes allocated
==6031==
==6031== 56 bytes in 1 blocks are still reachable in loss record 1 of 2
==6031== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==6031== by 0x401B74: load (dictionary.c:79)
==6031== by 0x4012BE: main (speller.c:40)
==6031==
==6031== 472 bytes in 1 blocks are still reachable in loss record 2 of 2
==6031== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==6031== by 0x4A2592D: __fopen_internal (iofopen.c:65)
==6031== by 0x4A2592D: fopen@@GLIBC_2.2.5 (iofopen.c:86)
==6031== by 0x401ACE: load (dictionary.c:62)
==6031== by 0x4012BE: main (speller.c:40)
==6031==
==6031== LEAK SUMMARY:
==6031== definitely lost: 0 bytes in 0 blocks
==6031== indirectly lost: 0 bytes in 0 blocks
==6031== possibly lost: 0 bytes in 0 blocks
==6031== still reachable: 528 bytes in 2 blocks
==6031== suppressed: 0 bytes in 0 blocks
==6031==
==6031== For lists of detected and suppressed errors, rerun with: -s
==6031== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
/opt/cs50/bin/valgrind: line 11: 6031 Segmentation fault (core dumped)
我已经关闭了 dict 文件并在我认为需要的地方释放了内存,但它仍然给我相同的输出,我无法查明代码中的问题。任何帮助表示赞赏。 :)
编辑:我忘了告诉我哈希函数是如何工作的。我的哈希函数根据单词的长度对单词进行排序,所以一个单词有多少个字母,所以“apple”和“action”在不同的链表中,但“action”和“banana”在同一个链表中。这就是为什么不。 of buckets = LENGTH,这是这个问题可能的最长单词。
【问题讨论】:
-
请在您的问题中提供minimal reproducible example。 (@xing 询问某些遗漏的细节可能会非常乏味,所以请不要说出具体的缺点,最好询问
[mre],这对于像你我这样的 cmets 来说是一个方便的快捷方式)。 -
你永远不会初始化
table来指向任何东西。更改node *table[N];-->node *table;然后在main中执行:table = calloc(N, sizeof(*table)); -
另外,为了更加安全,将
hash中的return n;更改为return n % N;
标签: c memory-leaks valgrind cs50