Вопрос об освобождении памяти malloc() в C

Я прохожу курс CS50 (поэтому, пожалуйста, не давайте мне точный правильный ответ, но укажите мне правильное направление!

Я заставил свою программу (ниже) работать (хотя я не уверен, что сделал это «правильно»); он печатает 8 номерных знаков из plate.txt. Однако valgrind по-прежнему говорит мне, что я теряю несколько байтов. Я точно знаю, что это связано с тем, что моя «временная» вещь выделяет память в цикле. Я просто не знаю, как это исправить. Если бы кто-нибудь мог указать мне в правильном направлении, это было бы замечательно!

Валгринд:

==18649== HEAP SUMMARY:
==18649== in use at exit: 49 bytes in 7 blocks
==18649== total heap usage: 10 allocs, 3 frees, 4,624 bytes allocated
==18649==
==18649== 49 bytes in 7 blocks are definitely lost in loss record 1 of 1
==18649== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==18649== by 0x109257: main (license.c:39)
==18649==
==18649== LEAK SUMMARY:
==18649== definitely lost: 49 bytes in 7 blocks
==18649== indirectly lost: 0 bytes in 0 blocks
==18649== possibly lost: 0 bytes in 0 blocks
==18649== still reachable: 0 bytes in 0 blocks
==18649== suppressed: 0 bytes in 0 blocks
==18649==
==18649== For lists of detected and suppressed errors, rerun with: -s
==18649== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Код программы:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    // Check for command line args
    if (argc != 2)
    {
        printf("Usage: ./read infile\n");
        return 1;
    }

    // Create buffer to read into
    char buffer[7];

    // Create array to store plate numbers
    char *plates[8];

    // Create a pointer that will later point to a place in memory on the heap for strcpy
    char *temp = NULL;

    FILE *infile = fopen(argv[1], "r");

    if (infile == NULL)
    {
        printf("File not found.\n");
        return 1;
    }

    int idx = 0;

    while (fread(buffer, 1, 7, infile) == 7)
    {
        // Replace '\n' with '\0'
        buffer[6] = '\0';

        // Allocate memory to temporarily store buffer contents
        temp = malloc(sizeof(buffer));

        // Copy buffer contents to temp
        strcpy(temp, buffer);

        // Save plate number in array
        plates[idx] = temp;
        idx++;
    }

    fclose(infile);

    for (int i = 0; i < 8; i++)
    {
        printf("%s\n", plates[i]);
    }

    free(temp);

    return 0;
}

Я закрыл файл и освободил свое «временное» местоположение в куче. Тем не менее, я несколько раз использую malloc() temp, но не могу освободить (temp) несколько раз?

Все, что выделено с помощью malloc, в конечном итоге должно быть освобождено с помощью free, что, очевидно, здесь не так.

Jabberwocky 13.02.2023 15:03

Подсказка: вы освобождаете память только о последней тарелке.

Jabberwocky 13.02.2023 15:06

Рассмотрим это: вы вызываете malloc в цикле. Разве вы не должны также вызывать free в цикле?

Some programmer dude 13.02.2023 15:07

Учитывая, что пластин видимо всего 8 и каждая минимальной длины, нужно ли вообще динамически выделять память?

jarmod 13.02.2023 15:08

Не делай free(temp);. Подсказка: вместо освобождения каждого malloc'а temp.... вы сохранили их в другой переменной

Support Ukraine 13.02.2023 15:12

ОТ: for (int i = 0; i < 8; i++) Что будет, если в файле всего 2 пластины? Подсказка: возможно, idx может быть здесь полезен

Support Ukraine 13.02.2023 15:13

Независимо от вопроса, действительно ли номерные знаки состоят всего из 6 символов?

Lundin 13.02.2023 15:16

Почему вы сохраняете номерные знаки в массиве перед их печатью? Это расточительно, потому что программа не делает ничего, что требовало бы от нее одновременного хранения всех номеров в памяти. Динамическое размещение не сыграло бы здесь никакой роли, если бы вы просто печатали номерные знаки сразу после их чтения, а не сохраняли их в памяти, а затем печатали через отдельный цикл.

John Bollinger 13.02.2023 15:18

Распространенная ошибка при изучении malloc/free — забыть, что вы освобождаете память, а не указатель. Эта программа выделяет несколько разных блоков памяти и освобождает только последний.

user253751 13.02.2023 15:19

Но даже учитывая, что вы храните их все в памяти, почему вы используете динамическое распределение? Вы точно знаете, сколько тарелок вы предоставляете, и сколько места вы для них выделяете, а общее пространство очень мало. Ни одна из причин динамического размещения здесь отсутствует.

John Bollinger 13.02.2023 15:19

OT: Если вы хотите динамическое распределение для отдельной пластины, вам также следует выполнить динамическое распределение для этого char *plates[8];, чтобы вы могли обрабатывать любое количество пластин.

Support Ukraine 13.02.2023 15:22

Пожалуйста, не добавляйте «решено» в заголовок. Вместо этого сделайте то, что вы уже сделали: проголосуйте и примите ответ, который вам поможет.

justANewb stands with Ukraine 13.02.2023 15:40
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
12
109
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

free(temp); неверно, он просто удаляет последний выделенный элемент.

Поскольку вы вызвали malloc в цикле, вам также придется вызывать free в цикле. Эмпирическое правило заключается в том, что каждый mallocвызов должен сопровождаться freeвызовом.

Таким образом, вы должны сделать for цикл, перебирающий char *plates[8]; и free все, на что указывает каждый plates указатель.

Ответ принят как подходящий

Вам нужно освободить все выделенные указатели.

for(i = 0; i < idx; i++) 
   free(plates[i]);

Вы также можете очень легко выйти за пределы вашего массива, так как вы не проверяете индекс

 while (idx < 8 && fread(buffer, 1, 7, infile) == 7)

Печать также неверна, поскольку вы предполагаете, что прочитали все 8 фрагментов.

    for (int i = 0; i < idx; i++)
    {
        printf("%s\n", plates[i]);
    }


Другие вопросы по теме