int** is no longer a 2d array; it's a pointer to a pointer, or more specifically a pointer to an array of pointers in our case.
That's why you are having problems assigning a pointer to a 2d array ((int[3][2]){{0,0}, {0,0}, {0,0}}) to it.
To initialize int**, you would need something like
xy_t xy = {
.M = 3,
.N = 2,
.x = (int[3]){ 0,0,0 },
.y = (int*[3]){
(int[2]){ 0,0 },
(int[2]){ 0,0 },
(int[2]){ 0,0 },
},
};
You can also let the compiler do the counting:
xy_t xy = {
.M = 3,
.N = 2,
.x = (int[]){ 0,0,0 },
.y = (int*[]){
(int[]){ 0,0 },
(int[]){ 0,0 },
(int[]){ 0,0 },
},
};
Despite not being a 2d array, you can still access y[i][j] using
xy.y[ i ][ j ].
The above structure needs M+2 pointers and M+3 memory blocks. If you wanted to make the structure smaller, you could use the following which only uses 2 pointers and 3 memory blocks:
typedef struct {
const int M;
const int N;
int *x; // Should be 1-D M elements
int *y; // 2-D M*N elements
} xy_t;
xy_t xy = {
.M = 3,
.N = 2,
.x = (int[]){ 0,0,0 },
.y = (int[]){ 0,0, 0,0, 0,0 },
};
You would access y[i][j] using xy.y[ i * xy.N + j ].
You could also cast it to a pointer to a 2d array in order to use y[i][j]. This is done as follows:
int (*y)[ xy.M ][ xy.N ] = (int(*)[ xy.M ][ xy.N ])xy.y;
You can make it even smaller! The following uses zero pointers and just one memory block.
typedef struct {
const int M;
const int N;
int xy[];
} xy_t;
xy_t xy = {
.M = 3,
.N = 2,
.xy = {
0,0,0,
0,0, 0,0, 0,0
},
};
You would access x[i] using xy.xy[ i ].
You would access y[i][j] using xy.xy[ xy.M + i * xy.N + j ].
Or:
int (*x)[ xy.M ] = (int(*)[ xy.M ])xy.xy;
int (*y)[ xy.M ][ xy.N ] = (int(*)[ xy.M ][ xy.N ])( xy.xy + xy.M );
x[i]
y[i][j]
That said, gcc warns
warning: initialization of a flexible array member [-Wpedantic]
So this last solution is probably non-standard.
xy_twith appropriate dynamic allocations. i.e.xy_t xy_t_create(unsigned int m, unsigned int n);You will also need a cleanup function to deallocate arrays.y[a][b]? Cannot you usey[a + b*c]instead?