tribble_acn%uta.csnet@csnet-relay.arpa (David Tribble) (12/23/85)
Recently a question arose on the net about the problem of passing a multi-
dimensional array, with varying (or `dynamic') dimension bounds, to a
function. (This is especially useful when dealing with dynamically
allocated arrays.) This is one way to do it-
#define D1 3 /* array bounds */
#define D2 5
#define D3 9
int a[D1][D2]; /* 2-D array of int */
... fnc(a, D1, D2) ... /* call fnc, passes address of a */
fnc(a, d1, d2)
int *a; /* pointer to int */
int d1, d2; /* dimension bounds */
{
int i, j;
... (*(a + i*d1 + j)) ... /* same as a[i][j] */
}
Or, to make things a little easier-
#define index(a,i,j) (*(a + i*d1 + j))
... index(a, i, j) ... /* same as a[i][j] */
Thus for more dimensions-
int a[D3][D2][D1]; /* 3-D array of int */
... fnc(a, D1, D2, D3) ... /* passes address of a */
#define index3(a,i,j,k) (*(a + (i*d2 + j)*d1 + k))
fnc(a, d1, d2, d3)
int *a; /* array int pointer */
int d1, d2, d3; /* dimension bounds */
{
int i, j, k;
... index3(a, i, j, k) ... /* same as a[i][j][k] */
}
Other indexing macros would be-
#define index1(a,i) (*(a + i))
#define index2(a,i,j) (*(a + i*d1 + j))
#define index3(a,i,j,k) (*(a + (i*d2 + j)*d1 + k))
#define index4(a,i,j,k,l) (*(a + ((i*d3 + j)*d2 + k)*d1 + l))
#define index5(a,i,j,k,l,m) (*(a + (((i*d4 + j)*d3 + k)*d2 + l)*d1 + m))
Etc.
What you are doing is passing the address of the first element
of the array (int * a) and calculating the address of the array
element you want. This is exactly what the compiler would
do if it knew the dimensions of the array. (Because it is just
a pointer, the compiler does not know any dimensions to associate with
it.)
This has the interesting side effect that you can pass (for example)
a 5-dimensional array and treat it as (for example) a 3-dimensional
array. This is because the parameter is declared as a 1-dimensional
array, and you are manually calculating the offset.
See Harbison & Steele section 5.5, "Array Types", especially section 5.5.2,
"Multidimensional Arrays". This is also discussed in the white book.
/* run this program to see how it works */
#define D1 3
#define D2 4
#define D3 5
#define index3(a,i,j,k) (*(a + (i*D2 + j)*D1 + k))
main()
{
int a[D3][D2][D1];
int i, j, k, l;
for (i = 0; i < D3; ++i) {
for (j = 0; j < D2; ++j) {
for (k = 0; k < D1; ++k) {
a[i][j][k] = i*100 + j*10 + k;
}
}
}
fnc(a, D3, D2, D1);
}
fnc(a, dim3, dim2, dim1)
int * a;
int dim3, dim2, dim1;
{
int i, j, k;
for (i = 0; i < dim3; ++i) {
for (j = 0; j < dim2; ++j) {
for (k = 0; k < dim1; ++k) {
printf("a[%d][%d][%d] = %03d\n",
i, j, k, index3(a, i, j, k));
}
}
}
}
Hope this helps.throopw@dg_rtp.UUCP (Wayne Throop) (12/26/85)
To reference an element of a variably sized multi-dimensional array, David Tribble recommends > (*(a + i*d1 + j)) /* same as a[i][j] */ along with using macros to simplify, like so: > #define index(a,i,j) (*(a + i*d1 + j)) > index(a, i, j) /* same as a[i][j] */ Good idea. I'd just like to note that, using pointer/array equivalence, the somewhat complicated expression can be written a little less confusingly, as a[i*d1 + j] It might still be advisable to use the macro, but then again, maybe not. The more-than-two-dimensional cases are still pretty confusing: a[(i*d1 + j)*d2 + k] Also, I'd recommend declaring the formal "a" as "int a[]" rather than "int *a", unless it is important for some reason to treat "a" as an lvalue. -- Wayne Throop at Data General, RTP, NC <the-known-world>!mcnc!rti-sel!dg_rtp!throopw
throopw@dg_rtp.UUCP (Wayne Throop) (12/26/85)
A small PS. Naturally, the macro
> #define index(a,i,j) (*(a + i*d1 + j))
really needs extra parenthesization, like so:
#define index(a,i,j) (*((a) + (i)*d1 + (j)))
or, (using subscripts) like so:
#define index(a,i,j) ((a)[(i)*d1 + (j)])
--
Wayne Throop at Data General, RTP, NC
<the-known-world>!mcnc!rti-sel!dg_rtp!throopw