C 中的内存泄漏,realloc

问题描述 投票:0回答:1

我正在用 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
不是将分配的内存转移到新地址吗?

c memory-leaks
1个回答
0
投票
  1. read_feiticos_from()
    使用局部变量
    capacity
    来跟踪您分配的元素数量,但您只返回
    out_size
    ,即正在使用的元素数量。
    *out_side <= capacity
    。您可以通过执行
    Feitico** temp = realloc(feiticos, *out_size * sizeof *temp); if(!temp) {}; feiticos = temp;
    来解决此问题。

  2. 如果
  3. description = realloc(description, neededSize * 2);

    失败,

    description
    将泄漏原始
    realloc()
    。如果为 NULL,则分配给临时对象并处理错误。考虑使用
    goto
    进行资源清理,而不是在每个返回路径上重复。

© www.soinside.com 2019 - 2024. All rights reserved.