Я прохожу курс 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
в цикле?
Учитывая, что пластин видимо всего 8 и каждая минимальной длины, нужно ли вообще динамически выделять память?
Не делай free(temp);
. Подсказка: вместо освобождения каждого malloc'а temp
.... вы сохранили их в другой переменной
ОТ: for (int i = 0; i < 8; i++)
Что будет, если в файле всего 2 пластины? Подсказка: возможно, idx
может быть здесь полезен
Независимо от вопроса, действительно ли номерные знаки состоят всего из 6 символов?
Почему вы сохраняете номерные знаки в массиве перед их печатью? Это расточительно, потому что программа не делает ничего, что требовало бы от нее одновременного хранения всех номеров в памяти. Динамическое размещение не сыграло бы здесь никакой роли, если бы вы просто печатали номерные знаки сразу после их чтения, а не сохраняли их в памяти, а затем печатали через отдельный цикл.
Распространенная ошибка при изучении malloc/free — забыть, что вы освобождаете память, а не указатель. Эта программа выделяет несколько разных блоков памяти и освобождает только последний.
Но даже учитывая, что вы храните их все в памяти, почему вы используете динамическое распределение? Вы точно знаете, сколько тарелок вы предоставляете, и сколько места вы для них выделяете, а общее пространство очень мало. Ни одна из причин динамического размещения здесь отсутствует.
OT: Если вы хотите динамическое распределение для отдельной пластины, вам также следует выполнить динамическое распределение для этого char *plates[8];
, чтобы вы могли обрабатывать любое количество пластин.
Пожалуйста, не добавляйте «решено» в заголовок. Вместо этого сделайте то, что вы уже сделали: проголосуйте и примите ответ, который вам поможет.
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]);
}
Все, что выделено с помощью
malloc
, в конечном итоге должно быть освобождено с помощьюfree
, что, очевидно, здесь не так.