变长数组
c99新增了变长数组允许使用变量表示数组维度:
int quarters = 4; int regions = 5; double sale[regions][quarters]; //一个变长数组(VLA)
变长数组有一些限制,必须是自动储存类别,这意味着无论在函数中声明还是在函数形参中声明,都不能使用static
和extern
储存类别说明符。而且不能在声明中初始化他们。最终c11把变长数组作为一个可选特性,而不是必须强制实现的特性。
注意:变长数组的“变”是指可以用变量来指定变长数组的维度。
要声明一个二维数组函数的参数,如下图所示:
int sum2d(int rows, int cols, int ar[rows][cols]); // ar是一个变长数组(VLA)
注意前两个形参rows
和cols
用作第三个形参二维数组ar的两个维度。因为ar声明要使用rows
和cols
所以在形参列表中必须在声明ar之前先声明这两个形参。因此下面的原型是错误的。
int sum2d(int ar[rows][cols], int rows, int cols); // 无效的顺序
c99/c11标准规定,可以省略原型中的形参名,但在这种情况下,必须用*来代替省略的维度:
int sum2d(int, int, int ar[*][*]); // ar是一个变长数组(VLA),省略了维度形参名
其次该函数的定义如下:
int sum2d(int rows, int cols, int ar[rows][cols]) { int r; int c; int tot = 0; for (r = 0; r < rows; r++) for (c = 0; c < cols; c++) tot += ar[r][c]; return tot; }
//vararr2d.c -- 使用变长数组的函数 #include <stdio.h> #define ROWS 3 #define COLS 4 int sum2d(int rows, int cols, int ar[rows][cols]); int main(void) { int i, j; int rs = 3; int cs = 10; int junk[ROWS][COLS] = { { 2, 4, 6, 8 }, { 3, 5, 7, 9 }, { 12, 10, 8, 6 } }; int morejunk[ROWS - 1][COLS + 2] = { { 20, 30, 40, 50, 60, 70 }, { 5, 6, 7, 8, 9, 10 } }; int varr[rs][cs]; // 变长数组(VLA) for (i = 0; i < rs; i++) for (j = 0; j < cs; j++) varr[i][j] = i * j + j; printf("3x4 array\n"); printf("Sum of all elements = %d\n", sum2d(ROWS, COLS, junk)); printf("2x6 array\n"); printf("Sum of all elements = %d\n", sum2d(ROWS - 1, COLS + 2, morejunk)); printf("3x10 VLA\n"); printf("Sum of all elements = %d\n", sum2d(rs, cs, varr)); return 0; } // 带变长数组形参的函数 int sum2d(int rows, int cols, int ar[rows][cols]) { int r; int c; int tot = 0; for (r = 0; r < rows; r++) for (c = 0; c < cols; c++) tot += ar[r][c]; return tot; }
const和数组大小
const int sz = 80; ... double ar[sz]; //是否允许?
C90标准不允许,也可能允许。数组的大小必须是给定的整形常量表达式,可以是整形常量组合。由于C实现可以扩大整形常量表达式的范围,所以可能会允许使用const,但这种代码可能无法移植。
C99/C11标准允许在声明变长数组时使用const变量。所以该数组的定义必须是声明在块中的自动存储类别数组。
变长数组还允许动态内存分配,这说明可以在程序运行时指定数组大小。普通的C数组都是静态内存分配,即在编译时确定数组大小。