通常,当我们事先不知道所需的大小时,我们使用 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];无效的原因吗?
让我总结一下评论/答案提出的一些观点:
malloc()返回NULL表示分配失败,而VLA没有这种设计,所以只有系统内存耗尽时程序才会崩溃;realloc()动态调整VLA的大小;(但如上面的例子所示,在很多情况下,我们只是想要一个巨大的本地VLA,其大小在运行时已知,但一旦知道就永远不会改变。但我们仍然必须使用malloc()它)
编辑:
许多人发现问题的意图不清楚,“为什么这么麻烦而不只是使用malloc()?”。目的很简单:我试图减少(如果消除不切实际)的使用,malloc()以便我们节省一些精神负担,以确保所有返回路径 free() 我的malloc()ed 内存。它有点像 C 中的本地化/基本 RAII。
一个主要原因是: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)