我昨天刚做了一个实验,发现了令人困惑的事情:
#include <stdio.h>
int main()
{
int j;
scanf("%d",&j);
const int i = j;
int arr[i];
return 0;
}
从键盘读取数字j
,它用于在堆栈上分配数组arr
。
编译器在编译时甚至不知道数组的大小(将j初始化为0?),但没有编译错误。怎么可能?
答案 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_local
,static
或extern
声明的数组对象 存储类说明符不能有可变长度数组(VLA) 类型。但是,使用static
存储类声明的对象 说明符可以具有VM类型(即指向VLA类型的指针)。 最后,使用VM类型声明的所有标识符都必须是普通的 因此,标识符不能成为组织结构或联合。
这意味着static
存储和automatic
存储是互斥的。
答案 1 :(得分:2)
有些人深入研究如何在堆栈上分配可变数量的内存可以工作,请参阅此深入研究编译器如何实现(non-standardized) alloca()
函数:
C99标准提供Variable Length Arrays ("VLA")基本相同的功能;虽然内存是按范围而不是按功能回收的:
What's the difference between alloca(n) and char x[n]?
有一些理由犹豫是否过于积极地使用无限大小。没有办法检查堆栈内存是否可用,因为您可以测试堆内存是否可用。来自malloc()
的NULL。如果您的可变长度数组太大,则会导致堆栈溢出并undefined behavior;对于两种堆栈分配方法都是如此:
答案 2 :(得分:0)
C具有可变长度数组等功能。可以在航班中定义具有自动存储持续时间的阵列。