From my observation, you may not know exactly what you want and confuse on the struct and pointer arithmetic. Please go through the following 2 possibilities.
1) A two dimensional array with each element has a pointer to test.
In this case the memory of all the pointers to tests are already statically allocated.
But, the memory of the real tests are not ready.
In this case you must fill in the test [i][j] one by one.
Each of the test is discrete in the memory and you have the advantage of create or destroy them individually dynamically.
typedef struct {
int i;
} test;
test* t[20][20];
/* or instead of statically allocated the memory of all the pointers to tests
you can do the following to dynamically allocate the memory
test ***t;
t = (test***)malloc(sizeof(test *) * 20 * 20);
*/
for (int i=0; i < 20; i++){
for (int j=0; j < 20; j++){
t[i][j] = malloc(sizeof(test));
}
}
2) A two dimensional array with each element is a test.
In this case the memory of all the tests are already allocated.
Also, the memory of the real tests are ready to use without extra preparation.
All of the tests are continuous in the memory as a big block and is always there. This mean that you may waste a chunk of memory if you only need all tests at certain peak time and most of the time you only use a few of them.
typedef struct {
int i;
} test;
test t[20][20];
/* or instead of statically allocated the memory of all tests
you can do the following to dynamically allocate the memory
test **t;
t = (test**)malloc(sizeof(test) * 20 * 20);
*/