您当前的位置:首页 > 计算机 > 编程开发 > VC/VC++

C语言变长数组(VLA)

时间:12-26来源:作者:点击数:

在《C语言的三套标准,C语言为什么有这么多编译器》一节中我们讲到,目前经常使用的C语言有三个版本,分别是 C89、C99 和 C11。C89(也称 ANSI C)是较早的版本,也是最经典的版本,国内大学几乎都是以该版本为基础进行授课。C99 和 C11 是后来对 C89 的升级,增添了一些新内容(不多),语法更加灵活了,同时兼容 C89。

各种编译器都能很好地支持 C89 标准,但对 C99 的支持却不同:开源组织的 GCC 和 Xcode 使用的 LLVM/Clang 已经支持了大部分(几乎全部)的 C99 标准,而微软的 VC、VS 对 C99 却不感兴趣,直到后来的 VS2013、VS2015、VS2017 才慢慢支持,而且支持得还不好。

为什么要讨论这个问题呢?因为 C89 和 C99 对数组做出了不同的规定:

  • 在 C89 中,必须使用常量表达式指明数组长度;也就是说,数组长度中不能包含变量,不管该变量有没有初始化。
  • 而在 C99 中,可以使用变量指明数组长度。
下面的代码使用常量表达式指明数组长度,在任何编译器下都能编译通过:
int a[10];  //长度为10
int b[3*5];  //长度为15
int c[4+8];  //长度为12

下面的代码使用变量指明数组长度,在 GCC 和 Xcode 下能够编译通过,而在 VC 和 VS(包括 VC 6.0、VS2010、VS2013、VS2015、VS2017 等)下都会报错:

int m = 10, n;
scanf("%d", &n);
int a[m], b[n];

在实际编程中,有时数组的长度不能提前确定,如果这个变化范围小,那么使用常量表达式定义一个足够大的数组就可以,如果这个变化范围很大,就可能会浪费内存,这时就可以使用变长数组。请看下面的代码:

#include <stdio.h>
int main()
{
    int n;
    printf("Input string length: ");
    scanf("%d", &n);
    scanf("%*[^\n]"); scanf("%*c");  //清空输入缓冲区
    char str[n];
    printf("Input a string: ");
    gets(str);
    puts(str);
    return 0;
}

在 GCC 和 Xcode 下的运行结果:

Input string length: 100↙
Input a string: http://www.cdsy.xyz/tools/wnl/↙
http://www.cdsy.xyz/tools/wnl/

变量的值在编译期间并不能确定,只有等到程序运行后,根据计算结果才能知道它的值到底是什么,所以数组长度中一旦包含了变量,那么数组长度在编译期间就不能确定了,也就不能为数组分配内存了,只有等到程序运行后,得到了变量的值,确定了具体的长度,才能给数组分配内存,我们将这样的数组称为变长数组(VLA, Variable Length Array)

普通数组(固定长度的数组)是在编译期间分配内存的,而变长数组是在运行期间分配内存的。

变长数组仍然是静态数组

注意,变长数组是说数组的长度在定义之前可以改变,一旦定义了,就不能再改变了,所以变长数组的容量也是不能扩大或缩小的,它仍然是静态数组。以上面的代码为例,第 8 行代码是数组定义,此时就确定了数组的长度,在此之前长度可以随意改变,在此之后长度就固定了。

一种“自欺欺人”的写法

有些初学者在使用变长数组时会像下面一样书写代码:

int n;
int arr[n];
scanf("%d", &n);

先定义一个变量 n 和一个数组 arr,然后用 scanf() 读入 n 的值。有些初学者认为,scanf() 输入结束后,n 的值就确认下来了,数组 arr 的长度也随即确定了。这种想法看似合理,其实是蛮不讲理,毫无根据。

从你定义数组的那一刻起(也就是第二行代码),数组的长度就确定下来了,以后再也不会改变了;改变 n 的值并不会影响数组长度,它们之间没有任何“联动”关系。用 scanf() 读入 n 的值,影响的也仅仅是 n 本身,不会影响数组。

那么,上面代码中数组的长度究竟是什么呢?鬼知道!n 是未初始化的局部变量,它的值是未知的。

修改上面的代码,将数组的定义放到最后就没问题了:

int n;
scanf("%d", &n);
int arr[n];

在定义数组之前就输入 n 的值,这样输入的值才有用武之地。

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门