C утечка памяти, несмотря на

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

    row = malloc(sizeof(Row));
    row->columns = malloc(sizeof(char*) * headcnt);
    row->numcol  = 0;

    ...

    row->numcol    = colcnt;
    rows           = realloc(rows, (rowcnt+1) * sizeof(Row));
    rows[rowcnt++] = *row;

Код, ответственный за освобождение памяти:

void cleanUp(){
    int i = 0;
    int j = 0;

    for (i = 0; i < rowcnt; i++){
        for (j = 0; j < rows[i].numcols; j++){
            free(rows[i].columns[j]);
        }
        free(&rows[i]);
    }
    free(rows); 
    exit(0);
}

Объявление строки:

typedef struct {
    char** columns;
    unsigned short int numcol;
} Row;

Row* rows = NULL;

Хуже того, эта программа иногда вызывает ошибку glibc в free(&rows[i]), которая жалуется на двойную свободную. Я новичок в C, и буду благодарен за любые указатели (гм), которые могут быть у кого-то.

Ответ 1

Выполнение rows[rowcnt++] = *row; эффективно делает копию выделенной вами памяти. Строки массива должны быть массивом указателей. Также, как отметил Оли Чалсуорт, вы бесплатно для столбцов должны быть свободными для всех столбцов.

rows = malloc(count * sizeof(Row*)); // This is probably done somewhere

row->columns = malloc(sizeof(char*) * headcnt);
row->numcol  = 0;

...

row->numcol    = colcnt;
rows           = realloc(rows, (rowcnt+1) * sizeof(Row*));
rows[rowcnt++] = row;

Теперь, если ваша очистка

void cleanUp(){
    int i = 0;
    int j = 0;

    for (i = 0; i < rowcnt; i++){
        free(rows[i]->columns);
    }
    free(rows); 
    exit(0);
}

Ответ 2

Каждый вызов malloc (или realloc) должен совпадать с соответствующим вызовом free. Если вы динамически выделяете массив таким образом:

int *p = malloc(sizeof(int) * NUM);

Вы освобождаете его так:

free(p);

Не так:

for (int i = 0; i < NUM; i++)
{
    free(p[i]);
}

Похоже, вы делаете это неправильно. Я подозреваю, что ваш код очистки должен быть:

void cleanUp(){
    int i = 0;
    int j = 0;

    for (i = 0; i < rowcnt; i++){
        for (j = 0; j < rows[i].numcols; j++){
            free(rows[i].columns[j]); // Free whatever rows[i].columns[j] points to
        }
        free(rows[i].columns); // Matches row->columns = malloc(sizeof(char*) * headcnt);
    }
    free(rows);  // Matches rows = realloc(rows, (rowcnt+1) * sizeof(Row));
    exit(0);
}

Кроме того, нет способа сопоставления row = malloc(sizeof(Row));. Я подозреваю, что ваш код распределения должен быть:

row->numcol    = colcnt;
rows           = realloc(rows, (rowcnt+1) * sizeof(Row));
rows[rowcnt].columns = malloc(sizeof(char*) * headcnt);
rows[rowcnt].numcol = 0;
rowcnt++;

Ответ 3

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