可變大小的多維陣列

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__ 進行測試。