topher@cyb-eng.UUCP (Topher Eliot) (05/22/86)
(I have dropped net.unix from the newsgroups list). There has been some debate on what the declaration double (*parray[15])[]; means. David Herron seems to be arguing that it declares a zero-length array of some sort, which some people and/or compilers might interpret as being a pointer of the same sort. I admit I found his note a little hard to follow, so maybe I misunderstood him. But I thought I would add my bit of net volume in the form of an explanation of HOW I would go about parsing such a statement. My basic rule, which I have trusted for many years, is to parse it as if it were an expression, starting inside the parentheses, and obeying operator precedence rules: double (*parray[15])[]; ^^^^ 1. It's an array with 15 elements double (*parray[15])[]; ^^^^^^^^^^^ 2. It's an array of 15 pointers. double (*parray[15])[]; ^^^^^^^^^^^^^^^ 3. It's an array of 15 pointers to arrays (the sizes of these arrays being pointed at is not specified). double (*parray[15])[]; ^^^^^^^^^^^^^^^^^^^^^^ 4. It's an array of 15 pointers to arrays of doubles. There's another way to parse it, sort of from the outside in: double (*parray[15])[]; ^^^^^^^^^^^^^^^ 1. The expression (*parray[15])[] has type double. double (*parray[15])[]; ^^^^^^^^^^^^^ 2. The expression (*parray[15]) has type "array of double", with the size of the array unspecified. double (*parray[15])[]; ^^^^^^^^^^ 3. The expression parray[15] has type "pointer to array of double". double (*parray[15])[]; ^^^^^^ 4. parray has type "array of pointers to arrays of doubles", parray has 15 elements. Notice that both these methods are nice and methodical, and they both come up with the same result. I get the impression that at least one of the participants of this discussion parsed the declaration something along the lines of: double (*parray[15])[]; ^^ 1. It's a zero-length array of somethings. double (*parray[15])[]; ^ ^^ 2. It's a zero-length array of pointers to something. double (*parray[15])[]; ^^^^^^^^^^^^^^ 3. It's a zero-length array of pointers to 15-element arrays of something. double (*parray[15])[]; ^^^^^^^^^^^^^^^^^^^^^^ 4. It's a zero-length array of pointers to 15-element arrays of doubles. It is my contention that parsing a declaration this way is just plain wrong, but I admit it's an easy mistake to make, one that I myself made back before I had given this subject as much thought as I have. The original discussion involved lint and malloc; I have nothing to add to that aspect of it, so I am not repeating it here. Cheers, Topher Eliot Cyb Systems, Austin, TX (512) 835-2266 {gatech,harvard,ihnp4,nbires,seismo,ucb-vax}!ut-sally!cyb-eng!topher
friesen@psivax.UUCP (05/24/86)
In article <863@cyb-eng.UUCP> topher@cyb-eng.UUCP (Topher Eliot) writes: >There has been some debate on what the declaration > double (*parray[15])[]; >means. David Herron seems to be arguing that it declares a zero-length >array of some sort, which some people and/or compilers might interpret as >being a pointer of the same sort. [Topher Eliot's parse] > > double (*parray[15])[]; > ^^^^ >1. It's an array with 15 elements > > double (*parray[15])[]; > ^^^^^^^^^^^ >2. It's an array of 15 pointers. > > double (*parray[15])[]; > ^^^^^^^^^^^^^^^ >3. It's an array of 15 pointers to arrays (the sizes of these arrays being >pointed at is not specified). > > double (*parray[15])[]; > ^^^^^^^^^^^^^^^^^^^^^^ >4. It's an array of 15 pointers to arrays of doubles. > This is indeed correct, and the problem with this declaration stems from #3. The declaration declares an array of pointers to entities of *undefined* size(not zero size). 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 */ Since this is likely what the user really wanted anyway this works out, but it is still wrong! -- Sarima (Stanley Friesen) UUCP: {ttidca|ihnp4|sdcrdcf|quad1|nrcvax|bellcore|logico}!psivax!friesen ARPA: ??
throopw@dg_rtp.UUCP (Wayne Throop) (05/28/86)
> friesen@psivax.UUCP (Sarima (Stanley Friesen)) >> topher@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