可變大小的多維陣列
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__
進行測試。