传递给为其分配内存的函数的指针仅在指针 NULL 初始化时有效

Pointer passed to function which allocates memory to it only works if pointer NULL intialized

我正在编写一个将文件读入内存的函数,遇到了一个奇怪的问题。如果在将返回的指针传递给函数之前将其初始化为 NULL,则返回的指针只能被 free() 成功。这是代码,

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/stat.h>


ssize_t
file_size(const char *path)
{
    struct stat stats;

    if (stat(path, &stats))
        return (-1);

    return (stats.st_size);
}

ssize_t
read_file(const char *path, char *data)
{
    data = NULL;

    FILE *fp;

    ssize_t tmp;
    size_t fl;

    tmp = file_size(path);
    if (tmp < 0) goto err;
    fl = (size_t)tmp;

    data = malloc(fl);
    if (data == NULL) goto err;
    
    fp = fopen(path, "rb");
    if (fp == NULL) goto err;

    if (fread(data, 1L, fl, fp) != fl) goto err;

    if (ferror(fp)) goto err;

    fclose(fp);

    return (fl);
    
err:
    if (fp)
    {
        int errno_save = errno;
        fclose(fp);
        errno = errno_save;
    }

    free(data);

    return (-1);
}

int
main(void)
{
    char *fdata; // If this is initialized to NULL, then the program works fine
    size_t fdata_len;
    
    fdata_len = read_file("/home/varad/wallpaper.jpg", fdata);

    printf("read %zu bytes.\n", fdata_len);

    free(fdata); // Segfault happens over here

    return (0);
}

如果main函数中的变量'fdata'没有初始化为NULL,程序运行失败,输出如下:

read 2599298 bytes.
Segmentation fault (core dumped)

但是,如果它被初始化为 NULL,那么它显然会按预期运行并输出以下内容:

read 2599298 bytes.

我试过用gdb调试这个程序,段错误发生在main函数末尾的free()调用处。任何帮助将不胜感激。

提前致谢, 瓦拉德

read_file(const char *path, char *data)

data 是局部变量。您的更改仅针对此功能。您需要传递对指针的引用。

ssize_t
read_file(const char *path, char **data)
{
    FILE *fp = NULL;

    ssize_t tmp;
    size_t fl;

    if(!data) goto err;
    tmp = file_size(path);
    if (tmp < 0) goto err;
    fl = (size_t)tmp;

    *data = malloc(fl);
    if (*data == NULL) goto err;
    
    fp = fopen(path, "rb");
    if (fp == NULL) goto err;

    if (fread(*data, 1L, fl, fp) != fl) goto err;

    if (ferror(fp)) goto err;

    fclose(fp);

    return (fl);
    
err:
    if (fp)
    {
        int errno_save = errno;
        fclose(fp);
        errno = errno_save;
    }

    if(data) free(*data);

    return (-1);
}

并相应地调用:

fdata_len = read_file("/home/varad/wallpaper.jpg", &fdata);