Valgrind утечки памяти, недопустимый free()

#c #memory-leaks #valgrind

#c #утечки памяти #valgrind

Вопрос:

 typedef struct {
   int **a;
   int **b;
   int **c;
   int i;
} test_t;

test_t *create(int i) {
    test_t *test = malloc(i * sizeof(test_t));

    test->i = i;

    test->c = malloc(i * sizeof(int *));
    for (int j = 0; j < i;   j) {
        test->c[j] = malloc(sizeof(int *));
    }

    test->a = malloc(sizeof(int *));
    test->a = amp;(test->c[0]);
    test->b = malloc(sizeof(int *));
    test->b = amp;(test->c[0]);
    return test;
}

void delete(test_t *test) {
    free(test->a);
    free(test->b);
    for (int i = 0; i < test->i;   i)
        free(test->c[i]);
    free(test->c);
    free(test);
}

int main() {
    test_t *test;

    test = create(3);

    delete(test);

    return 0;
}
 

Что не так с этим кодом?

Когда я запускаю Valgrind, я получаю 5 ошибок и некоторые утечки памяти.

Я не вижу никакой утечки памяти, а вы?

Я получаю такие ошибки, как:

 Invalid free() / delete / delete[] / realloc()
Address 0x4a380e0 is 0 bytes inside a block of size 24 free'd
Block was alloc'd at
Invalid read of size 8
 

Кто-нибудь может мне помочь с этим, пожалуйста?

PS Код работает нормально, но у него есть утечки памяти, поэтому это не так.

Комментарии:

1. @dxiv Извините, опечатка. Посмотрите на это сейчас.

2. @JohnDoe скопируйте / вставьте только тот код, который вы тестировали.

3. ‘test-> a’ получает malloced, но затем перезаписывается в следующей строке. То же самое с test->b.

4. test->a = malloc(sizeof(int *)); test->a = amp;(test->c[0]); Как вы думаете, что это делает? Второе выражение перезаписывает malloc результат первого. Это приводит к утечке памяти. И когда вы освободите test->a его, он будет где-то внутри c . Это именно то, что говорит вам valgrind.

5. @kaylum хммм. Итак, test->a = some-address перезаписывает test->a адрес? Когда я пытаюсь printf это сделать, он не перезаписывается. Это странно. Я хотел бы сохранить адрес первого элемента в массиве в test->a и test->b .

Ответ №1:

Наблюдаю за этим…

     test->a = malloc(sizeof(int *));
    test->a = amp;(test->c[0]);
    test->b = malloc(sizeof(int *));
    test->b = amp;(test->c[0]);
 

Поскольку test->a и test->b немедленно переназначаются, mallocs не имеют никакого эффекта, кроме утечки памяти. Вышеизложенное должно быть простым…

     test->a = amp;(test->c[0]);
    test->b = amp;(test->c[0]);
 

При этом работает эмпирическое правило, согласно которому количество mallocs должно равняться количеству освобождений. Три mallocs, один в цикле. Три освобождения, одно в цикле.

 void delete(test_t *test) {
    for (int i = 0; i < test->i; i  ) {
        free(test->c[i]);
    }
    free(test->c);
    free(test);
    test->a = NULL;
    test->b = NULL;
}
 

test->a и test->b не должны быть освобождены, поскольку они занимают test->c[0] память. Нам также нужно избегать освобождения его дважды. Поскольку эта заимствованная память недействительна и больше не может использоваться, мы устанавливаем ее в NULL качестве меры предосторожности.