C中堆栈上的动态数组分配
Posted
技术标签:
【中文标题】C中堆栈上的动态数组分配【英文标题】:Dynamic array allocation on stack in C 【发布时间】:2014-12-14 00:49:39 【问题描述】:我昨天刚做了一个实验,发现有些混乱:
#include <stdio.h>
int main()
int j;
scanf("%d",&j);
const int i = j;
int arr[i];
return 0;
从键盘读取数字j
,用于在堆栈上分配数组arr
。
编译器在编译时甚至不知道数组的大小(将j初始化为0?),但没有编译错误。怎么可能?
【问题讨论】:
事实上你应该澄清为什么你认为编译器应该给出一个错误 在本站搜索[c] VLA
。
我想你一直在学习c89..
作为旁注,通过附加变量i
是没用的,没有代码也可以。
由于添加了 C11 标签,请注意 C11 引入的 VLA 支持可选。 __STDC_NO_VLA__
类对象宏设置为 1
如果具体实现不处理它们。
【参考方案1】:
可变长度数组已添加到 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
10
EXAMPLE 4
可变修改(VM)的所有声明 类型必须在块范围或函数原型范围内。 使用_Thread_local
、static
或extern
声明的数组对象 存储类说明符不能有可变长度数组 (VLA) 类型。但是,使用static
存储类声明的对象 说明符可以具有 VM 类型(即,指向 VLA 类型的指针)。 最后,所有使用 VM 类型声明的标识符都必须是普通的 标识符,因此不能是结构或联合的成员。
这意味着静态存储和自动存储是互斥的。
【讨论】:
嗨,Remyabel,感谢您的回复。在这种情况下,编译器可能会生成代码,这些代码将使用变量而不是固定数字来修改堆栈指针,我的猜测是否正确? 我同意“堆栈上的动态数组分配”这句话的措辞非常糟糕,但它是运行时的,但它使用了我们习惯的语法,过去是编译时声明。更新答案说允许运行时数组分配(指定长度的运行时)比说不允许动态数组分配更好。【参考方案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?
【讨论】:
【参考方案3】:C 具有可变长度数组这样的特性。可以在飞行中定义自动存储时长的数组。
【讨论】:
以上是关于C中堆栈上的动态数组分配的主要内容,如果未能解决你的问题,请参考以下文章