Dynamically set array access pattern in C
I would like to do something like this in C(99):
int n = compute_size_of_matrices();
int T = compute_number_of_matrices();
float matrices[][n][n] = malloc( sizeof(float) * n*n* T ); //[sic!]
Watch the missing size in the first dimension. I would like to set the size of the dimension dynamically in order to do something like the following
/* Load each matrix with the unit matrix */
for( int t = 0; t < T; t++ )
for( int i = 0; i < n; i++ )
for( int j = 0; j < n; j++ )
matrices[t][i][j] = (i==j)?1.:0.;
Of course, I could simply allocate 'matrices' as a one-dimensional array and use some index magic, but obviously the above access pattern to the array is way more convenient. In particular, it is no technical black magic for the compiler, except some overhead to remember the dynamic array sizes. Is there a compiler extension of GCC, some dialect feature or similar which allows me to do som开发者_StackOverflowething like above?
In contrast to this, and in order to avoid ambiguity, a usual C code for the above task would look like this:
int n = compute_size_of_matrices();
int T = compute_number_of_matrices();
float* matrices = malloc( sizeof(float) * n*n* T ); //[sic!]
for( int t = 0; t < T; t++ )
for( int i = 0; i < n; i++ )
for( int j = 0; j < n; j++ )
matrices[t*n*n + i*n + j] = (i==j)?1.:0.;
In real examples, the one-letter variables might have more sounding names, which quickly renders such a piece of code clumsy.
Best I've found
Preserves the array size attributes of the matricies (though not of the list of matrices), and lets you use the native indexing notation
int n=5, T=2;
float (*a)[n][n] = calloc(T,sizeof(float[n][n])); // <== initializes to 0!
for (size_t t=0; t<T; ++t)
for (size_t i=0; i<n; ++i)
a[t][i][i] = 1.0; // <== only set the 1's
The declaration of the pointer to the 2d arrays is the tricky part, but calloc
(see below) takes care of the zero initialization for you, so you only set the non-zero elements.
Of course, the fun part comes when you try to pass these things around...but if you are careful with your declaration and are using c99 you can make either of
void foo(int n, float (*a)[n][n]) {
// ...
}
void bar(int t, int n, float a[t][n][n]) {
// ...
}
work. (Actually gcc
will let you get away with unless you use -std=c89 -pendantic
...)
Second best, but it will work with ansi-c
You can certainly make the traditional version (with ugly hand indexing) easier to read.
int n = compute_size_of_matrices();
int T = compute_number_of_matrices();
float* matrices = calloc(T, sizeof(float) * n*n); // <== initializes to 0!
for( int t = 0; t < T; t++ )
for( int i = 0; i < n; i++ )
matrices[t*n*n + i*n + i] = 1; // <== only set the 1's
Well, it seemed like a good idea...
Alas c won't let you do
int n=5, T=2;
float matrices[T][n][n] = {}; // <== ***ERROR!!!***
which would let you keep the "arrayness" of matricies and be even clearer.
Is it slow?
Because calloc
will use some heavily optimized system memory writer to set to 0 you won't be taking a big speed hit.
RE: missing size in the first direction
The reason you can omit the first dimension in array is because compiler can figure out the size from the number of values that you pass during initialization.
example:
int arr[] = { 0,1 }; // arr size is 2
int arr[][2] = { {0,1}, {0,1} }; // arr size is 2,
// each element points to an array of size 2
etc ...
Another case:
float * arr = calloc(float, sizeof(float) * n);
Here you allocated continuous memory for n
floats and arr
points to it.
You can access elements by pointer arithmetic or by array subscript which does the pointer arithmetic for you.
In all cases the size of each dimension of an array is determined once the array is defined (on the next line after the declaration or once the pointer points to the actual memory).
Compiler does not remember the size, if you use array subscripts that go outside of the array you are accessing memory which is not part of an array ...
精彩评论