当 C 中发生冲突(使用单独的链接)时,无法释放哈希表中的节点

标签 c memory-management hash hashtable free

好的,我有一个用 C 语言制作的哈希表。我使用单独的链接(链表)来解决冲突。我注意到如果没有冲突并且每个项目都散列到它自己的索引,我可以释放整个表。但是如果发生冲突并且我在一个索引处有多个值,它只能释放第一个值而不是该索引中的其余值。该程序在尝试释放该索引处的其他程序时崩溃。我尝试调试它,我意识到那些其他值已设置为 NULL,我不确定这是为什么,因为当我将它们插入到表中时,我使用的是 malloc。我知道我错过了什么。如果有人可以提供帮助那将是非常棒的,因为我已经尝试解决这个问题几个小时了:/

代码如下:

int symTabSearch(struct hashTable * h, char * label);
int insertToSymTab(struct hashTable * h, char * label, int locctr);

struct listNode
{
    char * label;
    int address;
    struct listNode * next;
};

struct hashTableNode
{
    int blockCount;         //number of elements in a block
    struct listNode * firstNode;
};

struct hashTable
{
    int tableSize;
    int count;              //number of elements in the table
    struct hashTableNode * table;
};

struct hashTable * createHashTable(int size)
{
    struct hashTable * ht;
    ht = (struct hashTable*)malloc(sizeof(struct hashTable));

    if (!ht)
        return NULL;

    ht->tableSize = size;
    ht->count = 0;
    ht->table = (struct hashTableNode *)malloc(sizeof(struct hashTableNode) * ht->tableSize);

    if (!ht->table)
    {
        printf("Memory error\n");
        return NULL;
    }

    int i;
    for (i = 0; i < ht->tableSize; i++)
    {
        ht->table[i].blockCount = 0;
        ht->table[i].firstNode = NULL;
    }

    return ht;
}

/*hash function: adds up the ascii values of each
character, multiplies by a prime number (37) and mods the sum wih the table size*/
int hash(char * label, int tableSize)
{
    int hashVal = 0;
    size_t i;

    for (i = 0; i < strlen(label); i++)
        hashVal = 37 * hashVal + label[i];

    hashVal %= tableSize;
    if (hashVal < 0)
        hashVal += tableSize;

    return hashVal;
}

int symTabSearch(struct hashTable * h, char * label)
{
    struct listNode * temp;
    temp = h->table[hash(label, h->tableSize)].firstNode; //temp points to the first listNode in table[hashedIndex]

    while (temp)
    {
        if (strcmp(temp->label, label) == 0)
            return 1;   //found

        temp = temp->next;      //go to next link
    }
    return 0;   //not found
}

int insertToSymTab(struct hashTable * h, char * label, int locctr)
{
    int index;
    struct listNode * currentNode, *newNode;

    index = hash(label, h->tableSize);
    currentNode = h->table[index].firstNode;

    newNode = (struct listNode *)malloc(sizeof(struct listNode));
    newNode->label = (char *)malloc(sizeof(char) * 7);  //allocates 7 chars to store label up to 6 chars long (0-5), last one is for the '\0'

    if (!newNode)   //if new node is null
    {
        printf("Error creating new node\n");
        return 0;
    }

    strcpy(newNode->label, label);
    newNode->address = locctr;

    if (h->table[index].firstNode == NULL)      //if first node at table index is empty
    {
        h->table[index].firstNode = newNode;
        h->table[index].firstNode->next = NULL;
    }
    else
    {                                           //firstNode was not empty, so chain newNode to the next empty node
        while (currentNode != NULL)             //go to next available node
            currentNode = currentNode->next;

        currentNode = newNode;
        currentNode->next = NULL;
    }

    h->table[index].blockCount++;
    h->count++;
    return 1;
}

void freeHashTable(struct hashTable * h)        //might not free memory properly, might crash too, test later
{
    int i, j;
    struct listNode * current, *temp;
    char * tempStr;

    if (!h)     //make sure table even has memory to be freed
        return;

    for (i = 0; i < h->tableSize; i++)
    {
        current = h->table[i].firstNode;
        for (j = 0; j < h->table[i].blockCount; j++)
        {
            temp = current;
            tempStr = current->label;
            current = current->next;
            free(temp);
            free(tempStr);
            temp = NULL;
            tempStr = NULL;
        }
    }

    free(h->table);
    h->table = NULL;
    free(h);
    h = NULL;
}

最佳答案

当您尝试将节点附加到列表时,问题出在 insertToSymTab 函数中。

这里的问题是这个循环:

while (currentNode != NULL)             //go to next available node
    currentNode = currentNode->next;

当该循环完成时,您已传递 列表的末尾并且currentNode 的值为NULL。更改该指针不会将新节点附加到列表的末尾。

相反,您需要将循环更改为例如

while (currentNode->next != NULL)
    currentNode = currentNode->next;

然后当循环结束时,currentNode 将成为列表中当前的最后一个节点,您可以通过更改 currentNode->next 来附加新节点:

currentNode->next = newNode;

不要忘记将 newNode->next 设置为 NULL

关于当 C 中发生冲突(使用单独的链接)时,无法释放哈希表中的节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33361834/

相关文章:

c - Atmega16 [预期;当将输出名称与数字一起使用时,在数字常量之前]

c - c 中的结构和文件

c - linux 上的 malloc 特定地址或页面(指定一个 "minimum offset")

ajax - 使用 URL 哈希保留 Ajax 页面状态

ruby - 为什么不能直接在 Ruby 中打印散列?

c - 为什么 builtin_expect 取的是 long 而不是 bool?

c - 堆、栈、文本等不同段与物理内存有何关系?

字符串的 Java GC 调优

c++ - 使用 OpenCV 读取视频帧到指定指针 (C++)

ruby - 使用函数填充 Ruby 哈希