C语言中的拼写检查

C语言中的拼写检查,c,arrays,pointers,cs50,C,Arrays,Pointers,Cs50,我一直在尝试使用一个大字典来实现一个拼写检查器,它针对一些包含大约2000个单词的文本文件。但是,我的拼写检查器返回所有拼写错误的单词。我真的不知道为什么-有人能帮我吗 #include <stdbool.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include "dictionary.h" #define le

我一直在尝试使用一个大字典来实现一个拼写检查器,它针对一些包含大约2000个单词的文本文件。但是,我的拼写检查器返回所有拼写错误的单词。我真的不知道为什么-有人能帮我吗

#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#include "dictionary.h"

#define lenght 45
#define hashtable_size 65536

char word[lenght+1];
int count = 0;

/*
*
* Hash function. Thanks to Brenda from cs50 reddit.
*/
int hash_it(const char* needs_hashing)
{
    unsigned int hash = 0;
    for (int i=0, n=strlen(needs_hashing); i<n; i++)
        hash = (hash << 2) ^ needs_hashing[i];
    return hash % hashtable_size;
}

typedef struct node
{
    char* word;
    struct node* next;
}node;

node* previous;
node* hashtable[hashtable_size];


/*
*
* Loads dictionary into memory.  Returns true if successful else false.
*/
bool load(const char* dictionary)
{
    char word[lenght+1];
    FILE* dict = fopen(dictionary,"r");

    for(int i = 0; i < 26;i++)
    {
        hashtable[i] = NULL;
        for(int a = fgetc(dict); a != EOF; a = fgetc(dict))
        {
            count++;

            int hashvalue = hash_it(word);

            node* new = malloc(sizeof(node));

            if(hashtable[hashvalue] == NULL)
            {
                hashtable[hashvalue] = new;
                new -> next = NULL;
            }
            else
            {
                new -> next = hashtable[hashvalue];
                hashtable[hashvalue] = new;
            }
        }
    }
    fclose(dict);
    return true;
}

/*
*
* Returns true if word is in dictionary else false.
*/
bool check(const char* word)
{

    char tmp[lenght + 1];
    int lenghtw = strlen(word);
    for (int i = 0; i < lenghtw; i++)
    {
        tmp[i] = tolower(word[i]);
    }


    int index = hash_it(tmp);

    if (hashtable[index] == NULL)
    {
        return false;
    }

    node* cursor = hashtable[index];

    while(cursor != NULL)
    {
        if(strcmp(tmp, cursor -> word) == 0)
        {
            return true;
        }
        cursor = cursor -> next;
    }

    return false;
}

/*
*
* Returns number of words in dictionary if loaded else 0 if not yet loaded.
*/
unsigned int size(void)
{
    return count;
}

/*
*
* Unloads dictionary from memory.  Returns true if successful else false.
*/
bool unload(void)
{
    int index = 0;

    while(index < hashtable_size)
    {
        if(hashtable[index] == NULL)
        {
            index++;
        }
        else
        {
            while(hashtable[index] != NULL)
            {
                node* cursor = hashtable[index];
                hashtable[index] = cursor -> next;
                free(cursor);
            }
            index++;
        }
    }
    return true;
}

