The issue: 我有目前正在测试的函数(add_filename()init_filename()).它们必须将文件中的行读入动态分配的字符串array.Init启动数组,而Add添加新元素.这两个函数都返回指向数组开头的指针.我已经采取了所有必要的预防措施,以确保realloc()不会丢失指针.还有一些标志表明内存分配有问题.我解放(我能想到的)所有东西.然而,它仍在泄漏……

Code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char **add_filename(char **filenames, char *new_file, int *file_num, int *flag);
char **init_filename(char *new_file, int *flag);

int main() {
    FILE *file;
    file = fopen("file.txt", "r");
    char *buffer = 0;
    size_t buf_size = 0;
    size_t chars = 0;
    int file_num = 0, check = 1;
    // char ch;
    if (file != NULL) {
        char **files;
        while ((int)(chars = getline(&buffer, &buf_size, file)) > 0) {
            if (!file_num) {
                files = init_filename(buffer, &check);
                file_num++;
            }
            files = add_filename(files, buffer, &file_num, &check);
            printf("files = %s", files[file_num - 1]);
            free(buffer);
            buffer = NULL;
            if (check == 0) {
                printf("we have problems\n");
                break;
            }
        }
        free(buffer);
        buffer = NULL;
        fclose(file);
        if (files) {
            for (int i = 0; i < file_num; i++) {
                free(files[i]);
            }
        } 
    }
    return 0;
}

char **init_filename(char *new_file, int *flag) {
    char **init = malloc((1) * sizeof(char*)); //
    if (init) {
        init[0] = malloc((strlen(new_file) + 1) * sizeof(char));
        if (!init[0])
            *flag = 0;
    } else {
        *flag = 0;
    }
    return init;
}

char **add_filename(char **filenames, char *new_file, int *file_num, int *flag) {
    char **temp = realloc(filenames, (*file_num + 1) * sizeof(char *));
    if (temp) {
        filenames = temp;
        filenames[*file_num] = malloc((strlen(new_file) + 1) * sizeof(char));
        if (filenames[*file_num] != NULL) {
            strcpy(filenames[*file_num], new_file);
            *file_num = *file_num + 1;
        } else {
            *flag = 0;
        }
    } else {
        *flag = 0;
    }
    return filenames;
}

This is the output of valgrind:

==5881== HEAP SUMMARY:
==5881==     in use at exit: 32 bytes in 1 blocks
==5881==   total heap usage: 15 allocs, 14 frees, 6,285 bytes allocated
==5881== 
==5881== 32 bytes in 1 blocks are definitely lost in loss record 1 of 1
==5881==    at 0x484DCD3: realloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==5881==    by 0x1094E2: add_filename (test.c:72)
==5881==    by 0x109335: main (test.c:23)
==5881== 
==5881== LEAK SUMMARY:
==5881==    definitely lost: 32 bytes in 1 blocks
==5881==    indirectly lost: 0 bytes in 0 blocks
==5881==      possibly lost: 0 bytes in 0 blocks
==5881==    still reachable: 0 bytes in 0 blocks
==5881==         suppressed: 0 bytes in 0 blocks
==5881== 
==5881== For lists of detected and suppressed errors, rerun with: -s
==5881== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

And this is the output of ASan:

Direct leak of 32 byte(s) in 1 object(s) allocated from:
    #0 0x7f200c4b4c18 in __interceptor_realloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:164
    #1 0x5591559a2a8a in add_filename /home/licht/Documents/Knowledge/school21/inProgress/C3_SimpleBashUtils-0/src/test.c:72
    #2 0x5591559a2631 in main /home/licht/Documents/Knowledge/school21/inProgress/C3_SimpleBashUtils-0/src/test.c:23
    #3 0x7f200c029d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58

SUMMARY: AddressSanitizer: 32 byte(s) leaked in 1 allocation(s).

推荐答案

代码中存在多个问题:

  • 必须将files初始化为NULL:如果文件不为空,则它将由init_filename初始化,但在main()结束时释放时将保持未初始化并导致未定义的行为(如果files最终被释放).
  • 你应该go 掉尾随的换行符,go 掉getline().
  • 不需要init_filename():允许将空指针传递给realloc(),在本例中,realloc的行为将与malloc相似.
  • 第一个文件名在数组中添加两次:一次是按init_filename添加,另一次是按add_filename添加
  • 不需要在循环内释放buffer:它将在下一行中重复使用,并根据需要重新分配.
  • 应该使用strdup()来分配字符串的副本,它在单个调用中安全地结合了内存分配和字符串复制.该功能是C23 C标准的一部分,在POSIX系统上已有数十年的历史.它很容易在不提供它的遗留系统上实现.毫无疑问,它在您的系统上是可用的,因为您依赖于getline.
  • last but not least:您忘记释放files,这可能是您观察到的漏洞.

以下是修改后的版本:

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char **add_filename(char **filenames, const char *new_file,
                    int *file_num, int *flag);

int main() {
    FILE *file;
    char *buffer = NULL;
    size_t buf_size = 0;
    char **files = NULL;
    int file_num = 0, check = 1;

    file = fopen("file.txt", "r");
    if (file == NULL) {
        fprintf(stderr, "cannot open %s: %s\n", "file.txt", strerror(errno));
        return 1;
    }
    while (getline(&buffer, &buf_size, file) > 0) {
        // clear the trailing newline if any
        buffer[strcspn(buffer, "\n")] = '\0';
        files = add_filename(files, buffer, &file_num, &check);
        if (check == 0) {
            printf("filename could not be inserted: %s\n", buffer);
            break;
        }
        printf("file = %s\n", files[file_num - 1]);
    }
    free(buffer);
    fclose(file);
    if (files) {
        for (int i = 0; i < file_num; i++) {
            free(files[i]);
        }
        free(files);
    } 
    return 0;
}

char **add_filename(char **filenames, const char *new_file,
                    int *file_num, int *flag) {
    int num = *file_num;
    char **temp = realloc(filenames, (num + 1) * sizeof(*filenames));
    if (temp) {
        filenames = temp;
        filenames[num] = strdup(new_file);
        if (filenames[num] != NULL) {
            // update the filename count and set the success flag
            *file_num = num + 1;
            *flag = 1;
        } else {
            // could not allocate new string: clear flag
            *flag = 0;
        }
    } else {
        // realloc failed: clear flag to indicate failure
        *flag = 0;
    }
    return filenames;
}

C++相关问答推荐

什么C代码将确定打开的套接字正在使用的网络适配器?

数据包未从DPDK端口传输到内核端口

为什么C语言允许你使用var =(struct NAME){

如何使fputs功能提示错误输入并要求用户重新输入.程序停止而不是请求新的输入

在传统操作系统上可以在虚拟0x0写入吗?

模拟shell并运行.sh文件

在 struct 中强制转换空指针

致命:ThreadSaniizer:在Linux内核6.6+上运行时意外的内存映射

为什么我不能只在内存地址中添加一个int来寻址任何数组?

N的值设置为0或1(未定义的行为),而我正在try 学习realloc和Malloc的用法

如何有效地编写代码来判断两个元素数量相同的数组即使在不同的位置也具有相同的元素?

如何用c语言修改shadow文件hash部分(编程)?

判断系统命令返回值的正确方法

C中的回文数字

C23标准是否向后兼容?

为什么GCC不能在 struct 初始值设定项中以sizeof作为条件的三进制中处理复合文字的编译时求值?

为什么<到达*时不会转换为>?

如何正确探测平台设备?

无法在 C 中打开文本文件,我想从中读取文本作为数据并将其写入数组

在 printf() 格式说明符中使用字段宽度变量