这两种方法中的哪一种是为静态数组提供维度的正确方法?

时间:2014-08-31 01:52:39

标签: c arrays dimension variable-length-array

这两种形式的数组声明是否正确?

首先:

int n;
n=3;
int A[n];

第二

#define N 300;
.
.
.
.
int a[N];

对我而言,这两种方式完全有效,但有人告诉我第一种方式是错误的。

第一个就像是说:

int A[10];

所以,对我而言,说第一个无效是没有意义的。

但要完全确定,我想在这里问一下。它只是关于编程风格还是第一个不正确的方式?

谢谢。

3 个答案:

答案 0 :(得分:6)

您的第一个示例使用名为variable length arrays VLA )的C99功能,draft C99 standard部分6.7.5.2 数组声明符第4段中对此进行了介绍

  

[...]如果size是一个整型常量表达式,并且元素类型具有已知的常量大小,则数组类型不是可变长度数组类型; 否则,数组类型是可变长度数组类型。

两种形式都不一定是坏的,但如果可以通过用户输入控制它们的大小,则可变长度数组可能是危险的。主要问题是并非所有编译器都支持C99,最好的例子是Visual Studio,尽管recently started supporting parts of C99据我所知仍然不支持VLA。如果你想在C ++中使用你的代码也是一个问题,因为C ++标准根本不支持VLA,尽管gccclang支持VLA作为C ++中的扩展。请注意,VLA是针对C ++ 14提出的,但被拒绝了。

另一个问题是C11使VLA成为可选功能,C11 draft standard部分6.10.8.3 条件功能宏涵盖了这一点:

_ _STDC_NO_VLA_ _   The integer constant 1, intended to indicate that the
                    implementation does not support variable length arrays or
                    variably modified types.

答案 1 :(得分:2)

根据C99 ISO变量长度数组有效。 GCC手册说

Variable-length automatic arrays are allowed in ISO C99, and as an extension GCC accepts them in C90 mode and in C++

gcc:viarable-length

答案 2 :(得分:1)

两种变体都有其优点和缺点:


可变长度阵列的优点:

  • 你不浪费记忆。您可以根据需要分配尽可能多的内存。这在字符串中最为明显:通常,您希望允许非常长的字符串,即使大多数字符串确实很短。为所有字符串分配半千字节是一个巨大的内存浪费,即使分配较少的内容可能已经太严格了。

  • 您没有引入人为限制。由于您精确分配了动态所需的内存,因此不会给用户带来名称/路径/文件/可能存在的上限的上限。

可变长度阵列的缺点:

  • 您不能在堆栈上分配任意大的数组。即使您的系统可以自动增加堆栈,您仍然可以通过分配一个使堆栈指针跳过操作系统使用的标记页面的数组来对程序进行分段。几千字节一般都可以,几兆字节不是。

固定大小缓冲区的优点:

  • 易于设置。

  • 他们是C ++。 C ++ 11标准明确禁止数组类型具有运行时大小,即使C甚至允许您键入自定义可变长度数组,因为C99(void foo(int n) { typedef int (*)[n]; ... }是完全合法的C99,但你不能写C ++中的void foo(int n) { int bar[n]; } 11)。

固定大小缓冲区的缺点:

  • 他们倾向于给用户带来固定限制。当然,您可以尝试处理通常需要更多内存的情况,但在大多数情况下,这些限制只会转发给有一天会对此非常不满的用户。

  • 他们通过缓冲区溢出来引发错误。您的程序需要明确正确地处理因超出数组大小而导致的所有错误。此错误处理代码中的一个错误,您的程序崩溃的方式很可能是一个安全漏洞。对于可变长度数组,您永远不会遇到超出缓冲区的情况,因为您总是将缓冲区分配给该作业足够大。


总而言之,我相信#define N ...int foo[N];几乎总是糟糕的风格。如果你可以证明一个较小的最大尺寸并且你没有编写C ++,那么请使用可变长度数组。如果你不能malloc() / new数组。只有当你能够证明你永远不能要求超过一个非常特定的大小时(例如在"四次根求解器永远不会返回超过四个根和#34;),继续使用固定大小。就个人而言,我使用malloc() / new分配几乎所有数组。