[comp.lang.c] How do you declare a pointer to a two dimensional array?

rogers@iris.ucdavis.edu (Brewski Rogers) (11/03/90)

given the array:

	float	spam[4][4];

How do I declare a pointer to it? Is this possible?


-bruce

poser@csli.Stanford.EDU (Bill Poser) (11/03/90)

In article <9197@aggie.ucdavis.edu> rogers@iris.ucdavis.edu (Brewski Rogers) writes:
>given the array:
>
>	float	spam[4][4];
>
>How do I declare a pointer to it? Is this possible?

	float (*spamp) [4][4];

declares spamp to be a pointer to a 4x4 array of floats.

chris@mimsy.umd.edu (Chris Torek) (11/04/90)

>In article <9197@aggie.ucdavis.edu> rogers@iris.ucdavis.edu
>(Brewski Rogers) asks:
>>	float	spam[4][4];
>>How do I declare a pointer to it? Is this possible?

In article <16189@csli.Stanford.EDU> poser@csli.Stanford.EDU
(Bill Poser) answers:
>	float (*spamp) [4][4];
>declares spamp to be a pointer to a 4x4 array of floats.

Correct, but chances are that this is not what is desired anyway.
Most likely Mr. Rogers (sorry, I just *had* to write it that way :-) )
wants either `float (*p)[4];' or `float *p;'.

Consider, e.g., the array

	int x[10];

This declares `x' as an object of type `array 10 of int'.  Objects
of type `array N of T', when placed in value contexts (most C contexts
are value contexts), `decay' into values of type `pointer to T' which
point to the first element of that array, i.e., the element whose
index is 0.  So to make use of `x' one would not write

	int (*ap)[10] = &x;	/* NB: legal only in ANSI C, not K&R-1 */

but rather

	int *ip = x;		/* or `= &x[0]' */

After all, the only thing you can do with `ap' that you cannot do with
`ip' is index (or point) off into the n'th array-10-of-int objects, and
there is no other such object.  There is only `ap[0]'.

The same holds for a `float spam[4][4];': this is an object of type
array N=4 of T=(array 4 of float), so you want a pointer to T, or a
pointer to `array 4 of float':

	float (*p)[4] = spam;	/* or `= &spam[0]' */

and now you can index p to get objects 0, 1, 2, and 3:

	float *f = p[1];	/* or &p[1][0] */

	p[3][2] += 3.0;		/* bump element 2 of array number 3 */
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 405 2750)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

gwyn@smoke.brl.mil (Doug Gwyn) (11/07/90)

In article <9197@aggie.ucdavis.edu> rogers@iris.ucdavis.edu (Brewski Rogers) writes:
>given the array:
>	float	spam[4][4];
>How do I declare a pointer to it? Is this possible?

You don't declare a pointer to spam; however, you might declare a pointer
to an array having the same type as spam and initialize it to point to spam.
This may not work in pre-ANSI C compilers that don't allow you to take the
address of an array, in which case you can use just spam or spam[0] and cast
it to the desired type.
	float	(*spamp)[4][4] = &spam;	/* ANSI */
	float	(*spamq)[4][4] = ((*)[4][4])spam;	/* others */

avery@netcom.UUCP (Avery Colter) (11/11/90)

Well, any array, when referred to by name only without subscripts,
translates into a pointer to the lowest element of the array, i.e.
the location of spam[0][0].

However, at least on my machine, pointers don't take kindly to more
than one dimension of indexing.

So I resorted to making a separate array of pointers, and setting
each of the elements of this array of pointers to match the addresses
of each of the subarrays of the original.

Kinda like:

int spam [10][10];
int *pointer[10];
int index;

for (index=0;index<10;++index)
   pointer[index]=spam[index];

-- 
Avery Ray Colter    {apple|claris}!netcom!avery  {decwrl|mips|sgi}!btr!elfcat
(415) 839-4567   "Fat and steel: two mortal enemies locked in deadly combat."
                                     - "The Bending of the Bars", A. R. Colter

gwyn@smoke.brl.mil (Doug Gwyn) (11/11/90)

In article <16580@netcom.UUCP> avery@netcom.UUCP (Avery Colter) writes:
>However, at least on my machine, pointers don't take kindly to more
>than one dimension of indexing.

But pointers to pointers do, e.g. int **spampp;

chris@mimsy.umd.edu (Chris Torek) (11/12/90)

