可变大小的多维数组
Version >= C99
从 C99 开始,C 具有可变长度数组 VLA,该数组模拟具有仅在初始化时已知的边界的数组。虽然你必须小心不要分配太大的 VLA(它们可能会粉碎你的堆栈),使用指向 VLA 的指针并在 sizeof
表达式中使用它们很好。
double sumAll(size_t n, size_t m, double A[n][m]) {
double ret = 0.0;
for (size_t i = 0; i < n; ++i)
for (size_t j = 0; j < m; ++j)
ret += A[i][j]
return ret;
}
int main(int argc, char *argv[argc+1]) {
size_t n = argc*10;
size_t m = argc*8;
double (*matrix)[m] = malloc(sizeof(double[n][m]));
// initialize matrix somehow
double res = sumAll(n, m, matrix);
printf("result is %g\n", res);
free(matrix);
}
这里 matrix
是指向 double[m]
类型的元素的指针,sizeof
表达的 sizeof
确保它包含 n
这样的元素的空间。
所有这些空间都是连续分配的,因此可以通过一次调用 free
来解除分配。
语言中 VLA 的存在也会影响函数头中数组和指针的可能声明。现在,在数组参数的 []
中允许使用通用整数表达式。对于这两个函数,[]
中的表达式使用参数列表中之前声明的参数。对于 sumAll
,这些是用户代码对矩阵所期望的长度。对于 C 中的所有数组函数参数,最内层维度被重写为指针类型,因此这等同于声明
double sumAll(size_t n, size_t m, double (*A)[m]);
也就是说,n
实际上并不是函数接口的一部分,但是这些信息对于文档很有用,它也可以被边界检查编译器用来警告越界访问。
Likwise,对于 main
,表达式 argc+1
是 C 标准为 argv
参数规定的最小长度。
请注意,正式的 VLA 支持在 C11 中是可选的,但我们知道没有编译器实现 C11 并且没有它们。如果必须,你可以使用宏 __STDC_NO_VLA__
进行测试。