我在C中有一个结构体,它模仿哈希表,除了它是一个链表数组。
数组的长度由hash_length
预先确定,并设置为2^hash_length
。
我的函数在这里应该释放所有由其各自的ht_create
函数分配的内存。通过循环链表数组,释放其所有节点,然后释放数组,然后释放哈希表本身。
然而,通过运行这段代码,我遇到了一个免费后堆使用。我相信问题在于我写函数本身的方式,但我似乎无法查明错误。我不确定这是否是足够的信息来确定一个问题,让我知道如果需要进一步澄清。
void ht_destroy(struct hashtable *ht) {
for(int i = 0; i < my_exp(2,ht->hash_length); ++i) {
struct llist *lst = &ht->list[i];
struct llnode *curnode = lst->front;
struct llnode *nextnode = NULL;
while (curnode) {
nextnode = curnode->next;
free(curnode->str);
free(curnode);
curnode = nextnode;
}
free(&ht->list[i]);
}
free(ht->list);
free(ht);
}
这应该是一个最小的可重复示例,它只是使用ht_create
创建一个哈希表,然后使用ht_destroy
释放内存
// my_exp(a,b): raises a to the bth power.
// Requires: b >= 0
int my_exp(int a, int b) {
if (b == 0) {
return 1;
}
int tot = a;
for (int i = 1; i < b; ++i) {
tot *= a;
}
return tot;
}
struct llnode {
char *str;
struct llnode *next;
};
struct llist {
struct llnode *front;
};
struct hashtable {
int hash_length;
struct llist *list;
};
struct hashtable *ht_create(int hash_length) {
struct hashtable *ht = malloc(sizeof(struct hashtable));
ht->list = malloc(my_exp(2,hash_length) * sizeof(struct llist));
ht->hash_length = hash_length;
for(int i = 0; i < my_exp(2,hash_length); ++i ){
(ht->list)[i].front = NULL;
}
return ht;
}
void ht_destroy(struct hashtable *ht) {
for(int i = 0; i < my_exp(2,ht->hash_length); ++i) {
struct llist *lst = &ht->list[i];
struct llnode *curnode = lst->front;
struct llnode *nextnode = NULL;
while (curnode) {
nextnode = curnode->next;
free(curnode->str);
free(curnode);
curnode = nextnode;
}
free(&ht->list[i]);
}
free(ht->list);
free(ht);
}
int main(void) {
struct hashtable *ht = ht_create(2);
ht_destroy(ht);
}
1条答案
按热度按时间68bkxrlz1#
这一行导致了未定义的行为:
ht->list[i]
是一个数组元素。数组ht->list
是动态分配的,但它的各个元素的地址不是,所以你不能释放它们。动态分配的元素在从ht->list[i].head
到达的链表中,你在while
循环中释放了它们。“use after free”是因为
&ht->list[0]
等价于ht->list
,所以for
循环的第一次迭代释放了整个数组,然后后续的迭代尝试使用该释放数组的元素。然后你再尝试使用free(ht->list)
释放它。删除上面的行。