【问题标题】:Why not use free() in this instance为什么不在这种情况下使用 free()
【发布时间】:2017-01-07 11:29:16
【问题描述】:

所以我还有一个新手问题要问你。该函数用于从传入的文件中读取所有字节,将它们存储在堆中,然后将这些字节的地址存储在传入的 'content' 参数和传入的 'length' 参数中。

bool load(FILE* file, BYTE** content, size_t* length)
{
if (file == NULL)
{
    return false;
}

//array to hold the bytes??
BYTE* buffer = malloc(sizeof(BYTE));

//To hold the number of bytes currently loaded
size_t size = 0;


//Pointer to keep track of where I am adding the data to in buffer

//get all the bytes from the file and put them in the buffer
for(int i = fgetc(file); i != EOF; i = fgetc(file))
{
    buffer[size] = (char) i; 
    size++;
    buffer = realloc(buffer, size + 1);
}

//dereference length
*length = size;

//derefernce content
*content = buffer;

//free(buffer);
return true;
}

所以以前这个函数所属的较大程序不起作用,但是当我注释掉

free(buffer);

在底部调用我的程序开始完美运行。当我遇到双重免费错误时,我有动力对此发表评论。所以我的问题是:为什么在这种情况下调用 free 会导致错误?

我的直觉告诉我,是因为数据

*content

points to 现在已“删除”,因此我的程序无法正常工作。此外,稍后在代码中的某个地方我也释放了内容*,这就是双重释放错误的来源。但是出于某种原因,我倾向于认为数据实际上并未“删除”。

对不起,如果这很多,我一直对内存分配,空闲和指针感到困惑,并试图获得更深入的了解。

【问题讨论】:

  • 只是一个注释。您通过为从文件中读取的每个字符重复调用realloc 进行分配,这是您可以想象的最低效的realloc 使用。相反,分配一些合理数量的字节(例如10244096 或更多),然后保留索引并从文件中读取字符,直到索引(+1)达到您的原始限制,然后调用realloc并分配另一个4096 等并重复。对一个 1 兆字节的文件,您将调用多少次 realloc
  • David 说的……或者每次调用realloc() 时分配的空间量加倍——如果有太多多余的空间可用(例如,如果有更多超过 1 KiB 的未使用空间)。
  • @DavidC.Rankin realloc 函数的内部工作将只是进行相同的检查,然后如果超出当前容量,则调用其他函数,所以我认为它不必要地复杂化OP 的代码来提升这些检查。操作系统可能至少提供几千字节的块。
  • "出于某种原因,我倾向于相信数据实际上并没有被“删除”——这不太合乎逻辑

标签: c pointers malloc free realloc


【解决方案1】:

在分配内存(或一般的资源)时,您必须确保拥有清晰的所有权语义。谁拥有分配的资源并负责释放它?

对于分配资源的函数,合理的语义是函数在成功时返回分配的资源,除非另有说明,否则调用者拥有该资源。如果函数失败,调用者不必执行任何清理操作。

您的load() 函数分配了一个缓冲区。在其大部分函数体中,load() 拥有该缓冲区。就在它返回成功之前,它有效地将缓冲区的所有权转移给调用者(通过content 输出参数)。如果load() 在分配缓冲区后出现故障点,那么它应该沿着该故障路径调用free(buffer)


我也觉得有必要指出您的代码的一些问题:

BYTE* buffer = malloc(sizeof(BYTE));

您应该测试malloc 是否失败。此外,sizeof (BYTE) 没有用处,因为根据定义,它是 1。

buffer = realloc(buffer, size + 1);

这是不好的做法。如果realloc 失败,您将丢失buffer 的旧值并泄漏内存。最好这样做:

BYTE* tmp = realloc(buffer, size + 1);
if (tmp == NULL)
{
    free(buffer);
    return false;
}
buffer = tmp;

最后,每次将缓冲区增加 1 个字节是非常低效的。更典型的做法是将缓冲区大小加倍或增加更大的数量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-24
    • 2020-04-21
    • 1970-01-01
    • 2015-05-20
    • 2013-07-22
    • 2021-08-09
    • 2017-11-26
    相关资源
    最近更新 更多