将双指针释放到结构的正确方法
Proper way of deallocation of double pointer to struct
我正在尝试向旧 C 代码添加内存释放。
我有自定义对象 (HASHREC) 的散列 table。在分析当前代码并阅读其他 SO 问题后,我知道我需要提供三个级别的释放。 Fist - 单词成员,下一个是 HASHREC*,然后是 HASHREC**。
我的 free_table() 函数版本释放了提到的对象。不幸的是,Valgrind 仍然抱怨一些字节丢失了。
我无法提供完整的代码,它会太长,但我正在展示如何在 initithashtable()[ 中填充 HASHREC **vocab_hash =20=] 和 hashinsert()。
你能给我一个建议,我应该如何修复 free_table() 吗?
typedef struct hashrec {
char *word;
long long count;
struct hashrec *next;
} HASHREC;
HASHREC ** inithashtable() {
int i;
HASHREC **ht;
ht = (HASHREC **) malloc( sizeof(HASHREC *) * TSIZE );
for (i = 0; i < TSIZE; i++) ht[i] = (HASHREC *) NULL;
return ht;
}
void hashinsert(HASHREC **ht, char *w) {
HASHREC *htmp, *hprv;
unsigned int hval = HASHFN(w, TSIZE, SEED);
for (hprv = NULL, htmp = ht[hval]; htmp != NULL && scmp(htmp->word, w) != 0; hprv = htmp, htmp = htmp->next);
if (htmp == NULL) {
htmp = (HASHREC *) malloc( sizeof(HASHREC) ); //<-------- problematic allocation (Valgrind note)
htmp->word = (char *) malloc( strlen(w) + 1 );
strcpy(htmp->word, w);
htmp->next = NULL;
if ( hprv==NULL ) ht[hval] = htmp;
else hprv->next = htmp;
}
else {/* new records are not moved to front */
htmp->count++;
if (hprv != NULL) { /* move to front on access */
hprv->next = htmp->next;
htmp->next = ht[hval];
ht[hval] = htmp;
}
}
return;
}
void free_table(HASHREC **ht) {
int i;
HASHREC* current;
HASHREC* tmp;
for (i = 0; i < TSIZE; i++){
current = ht[i];
while(current != NULL) {
tmp = current;
current = current->next;
free(tmp->word);
}
free(ht[i]);
}
free(ht);
}
int main(int argc, char **argv) {
HASHREC **vocab_hash = inithashtable();
// ...
hashinsert(vocab_hash, w);
//....
free_table(vocab_hash);
return 0;
}
我认为问题出在这里:
current = ht[i];
while(current != NULL) {
tmp = current;
current = current->next;
free(tmp->word);
}
free(ht[i]);
你释放了word
但你没有释放tmp
。在释放链表中的第一项但不释放导致泄漏的其他项之后。
在那里释放 tmp
,之后不要释放 ht[i]
,因为它已经在这里释放了。
current = ht[i];
while(current != NULL) {
tmp = current;
current = current->next;
free(tmp->word);
free(tmp);
}
我正在尝试向旧 C 代码添加内存释放。 我有自定义对象 (HASHREC) 的散列 table。在分析当前代码并阅读其他 SO 问题后,我知道我需要提供三个级别的释放。 Fist - 单词成员,下一个是 HASHREC*,然后是 HASHREC**。
我的 free_table() 函数版本释放了提到的对象。不幸的是,Valgrind 仍然抱怨一些字节丢失了。
我无法提供完整的代码,它会太长,但我正在展示如何在 initithashtable()[ 中填充 HASHREC **vocab_hash =20=] 和 hashinsert()。 你能给我一个建议,我应该如何修复 free_table() 吗?
typedef struct hashrec {
char *word;
long long count;
struct hashrec *next;
} HASHREC;
HASHREC ** inithashtable() {
int i;
HASHREC **ht;
ht = (HASHREC **) malloc( sizeof(HASHREC *) * TSIZE );
for (i = 0; i < TSIZE; i++) ht[i] = (HASHREC *) NULL;
return ht;
}
void hashinsert(HASHREC **ht, char *w) {
HASHREC *htmp, *hprv;
unsigned int hval = HASHFN(w, TSIZE, SEED);
for (hprv = NULL, htmp = ht[hval]; htmp != NULL && scmp(htmp->word, w) != 0; hprv = htmp, htmp = htmp->next);
if (htmp == NULL) {
htmp = (HASHREC *) malloc( sizeof(HASHREC) ); //<-------- problematic allocation (Valgrind note)
htmp->word = (char *) malloc( strlen(w) + 1 );
strcpy(htmp->word, w);
htmp->next = NULL;
if ( hprv==NULL ) ht[hval] = htmp;
else hprv->next = htmp;
}
else {/* new records are not moved to front */
htmp->count++;
if (hprv != NULL) { /* move to front on access */
hprv->next = htmp->next;
htmp->next = ht[hval];
ht[hval] = htmp;
}
}
return;
}
void free_table(HASHREC **ht) {
int i;
HASHREC* current;
HASHREC* tmp;
for (i = 0; i < TSIZE; i++){
current = ht[i];
while(current != NULL) {
tmp = current;
current = current->next;
free(tmp->word);
}
free(ht[i]);
}
free(ht);
}
int main(int argc, char **argv) {
HASHREC **vocab_hash = inithashtable();
// ...
hashinsert(vocab_hash, w);
//....
free_table(vocab_hash);
return 0;
}
我认为问题出在这里:
current = ht[i];
while(current != NULL) {
tmp = current;
current = current->next;
free(tmp->word);
}
free(ht[i]);
你释放了word
但你没有释放tmp
。在释放链表中的第一项但不释放导致泄漏的其他项之后。
在那里释放 tmp
,之后不要释放 ht[i]
,因为它已经在这里释放了。
current = ht[i];
while(current != NULL) {
tmp = current;
current = current->next;
free(tmp->word);
free(tmp);
}