我正在用 C 语言做一个关于从文件中读取咒语的项目,在代码报告中它说我没有释放所有使用的内存。我使用
leaks
(终端命令)来帮助我找到泄漏,这就是响应:
Leak: 0x152008200 size=3584 zone: MallocStackLoggingLiteZone_0x104e10000 realloc in read_feiticos_from C memoryleak
Call stack: 0x184da90e0 (dyld) start | 0x1048178d4 (memoryleak) main F_MOOSHAK.c:389 | 0x104817680 (memoryleak) test_F F_MOOSHAK.c:346 | 0x10481700c (memoryleak) read_feiticos_from F_MOOSHAK.c:221 | 0x184f651e4 (libsystem_malloc.dylib) _realloc | 0x184f64ae0 (libsystem_malloc.dylib) _malloc_zone_realloc
这是有问题的代码:
Feitico* read_feitico_from(FILE *stream) {
if (stream == NULL) return NULL;
char nome[100], castTime[100], escola[100];
int nivel, alcance, duracao, concentracao;
char *description = malloc(1000 * sizeof(char)); // Dynamically allocate memory for description
if (description == NULL) {
printf("Failed to allocate memory for description.\n");
return NULL;
}
description[0] = '\0';
if (fscanf(stream, "%99[^\n] %d %99s %99[^\n] %d %d %d ", nome, &nivel, escola, castTime, &alcance, &duracao, &concentracao) == 7) {
char buffer[1000];
while (fgets(buffer, sizeof(buffer), stream) != NULL) {
if (strcmp(buffer, "\\EOD\n") == 0 || strcmp(buffer, "\\EOD") == 0) break; // Correctly identifying end of description
size_t neededSize = strlen(description) + strlen(buffer) + 1;
if (neededSize > 1000) {
description = realloc(description, neededSize * 2); // Adjusting size as needed
if (!description) {
printf("Failed to reallocate memory for description.\n");
return NULL;
}
}
strcat(description, buffer);
}
Feitico *novoFeitico = create_feitico(nome, castTime, escola, nivel, alcance, duracao, concentracao, description);
if (novoFeitico == NULL) {
printf("Invalid Spell: %s\n", nome);
free(description); // Free description only if create_feitico fails
return NULL;
}
// Do not free description here as it's used within novoFeitico
return novoFeitico;
}
else {
free(description); // Free description if the initial read fails
return NULL;
}
}
Feitico** read_feiticos_from(FILE *stream, int* out_size) {
if (stream == NULL || out_size == NULL) return NULL;
*out_size = 0;
Feitico* feitico;
int capacity = 100;
Feitico** feiticos = malloc(capacity * sizeof(Feitico*));
if (!feiticos) {
printf("Erro de alocação de memória\n");
return NULL;
}
while (!feof(stream)) {
feitico = read_feitico_from(stream);
if (feitico != NULL) {
if (*out_size == capacity) {
capacity *= 2;
Feitico** temp = realloc(feiticos, capacity * sizeof(Feitico*));
if (!temp) {
printf("Erro de realocação de memória\n");
for (int i = 0; i < *out_size; ++i) {
free_feitico(feiticos[i]);
}
free(feiticos);
return NULL;
}
feiticos = temp;
}
feiticos[*out_size] = feitico;
(*out_size)++;
}
}
return feiticos;
}
稍后在 main 中使用它,如下所示:
else if (strcmp("LOAD", comando) == 0) {
char ficheiroParaLoad[40];
if (fgets(ficheiroParaLoad, 40, stdin) != NULL) {
sscanf(ficheiroParaLoad," %s",ficheiroParaLoad);
if (ficheiroParaLoad[0] == '\n') {
printf("Invalid command arguments!\n");
}
else {
FILE *file = fopen(ficheiroParaLoad, "r");
if (file == NULL) {
printf("Invalid file or error opening file!\n");
}
else {
for (int i = 0; i < numeroFeiticos; i++) {
free_feitico(feiticosLidos[i]);
}
feiticosLidos = NULL;
numeroFeiticos=0;
feiticosLidos = read_feiticos_from(file, &numeroFeiticos);
if (feiticosLidos == NULL) {
printf("Error loading spells from file!\n");
}
printf("%d spells successfully loaded.\n", numeroFeiticos);
fclose(file);
}
}
}
}
在迭代结束时,我认为我正在正确释放内存,如下所示:
for(int i = 0; i < numeroFeiticos; i++){
free_feitico(feiticosLidos[i]);
}
供参考,
free_feitico
释放每个咒语的内存,因为在构造函数中我在某些咒语的参数中使用了strdup
。
我试图寻找代码中的所有
malloc
,但是当使用泄漏工具时,它告诉我泄漏就在那里,但我不明白它是如何泄漏的; malloc
不是将分配的内存转移到新地址吗?
read_feiticos_from()
使用局部变量 capacity
来跟踪您分配的元素数量,但您只返回 out_size
,即正在使用的元素数量。 *out_side <= capacity
。您可以通过执行 Feitico** temp = realloc(feiticos, *out_size * sizeof *temp); if(!temp) {}; feiticos = temp;
来解决此问题。
description = realloc(description, neededSize * 2);
失败,
description
将泄漏原始 realloc()
。如果为 NULL,则分配给临时对象并处理错误。考虑使用 goto
进行资源清理,而不是在每个返回路径上重复。