From: torek@horse.ee.lbl.gov (Chris Torek)
Newsgroups: comp.lang.c
Subject: Re: pointer to array of structs
Date: 3 Sep 1992 17:41:01 GMT
Organization: Lawrence Berkeley Laboratory, Berkeley
Reply-To: torek@horse.ee.lbl.gov (Chris Torek)
NNTP-Posting-Host: 128.3.112.15
Keywords: pointers

>>>void func(struct aaa (*bbb)[]) { ... z = bbb[3]->z; ... }

In article <1992Sep2.003355.29404@Synopsys.Com> jerry@synopsys.com
(Jerry Huth) writes:
>Your parameter declaration "struct aaa (*bbb)[]" is indeed a pointer
>to an array of aaa structures, but your use of it "z = bbb[3]->z;"
>tries to access it as if bbb is an array of pointers to aaa
>structures.  So, the compiler is correct in complaining.

The conclusion here is correct (the compiler is right to reject this)
but the analysis is wrong.

The variable `bbb' is declared as a formal parameter.  In this
particular case this is not relevant, but in other cases (including
several below) it is.

The type `struct aaa (*bbb)[]' is equivalent to the pseudo-English
type `pointer to array of unknown size of struct aaa'.  Such a pointer
can point to zero or more such arrays.  Each such array, if there are
any, has an unknown number of elements; each element of each array is 
in turn a `struct aaa'.

Now, `bbb[3]' means the same as `*((bbb) + (3))'.  Obviously we have
to calculate bbb+3.  To do so, we must step over three of the objects
to which bbb presumably points.  What are these objects?  How big are
they?  We need to know how big they are so that we can step over them.
As we noted in the last paragraph, each of the arrays to which bbb
may point has an unknown number of elements, so there is no way to
know how big they are.

Suppose we changed the type of `bbb' to:

	struct aaa (*bbb)[5];

In this case, bbb would point to zero or more arrays, each array being
made up of 5 `struct aaa's.  Now we could write bbb[i][j], for any
valid integers i and j, to get the i'th array and the j'th element of
that array.  Valid values for j would be in [0..4]; we have no way to
know what values, if any, would be valid for i.  Each bbb[i][j] would
then be an object of type `struct aaa', so we could write

	z = bbb[i][j].z;

>You can do any of the following:
>
>  1) bbb is a pointer to an array of aaa structures
>
>     decl:  struct aaa (*bbb)[]
>     use:   z = (*bbb)[3].z ;        <- new use

Here we are back to the unknown size, but this time we do not have to
calculate bbb+3.  We know how to find *bbb, or bbb[0], because we do
not have to step over any of these arrays: we want one to which bbb
points directly.

Now, bbb[0] is (still) an object of type `array ? of struct aaa'.
We have this in a value context, because we are trying for bbb[0][3]
(the fact that we spelled it `(*bbb)[3]' is irrelevant; these are
semantically identical).  To find bbb[0][3] we must add 3 to bbb[0];
to do that we need its value.

According to The Rule, the value of an <object, array N of T, A> is a
<value, pointer to T, &A[0]>.  We drop the value of N---which we still
do not know---and concentrate on the type T, here `struct aaa'.  We
then find the address of the first element of the array, which is quite
straightforward, since we know where the whole array starts even though
we have no idea how big it is.

This gives us the triple <value, pointer to struct aaa, &bbb[0][0]>,
to which we can add three by skipping over three `struct aaa's.  Then
we indirect again to get the entire `struct aaa' object, giving us
the triple <object, struct aaa, bbb[0][3]>.  We apply the structure
member selection operator `.' to this to find (*bbb)[3].z.

As these two examples show, there *is* a sensible use for the type
`pointer to array N of T' when N is a known integer constant, but there
is much less use for `pointer to array ? of T'.  The only thing we can
do with the latter is find the first whole array (whose size we do not
know) and convert it to a pointer to its first element.  Well, if all
we can get is a pointer to the first element of the first array, why
not just pass a pointer to that element?  In this case, instead of
passing a `pointer to array ? of struct aaa', we can pass a `pointer to
struct aaa', pointing to the first element of the first array.  There
is nothing we could do with the former that we cannot do just as well
with the latter.

On to the other two examples:

>  2) bbb is an array of pointers to aaa structures
>
>     decl:  struct aaa *(bbb[])      <- new decl
>     use:   z = bbb[3]->z ;

(This declaration uses redundant parentheses, and can also be spelled

	struct aaa *bbb[];

)  Remember that we said that `bbb' is a formal parameter.  This is now
important.  When you declare a formal parameter using a type of the
form `array N of T', the compiler must pretend that you wrote instead
`pointer to T'.  This is a logical consequence of C's by-value
parameter semantics and The Rule.  We know that the `value' of an array
is the address of its first element.  Since all parameters are passed
as values, it is impossible to pass an array: it becomes a pointer,
by The Rule, and we pass a pointer instead.

Thus, this declaration is not in fact

	array ? of pointer to struct aaa

but rather reads

	pointer to pointer to struct aaa

This is ONLY because `bbb' is a formal parameter.  *Nowhere else* does
the spelling `[N]' in a declaration mean `pointer to'.  Pointers and
arrays are NOT equivalent.  Formal parameters simply have a special
case attached.  This special case occurs frequently, but it remains a
special case.

Anyway, this time around, bbb has type `pointer to pointer to struct aaa',
and bbb[3] means *(bbb+3) or `go get the fourth pointer' (remember that
the first pointer is bbb[0], not bbb[1]).  This pointer has type
`pointer to struct aaa', so we can then use the `->' indirection-and-
selection operator to fetch bbb[3]->z.  Note that we could also write
(*bbb[3]).z or even bbb[3][0].z.  Indeed, `p->field' and `p[0].field'
are completely interchangeable, just as *p and p[0] are interchangeable
(though if there are other operators around we have to watch out for
binding; we might need to add some parentheses).

>But, it may be that BOTH your use and your decl are wrong, and
>what you really want is:
>
>  3) bbb is an array of aaa structures
>
>     decl:  struct aaa bbb[]	     <- new decl
>     use:   z = bbb[3].z             <- new use

Again, `bbb' is a formal parameter, and this declaration is adjusted
to read `struct aaa *bbb'.  This is thus the same as writing:

	void func(struct aaa *bbb) { ... z = bbb[3].z; ... }

As Jerry Huth suggested, this is probably what you should be using in
the first place.
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 510 486 5427)
Berkeley, CA		Domain:	torek@ee.lbl.gov