[comp.lang.c] pointers/arrays

chris@mimsy.umd.edu (Chris Torek) (07/26/90)

In article <31506@eerie.acsu.Buffalo.EDU> axaris@acsu.buffalo.edu
(vassilios e axaris) writes:
>I need to use a 4 dimensional array of which only the last dimension I know.

The short answer: you are out of luck.  In order to use a multidimensional
array you must know the dimensions.  In some cases you can omit the first
one, but never three out of four.

See the `frequently asked questions' posting for (some) more details.

>... I allocate memory with calloc of course. I would appreciate
>some info. on this: how to declare such a beast, how to allocate memory for
>the other dimensions, and how to prototype it.

Now this is a different situation entirely.  `We control the horizontal...
we control the vertical': if you control the data representation, you can
do one of two things (or other things not mentioned here):

a) use vectors of vectors;
b) use a flat array, doing the subscript calculations yourself.

Method (a) is fairly straightforward; see any reasonable book on C.
Method (b) is also straightforward, if rather messy.  Nonetheless it
merely amounts to doing what the compiler would have to anyway.

If you know that your arrays will always be `k by l by m by N' (where
k, l, m are variable but N is a constant, hence uppercase here) you
can declare a pointer to arrays of size N of whatever base data type
you wish:

	typedef double T;	/* the type of our k,l,m,N arrays */

	T (*p)[N];		/* p points to 0 or more arrays N of T */
	int k, l, m;		/* k, l, and m */
	int a, b, c, d;

	p = (T (*)[N])malloc(k * l * m * N * sizeof(T));
	if (p == NULL)
		panic("out of memory");
	for (a = 0; a < k; a++)
		for (b = 0; b < l; b++)
			for (c = 0; c < m; c++)
				for (d = 0; d < N; d++)
					p[(((a * l) + b) * m) + c][d] = 123.4;


Alternatively (somewhat better, in my opinion):

	struct foomat {		/* a k by l by m by N array of T */
		int	fmat_k;	/* first size */
		int	fmat_l;	/* second */
		int	fmat_m;	/* third */
		T	(*fmat_p)[N];	/* pointer to data arrays */
	};

or (with vectors of vectors)

	struct foovec {		/* k vectors of l vectors of m arrays N of T */
		int	fvec_k;
		int	fvec_l;
		int	fvec_m;
		T	(***fvec_p)[N];
		/* reference as x.fvec_p[a][b][c][d] */
	};

The idea here is to combine all the interesting information (i.e., the
dimensions and the pointer to the runtime-allocated memory).

On a related topic:

>(*)[10] is a pointer to an array of 10.

Correct (though this needs a `base type' to be complete [array 10 of what?]).

>(*(*))[10] is a pointer to a pointer to an array of 10?

Yes; this type contains one redundant pair of parentheses.  A shorter
name for the same type is

	basetype (**)[10]	/* for some suitable basetype */

>And if the size of 10 is not specified is this equivalent to *** ?

No.  (Very absoultely not.  [`Very absolutely' is more absolute than
just `absolutely'. :-) ])  If the size 10 is left out, the type changes
from `pointer to pointer to array 10 of basetype' to `pointer to pointer
to array unknown_size of basetype'.  All that happens, in other words,
is that the compiler loses the size (and therefore can no longer do
useful pointer arithmetic).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris