Я написал программу для поиска самого длинного предложения в нескольких текстовых файлах:
/* lngst_sentence_file_competition.c */
#include <stdio.h>
#include <stdlib.h>
enum consts {
str_len = 5
};
typedef struct tag_item {
int sentence_length;
char *sentence;
struct tag_item *next;
} item;
void free_str_if_it_is_not_lngst(
char **str, char **lngst_file_str, int *curr_sentence_len,
int *file_lngst_sentence_len
)
{
if (*curr_sentence_len <= *file_lngst_sentence_len)
free(*str);
else {
if (*lngst_file_str) {
free(*lngst_file_str);
*lngst_file_str = NULL;
}
*lngst_file_str = *str;
*file_lngst_sentence_len = *curr_sentence_len;
}
*curr_sentence_len = 0;
*str = NULL;
}
void find_lngst_sentence_in_next_file(
FILE *file, char **lngst_file_str, int *lngst_sentence_len
)
{
char *str = malloc(str_len*sizeof(char));
int str_mem_size = str_len;
int c;
int curr_sentence_len = 0;
int file_lngst_sentence_len = 0;
while ((c=fgetc(file)) != EOF) {
switch (c) {
case '.':
str[curr_sentence_len] = '.';
str[curr_sentence_len + 1] = '\0';
free_str_if_it_is_not_lngst(
&str, lngst_file_str, &curr_sentence_len,
&file_lngst_sentence_len
);
str = malloc(str_len*sizeof(char));
str_mem_size = str_len;
/* falls through */
case '\n':
case '\t':
continue;
}
curr_sentence_len++;
if (curr_sentence_len+1 == str_mem_size) {
str = realloc(str, str_mem_size + str_len);
str_mem_size += str_len;
}
str[curr_sentence_len - 1] = c;
}
free_str_if_it_is_not_lngst(
&str, lngst_file_str, &curr_sentence_len, &file_lngst_sentence_len
);
if (*lngst_sentence_len < file_lngst_sentence_len)
*lngst_sentence_len = file_lngst_sentence_len;
}
int main(int argc, char **argv)
{
FILE *file;
item *first = NULL;
int lngst_sentence_len = 0;
int i;
for (i=1; i < argc; i++) {
char *str = NULL;
file = fopen(argv[i], "r");
if (!file) {
perror(argv[i]);
exit(1);
}
find_lngst_sentence_in_next_file(file, &str, &lngst_sentence_len);
printf("%s\nString length is %d.\n", str, lngst_sentence_len);
/* add_new_element_to_linked_list(&first, str); */
}
/* print_sentences(first); */
return 0;
}
Я также написал небольшой тестовый файл test.txt:
a.
ab.
abc.
Я запустил свою программу с помощью Valgrind:
valgrind --tool=memcheck --leak-check=full -s ./lngst_sentence_file_competition test.txt
Valgrind выдал следующий результат:
==359271==
abc.
String length is 3.
==359271==
==359271== HEAP SUMMARY:
==359271== in use at exit: 477 bytes in 2 blocks
==359271== total heap usage: 7 allocs, 5 frees, 5,612 bytes allocated
==359271==
==359271== 5 bytes in 1 blocks are definitely lost in loss record 1 of 2
==359271== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==359271== by 0x109389: find_lngst_sentence_in_next_file (lngst_sentence_file_competition.c:53)
==359271== by 0x1094F4: main (lngst_sentence_file_competition.c:87)
==359271==
==359271== LEAK SUMMARY:
==359271== definitely lost: 5 bytes in 1 blocks
==359271== indirectly lost: 0 bytes in 0 blocks
==359271== possibly lost: 0 bytes in 0 blocks
==359271== still reachable: 472 bytes in 1 blocks
==359271== suppressed: 0 bytes in 0 blocks
==359271== Reachable blocks (those to which a pointer was found) are not shown.
==359271== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==359271==
==359271== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Может ли кто-нибудь увидеть источник утечки памяти?
По-моему, я правильно освободил всю выделенную память.
Memcheck сообщил вам, что это ==359271== by 0x109389: find_lngst_sentence_in_next_file (lngst_sentence_file_competition.c:53).
И у вас также есть 472 байта, которые все еще доступны. Memcheck предложил вам повторить запуск с помощью --show-leak-kinds=all.
@Computable Спасибо :) Это помогло мне исправить ошибку definitely lost: 5 bytes in 1 blocks. Хотя я не совсем понимаю, почему Valgrind пометил это как definitely lost, если указатель first указывал на данные в конце работы программы.
@Computable @PaulFloyd Интересно, что даже если я добавлю free(str); в качестве строки 90 (самый конец цикла for в функции main), даже тогда Valgrind покажет, что у меня есть HEAP SUMMARY: in use at exit: 472 bytes in 1 blocks total heap usage: 7 allocs, 6 frees, 5,612 bytes allocated. Если мы воспользуемся GDB и установим точки останова для всех функций mallocs и frees, мы увидим, что на самом деле у нас есть 4 выделения и 4 освобождения соответственно. Кроме того, я понятия не имею, как у меня может остаться 472 байта в 1 блоке, если все мои malloc выделяют только 5 байт памяти:/
У вас есть fopen, которого у вас нет fclose - fopen, по всей вероятности, выделяет память для блока FILE - и, естественно, можно ожидать, что он будет освобожден при правильном закрытии. Вам следует добавить это внутри цикла в конце, поскольку вы обрабатываете несколько файлов.





В общей куче использования у вас есть 7 выделенных мест и 5 освобожденных, последние два оставшихся связаны с файлом указателя файла и указателем str.
В начале цикла for вы определяете указатель char как нулевой, после завершения цикла for все еще будет оставаться неиспользуемый указатель, поэтому поместите free(str) после printf(), таким образом при каждом новом взаимодействии вы выделит и освободит это пространство памяти. Кроме того, закройте указатель файла, поскольку при этом отключается пространство памяти, используемое для его чтения.
int main(int argc, char **argv)
{
FILE *file;
item *first = NULL;
int lngst_sentence_len = 0;
int i;
for (i=1; i < argc; i++) {
char *str = NULL;
file = fopen(argv[i], "r");
if (!file) {
perror(argv[i]);
exit(1);
}
find_lngst_sentence_in_next_file(file, &str, &lngst_sentence_len);
printf("%s\nString length is %d.\n", str, lngst_sentence_len);
/* add_new_element_to_linked_list(&first, str); */
free(str);
fclose(file);
}
/* print_sentences(first); */
return 0;
}
Может быть, самая длинная строка, являющаяся результатом функции, не освобождается? (просто используя название функции в качестве руководства). Вам придется освободить его в main.