[英]Memory leaks when reading and transforming a file into a two-dimensional array in C
我正在 C 中寫一個 function 來加載一個文件作為雙維數組( char **
),問題是根據 Valgrind 我有 memory 泄漏,你能幫我嗎?
我為您提供了一個可以復制的完整示例。 此外,我的學校只允許我執行此任務的某些功能: open
、 fopen
、 close
、 fclose
、 malloc
、 free
、 getline
、 lseek
...(我不允許使用stat
)。
我也可以使用我自己的realloc
實現。
我的代碼:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void my_free_word_array(char **word_array)
{
size_t i = 0;
if (!word_array) {
return;
}
while (word_array[i] != NULL) {
free(word_array[i]);
++i;
}
free(word_array);
}
char **append_word_array(char **array, char *line)
{
size_t array_len = 0;
while (array[array_len])
array_len++;
size_t len = strlen(line);
if (line[len - 1] == '\n')
line[len - 1] = '\0';
char **new_array = malloc(sizeof(char *) * (array_len + 2));
for (size_t i = 0; i < array_len; i++)
new_array[i] = array[i];
new_array[array_len] = strdup(line);
new_array[array_len + 1] = NULL;
free(array);
return new_array;
}
char **fill_from_file(char **array, FILE *file)
{
char *line_buff = NULL;
size_t line_buff_size = 0;
ssize_t line_size = getline(&line_buff, &line_buff_size, file);
while (line_size >= 0) {
array = append_word_array(array, line_buff);
free(line_buff);
line_buff = NULL;
line_size = getline(&line_buff, &line_buff_size, file);
}
free(line_buff);
return array;
}
char **my_load_file_to_line_array(const char *filepath)
{
char **word_array = NULL;
FILE *file = fopen(filepath, "r");
if (!file)
return NULL;
word_array = malloc(sizeof(char *));
if (!word_array)
return NULL;
word_array[0] = NULL;
word_array = fill_from_file(word_array, file);
fclose(file);
return word_array;
}
int main(int argc, char **argv)
{
if (argc < 2)
return -1;
char **array = my_load_file_to_line_array(argv[1]);
my_free_word_array(array);
return 0;
}
我的輸入測試文件:
|A B C D E F G H
-+---------------
1|. . . . . . . .
2|. . . . . . . .
3|. . . . . . . .
4|. . . . . . . .
5|. . . . . . . .
6|. . . . . . . .
7|. . . . . . . .
8|. . . . . . . .
Valgrind 的報告:
❯ valgrind --leak-check=full ./navy coord.txt
==99157== Memcheck, a memory error detector
==99157== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==99157== Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
==99157== Command: ./navy coord.txt
==99157==
==99157==
==99157== HEAP SUMMARY:
==99157== in use at exit: 72 bytes in 5 blocks
==99157== total heap usage: 84 allocs, 79 frees, 18,512 bytes allocated
==99157==
==99157== 72 (40 direct, 32 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2
==99157== at 0x4842888: malloc (vg_replace_malloc.c:381)
==99157== by 0x10980F: append_word_array (my_load_file_to_line_array.c:18)
==99157== by 0x109914: fill_from_file (my_load_file_to_line_array.c:33)
==99157== by 0x1099F0: my_load_file_to_line_array (my_load_file_to_line_array.c:62)
==99157== by 0x1092A5: main (navy.c:17)
==99157==
==99157== LEAK SUMMARY:
==99157== definitely lost: 40 bytes in 1 blocks
==99157== indirectly lost: 32 bytes in 4 blocks
==99157== possibly lost: 0 bytes in 0 blocks
==99157== still reachable: 0 bytes in 0 blocks
==99157== suppressed: 0 bytes in 0 blocks
==99157==
==99157== For lists of detected and suppressed errors, rerun with: -s
==99157== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
這里有一些問題:
您應該在line_buff = NULL;
之后將line_buff_size
重置為0
; 在fill_from_file
中。 或者更好:在循環中迭代時保持line_buff
緩沖區增長,並且只在循環結束后釋放它。
您應該將當前數組長度傳遞給append_word_array
以避免掃描 NULL 終止符。
如果line
的長度為0
,則測試if (line[len - 1] == '\n')
是否具有未定義的行為,如果文件包含嵌入的 null 字節,這是可能的。
如果初始調用malloc()
時出現分配錯誤,則返回NULL
省略fclose(file)
。
如果允許append_word_array
realloc
謹慎使用它。
這些問題不太可能導致報告的 memory 泄漏。 問題有可能與您的代碼(或此版本的代碼)無關。 您應該嘗試減少測試文件的長度,並使用 valgrind 發布仍會產生泄漏摘要的最小輸入?
您也可以試試這個修改后的版本:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void my_free_word_array(char **word_array)
{
if (word_array) {
size_t i = 0;
while (word_array[i] != NULL) {
free(word_array[i]);
++i;
}
free(word_array);
}
}
char **append_word_array(char **array, size_t *array_len, const char *line)
{
char *copy = strdup(line);
char **new_array = realloc(array, sizeof(*array) * (*array_len + 2));
if (copy == NULL || new_array == NULL) {
fprintf(stderr, "memory allocation error");
exit(1);
}
new_array[*array_len] = copy;
new_array[*array_len + 1] = NULL;
*array_len += 1;
return new_array;
}
char **fill_from_file(FILE *file)
{
char **array = NULL;
size_t array_len = 0;
char *line_buff = NULL;
size_t line_buff_size = 0;
ssize_t line_length;
while ((line_size = getline(&line_buff, &line_buff_size, file)) >= 0) {
if (line_length > 0 && line_buff[line_length - 1] == '\n')
line_buff[line_length - 1] = '\0';
array = append_word_array(array, &array_len, line_buff);
}
free(line_buff);
return array;
}
char **my_load_file_to_line_array(const char *filepath)
{
FILE *file = fopen(filepath, "r");
if (!file)
return NULL;
char **word_array = fill_from_file(file);
fclose(file);
return word_array;
}
int main(int argc, char **argv)
{
if (argc < 2)
return -1;
char **array = my_load_file_to_line_array(argv[1]);
my_free_word_array(array);
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.