【问题标题】:cs50 Pset5 Speller segmentation fault and memory leakscs50 Pset5 Speller 分段错误和内存泄漏
【发布时间】: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


猜你喜欢
  • 1970-01-01
  • 2020-10-18
  • 2020-09-28
  • 2021-07-31
  • 2020-06-06
  • 1970-01-01
  • 2020-08-18
  • 2020-10-04
  • 2022-01-15
相关资源
最近更新 更多