为什么我们不能拥有大的 VLA 并(部分)取代 malloc

D.J*_*ind -1 c

通常,当我们事先不知道所需的大小时,我们使用 malloc() ,如下所示(删除检查/错误处理等):

FILE * fp = fopen(path, "rb");
fseek(fp, 0, SEEK_END);
ssize_t length = ftell(fp);
rewind(fp);
char* buffer = malloc(length * sizeof(char));
fread(buffer, 1, *length, fp);
fclose(fp);
free(buffer);
Run Code Online (Sandbox Code Playgroud)

我们需要使用char* buffer = malloc(length * sizeof(char));而不是char buffer[length];因为堆栈的大小非常有限。我的问题是,由于 C 支持可变长度数组,至少对于局部变量来说,是什么阻止我们使堆栈变得更大而只使用堆栈内存呢?

我确实在这里找到了答案。它提出了一个有效的观点:malloc有一个接口可以报告内存的不可用性。但这是唯一char* buffer = malloc(length * sizeof(char));;有效和char buffer[length];无效的原因吗?

让我总结一下评论/答案提出的一些观点:

  1. malloc()返回NULL表示分配失败,而VLA没有这种设计,所以只有系统内存耗尽时程序才会崩溃;
  2. 由于其本地作用域,我们无法将本地 VLA 从被调用者函数返回给调用者;
  3. 我们不能realloc()动态调整VLA的大小;
  4. VLA 不是 ISO C 标准中的必需功能,因此某些平台可能不支持它。

(但如上面的例子所示,在很多情况下,我们只是想要一个巨大的本地VLA,其大小在运行时已知,但一旦知道就永远不会改变。但我们仍然必须使用malloc()它)

编辑: 许多人发现问题的意图不清楚,“为什么这么麻烦而不只是使用malloc()?”。目的很简单:我试图减少(如果消除不切实际)的使用,malloc()以便我们节省一些精神负担,以确保所有返回路径 free() 我的malloc()ed 内存。它有点像 C 中的本地化/基本 RAII。

dbu*_*ush 8

一个主要原因是:VLA 的生命周期与任何本地定义的数组一样,一旦定义的范围结束,它的生命周期也结束。因此,您不能使用它从函数返回内存块。

例如,这是无效的:

int *get_array(size_t size)
{
    int array[size];
    return array;
}
Run Code Online (Sandbox Code Playgroud)

但这很好:

int *get_array(size_t size)
{
    int *array = malloc(size * sizeof *array);
    return array;
}
Run Code Online (Sandbox Code Playgroud)

如果您需要依赖于本地创建的变量,您也无法创建超过一个小尺寸的链​​接列表。

struct list node1 = { 1, NULL };
struct list node2 = { 2, &node1 };
struct list head = { 3, &node2 };
Run Code Online (Sandbox Code Playgroud)

这只在事情变得难以处理之前就到此为止。再次,存在返回局部变量地址的问题。

struct list *get_node(int value)
{
    struct list node = { value, NULL };
    return &node;     // INVALID
}
Run Code Online (Sandbox Code Playgroud)