C中堆栈上的动态数组分配

时间:2014-10-18 16:21:38

标签: c c99 c11 variable-length-array

我昨天刚做了一个实验,发现了令人困惑的事情:

#include <stdio.h>

int main()
{
    int j;
    scanf("%d",&j);
    const int i = j;
    int arr[i];
    return 0;
}

从键盘读取数字j,它用于在堆栈上分配数组arr

编译器在编译时甚至不知道数组的大小(将j初始化为0?),但没有编译错误。怎么可能?

3 个答案:

答案 0 :(得分:13)

将可变长度阵列添加到C99。它在C99理论中描述:

6.7.5.2数组声明符

  

C99添加了一种称为可变长度数组类型的新数组类型。该   无法声明仅在执行时知道其大小的数组   通常被认为是使用C作为数值的主要威慑力   计算语言。采用一些标准的执行时间概念   数组被认为对C的接受至关重要   计算世界。

     

变量声明中指定的元素数   length数组类型是运行时表达式。在C99之前,这个尺寸   表达式必须是一个整数常量表达式。

没有“堆栈上的动态数组分配”。必须在声明中指定数组大小。

一些编译器,如GCC允许它们作为C90(在GCC中,这相当于ansi和C89)模式和C ++中的扩展。在这些情况下,您会收到警告(-Wpedantic)或错误(-Werror-pedantic-errors)。请参阅编译器的文档。

Per @ Deduplicator的评论,你似乎有一种误解。可变长度数组不能声明为静态。

§6.7.6.2

  

10 EXAMPLE 4所有可变修改声明(VM)   类型必须在块范围或函数原型范围内。   使用_Thread_localstaticextern声明的数组对象   存储类说明符不能有可变长度数组(VLA)   类型。但是,使用static存储类声明的对象   说明符可以具有VM类型(即指向VLA类型的指针)。   最后,使用VM类型声明的所有标识符都必须是普通的   因此,标识符不能成为组织结构或联合。

这意味着static存储和automatic存储是互斥的。

答案 1 :(得分:2)

有些人深入研究如何在堆栈上分配可变数量的内存可以工作,请参阅此深入研究编译器如何实现(non-standardized) alloca()函数:

Alloca implementation

C99标准提供Variable Length Arrays ("VLA")基本相同的功能;虽然内存是按范围而不是按功能回收的:

What's the difference between alloca(n) and char x[n]?

有一些理由犹豫是否过于积极地使用无限大小。没有办法检查堆栈内存是否可用,因为您可以测试堆内存是否可用。来自malloc()的NULL。如果您的可变长度数组太大,则会导致堆栈溢出并undefined behavior;对于两种堆栈分配方法都是如此:

Why is the use of alloca() not considered good practice?

答案 2 :(得分:0)

C具有可变长度数组等功能。可以在航班中定义具有自动存储持续时间的阵列。