在C链表遍历中删除条目和释放bucket节点时出错

在C链表遍历中删除条目和释放bucket节点时出错,c,memory-management,linked-list,free,traversal,C,Memory Management,Linked List,Free,Traversal,我试图开发一个带有链式链表哈希的哈希表来弥补冲突,但我的remove_entry函数似乎有一个错误。我几乎只使用指针,因此我会根据需要动态分配和释放内存 以下是我的表和Bucket数据类型的结构: typedef struct bucket { char *key; void *value; struct bucket *next; } Bucket; typedef struct { int key_count; int table_size; void (*free_va

我试图开发一个带有链式链表哈希的哈希表来弥补冲突,但我的remove_entry函数似乎有一个错误。我几乎只使用指针,因此我会根据需要动态分配和释放内存

以下是我的表和Bucket数据类型的结构:

typedef struct bucket {
char *key;
void *value;
struct bucket *next;
} Bucket;

typedef struct {
   int key_count;
   int table_size;
   void (*free_value)(void *);
   Bucket **buckets;
} Table;
这是我的删除函数。我试图加入评论来解释发生了什么:

int remove_entry(Table *table, const char *key) {

    int hash;
    Bucket *cur, *prev;

    if (table == NULL || key == NULL) {
        return FAILURE;
    }

    hash = hash_code(key) % (table->table_size);

    /* case: key not present at lead bucket position */
    if (table->buckets[hash] == NULL) {
        return FAILURE;

    } else {
        cur = table->buckets[hash];
        /* traverse thru the chain from table->buckets[hash]
         * to see if the key exists somewhere. loop only can run the 
         * first time if its key does not match the paramteter key, so
         * if they do match then we proceed to the logic below this
         * loop (2nd if statement), acting on the FIRST (lead) bucket */
        while (strcmp(cur->key, key) != 0 && cur != NULL) {
            prev = cur;
            cur = cur->next;
        }

        /* case - key not found anywhere (cur == null) */
        if (cur == NULL) {
            return FAILURE;
        }
        /* case - key found in chain (strcmp returned 0, keys match) */
        if (strcmp(cur->key, key) == 0) {
            if (table->free_value != NULL) {
                table->free_value(cur->value);
                cur->value = NULL;
            }
            free(cur->key);
            cur->key = NULL;
            if (cur->next != NULL) {
                prev->next = cur->next;
            }
            free(cur);
            cur = NULL;
            table->key_count -= 1;
            return SUCCESS;
        }
    }
    return FAILURE;
}
valgrind告诉我在函数的底部调用free on cur有一个问题,但我不明白为什么会有这个问题。我发现的总体问题是,即使cur发生了变化,相应索引散列中的bucket地址也不会发生变化


提前谢谢

我认为您的错误涉及在存在多个存储桶时删除第一个存储桶

在此代码段中:

 cur = table->buckets[hash];
 while (strcmp(cur->key, key) != 0 && cur != NULL) {
     prev = cur;
     cur = cur->next;
 }
如果key确实等于cur指针指向的第一个bucket,那么WHILE循环的内部代码永远不会被调用。结果是指针prev未定义。。。您从未将其预先设置为NULL,也没有在绕过的循环中设置它

接下来的代码片段是:

if (cur->next != NULL) {
    prev->next = cur->next;
}
将失败,因为prev中要么有零NULL,要么有一些未定义的内存位置存储在其中

此外,上述代码片段的逻辑也不太正确;如果这是最后一个被删除的bucket,因此cur->next确实等于NULL,那么您仍然希望将该NULL移回prev->next或列表头,以便prev知道它现在是链接列表的末尾

当第一个bucket被移除时,您也无法解释需要重置链表标题而不是prev->next的情况。这是一个常见的错误,就在本周,我最近已经回答了好几次了

因此,我认为您需要将代码更改为:

int remove_entry(Table *table, const char *key) {

    int hash;
    Bucket *cur;
    Bucket *prev = NULL;

    if (table == NULL || key == NULL) {
        return FAILURE;
    }

    hash = hash_code(key) % (table->table_size);

    /* case: key not present at lead bucket position */
    if (table->buckets[hash] == NULL) {
        return FAILURE;

    } else {
        cur = table->buckets[hash];
        /* traverse thru the chain from table->buckets[hash]
         * to see if the key exists somewhere. loop only can run the 
         * first time if its key does not match the paramteter key, so
         * if they do match then we proceed to the logic below this
         * loop (2nd if statement), acting on the FIRST (lead) bucket */
        while (strcmp(cur->key, key) != 0 && cur != NULL) {
            prev = cur;
            cur = cur->next;
        }

        /* case - key not found anywhere (cur == null) */
        if (cur == NULL) {
            return FAILURE;
        }
        /* case - key found in chain (strcmp returned 0, keys match) */
        if (strcmp(cur->key, key) == 0) {
            if (table->free_value != NULL) {
                table->free_value(cur->value);
                cur->value = NULL;
            }
            free(cur->key);
            cur->key = NULL;
            if (prev != NULL) {
                prev->next = cur->next;  // even want to copy-back when cur->next == NULL
            }
            else
            {
                table->buckets[hash] = cur->next;  // even want to copy-back when cur->next == NULL
            }
            free(cur);
            cur = NULL;
            table->key_count -= 1;
            return SUCCESS;
        }
    }
    return FAILURE;
}
我不知道为什么freecur会给你一个错误,但是一旦你修复了正确处理链表的代码,并且没有一个未正确初始化的prev指针,你就可以找出仍然错误的地方


还有一个小问题,您真的不需要以下独立的IF语句:IF strcmptur->key,key==0{.WHILE循环退出时,只有两个条件是cur decision==NULL,或者strcpcur->key,key decision==0。您不需要第二个IF语句。它没有错,只是效率有点低。

此外,尽管这是一个小点,成功是将“d”定义为1,失败是将“d”定义为-1