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.