The difficulty with your code sample is that one of the function parameters is protoyped, double xu_col[n_col][n_x + n_u]
, where n_x
and n_u
are variables, not constants. If you just pass this as a double[]
instead, some C++ compilers might allow a cast such as double (&table)[n_col][n_x + n_u] = (double(&)[n_col][n_x + n_u])xu_col;
to work as a non-standard extension, but the portable approach would be to write accesses like xu_col[i*(n_x+n_u) + j]
, which you could simplify with a helper function if that’s too ugly.
An alternative approach, probably more in keeping with the spirit of the STL, might be to write a minimal container class that knows its dimensions, stores elements in a linear array for efficiency. Then you might declare redim_array<double> table = redim_array<double>(xu_col, n_col*(n_x+n_u)).redim(n_col, n_x+n_u);
and access table(i,j)
.
Several of the other answers have described the syntax of variable-length arrays, but another aspect of your question is how it’s legal to implicitly convert a rectangular¹ two-dimensional array to a one-dimensional array.
What happens is that the rectangular array is laid out as consecutive elements in memory, so it can degenerate to a pointer to the elements, and then the function parameter can interpret that as an array with a different geometry.
Here’s a short little program that demonstrates this behavior.
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#define ROWS 2
#define COLS 4
#define ELEMS (ROWS*COLS)
int flatten_array( const ptrdiff_t n, const int a[n] )
{
int printed = 0;
for ( ptrdiff_t i = 0; i < n; ++i )
printed += printf( "%d ", a[i] );
return printed + printf("\n");
}
int rectangular_array( const ptrdiff_t m,
const ptrdiff_t n,
const int a[m][n] )
{
int printed = 0;
for ( ptrdiff_t i = 0; i < m; ++i ) {
for ( ptrdiff_t j = 0; j < n; ++j )
printed += printf( "%d ", a[i][j] );
printed += printf("\n");
}
return printed + printf("\n");
}
int main(void)
{
static const int matrix[ROWS][COLS] = {
{11, 12, 13, 14},
{21, 22, 23, 24}
};
static const int vector[ELEMS] = {11, 12, 13, 14, 21, 22, 23, 24};
flatten_array( ELEMS, *(const int (*const)[ELEMS])matrix );
printf("\n");
rectangular_array( ROWS, COLS, *(const int (*const)[ROWS][COLS])vector );
return EXIT_SUCCESS;
}
There’s some language-lawyering in the comments below² about whether passing the array arguments without the explicit casts is technically legal by standard. I’ve chosen to relegate that to a footnote and just delete the example with no casts. In the real world, you will sometimes see code without the pointer-to-array-of-different-geometry cast, and it might generate a warning. The memory layout of the two arrays is required by the standard to be the same.
To convert to C++, you can use the pointer-conversion trick, or you now can code-golf it a bit by using references.
Here is a C++ translation of the program above. It requires all but the first dimension of the array being passed in to be constexpr
, but some compilers support C99-style variable-length arrays as an extension.
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
constexpr ptrdiff_t rows = 2;
constexpr ptrdiff_t cols = 4;
constexpr ptrdiff_t elems = rows * cols;
int flatten_array( const ptrdiff_t n, const int a[] )
{
int printed = 0;
for ( ptrdiff_t i = 0; i < n; ++i )
printed += printf( "%d ", a[i] );
return printed + printf("\n");
}
int rectangular_array( const ptrdiff_t n, const int a[][cols] )
{
int printed = 0;
for ( ptrdiff_t i = 0; i < n; ++i ) {
for ( ptrdiff_t j = 0; j < cols; ++j )
printed += printf( "%d ", a[i][j] );
printed += printf("\n");
}
return printed + printf("\n");
}
int main(void)
{
static const int matrix[rows][cols] = {
{11, 12, 13, 14},
{21, 22, 23, 24}
};
static const int vector[elems] = {11, 12, 13, 14, 21, 22, 23, 24};
flatten_array( elems, (const int(&)[elems])matrix );
printf("\n");
rectangular_array( rows, (const int(&)[rows][cols])vector );
return EXIT_SUCCESS;
}
¹ C programmers sometimes call either arrays like int matrix[ROWS][COLS]
or arrays like char** argv
“two-dimensional arrays.” Here, I call the former rectangular and the latter ragged.
² The constraint on function arguments in the C11 standard is ‘Each argument shall have a type such that its value may be assigned to an object with the unqualified version of the type of its corresponding parameter.’ Furthermore ‘A declaration of a parameter as ''array of type'' shall be adjusted to ''qualified pointer to type''’ and, if this applies recursively, a multidimensional array of some type will be adjusted to a flat pointer of that type.