kd said:
Newbie question here. It's been a while since I've done C programming,
and I hit a wall last night.
Let's say I have a three dimensional array, like so:
int p[2][3][3] =
{{{0,0,0},
{1,1,1},
{0,1,0}},
{{0,1,0},
{1,1,0},
{0,1,0}}};
I also have a number of other three dimensional arrays, generated with
a code generating script. The size of each dimension varies with each
one. Some are [5][3][3], some are [2][5][5], etc...
How would I declare a variable that could hold any of these
3-dimensional arrays? I'm tripping over the pointer syntax.
I'd like to be able to do something like:
int ***val = p; //The variable p from the last example.
I'm pretty sure that ***val is the wrong way to go about it.
It is the wrong way.
int (*val)[3][3] = p;
is the right way to deal with arbitrary amounts of "3 by 3" matrices.
If you want to be able to deal with "arbitrary amounts of arbitrary
row by arbitrary column number matrices", you need three levels of
indirection. For every level but the last you need "index arrays".
Now, there are two ways of representing your "3D array" in memory
which _can_ make things easier:
1) Condensed. I.e. the last column of the first row of the
first matrix is immediately followed by the first column of the
second row of the first matrix and the last column of the last
row of the first matrix is immediately followed by the first
column of the first row of the second matrix.
This means that you could do with one array of int and could
access everything "matrixlike" via
#define INDEX(i, j, k, num_j, num_k) \
(((i) * (max_j) + (j)) * (max_k) + (k))
and
int *array = malloc(sizeof p);
if (NULL == array) {
/* error handling and abort */
}
memcpy(array, p, sizeof p);
for (mat = 0; mat < num_mat; ++mat)
for (row = 0; row < num_row; ++row)
for (col = 0; col < num_col; ++col) {
do_something(array[INDEX(mat,row,col, num_row,num_col)]);
}
If you really insist on
int ***val;
you need the following steps:
num_mat = sizeof p/sizeof p[0];
val = malloc(num_mat * sizeof *val);
if (NULL == val) {
/* error handling and abort */
}
num_row = sizeof p[0] / sizeof p[0][0];
*val = malloc(num_mat*num_row * sizeof **val);
if (NULL == *val) {
/* error handling and abort */
}
for (mat = 1; mat < num_mat; ++mat) {
val[mat] = val[0] + mat*num_row;
}
/* 1 */
for (mat = 0; mat < num_mat; ++mat)
for (row = 0; row < num_row; ++row)
val[mat][row] = p[mat][row];
/* 2 */
in order to use
for (mat = 0; mat < num_mat; ++mat)
for (row = 0; row < num_row; ++row)
for (col = 0; col < num_col; ++col) {
do_something(val[mat][row][col]);
}
Note that this operates on the original array p.
If you want to have val as a "copy of p", you have to replace
/* 1 */ to /* 2 */ by
num_col = sizeof p[0][0] / sizeof p[0][0][0];
**val = malloc(num_mat*num_row*num_col * sizeof ***val); /*3*/
if (NULL == **val) {
/* error handling and abort */
}
memcpy(val, p, sizeof p);
for (mat = 0; mat < num_mat; ++mat)
for (row = 0; row < num_row; ++row)
val[mat][row] = val[0][0] + (mat*num_row + row)*num_col;
2) Maximum array: Say you know that the largest possible array
dimensions are MAX_MAT, MAX_ROW, MAX_COL and
MAX_MAT*MAX_ROW*MAX_COL is not too large. Then declare your
"intermediate" matrix as
int val[MAX_MAT][MAX_ROW][MAX_COL];
and copy the values:
for (mat = 0; mat < num_mat; ++mat)
for (row = 0; row < num_row; ++row)
for (col = 0; col < num_col; ++col) {
val[mat][row][col] = p[mat][row][col];
}
Merits: 1) makes it possible to just memcpy() the array but
can mean resizing of "array" or "**val", "*val", and "val",
respectively. 2) means no resizing but potentially increased
cost for copying -- and much memory consumption.
If you allocate each row separately instead of at once (/*3*/),
you can "resize" the matrix in an easier manner but have
more allocations to take care of.
It depends on your application whether 1) or 2) or a mixed
form or something completely different is best for your...
Cheers
Michael