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