double (*parray[15])[];

Wayne Throop throopw at dg_rtp.UUCP
Wed May 28 07:01:21 AEST 1986


> friesen at psivax.UUCP (Sarima (Stanley Friesen))
>> topher at cyb-eng.UUCP (Topher Eliot)

>>There has been some debate on what the declaration
>>	double (*parray[15])[];
>>means.

> The declaration declares an array of pointers to
> entities of *undefined* size(not zero size).

Right.

> Due to the way pointer
> arithmetic is defined in "C" this is not kosher(the compiler cannot
> determine how much to add to the pointer). At least one compiler I
> know of "accepts" this declaration by treating the unspecified arrays
> as having size 1, thus making the declaration eqiuvalent to:
>
> 	double *parray[15];	/* Array of pointers to double */

No, no, no, no, no!  (But almost yes. :-)

First, the declaration

        double (*a[15])[];

is completely kosher, legal, proper, correct, loyal, honorable, brave,
meaningful, trustworthy, and a fine declaration in its own right.
Harbison and Steele (page 69) say

    The length of the array, a constant expression, may be omitted as
    long as it is not needed to allocate storage.

It does *not* (I say, *NOT*) declare the same thing as

        double *a[15];

nor can any correct compiler for C take these two declarations to be
equivalent.  On the other hand, the expression (a[n]+m) *is*
meaningless, since the size of the denotation type of the pointer
expression a[n] is unknown, which is the problem Stanley points out
above.


Now, how do arrays of unknown size get along with pointer arithmetic?
For array subscription to work, what must be known is the size of the
*components* of the array, or the "inter-element spacing" (digression:
size of an element is *not* the same thing as the inter-element spacing,
but in C the latter can be deduced from the former by fiat (not renault,
mind you, this only works for Italian cars :-)).  The size of the
containing array need not be known, only the lower bound (which is
always zero in C).  Thus, the "innermost" array descriptor (following a
pointer declaration, or in a formal argument or external context) may be
of unknown size.

>From this we see that as formal arguments or externals, these
declarations are legal:

        int a[];
        int b[][10];
        int c[][10][10];

and these are not

        int d[10][];
        int e[10][10][];
        int f[10][][10];

and in any context, these declarations are legal

        int (*g)[];
        int (*h)[][10];
        int (*i)[][10][10];

(I will note that, despite the H&S quote above, the legitimacy of the
 (*)[] declaration with unknown size is not totally clear, but most
 compilers and typecheckers side with me on this.)

Now then, the above is mostly the "no, no, no, no, no" part... what
about the "almost yes" part?  Well, it turns out that, due to the
peculiar way pointer/array equivalence works in C, it is impossible to
tell if a pointer-to-foo points to a single foo, or to an element of an
array-of-foo, and therefore if what you want is a pointer which
indicates an array-of-foo, it is often expedient to declare
pointer-to-foo only, and have the array part be implicit via
array-pointer equivalence.  Note well that this notion does *not* make
the two forms identical.  Let's take these definitions:

        int *pi, (*pai)[];

For one example of non-equivalence, to reference "the nth int" via a
pointer to int, one uses

                        *(pi+n)
or, equivalently
                        pi[n]

while with a pointer to array of foo, one uses

                        (*pai)[n]

Uttering "pi" in a value context yields the address of an int (or,
implicitly, the address of the first in an unknown size array of int).
Uttering "pai" in a value context yeilds the address of an array of int.
The distinction between "address of array of int" and "address of the
first element of an array of int" is very important to keep clear.  The
two are definitely *not* the same thing.  (Trust me.  But if you don't,
it might help if you consider what happens when such a pointer is
incremented.)

The brevity of the "pi[n]" notation, and the practical equivalence in
use of this to the "(*pai)[]" form, makes pointer-to-foo the normal way
of talking about pointers to arrays in C.  This does *not* mean that the
distinction between these concepts is absent from C, however.
--
"I would have *sworn* that *somebody* understood arrays in C!"
                                --- overheard in the hallway
--
"'Fiat' is Italian for 'hobby'."
                                --- Eric Hamilton
-- 
Wayne Throop      <the-known-world>!mcnc!rti-sel!dg_rtp!throopw



More information about the Comp.lang.c mailing list