Правильный способ освобождения двойного указателя на структуру - PullRequest
2 голосов
/ 19 января 2020

Я пытаюсь добавить освобождение памяти к старому C коду. У меня есть таблица пользовательских объектов ha sh (HASHRE C). После анализа текущего кода и прочтения других вопросов SO я знаю, что мне нужно предоставить три уровня освобождения. Первый член слова, затем HASHRE C*, а затем HASHRE C**.

Моя версия функции free_table () освобождает упомянутые объекты. К сожалению, Valgrind все еще жалуется, что некоторые байты потеряны.

Я не могу предоставить полный код, он будет слишком длинным, но я представляю, как HASHRE C ** vocab_ha sh заполняется внутри inithashtable () и 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;
}

1 Ответ

4 голосов
/ 19 января 2020

Я предполагаю, что проблема здесь:

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);
}
...