Array and binding question.

M

mdh

From p112 ( K&R).
Given an array declared as
static char arr[2][13]= { { 0,1,........},{0,1,.....}};


let arr be passed as an argument to f.

f( int (*arr)[13] ) {....}

It is noted that the parentheses are necessary else it would be
interpreted as

int *arr[13] ( an array of 13 pointers to integers, as opposed to the
intended pointer to an array of 13 integers. The basis of this
explanation is that "[ ]" bind tighter than " * ".

Now, there have been extensive discussions about precedence and
associativity ....but my question is this.

RH has described precedence and associativity as deciding which
operators are associated with which operands.

In the case above, I assume the operator is the "[]", but what are
operands?
Or am I missing something else here...probably.

Thanks
 
B

Ben Bacarisse

mdh said:
From p112 ( K&R).
Given an array declared as
static char arr[2][13]= { { 0,1,........},{0,1,.....}};


let arr be passed as an argument to f.

f( int (*arr)[13] ) {....}

It is noted that the parentheses are necessary else it would be
interpreted as

int *arr[13] ( an array of 13 pointers to integers, as opposed to the
intended pointer to an array of 13 integers. The basis of this
explanation is that "[ ]" bind tighter than " * ".

Now, there have been extensive discussions about precedence and
associativity ....but my question is this.

RH has described precedence and associativity as deciding which
operators are associated with which operands.

In the case above, I assume the operator is the "[]", but what are
operands?
Or am I missing something else here...probably.

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.

The same is true, incidentally, for expressions. There is no operator
precedence table in the standard, just a grammar that says, for
example, that an addition can't be one of the parts of a
muliticative-expression, unless it is via the rule that allows a
cast-expression, which can be a unary-expression, which can be a
postfix-expression which can be a primary-expression, which can be an
expression in brackets! You can see why a summary tables is popular.
 
M

mdh

mdh said:
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
 
A

Ark Khasin

mdh said:
mdh said:
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
I think the raw syntax for a pointer to an array (or a function pointer,
for that matter) is outright evil. If you need to look it up often, the
same perhaps applies to those who read your code... which means they won't.

To me, the salvation comes as typedef.
If
int a[13];
means array of 13 ints, then
typedef int atype[13];
defines atype as a type of array of 13 ints.
A pointer to an array of 13 ints is then of type atype*.
It is wordier but much more readable.

-- Ark
 
B

Barry Schwarz

mdh said:
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.

It is the same as the difference between a+b*c and (a+b)*c.

If you take the precedence table on page 53 of K&R II at face value,
[] binds tighter than * so the expression int *arr[13] is treated the
same as int *(arr[13]). With these parentheses as a hint/crutch, the
difference from int (*arr)[13] should be clearer.


Remove del for email
 
M

mdh

If you take the precedence table on page 53 of K&R II at face value,
[] binds tighter than * so the expression int *arr[13] is treated the
same as int *(arr[13]). With these parentheses as a hint/crutch, the
difference from int (*arr)[13] should be clearer.

Thanks ...nice explanation.

I also just found the FAQ and the footnote of the explanation.(http://
c-faq.com/aryptr/ptrary2.html) I think what I was missing as well was
that these are type declarations.... well, I hope they are. I also
think I was trying to make it more complicated than it deserves.
Strange how frequent puzzling issues turn up in the FAQ :)

Thank you.
 
M

mdh

I think the raw syntax for a pointer to an array (or a function pointer,
for that matter) is outright evil. If you need to look it up often, the
same perhaps applies to those who read your code... which means they won't.

To me, the salvation comes as typedef.

Ah...salvation....for me ....lies in the next chapter of K&R!! :)

Thanks for your input.
 
J

Jack Klein

mdh said:
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

In this case, binding defines what "attributes" are applied to the
identifier first. I put "attributes" in quotation marks because it is
not a word defined in the standard, but one I think might be useful
here.

In the declaration:

int *arr[13]

....the tighter binding of [] means that [] is applied to "arr" first:

arr[/*anything*/] means "arr is an array"

arr[13] means "arr is an array of 13 ?"

*arr[13] means "arr is an array of 13 pointers"

int *arr[13] means "arr is an array of 13 pointers to int"

In the declaration:

int (*arr)[13]

....the parentheses enforce a grouping, all elements inside the
parentheses are applied before anything outside the parentheses, so:

(*arr) means "arr is a pointer"

(*arr)[/*anything*/] means "arr is a pointer to an array"

