【问题标题】:Hashtable words get overwritten in C哈希表单词在 C 中被覆盖
【发布时间】:2013-11-10 22:10:08
【问题描述】:

我是第一次使用哈希表,我想我对它们的工作原理有了基本的了解。我正在使用哈希表来检查文件中是否存在单词。该程序接收一个“字典”文件和一个单词检查文件。当我有一本小字典时,该程序运行良好,但当我使用非常大的字典时,单词会被覆盖。我希望能对原因有所了解。这是我的代码:

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <pthread.h>
#include <tgmath.h>
#include <ctype.h>
#include "hashtable_constants.h"


#define HASH_SIZE 500
#define MAX_WORD_SIZE 50

struct hashTable {
    int collisions;
    char** words;
};

struct hashTable hashTables[HASH_SIZE];

int hashKey(char * str)
{
    int key = 0;
    for(int j = 0; j <= 51; j++)
    {
        if(str[j] == '\0')
            break;

        key += (int)str[j];
    }
    key = key % HASH_SIZE;
    return key;
}

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

    if(argc > 3)
    {
        fprintf(stderr, "Too many arguments!\n");
        return -1;
    }
    else if(argc < 3)
    {
        fprintf(stderr, "Not enough arguments!\n");
        return -1;
    }

    FILE *dictionary = fopen(argv[1], "r");
    FILE *wordCheck = fopen(argv[2], "r");

    if(dictionary == NULL || wordCheck == NULL ) //ensure input file exists
    {
        fprintf(stderr, "Error accessing input files\n");
        return -1;
    }

    for(int i = 0; i < HASH_SIZE; i++)
    {
        hashTables[i].collisions = 0;
        hashTables[i].words = malloc(HASH_SIZE * MAX_WORD_SIZE);
    }

    struct stat fileStat1;
    struct stat fileStat2;

    stat(argv[1], &fileStat1);
    stat(argv[2], &fileStat2);

    char* dictBuffer = (char*)malloc(fileStat1.st_size + 1);
    char* wordCheckBuff = (char*)malloc(fileStat2.st_size + 1);

    if (dictBuffer == NULL || wordCheckBuff == NULL) 
    {
        fprintf (stderr, "Memory error");
        return -1;
    }

    fread(dictBuffer, 1, (int)fileStat1.st_size, dictionary);
    fread(wordCheckBuff, 1, (int)fileStat2.st_size, wordCheck);

    char* word = malloc(MAX_WORD_SIZE + 1);
    int count = 0;

    for(int i = 0; i < (int)fileStat1.st_size; i++)
    {
        char c = dictBuffer[i];
        if(isspace(c))
        {
            word[count] = '\0';
            char* wordToAdd = word;
            int key = hashKey(wordToAdd);
            int collisionIndex = hashTables[key].collisions; 
            hashTables[key].words[collisionIndex] = wordToAdd;
            hashTables[key].collisions++;   
            count = 0;

            free(word);
            word = malloc(MAX_WORD_SIZE + 1);

            //printf("Added: %s to hashtable at key: %d\n",word,key);
        }
        else
        {
            word[count] = c;
            count++;
        }
    }

    count = 0;

    for(int i = 0; i < (int)fileStat2.st_size; i++)
    {
        char c = wordCheckBuff[i];
        if(isspace(c))
        {
            word[count] = '\0';
            char* wordToCheck = word;
            int key = hashKey(wordToCheck);
            int collisionIndex = hashTables[key].collisions;
            int foundWord = 0;

            for(int j = 0; j < collisionIndex; j++)
            {
                if(hashTables[key].words[j] == wordToCheck)
                {
                    printf("%s == %s\n",hashTables[key].words[j], wordToCheck);
                    foundWord = 1;
                    break;
                }
            }

            if(foundWord == 0)
                printf("Not a word: %s\n", wordToCheck);
            /*else
                printf("Key: %d -- Is a word: %s\n",key, word);*/

            free(word);
            word = malloc(MAX_WORD_SIZE + 1);
            count = 0;
        }
        else
        {
            word[count] = c;
            count++;
        }
    }

    for(int i = 0; i < HASH_SIZE; i++)
        free(hashTables[i].words);

    free(word);
    fclose(dictionary);
    fclose(wordCheck);      

    printf("done\n");

    return 0;   
}

【问题讨论】:

    标签: c memory dictionary hashtable


    【解决方案1】:

    问题在于:

    hashTables[key].words[collisionIndex] = wordToAdd;
    

    您将“wordToAdd”添加到表中。

    但是 wordToAdd 等于 word。几行之后你调用

    free(word);
    

    所以哈希表现在拥有一个指向已释放内存的指针。

    这将导致程序中出现各种未定义的行为,也很可能是段错误。而且很可能由于内存现在是“空闲的”,随后对 malloc 的调用可能会再次返回相同的指针 - 然后您将用另一个单词填充该指针。因此,您会看到字符串被覆盖。

    你需要回顾一下你在程序中一般是如何使用“malloc”/“free”的。如果您希望指针指向有效字符串,则不能在该字符串的预期生命周期内对该指针调用“free”。

    你想要做的是 malloc 每个字符串,并添加指向哈希表的指针。然后,当您完成哈希表并且不再需要字符串数据时,对其中包含的所有指针调用“free”。在您的情况下,这可能需要在程序执行结束时出现在您的清理代码中。

    【讨论】:

    • +1 这绝对是问题所在。那条线应该只是hashTables[key].words[collisionIndex] = word;,根本没有free()。实际上,这种设计有点低调,因为除非您已经知道这个词,否则甚至不应该分配内存。 IE。循环外的第一个分配根本不应该在那里,循环中的分配应该在文件缓冲区中找到字符串内容之后。 然后添加到哈希表中。
    • 谢谢。从 c# 到 c 是一个艰难的过渡。那么我不需要为要添加到哈希表中的单词分配内存吗?
    • 您确实需要为添加的每个单词分配内存,只是在您真正完成之前不要释放它。因为 C 中没有自动内存管理,所以您必须非常小心地了解每个对象的确切生命周期。如果您创建一个指针,将其分配给一块内存,然后存储该指针,则在您真正完成该内存块中的数据之前,您不得对该指针调用“free”。
    猜你喜欢
    • 1970-01-01
    • 2020-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-17
    • 1970-01-01
    • 1970-01-01
    • 2015-09-27
    相关资源
    最近更新 更多