是否可以创建具有可变数量元素的数组?

Posted

技术标签:

【中文标题】是否可以创建具有可变数量元素的数组?【英文标题】:Is creating array with a variable number of elements possible? 【发布时间】:2016-12-04 14:23:41 【问题描述】:

每当我需要创建一个包含许多直到执行时才知道的元素的数组时,我都会这样做。

int n, i;
printf("Number of elements: ");
scanf("%d", &n);
int myArray[n];
for(i = 0; i < n; i++)
    myArray[i] = 0;

但是,3 个拥有计算机科学博士学位的人告诉我不要这样做,因为“不能保证在每个编译器上都可以工作”,并且必须在编译时知道数组中元素的数量-时间。所以他们就这样做了。

int myArray[1000];
int n, i;
printf("Number of elements: ");
scanf("%d, &n);
//we must stop at the n element
for(i = 0; i < n; i++)
    myArray[i] = 0;

我应该使用哪一个?什么时候不能保证有效?只是浪费内存还是需要维护传统?

【问题讨论】:

如果要在 C 中实现动态数组,请使用动态内存分配。 两者都不是。使用 int * myArray = malloc( n * sizeof *myArray); 之类的东西,然后在完成后进行清理。 完全符合C99版本的标准。它被称为可变长度数组(VLA)。由于一些未知的原因,委员会在当前版本 (C11) 中将 VLA 设为可选 - 违背了他们不惜一切代价建立的向后兼容实践。我仍然建议使用它。现代桌面编译器将支持它(例如 gcc 和 clang)。不要使用 MSVC 等过时的编译器。现代 C 语言也存在其他问题。有时必须进行削减。 WQe 也不再使用马车了。或莫尔斯电子邮件。你的博士应该继续前进 @clarasoft-it:VLA 不是动态分配的数组,而是普通的自动变量。 以防我的评论不清楚:使用 VLA,但要确保它们不会溢出堆栈(与任何其他自动变量一样!)。使用现代编译器,不要以 1k 美元/欧元/等价格出售它们的供应商提供过时的垃圾。没有前进。 【参考方案1】:

“不能保证在每个编译器上都能工作”

是的,基本上是正确的。

第一种方法VLA, variable length array 是C99 标准的一部分。不过,

C11 中,已设为可选。您最好不要依赖该功能。 C89 没有将其作为标准的端口。但是,gcc 扩展程序可以支持它们。

引用C11,第 §6.7.6.2/p5 章

[....] 如果大小是整数常量表达式 并且元素类型具有已知的常量大小,数组类型不是可变长度 数组类型;否则,数组类型是可变长度数组类型。 (可变长度 数组是实现不需要支持的条件特性;见 6.10.8.3。)

作为一种替代方法,如果您必须依赖运行时值,您始终可以使用指针和动态内存分配,如 malloc() 和系列。

综合起来,回答问题

是否可以创建具有可变数量元素的数组?

这是可能的,但仅限于 VLA 支持。没有它,你最多只能用指针和内存分配函数来满足自己。

【讨论】:

嗨,苏拉夫!我非常不同意你不使用 VLA 的结论。仅仅因为仍有人使用马车,并不意味着所有高速公路都将限速20公里/小时。有足够多的现代编译器确实支持 C99,因此也支持 VLA。不支持 C99/完整 C11 的编译器可能也不支持其他功能,在现代 C 中也是如此。C 似乎是唯一坚持 27 年旧版本的语言,只是因为人们拒绝学习新东西并要求他们的现代功能供应商。 @Olaf 先生,感谢 cmets。首先,我并不反对 VLA,我只是尝试将其作为 alternative 的建议,如您所见。其次,我试图为它们中的每一个指定编译器支持。如果您认为我的回答有任何偏见,请建议更改措辞或随时修改。 :) 动态分配通常不是替代 VLA。不仅这些功能不适用于大多数实现 - 考虑到大多数实现都是独立的,没有标准库中不需要的部分。如果您需要多维数组,那么它们将不可用,因为如果您使用动态分配,您已经需要一个指向 VLA 的 2D 指针.. @Olaf 你说的很对。更换,没有。替代方法,是的。如果 VLA 不存在(不支持),那么我们必须使用指针和malloc() 来解决它们,您不同意吗?此外,VLA 的堆栈大小是有限的,至少在 gcc 中,而 malloc() 可能更慷慨。 :) 不,解决方法是放弃对垃圾(通常是昂贵的)编译器的支持。听起来可能很刺耳,但这是让他们承受压力的唯一方法。没有这个,C 将永远无法摆脱 C90 的萧条。回覆。堆栈大小:这与固定大小的数组或其他变量或递归有什么不同?抱歉,但这不是反对 VLA 的论据,而是一般的自动变量(您希望您同意这是非常无稽之谈)。顺便提一句。 C 标准不要求使用堆栈,您可以使用动态内存分配很好地分​​配自动变量。而且大小不是特定于编译器的【参考方案2】:

如果您想要符合 C89 且不使用太多内存的东西,还有第三种选择,即动态分配内存:

int n, i;
printf("Number of elements: ");
scanf("%d", &n);
int *myArray = malloc(sizeof(int)*n);   // allocate space for n ints
if (myArray == NULL) 
    perror("malloc failed");
    exit(1);

for(i = 0; i < n; i++)
    myArray[i] = 0;

请务必在分配的内存上调用free

【讨论】:

@dbush 每当我需要动态更改大小时,我总是使用指针和 malloc,在这种情况下我不需要。当使用带有 c89 编译器标志的 MinGW 时,它以第一种方式工作。我为什么要改用这个? (什么是“好处”) @Sheldon 使用动态分配更便携。但是,如果您的编译器支持可变长度数组并且您不打算迁移它,它的优点是不必担心释放已分配的内存。 @KevinDTimm: calloc 将所有位归零。这与仅用于整数的值 0 相同。在这里很好,但对于浮点或指针来说不是这样。 (顺便说一句,它在这方面与默认初始化程序不同。)只需让编译器弄清楚如何优化它,一个好的编译器可能会使用memset/memclr,甚至将这两个部分都折叠成calloc。如果可行。 @Olaf - OP 声明了一个 int 数组,我正在解决他的问题,而不是其他人的问题。如果他想要一个通用问题的解决方案,我想他会问的。

以上是关于是否可以创建具有可变数量元素的数组?的主要内容,如果未能解决你的问题,请参考以下文章

如何快速创建具有定义数量的元素的数组

在数组中存储可变数量的点

Prolog中是不是可以接受具有可变数量的谓词?

编写高质量代码改善C#程序的157个建议——建议16:元素数量可变的情况下不应使用数组

Oracle之数组

PySpark - 获取具有相同值的数组元素的数量