一、问题背景
最近在学习C语言时候发现VLA(variable-length array)这个有趣的概念,也就是变长数组、或者称为不定长数组、软性数组。
以前我们在本科学的谭浩强版本C语言中,明确表示数组在定义时必须用常数或常量表达式来描述数组的长度。
但是VLA就打破了这个限制(在C语言标准C99中引入,但是在C++的编译标准中一直没引入),允许在程序中定义一个根据变量取值变化而变化的数组。
也即下面的代码是合法的。
int n = 3;
int arr[n] = {0 , 1, 2};
但是我发现我编写下面这段简单的程序,执行过程中仍然报错【variable “arr1” may not be initialized】。
#include <stdio.h>
int main()
{
int a = 4;
int arr1[a]={
7, 8, 9};
int arr2[3] = {
1, 2, 3};
int i=0;
// arr1[2] = arr2[2];
// for(i=0; i<3; i++)
// printf("%d\n", i);
for(i=0; i<3; i++)
printf("%d\n", arr1[i]);
return 0;
}
虽然在console中输出了正确结果,但是我仍然心有余悸,对这个错误很是不爽。
二、解决办法
C99中对VLA有一些限制:
1、VLA必须是自动存储类型,也即必须在函数中定义,也即必须是那种用完就删的局部变量。
2、VLA不能对数组进行初始化,因为它的长度在运行时才能确定。为什么在运行时才能确定呢?因为变量在运行时才能确定,有些人给变量赋予值得方式是用scanf函数,这就导致必须在代码运行过程中由人类手动输入取值,数组的长度才得以确定。而在C90标准中,数组长度在编译结束后就已经确定了。
虽然我上面就是把数组的初始化放在main函数中进行的,也即符合自动存储类型(符合第一条),但是我在定义的时候同时对数组arr1进行了初始化,所以出错了。
在我更改代码如下所示后,运行完美。
#include <stdio.h>
int main()
{
int a = 4;
int arr1[a];
arr1[0] = 7;
arr1[1] = 8;
arr1[2] = 9;
int arr2[3] = {
1, 2, 3};
int i=0;
// arr1[2] = arr2[2];
// for(i=0; i<3; i++)
// printf("%d\n", i);
for(i=0; i<3; i++)
printf("%d\n", arr1[i]);
return 0;
}
输出当然更是正常地!
三、一些小建议
我再细心网上冲浪,发现大多数程序员并不是很认可这个VLA的使用。
大家都是喜欢直接用malloc和free通过指针来定义一个可变长度数组,据说这样更稳定、更兼容(不用C99也可以),而且不容易出错。
在使用VLA的时候,有些人发现如果初始化过程中将0赋值进去,可能会出现数据错乱。
因此我觉得最好的解决办法就是不用变量来描述数组长度,就可以彻底避免这个BUG的发生。
毕竟,C++的很多标准(C++90 C++99 C++11)压根就不包括这个特性,而且C++中有更好的工具(vector和array,相对VLA来说是货真价实的随时随地变长数组)来定义类似变长数组这种数据。