Dynamically defined 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 for the missing size in the first dimension. I would like to set the dimension size 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 just separate the “matrices” as a one-dimensional array and use some index magic, but obviously the above array access pattern is more convenient. In particular, this is not technical black magic for the compiler, except for some overhead to remember the sizes of dynamic arrays. Is there a GCC compiler extension, any dialect function or similar function that allows me to do something like the above?

In contrast, and in order to avoid ambiguity, regular 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-world examples, single-letter variables can have more sounding names, which quickly makes such a piece of code awkward.

+2
source share
2 answers

The best I've found

Preserves the size attributes of the matrix array (although not from the matrix list) and allows you to use your own 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 

Declaring a pointer to 2d arrays is the hard part, but calloc (see below) takes care of zero initialization for you, so you only set non-zero elements.

Of course, the fun part comes when you try to convey these things ... but if you are careful about your declaration and use c99, you can do any of

 void foo(int n, float (*a)[n][n]) { // ... } void bar(int t, int n, float a[t][n][n]) { // ... } 

Job. (Actually gcc will let you go if you don't use -std=c89 -pendantic ...)

Best of all, but it will work with ansi-c

You can, of course, simplify reading the traditional version (with ugly manual indexing).

 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, that seemed like a good idea ...

Alas, c won't let you do

  int n=5, T=2; float matrices[T][n][n] = {}; // <== ***ERROR!!!*** 

which will allow you to maintain the "massiveness" of the matrices and be even more clear.

Is he slow?

Since calloc will use some highly optimized write to system memory to set to 0, you will not be hit hard by speed.

+2
source

RE: missing size in the first direction

The reason you can omit the first dimension in the array is because the compiler can determine 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 have allocated contiguous memory for n float and arr points to it. You can access elements by pointer arithmetic or by the index of an array that does pointer arithmetic for you.

In all cases, the size of each dimension of the array is determined after the array is determined (on the next line after the declaration or after the pointer to the actual memory).

The compiler does not remember the size if you use array indices that go beyond the array you are accessing memory that is not part of the array ...

0
source

Source: https://habr.com/ru/post/1437437/


All Articles