int main(int argc, char **argv)
{

    if (argc != 2)
        return 3;

    if (!load("dictionary"))
        return 1;

    printf("loaded %d words\n", size());
    printf("word '%s'%s found\n", argv[1], check(argv[1]) ? "" : " not");
    unload();
    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括“dictionary.h”
#定义长度45
#定义哈希表大小65536
字符字[长度+1];
整数计数=0;
/*
*
*散列函数。感谢cs50 reddit的Brenda。
*/
int散列(const char*需要散列)
{
无符号整数散列=0;
for(int i=0,n=strlen(需要散列);i next=hashtable[hashvalue];
hashtable[hashvalue]=新的;
}
}
}
fclose(dict);
返回true;
}
/*
*
*如果单词在字典中,则返回true,否则返回false。
*/
布尔检查(常量字符*单词)
{
字符tmp[长度+1];
int lenghtw=strlen(字);
对于(int i=0;i单词)==0)
{
返回true;
}
光标=光标->下一步;
}
返回false;
}
/*
*
*如果已加载,则返回字典中的字数;如果尚未加载,则返回0。
*/
无符号整数大小(void)
{
返回计数;
}
/*
*
*从内存中卸载字典。如果成功,则返回true;否则返回false。
*/
bool卸载(无效)
{
int指数=0;
while(索引<哈希表大小)
{
if(哈希表[索引]==NULL)
{
索引++;
}
其他的
{
while(哈希表[索引]!=NULL)
{
节点*游标=哈希表[索引];
哈希表[索引]=光标->下一步;
自由(光标);
}
索引++;
}
}
返回true;
}
int main(int argc,字符**argv)
{
如果(argc!=2)
返回3;
如果(!加载(“字典”))
返回1;
printf(“加载了%d个字,\n”,size());
printf(“找到单词'%s'%s\n',argv[1],检查(argv[1])?”“:“未”);
卸载();
返回0;
}

您的代码中有许多问题:

  • load
    函数中,您不会将字典中的单词加载到哈希表中。您可以使用
    fgetc()
    一次读取一个字符,并从未初始化的本地缓冲区
    word
    创建一个节点

  • hashtable\u-it
    函数只对单词的最后16个字符进行哈希运算。此外,
    hashtable\u-size
    是2的幂,这是一个坏主意。实际上,只有最后8个字符参与哈希值。这不是一个错误,只是一种低效的哈希方法

  • check
    函数中,复制单词并将其转换为小写,但忘记将
    tmp
    数组的最后一个字节设置为
    '\0'

下面是一个更正版的
load
,它在每行字典中读取一个单词:

bool load(const char *dictionary) {
    char line[256];
    FILE *dict = fopen(dictionary, "r");

    if (!dict)
        return false;

    while (fgets(line, sizeof line, dict) != NULL) {
        char *p = line + strspn(line, " \t");  // skip blanks

        p[strcspn(p, " \t\r\n")] = '\0'; // strip trailing blanks

        if (*p == '\0' || *p == '#' || *p == ';')
            continue;  // ignore blank lines and comments

        count++;

        int hashvalue = hash_it(p);
        node *np = malloc(sizeof(node));

        np->word = strdup(p);
        np->next = hashtable[hashvalue];
        hashtable[hashvalue] = np;
    }
    fclose(dict);
    return true;
}

请提供一个。特别是一个
main
函数,该函数显示如何设置字典、如何调用
check
以及输入文件包含的内容。我格式化了代码,注意到没有
main()
function。鉴于目前为止的答案,很明显,您最好在调试器中单步执行此代码并观察变量状态和代码流,而不是要求调试器为您调试它。使用调试器总是比发布代码和问题更有效的调试方法。如果您从未使用过调试器,则您需要花费的时间基本功能(如果您不只是使用GDB命令行调试器,可能会少一些,如果您使用Visual Studio,可能会少一些)将为您节省许多小时的开发时间。IMHO,您可以删除不使用的行声明,并且可能会强调由
strdup()分配的缓冲区
需要释放。检查一下
哈希表[hashvalue]
在将节点放入内部之前为NULL可能会防止出现异常行为collision@OznOg:感谢您指出不一致之处。实际上没有使用全局数组
word
。启动时,全局数组
哈希表[]中的所有条目
初始化为
NULL
,因此不需要额外的检查。如果插槽为空,
np->next
接收
NULL
,否则
np
在列表前面。检查是关于哈希中的冲突,如果我理解,它将自动失败correctly@OznOg:一点也不,支票是多余的hashtable是一个插槽数组,每个插槽都有一个具有相同hashvalue的节点列表。上面的代码将节点插入列表开头的适当插槽中。谢谢!您帮了我很多忙。在实现代码之前,我将花时间回顾和理解代码。