[net.lang.c] how do you dynamically allocate multidimensional arrays?

geoff@burl.UUCP (geoff) (04/25/85)

Greetings,
	I am trying to allocate a dynamic two-dimensional array of structures.
I don't get any complaints from the compiler about this test program, but it
doesn't work correctly, either.  I would expect the array 'l' and the pointer
'p' to store the data in the same places (relative to the beginning of
storage, that is).  However, while 'l' correctly packs the data into 8
contiguous words, 'p' loads the data into every other 2-word segment. If
I increase the column dimension of p to 3, it loads it into every third
2-word segment.  It obviously considers each element to be the full column
size, but only uses the first structure in that element.  The assembly
language is of no help -- it shows the data loaded into constant offsets
from the address of j (as it should -- the offsets are just wrong).
I am including the program and its output.  What am I doing wrong??
How do I do it right??

	many thanks--

		geoff sherwood


int j[100];	/* just getting some initialized space */
main()
{
	struct fred {
		int i;
		int j;
	};
	struct fred (*p)[2][2];
	struct fred (l)[2][2];
	int i, *ip;

	p = (struct fred (*)[2][2])j;

	/* I was rather suprised to have to use -> rather than .
	/* does make some sense -- p is a pointer -- but if c is
	 * a character pointer, c[0] is the zero-eth element, not
	 * a pointer to it.
	 */

	p[0][0]->i = 9;
	p[0][0]->j = 10;
	p[0][1]->i = 99;
	p[0][1]->j = 100;
	p[1][0]->i = 999;
	p[1][0]->j = 1000;
	p[1][1]->i = 9999;
	p[1][1]->j = 10000;

	l[0][0].i = 9;
	l[0][0].j = 10;
	l[0][1].i = 99;
	l[0][1].j = 100;
	l[1][0].i = 999;
	l[1][0].j = 1000;
	l[1][1].i = 9999;
	l[1][1].j = 10000;

	for (i = 0; i <  16; i++ )
		printf("j[%d] = %d\n", i, j[i]);
	ip = (int *)l;
	for (i=0, ip = (int *)l; i < 8; i++)
		printf("ip[%d] = %d\n", i, ip[i]);
}
(output of said test)
j[0] = 9
j[1] = 10
j[2] = 0
j[3] = 0
j[4] = 99
j[5] = 100
j[6] = 0
j[7] = 0
j[8] = 999
j[9] = 1000
j[10] = 0
j[11] = 0
j[12] = 9999
j[13] = 10000
j[14] = 0
j[15] = 0
ip[0] = 9
ip[1] = 10
ip[2] = 99
ip[3] = 100
ip[4] = 999
ip[5] = 1000
ip[6] = 9999
ip[7] = 10000

alexis@reed.UUCP (Alexis Dimitriadis) (04/29/85)

In article <669@burl.UUCP> geoff@burl.UUCP (geoff) writes:
> ... while 'l' correctly packs the data into 8
>contiguous words, 'p' loads the data into every other 2-word segment. If
>I increase the column dimension of p to 3, it loads it into every third
>2-word segment.  
>What am I doing wrong??  How do I do it right??
>
>int j[100];	/* just getting some initialized space */
>main()
>{
>	struct fred {
>		int i;
>		int j;
>	};
>	struct fred (*p)[2][2];
>	struct fred (l)[2][2];
>	int i, *ip;
>
>	p = (struct fred (*)[2][2])j;


  That's easy!  The way you declare p, it is a pointer to a two-by-two
array of fred.  Since p[n] is equivalent to *(p+n), the first index
increments by the size of the pointed object--In fact you could use
p[x][y][z] without getting a diagnostic from the compiler.

  The correct way to do this would be to declare

struct fred l[2][2], *p[2];

Then you could use p[n], to access the n-1st 8 byte block of memory
starting at *p, as in p[n][1].i (and not p[n][1]->i !)

Alexis Dimitriadis
-- 
_______________________________________________
  As soon as I get a regular job, the opinions expressed above
will attach themselves to my employer, who will never be rid of
them again.

	  alexis @ reed
	...ihnp4!{harvard|tektronix}!reed
	...decvax!tektronix!reed
	...teneron!reed

donn@utah-gr.UUCP (Donn Seeley) (04/30/85)

	From: geoff@burl.UUCP (geoff)

	I am trying to allocate a dynamic two-dimensional array of
	structures. ...

(Did you figure this out?  I noticed some cancel messages lying around
that looked like they might have been intended to nab your article...
In the event you were serious about posting this, and in consideration
that this might conceivably be of general interest, I'll answer your
question anyway...)

The problem is that you aren't dereferencing your pointer properly.
The pointer is declared correctly:

	struct fred (*p)[2][2];

But for some reason you didn't use it the way it was declared:

	p[1][1]->j = 10000;

We can rewrite this in a trivial way so that we can see what's wrong:

	p[1][1][0].j = 10000;

What this actually does is select the NEXT two-dimensional array after
the one to which 'p' points, extract element <1,0> from it and assign
10000 to its member, 'j'.

The rule of thumb that was overlooked here is that the declaration of a
C object parallels its use; thus the proper way to write what you want is:

	(*p)[1][1].j = 10000;

Hope this helps,

Donn Seeley    University of Utah CS Dept    donn@utah-cs.arpa
40 46' 6"N 111 50' 34"W    (801) 581-5668    decvax!utah-cs!donn