Куча не освобождается в C

Это мой фрагмент кода. Я получаю сообщение об ошибке при попытке освободить выделенную память.

int main()
{
    int value = 10; 
    totValues = pow(2, value);
    head = (node_t *)calloc(totValues, sizeof(node_t));
    createNode(head, 10, 20);
    free(head);
}

void createList(node_t *head, int tag, int index)
{
      node_t temp = (node_t) calloc(1, sizeof(sizeof(node_t)));
      temp->tag = tag;
      temp->next = head[index];
      head[index] = temp;
      free(temp);
 }

Я пытаюсь освободить головной и временный узел, но это не работает, и я вижу ошибки. Я отслеживаю утечки памяти с помощью valgrind. Не уверен, что делаю не так.


person rampuriyaaa    schedule 13.10.2016    source источник
comment
Во-первых, хотя вы не показали totValues, я подозреваю, что calloc(sizeof(totValues), sizeof(node_t)); должно быть calloc(totValues, sizeof(node_t));   -  person Weather Vane    schedule 14.10.2016
comment
Почему ты делаешь sizeof(sizeof(node_t))? Удвоение оператора sizeof - это не то, что вам нужно.   -  person callyalater    schedule 14.10.2016
comment
Я поправил, но все равно куча занята   -  person rampuriyaaa    schedule 14.10.2016
comment
Вы не должны освобождать temp, так как вы помещаете его в список с помощью head[index] = temp;.   -  person Barmar    schedule 14.10.2016
comment
Зачем вы выделяете память, заполняете ее полезной информацией, а затем освобождаете ?! Какой цели это служит?   -  person David Schwartz    schedule 14.10.2016
comment
даже если я не освобождаю темп, голова все равно выделяется ..   -  person rampuriyaaa    schedule 14.10.2016
comment
Да, но он ни на что не указывает.   -  person David Schwartz    schedule 14.10.2016
comment
Я завершил операцию, что хотел, мне больше не нужна память кучи, верно? мы должны явно освобождать динамически выделяемую память, верно?   -  person rampuriyaaa    schedule 14.10.2016
comment
sizeof(sizeof(node_t)) неверно. Он выделяет достаточно места только для одного int, поэтому вы пишете за пределами границ, когда делаете temp->next = head[index];   -  person Barmar    schedule 14.10.2016
comment
temp->next = head[index];, вероятно, должно быть temp->next = &head[index];.   -  person Barmar    schedule 14.10.2016
comment
Также node_t temp = (node_t) calloc(...) должен быть указателем (т.е. node_t* temp = (node_t*)calloc(...)).   -  person callyalater    schedule 14.10.2016
comment
@rampuriyaaa Операция заключалась в создании списка. Когда вы закончите создавать список, вы еще не закончили со списком! Вы не можете освободить его части, пока не закончите со списком.   -  person David Schwartz    schedule 14.10.2016
comment
Другое дело, вы хотите, чтобы head был указателем на группу узлов, верно? Тогда head, вероятно, должен быть node_t**, не так ли?   -  person callyalater    schedule 14.10.2016
comment
temp и head не являются узлами, это переменные, которые содержат адреса узлов.   -  person user253751    schedule 14.10.2016


Ответы (1)


В вашем примере есть несколько проблем. Вот посмотрите на ваш код с некоторыми исправлениями:

#include <math.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>

typedef struct node {
    int tag;
    struct node* next;
} node_t;

void createList(node_t**, int, int);

int main(int argc, char** argv)
{
    int value = 10; 
    int totValues = (int)pow(2, value);
    // `head` is an array of `node_t` pointers
    // (aka. it is a `node_t**` not a `node_t*`)
    node_t** head = (node_t**)calloc(totValues, sizeof(node_t*));
    createList(head, 10, 20);
    free(head);
    return 0;
}

void createList(node_t **head, int tag, int index)
{
    // You don't want `sizeof(sizeof(node_t))` because that is
    // equivalent to sizeof(size_t) which is implementation defined,
    // but usually equal to 4 or 8 depending on word size.
    node_t* temp = (node_t*)calloc(1, sizeof(node_t));
    temp->tag = tag;
    temp->next = head[index];
    head[index] = temp;
    // You fill `temp` with information, point a spot in `head` to
    // that pointer and then free the memory...
    // That makes no sense. Don't do it!
    free(temp);
}

Важно помнить, что free не освобождает рекурсивно память для двойного указателя: вам нужно будет сделать это самостоятельно.

Вы должны вызвать free на каждом узле в head, а затем на самом head:

createList(head, 10, 20);
free(head[20]); //Free the one node we created
free(head); // Free the array of nodes we created

и убедитесь, что вы закомментировали или удалили вызов free(temp); в функции createList.

Когда вы запустите valgrind на этом, утечек памяти больше не будет.

==6322== Memcheck, a memory error detector
==6322== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==6322== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==6322== Command: ./dynamic_memory
==6322== 
==6322== 
==6322== HEAP SUMMARY:
==6322==     in use at exit: 0 bytes in 0 blocks
==6322==   total heap usage: 2 allocs, 2 frees, 8,208 bytes allocated
==6322== 
==6322== All heap blocks were freed -- no leaks are possible
==6322== 
==6322== For counts of detected and suppressed errors, rerun with: -v
==6322== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
person callyalater    schedule 13.10.2016