9

I just did a experiment yesterday, and find something confusing:

#include <stdio.h>

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

The number j is read from keyboard and it’s used to allocate the array arr on the stack.

The compiler does not even know the size of the array at compile time (initializes j to 0?), but there is no compilation error. How is it possible?

4

3 回答 3

15

可变长度数组被添加到 C99。它在 C99 的基本原理中有所描述:

6.7.5.2 数组声明符

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

在可变长度数组类型的声明中指定的元素数量是运行时表达式。在 C99 之前,这个大小表达式必须是整数常量表达式。

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

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

根据@Deduplicator 的评论,您似乎有一个误解。可变长度数组不能声明为静态的。

§ 6.7.6.2

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

这意味着静态存储和自动存储是互斥的。

于 2014-10-18T16:39:33.460 回答
3

要深入研究如何在堆栈上分配可变数量的内存,请参阅深入研究编译器如何实现(非标准化) alloca()函数:

Alloca 实施

C99 标准提供了具有基本相同功能的可变长度数组(“VLA”) ;尽管内存是按作用域而不是按功能回收的:

alloca(n) 和 char x[n] 有什么区别?

有一些理由会犹豫是否过于激进地使用无限制的大小。无法检查堆栈内存是否可用,因为您可以测试堆内存是否可用。NULL 从malloc(). 如果您的可变长度数组太大,则会导致堆栈溢出和未定义的行为;两种堆栈分配方法都为真:

为什么使用 alloca() 不被认为是好的做法?

于 2014-10-18T16:49:46.613 回答
0

C具有可变长度数组这样的功能。可以在飞行中定义具有自动存储持续时间的数组。

于 2014-10-18T16:34:00.227 回答