(*arr)[13] means "arr is a pointer to an array of 13 ?"

int (*arr)[13] means "arr is a pointer to an array of 13 ints"

Note that there is a rule of thumb that you can use that holds in
many, but not all cases, the "right-left" rule. It is based on the
fact that in most cases, postfix operators (on the right) bind more
tightly prefix operators (on the left).

That is why:

*char_ptr++;

....increments the pointer, and not what it points to, because the
postfix ++ operator binds more tightly than the prefix pointer
indirection operator.

If you actually want to increment the character pointed to, and not
the pointer, you would need to do:

(*char_ptr)++;

In the absence of parentheses, you start at the identifier (object,
function, or typedef name), and start looking to the right. One you
have found the "attribute" on the right, go left. And, if necessary,
back-and-forth right-to-left as necessary.

If you look back at the way I stepped through int *arr[13], you can
see the application of the right-left rule.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
 
D

Default User

mdh said:
From p112 ( K&R).
Given an array declared as
static char arr[2][13]= { { 0,1,........},{0,1,.....}};


let arr be passed as an argument to f.

f( int (*arr)[13] ) {....}

It is noted that the parentheses are necessary else it would be
interpreted as

int *arr[13] ( an array of 13 pointers to integers, as opposed to the
intended pointer to an array of 13 integers. The basis of this
explanation is that "[ ]" bind tighter than " * ".

In the case of a function parameter (as you have), that's not the case.
It's actually the same as int *arr[], which is the same as int **arr.



Brian
 
B

Ben Bacarisse

Default User said:
mdh said:
From p112 ( K&R).
Given an array declared as
static char arr[2][13]= { { 0,1,........},{0,1,.....}};


let arr be passed as an argument to f.

f( int (*arr)[13] ) {....}

It is noted that the parentheses are necessary else it would be
interpreted as

int *arr[13] ( an array of 13 pointers to integers, as opposed to the
intended pointer to an array of 13 integers. The basis of this
explanation is that "[ ]" bind tighter than " * ".

In the case of a function parameter (as you have), that's not the case.
It's actually the same as int *arr[], which is the same as int
**arr.

As a parameter 'int *arr[]' is indeed the same 'int **arr' but, even
as a parameter 'int (*arr)[13]' is only the same as 'int arr[][13]'
(and parenthesised versions of the same like 'int (arr[])[13]'). It
is quite different to 'int **arr'.

The parse is crucial to determining the meaning since 'int (*arr)[13]'
and 'int *arr[13]' are, as the OP states, quite different parameter
types.
 
J

John Bode

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).
 
J

John Bode

[snip]
"array-of" type information -- hence, "int *(arr)[13]" evaluates to
"pointer to 13-element array of int".

[snip]

Argh -- of course, "*(arr)[13]" should be written "(*arr)[13]".

Grump.
 
D

Default User

Ben said:
Default User said:
mdh said:
From p112 ( K&R).
Given an array declared as
static char arr[2][13]= { { 0,1,........},{0,1,.....}};


let arr be passed as an argument to f.

f( int (*arr)[13] ) {....}

It is noted that the parentheses are necessary else it would be
interpreted as

int *arr[13] ( an array of 13 pointers to integers, as opposed to the >> intended pointer to an array of 13 integers. The basis of this
explanation is that "[ ]" bind tighter than " * ".

In the case of a function parameter (as you have), that's not the
case. It's actually the same as int *arr[], which is the same as
int **arr.

As a parameter 'int *arr[]' is indeed the same 'int **arr' but, even
as a parameter 'int (*arr)[13]' is only the same as 'int arr[][13]'
(and parenthesised versions of the same like 'int (arr[])[13]'). It
is quite different to 'int **arr'.

Did anyone say any differently?


The parse is crucial to determining the meaning since 'int (*arr)[13]'
and 'int *arr[13]' are, as the OP states, quite different parameter
types.

The second is not, in the example give, the type the OP stated.




Brian
 
B

Ben Bacarisse

Default User said:
Ben said:
Default User said:
mdh wrote:

From p112 ( K&R).
Given an array declared as
static char arr[2][13]= { { 0,1,........},{0,1,.....}};


let arr be passed as an argument to f.

f( int (*arr)[13] ) {....}

It is noted that the parentheses are necessary else it would be
interpreted as

int *arr[13] ( an array of 13 pointers to integers, as opposed to
the >> intended pointer to an array of 13 integers. The basis of this
explanation is that "[ ]" bind tighter than " * ".

In the case of a function parameter (as you have), that's not the
case. It's actually the same as int *arr[], which is the same as
int **arr.

As a parameter 'int *arr[]' is indeed the same 'int **arr' but, even
as a parameter 'int (*arr)[13]' is only the same as 'int arr[][13]'
(and parenthesised versions of the same like 'int (arr[])[13]'). It
is quite different to 'int **arr'.

Did anyone say any differently?

Well, I thought you did but obviously I am mistaken! Sorry.

To what did your "it" refer in "It's actually the same as int *arr[]"?
I thought you were referring to one of the OP's two readings of his
type 'int (*arr)[13]'.
 
D

Default User

Ben said:
As a parameter 'int *arr[]' is indeed the same 'int **arr'
Did anyone say any differently?

Well, I thought you did but obviously I am mistaken! Sorry.

To what did your "it" refer in "It's actually the same as int *arr[]"?
I thought you were referring to one of the OP's two readings of his
type 'int (*arr)[13]'.

Here's what the OP said:

============================================================
let arr be passed as an argument to f.

f( int (*arr)[13] ) {....}

It is noted that the parentheses are necessary else it would be
interpreted as

int *arr[13] ( an array of 13 pointers to integers, as opposed to the
intended pointer to an array of 13 integers. The basis of this
explanation is that "[ ]" bind tighter than " * ".

============================================================



Brian



Brian
 
B

Ben Bacarisse

Default User said:
Ben said:
As a parameter 'int *arr[]' is indeed the same 'int **arr'
Did anyone say any differently?

Well, I thought you did but obviously I am mistaken! Sorry.

To what did your "it" refer in "It's actually the same as int *arr[]"?
I thought you were referring to one of the OP's two readings of his
type 'int (*arr)[13]'.

Here's what the OP said:

============================================================
let arr be passed as an argument to f.

f( int (*arr)[13] ) {....}

It is noted that the parentheses are necessary else it would be
interpreted as

int *arr[13] ( an array of 13 pointers to integers, as opposed to the
intended pointer to an array of 13 integers. The basis of this
explanation is that "[ ]" bind tighter than " * ".

============================================================

Ah, right. I hope you can see the source of my confusion. The text
you commented on also used "it" ("it [the form with parentheses] would
be...") and so when you then went on to talk about "it", the natural
reading (at least in *my* head) was that your "it" referred to the
original "it"!

Sorry for the confusion.
 
D

Default User

Ben said:
Here's what the OP said:

============================================================
let arr be passed as an argument to f.

f( int (*arr)[13] ) {....}

It is noted that the parentheses are necessary else it would be
interpreted as

int *arr[13] ( an array of 13 pointers to integers, as opposed to
the intended pointer to an array of 13 integers. The basis of this
explanation is that "[ ]" bind tighter than " * ".

============================================================

Ah, right. I hope you can see the source of my confusion. The text
you commented on also used "it" ("it [the form with parentheses] would
be...") and so when you then went on to talk about "it", the natural
reading (at least in my head) was that your "it" referred to the
original "it"!

Sorry for the confusion.


Not a problem, the messages tended to be somewhat confusing. I tried to
straighten out one point of what seemed to me to confusion, but I feel
I only muddied the waters further.



Brian
 
M

mdh

In the declaration:

int *arr[13]

...the tighter binding of [] means that [] is applied to "arr" first:

arr[/*anything*/] means "arr is an array"

arr[13] means "arr is an array of 13 ?"

*arr[13] means "arr is an array of 13 pointers"

int *arr[13] means "arr is an array of 13 pointers to int"

In the declaration:

int (*arr)[13]

...the parentheses enforce a grouping, all elements inside the
parentheses are applied before anything outside the parentheses, so:

(*arr) means "arr is a pointer"

(*arr)[/*anything*/] means "arr is a pointer to an array"

(*arr)[13] means "arr is a pointer to an array of 13 ?"

int (*arr)[13] means "arr is a pointer to an array of 13 ints"

Note that there is a rule of thumb that you can use that holds in
many, but not all cases, the "right-left" rule. It is based on the
fact that in most cases, postfix operators (on the right) bind more
tightly prefix operators (on the left).

Thank you very much for that great explanation....
 
M

mdh

eclaration reads as "13-element array of pointers to int."

Hopefully that made sense (and was close to right).


Thanks for all that effort...it certainly illuminates Ben Bacarisse's
point about rules of syntax. It will become part of my permanent C
notes.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,280
Latest member
BGBBrock56

Latest Threads

Top