f( int (*arr)[13] ) {....}
It is noted that the parentheses are necessary else it would be
interpreted as
int *arr[13] ......snip
There are no operators and no operands, here, just syntax. The *, []
and ()s used in types are not operators operating on anything.
The reason (*x)[13] means what is does comes from the syntax rules of
C, but because these are very wordy, it is much easier to summarise
the effect of the syntax rules by saying things like "[] binds more
tightly that * in a type". You need to remember, though, that is just
a shorthand for the consequences of a formal grammar, written out in the
language specification.
Thanks...but may I ask this.
Accepting the rules as you described, could you perhaps explain why
one would mean
"a pointer to an array of 13 integers" -> int (*arr)[13]
vs
"an array of 13 ptrs to integers" -> int *arr[13].
I might be missing something quite basic here, hence the question.
Although the syntax and meaning of "binding" seem quite obvious, the
fact that I need to look it up each time, tells me I am missing
something.
thanks
Probably the best way to answer this question is to walk through the
grammar for each declaration (I'm using the grammar from Harbison &
Steele, 5th ed., but the grammar in K&R should be similar). I'll use
uppercase to identify non-terminal symbols. The following chart is
best viewed with a fixed-width font (and hopefully Google Groups won't
munge it beyond all hope).
In each case we start with the non-terminal symbol DECLARATION.
Remember that the compiler scans left-to-right, and tries to build the
longest valid tokens that it can. So in a declaration, the first
thing we see is the type specifier "int". Following the type
specifier is one or more declarators. Declarators serve two purposes
-- they introduce the name of the symbol being defined, as well as
providing additional type information. The presence of the '*' token
in a declarator indicates that the declared symbol is of type "pointer-
to" something, whereas the subscript tokens '[' and ']' indicate that
the symbol is of type "array-of" something.
int (*arr)[13]
DECLARATION
/ \
DECLARATION-SPECIFIERS INITIALIZED-DECLARATOR-LIST
| |
TYPE-SPECIFIER INITIALIZED-DECLARATOR
| |
SIGNED-TYPE-SPECIFIER DECLARATOR
| |
int DIRECT-DECLARATOR
|
ARRAY-DECLARATOR
/ \
DIRECT-DECLARATOR '[' CONSTANT-EXPRESSION ']'
| |
'(' DECLARATOR ')' 13
|
POINTER-DECLARATOR
/ \
'*' DIRECT-DECLARATOR
|
SIMPLE-DECLARATOR
|
IDENTIFIER
|
arr
As you can see from this evaluation tree, the presence of the
parentheses in the declarator causes the '*' token to be more closely
associated with the symbol 'arr' than the subscript tokens. That
means the "pointer-to" type information is applied to arr before the
"array-of" type information -- hence, "int *(arr)[13]" evaluates to
"pointer to 13-element array of int".
Now let's look at the other declaration:
int *arr[13]
DECLARATION
/ \
DECLARATION-SPECIFIERS INITIALIZED-DECLARATOR-LIST
| |
TYPE-SPECIFIER INITIALIZED-DECLARATOR
| |
SIGNED-TYPE-SPECIFIER DECLARATOR
| |
int POINTER-DECLARATOR
/ \
POINTER DIRECT-DECLARATOR
| |
'*' ARRAY-DECLARATOR
/ \
DIRECT-DECLARATOR '[' CONSTANT-EXPRESSION
']'
| |
SIMPLE-DECLARATOR 13
|
IDENTIFIER
|
arr
In this case, the subscript tokens are more closely associated with
the symbol arr than the '*' token, so the "array-of" type information
is applied before the "pointer-to" type information, so the
declaration reads as "13-element array of pointers to int."
Hopefully that made sense (and was close to right).