3

当我发现数组大小必须在声明时给出或在运行时使用 malloc 从堆中分配时,我正在读一本书。我用 C 编写了这个程序:

#include<stdio.h>

int main() {
  int n, i;
  scanf("%d", &n);
  int a[n];
  for (i=0; i<n; i++) {
    scanf("%d", &a[i]);
  }
  for (i=0; i<n; i++) {
    printf("%d ", a[i]);
  }
  return 0;
}

这段代码工作正常。

我的问题是这段代码如何才能正常工作。数组大小必须在运行前声明或在运行时使用 malloc() 分配它是否违反了 C 的基本概念。这两件事我都没有做,那为什么它工作正常?

我的问题的解决方案是 C99 支持的可变长度数组,但是如果我玩弄我的代码并将语句 int a[n]; 以上 scanf("%d,&n); 然后它停止工作为什么会这样。如果 C 中支持可变长度数组?

4

4 回答 4

5

C99 标准支持可变长度数组。这些数组的长度是在运行时确定的。

于 2012-04-08T12:01:06.190 回答
3

从 C99 开始,您可以在块范围内声明可变长度数组。

例子:

void foo(int n)
{
    int array[n];

    // Initialize the array
    for (int i = 0; i < n; i++) {
        array[i] = 42;
    }
}
于 2012-04-08T12:01:41.967 回答
0

只要您在使用之前声明了数组并为其分配了内存,C 就会很高兴。C 的“特性”之一是它不验证数组索引,因此程序员有责任确保所有内存访问都是有效的。

于 2012-04-08T12:03:35.837 回答
0

可变长度数组是 C99 中添加到 C 中的一项新功能。

这里的“可变长度”意味着数组的大小是在运行时决定的,而不是编译时。这并不意味着数组的大小在创建后可以更改。数组是在声明它的地方逻辑创建的。所以你的代码看起来像。

int n, i;

创建两个变量 n 和 i。最初这些变量是未初始化的。

scanf("%d", &n);

将一个值读入 n。

int a[n];

创建一个数组“a”,其大小是 n 的当前值。

如果您交换第二步和第三步,您将尝试创建一个大小由未初始化值确定的数组。这不太可能有好的结局。

C 标准并没有具体说明数组的存储方式,但实际上大多数编译器(我相信有一些例外)都会在堆栈上分配它。执行此操作的正常方法是将堆栈指针复制到“帧指针”作为函数前导码的一部分。然后,这允许函数动态修改堆栈指针,同时跟踪它自己的堆栈帧。

可变长度数组是一个应该谨慎使用的特性。编译器通常不会在堆栈分配上插入任何形式的溢出检查。操作系统通常在堆栈之后插入一个“保护页面”以检测堆栈溢出并引发错误或增加堆栈,但足够大的数组可以轻松跳过保护页面。

于 2019-02-11T16:05:00.667 回答