In article <16580@netcom.UUCP> avery@netcom.UUCP (Avery Colter) writes:
>Well, any array, when referred to by name only without subscripts,
>translates into a pointer to the lowest element of the array,

In value contexts, yes;

>i.e. the location of spam[0][0].

no.  The declaration was `float spam[M][N];' for some constants M and
N.  The type of the object `spam' is thus `array M of array N of float'.
In a value context, this becomes a pointer to the first element of `the'
array.  Which array?---we have two `array of's above.

The answer is that it becomes a `pointer to array N of float'.  This
value is not an <object, array N of T> and therefore does NOT undergo
a second conversion.  The result is a pointer to first of the sub-arrays
that make up the array `spam'.  As I wrote before, this is

	float (*p)[N] = spam;

>However, at least on my machine, pointers don't take kindly to more
>than one dimension of indexing.

The result of `indexing' (which is in C a sham: e1[e2] does not really
`index' e1 `by' e2; instead, it adds e1 and e2 and indirects through
the result) a `pointer to T' is, if not an error, an object (lvalue) of
type T.  If each pointer points to one or more `int's, then ptr[value]
is a single int (or an error).

In this case, p points to one or more---in fact, it points to exactly M
---`array N of float's, so p[value] is an object of type `array N of
float'.  Since this *is* an array object, it goes through another of
those `array to pointer' conversions whenever it appears in a value
context, so p[v1][v2] is entirely legal and means to take the v1'th
`array N of float' at which p currently points, turn that object into
the address of the first of the N floats in that array, then take the
v2'th float at which the resulting pointer points:

			  0  1  2  ... N-1
	+---+		+------------------+
	| p |---------->| array N of float | p[0]
	+---+		+------------------+
			| array N of float | p[1]
			+------------------+
			|	 .	   |
			|	 .	   | ...
			|	 .	   |
			+------------------+
			| array N of float | p[M-1]
			+------------------+

`p' points directly *to* one `array N of float' (p[0]), but p points
*at* a whole passel of `array N of float's (p[0] through p[M-1]).  An
`array N of float' is slippery, though, and when you try to grab the
whole thing with p[0]:

	+---+		+------------------+
	| p |---------->| array N of float | p[0]
	+---+		+------------------+

you have to loosen your hold and you end up with a pointer to the first
one:

			  $   p[0] in value context
			  |
			  v
	+---+		+---+---+...+---+--+
	| p |---------->| array N of float | p[0]
	+---+		+------------------+

`$' is an intermediate value and is not (necessarily) actually stored
in memory anywhere in the computer (hence no box).  It points to a
single float (here p[0][0]) but it points `at' N floats (p[0][0]
through p[0][N-1]).  This means you can fetch `$[0]' (so to speak) to
get p[0][0], or `$[4]' to get p[0][4], and so on.  Of course `$' is not
a legal character in C, except inside string and character constants
and comments.

(In the picture above, p points *to* the entire `array N of float', but
`$'---p[0] taken as a value---points *to* only one float, hence the
extra `+' marks along the top.)

>So I resorted to making a separate array of pointers, and setting
>each of the elements of this array of pointers to match the addresses
>of each of the subarrays of the original.

[edited to be `array M of array N of float', etc]

>float spam[M][N];
>float *pointer[M];
>int index;
>for (index = 0 ;index < M; ++index)
>   pointer[index] = spam[index];

This is entirely legal, and amounts to copying each `$' into an actual
variable (pointer[index]) by placing each spam[index] computation in a
value context (the right hand side of the last `=').  Each spam[index]
is an `object, array N of float' and therefore is transformed into a
`value, pointer to float', which is proper to store in pointer[index].
The result is an array M of pointers, each pointing *to* one float but
`at' N floats:

				  0  ... N-1
	+--------------+	+---+---+---+
	|  pointer[0]  |------->|   |...|   | spam[0]
	+--------------+	+---+---+---+
	|  pointer[1]  |------->|   |...|   | spam[1]
	+--------------+	+---+---+---+
	|       .      |	| . |   | . |
	|       .      |	| . |...| . | ...
	|       .      |	| . |   | . |
	+--------------+	+---+---+---+
	| pointer[M-1] |------->|   |...|   | spam[M-1]
	+--------------+	+---+---+---+

Each pointer[i] points *to* the 0'th spam[i] (hence the extra `|'s
making each spam[x][y] a separate box, vs the diagram for `p' in which
each spam[x] was a single continuous box) but `at' the entire
`spam[i][0] through spam[i][N-1]'.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 405 2750)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris