C Language Memory management Multidimensional arrays of variable size


Example

C99

Since C99, C has variable length arrays, VLA, that model arrays with bounds that are only known at initialization time. While you have to be careful not to allocate too large VLA (they might smash your stack), using pointers to VLA and using them in sizeof expressions is fine.

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);
}

Here matrix is a pointer to elements of type double[m], and the sizeof expression with double[n][m] ensures that it contains space for n such elements.

All this space is allocated contiguously and can thus be deallocated by a single call to free.

The presence of VLA in the language also affects the possible declarations of arrays and pointers in function headers. Now, a general integer expression is permitted inside the [] of array parameters. For both functions the expressions in [] use parameters that have declared before in the parameter list. For sumAll these are the lengths that the user code expects for the matrix. As for all array function parameters in C the innermost dimension is rewritten to a pointer type, so this is equivalent to the declaration

  double sumAll(size_t n, size_t m, double (*A)[m]);

That is, n is not really part of the function interface, but the information can be useful for documentation and it could also be used by bounds checking compilers to warn about out-of-bounds access.

Likwise, for main, the expression argc+1 is the minimal length that the C standard prescribes for the argv argument.

Note that officially VLA support is optional in C11, but we know of no compiler that implements C11 and that doesn't have them. You could test with the macro __STDC_NO_VLA__ if you must.