In a two dimensional array of constant integer values, each row may have a different number of valid columns. The number or rows and the number of columns in each row are known and constant. They could be placed in a struct of structs together with the values as follows:
typedef struct {
uint32_t numColumns;
uint32_t column[100];
} row_T;
typedef struct {
uint32_t numRows;
row_T row[100];
} array_T;
The array is initialized with constant values (I have no preference whether this is done at compile time or at run time):
array_T a = {0};
a.numRows = 2;
a.row[0].numColumns = 2; // two values in row 0
a.row[0].column[0] = 7;
a.row[0].column[1] = 17;
a.row[1].numColumns = 5; // five values in row 1
a.row[1].column[0] = 100;
a.row[1].column[1] = 2;
a.row[1].column[2] = 5;
a.row[1].column[3] = 12;
a.row[1].column[4] = 4;
Stepping through the array is then possible by:
for (uint32_t i=0; i<a.numRows; i++) {
for (uint32_t j=0; j<a.row[i].numColumns; j++) {
//do something with a.row[i].column[j];
}
}
The problem is that the number of columns in each row may vary dramatically. Therefore defining a large enough array is a waste of memory.
Defining types for rows of different length, e.g.
typedef struct {
uint32_t numColumns;
uint32_t column[5];
} row_5_T;
typedef struct {
uint32_t numColumns;
uint32_t column[2];
} row_2_T;
and
typedef struct {
uint32_t numRows;
row_2_T row_0;
row_5_T row_1;
} array_2_T;
is memory efficient but does not allow using a loop counter as an index for fetching the row data.
Finding the memory location of each entry in such struct, based on the row and column indexes (i,j), would be possible but inconvenient:
1+(sum of numColumns+1 for columns 0..i-1)+1+j
Suggestions for any elegant solution are welcome.
We can store the data in a single master array of the element type (apparently uint32_t
) with an array indicating where each row starts within the master array.
For an array with NRows
rows with each row containing NColumns[i]
columns:
size_t *Offset = malloc(NRows * sizeof *Offset);
.Offset[0] = 0; for (size_t r = 0; r < NRows; ++r) Offset[r] = Offset[r-1] + NColumns[r-1];
.uint32_t *Array = malloc((Offset[NRows-1] + NColumns[NRows-1]) * sizeof *Array);
.for (size_t r = 0; r < NRows; ++r)
for (size_t c = 0; c < NColumns[r-1]; ++c)
... // Here array element r, c is in Array[Offset[r] + c].
We could also set a pointer to the start of the current row:
for (size_t r = 0; r < NRows; ++r)
{
uint32_t *Row = Array + Offset[r];
for (size_t c = 0; c < NColumns[r-1]; ++c)
... // Here array element r, c is in Row[c].
}