CS50 PSET 5排纸器无法正常工作(和valgrind问题)

时间:2020-08-18 22:37:05

标签: c cs50

我是CS新手,可以在拼写pset上真正使用一些帮助。我有一个基本的轮廓,似乎没有错误,但是我仍然有问题。它在check50中失败:

  • 它不能正确处理大多数基本单词
  • 拼写检查不区分大小写
  • 它不能正确处理子字符串
  • 并且有内存错误

如果我通过它运行一个测试器文件,则计数器仅显示字典中有2个单词,因此它会吐出文档中几乎每个单词都拼写错误(导致我认为加载有错误,但我不知道在哪里。

还有一个valgrind错误。它显示以下内容:

堆摘要:在退出时使用:14个块中的1,300字节。 堆总使用量:15个分配,1个释放,5406个字节分配。

任何帮助将不胜感激;我已经坚持了三天!

#include <stdbool.h>
#include <string.h>
#include <strings.h>
#include <stdio.h>
#include <stdlib.h>
#include "dictionary.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 = 26;

// Hash table
node *table[N];

// Returns true if word is in dictionary else false
bool check(const char *word)
{
    int numloc = hash(word);
    node *cursor = table[numloc];
    while (cursor != NULL)
    {
        if (strcasecmp(cursor->word, word) == 0)
        {
            return true;
        }
        cursor = cursor->next;
    }
    return false;
}

// Hashes word to a number
unsigned int hash(const char *word)
{
    unsigned long hash = 5381;
    int c;
    while ((c = *word++))
    {
        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
    }
    return hash % N;
}

// Loads dictionary into memory, returning true if successful else false
int counter = 0;
bool load(const char *dictionary)
{
    FILE *dictionary = fopen(dictionary, "r");
    if (dictionary == NULL)
    {
        return false;
    }
    char tempword[LENGTH + 1];
    for (int i = 0; i < N; i++)
    {
        table[i] = NULL;
    }
    while (fscanf(dict, "%s", tempword) != EOF)
    {
        node *n = malloc(sizeof(node));
        if (n == NULL)
        {
            return false;
        }
        strcpy(n->word, tempword);
        int A = hash(tempword);
        if (table[A] == NULL)
        {
            table[A] = n;
            n->next = NULL;
        }
        else
        {
            n->next = table[A];
            table[A] = n;
        }
        counter++;
    }
    fclose(dictionary);
    return true;
}


// Returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void)
{
    if (counter == 0)
    {
        unload();
        return 1;
    }
    else
    {
        return counter;
    }
}

// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
    for (int i = 0; i < N; i++)
    {
        node *cursor = table[i];
        node *tmp = table[i];
        while (cursor != NULL)
        {
            cursor = cursor->next;
            free(tmp);
            tmp = cursor;
        }
        return true;
    }
    return false;
}

2 个答案:

答案 0 :(得分:0)

dictionary.h的内容是什么?照原样,发布的代码无法编译!

以下是通过编译器运行的结果,其中包含有关如何解决问题的一些建议。

编译语句:

gcc -ggdb3 -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled1.c" -o "untitled1.o"

编译器的输出消息:

untitled1.c:20:7: error: variably modified ‘table’ at file scope
   20 | node *table[N];
      |       ^~~~~

this is not C++.. Therefore suggest replacing: 

const unsigned int N = 26;

使用

#define N 26

因此表[[]将被正确声明

untitled1.c: In function ‘check’:

untitled1.c:25:18: warning: implicit declaration of function ‘hash’ [-Wimplicit-function-declaration]
   25 |     int numloc = hash(word);
      |                  ^~~~

在代码的这一点上,编译器不知道函数hash()的原型。建议将hash()函数移到包含此语句的函数之前。

untitled1.c: At top level:

untitled1.c:39:14: error: conflicting types for ‘hash’
   39 | unsigned int hash(const char *word)
      |              ^~~~

untitled1.c:25:18: note: previous implicit declaration of ‘hash’ was here
   25 |     int numloc = hash(word);
      |                  ^~~~

untitled1.c: In function ‘hash’:

untitled1.c:45:37: warning: conversion to ‘long unsigned int’ from ‘int’ may change the sign of the result [-Wsign-conversion]
   45 |         hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
      |                                     ^

请勿将局部变量命名为与函数名称相同的名称。在上述情况下,编译器认为代码是递归调用函数:hash()

untitled1.c:47:17: warning: conversion from ‘long unsigned int’ to ‘unsigned int’ may change value [-Wconversion]
   47 |     return hash % N;
      |            ~~~~~^~~

untitled1.c: In function ‘load’:

untitled1.c:54:11: error: ‘dictionary’ redeclared as different kind of symbol
   54 |     FILE *dictionary = fopen(dictionary, "r");
      |           ^~~~~~~~~~

dictionary已被声明为字符串。因此,请在此处使用其他一些变量名。

untitled1.c:52:23: note: previous definition of ‘dictionary’ was here
   52 | bool load(const char *dictionary)
      |           ~~~~~~~~~~~~^~~~~~~~~~

untitled1.c:54:30: warning: passing argument 1 of ‘fopen’ from incompatible pointer type [-Wincompatible-pointer-types]
   54 |     FILE *dictionary = fopen(dictionary, "r");
      |                              ^~~~~~~~~~
      |                              |
      |                              FILE * {aka struct _IO_FILE *}

In file included from untitled1.c:4:

/usr/include/stdio.h:246:14: note: expected ‘const char * restrict’ but argument is of type ‘FILE *’ {aka ‘struct _IO_FILE *’}
  246 | extern FILE *fopen (const char *__restrict __filename,
      |              ^~~~~

untitled1.c:60:23: warning: comparison of integer expressions of different signedness: ‘int’ and ‘unsigned int’ [-Wsign-compare]
   60 |     for (int i = 0; i < N; i++)
      |                 
  ^

不比较有符号和无符号值。它“可能”有效,但是您不能依靠它起作用。

untitled1.c:64:19: error: ‘dict’ undeclared (first use in this function)
   64 |     while (fscanf(dict, "%s", tempword) != EOF)
      |                   ^~~~

dict的类型必须为FILE *,但是从未通过调用fopen()

来设置此类变量。
untitled1.c:64:19: note: each undeclared identifier is reported only once for each function it appears in

untitled1.c:72:17: warning: conversion to ‘int’ from ‘unsigned int’ may change the sign of the result [-Wsign-conversion]
   72 |         int A = hash(tempword);
      |                 ^~~~

untitled1.c: In function ‘size’:

untitled1.c:100:16: warning: conversion to ‘unsigned int’ from ‘int’ may change the sign of the result [-Wsign-conversion]
  100 |         return counter;
      |                ^~~~~~~

untitled1.c: In function ‘unload’:

untitled1.c:107:23: warning: comparison of integer expressions of different signedness: ‘int’ and ‘unsigned int’ [-Wsign-compare]
  107 |     for (int i = 0; i < N; i++)
      |                       ^

Compilation failed.

答案 1 :(得分:0)

内存泄漏的原因是,在卸载的最后一步,您还没有释放最后一个节点。试用这个版本的while循环。您希望将free(temp)作为循环的最后一行,以便在游标= NULL时不会初始化/占用内存

bool unload(void)
{
    for (int i = 0; i < N; i++)
    {
        node *cursor = table[i];

        while (cursor != NULL)
        {
            node *tmp = cursor;
            cursor = cursor->next;
            free(tmp);
        }
        free(cursor);
        return true;
    }
    return false;
}