为什么我可以使用变长数组,为什么还需要使用malloc()?

5
我发现一篇介绍在C语言中动态创建数组的文章。根据该文章所述,正确的做法是:
int n;
scanf("%d", &n);
int *arr = (int*)malloc(n*sizeof(int));

但是我想,如果我能做出这样的事情——
int n, i, sum=0;
scanf("%d", &n);
int arr[n];

我已经编译并运行了它,没有任何错误。那么,我的问题是为什么我需要使用malloc()呢?这与C语言的新旧版本有关吗?


1
小心使用 scanf。如果你输入 -10 会发生什么? - tadman
2
重复的答案关于C99,但在C11中,可变长度数组是“可选的”,无论您对该决定的优点或政治问题怎么看。因此,可移植代码不使用VLA。 - Weather Vane
1
是的,你说得对,使用更大的数字时,该过程会终止,而不像malloc()。@chux - Farhan Fuad
1
如果您使用fgets并对其应用sscanf,则更容易从错误的输入中恢复。 - Weather Vane
1
@ryyker,我在重新开放的问题中发布了一个答案。 - Weather Vane
显示剩余13条评论
2个回答

13

使用malloc而非可变长度数组至少有以下五个好处:

  1. 最显著的是,使用malloc创建的对象在当前块执行结束后仍然存在。这意味着这些对象可以被返回(通过指针)给函数的调用者。这种用法在实际应用中很常见。而作为可变长度数组创建的数组在它们所在的块执行结束时就不存在了。

  2. 使用malloc创建的数组可以使用realloc进行大小调整,而可变长度数组无法调整大小。

  3. 截至2011年C标准,可变长度数组是C实现可选支持的一项。任何质量上乘的通用C实现都会支持它们,但它们是可选的这一事实意味着打算可移植的代码必须避免使用可变长度数组或者必须通过测试预处理器宏__STDC_NO_VLA__并提供备选代码来防范缺乏支持。

  4. 通常情况下,可变长度数组的大小比使用malloc分配的数组小得多。可变长度数组通常使用栈空间实现,而栈通常只能存储一定数量的Mebibytes(虽然在构建可执行文件时可以增加这一限制)。而对于使用malloc创建的对象,现代系统中可能有Gibibytes的内存可用。

  • 如果使用malloc创建数组失败,将返回NULL,程序员可以轻松编写代码检测并处理此错误。如果创建可变长度数组失败,则通常的行为是操作系统以某种内存错误终止程序。(各种C实现可能提供拦截此错误的方法,但这比测试malloc返回值是否为NULL更加繁琐,并且不具有可移植性。)


  • 2
    我编译并运行它,没有任何错误。那么,我的问题是为什么我真的需要使用malloc()呢?这与旧版和新版C有关吗?
    栈分配的数组与自由存储区(堆,malloc和calloc使用的内存区域)中的缓冲区不相同。
    1. 假设该数组存在于堆栈上(暗示为自动变量),则您的数组不能超过平台的最大堆栈大小。在Linux上,使用pthread时默认值为2兆字节。限制在Windows上类似。
    2. 由于作用域和对象生命周期:指向存在于堆栈上的数组中元素的指针不能比它们所指向的数组和元素更长寿,这意味着在声明它们的范围过期后,您不能返回指向那些数组和元素的指针。
    3. VLA数组在C11中是可选的。在C++中,它们根本不属于规范(即它们是供应商扩展),因此您的代码将不具备可移植性。

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接