question about pointer

B

Bo Sun

hi:

please take a look at the following code:

int p[4]={111, 222, 333, 444}, *q = p, p1, p2, p3;

p1 = *q++;
p2 = *(q++);
p3 = *(++q);


what is value of p2? I think it should be 333. however, the result of p2
is 222.

what is wrong here?

thanks,

bo
 
M

Mark A. Odell

int p[4]={111, 222, 333, 444}, *q = p, p1, p2, p3;

p1 = *q++;
p2 = *(q++);

*p++ and *(q++) generate the same result, just drop the ()'s.
p3 = *(++q);

Again, the ()'s are not doing anything since ++ has higher precedence than
* as they are evaluated left to right.
what is value of p2? I think it should be 333. however, the result of
p2 is 222.

So in the first two cases you get the value q pointed to and then
increment q. In the last case you increment q and then get the value it
points to. So p1 points to p[0], p2 points to p[1], then you skip p[2] and
p3 points to p[3].
what is wrong here?

Nothing.
 
H

Horst Kraemer

hi:

please take a look at the following code:

int p[4]={111, 222, 333, 444}, *q = p, p1, p2, p3;

p1 = *q++;
p2 = *(q++);
p3 = *(++q);


what is value of p2? I think it should be 333. however, the result of p2
is 222.
what is wrong here?

That you probably think that

p2 = *(q++);

which is in fact the same as

p2 = *q++;

is equivalent to

p2 = *++q;


*(q++) doesn't mean "increment q and then dereference the
(incremented) variable q", instead it means: take the (old) value of q
and dereference it - and increment q at some moment up to the next
sequence point. I.e. the result of the *assigment* is the same as the
result of p2=*q. The only difference is that q has been incremented
afterwards.
 
C

Chris Torek

Bo Sun said:
int p[4]={111, 222, 333, 444}, *q = p, p1, p2, p3;

p1 = *q++;
p2 = *(q++);

*p++ and *(q++) generate the same result, just drop the ()'s.


Again, the ()'s are not doing anything since ++ has higher precedence than
* as they are evaluated left to right.

It is, I think, better to say "++ binds more tightly" than "++
has higher precedence". In some sense these are the same thing,
but in another important way, they are very different.

The word "precedence" contains the word "precede", which means "to
go in front of" or "to be earlier than". People seem to read things
into this that are not there. For instance, in "f() + g() * h()",
one can say that "*" has "higher precedence" than "+". The assumption
people make is that g() and h() will get called first -- but there
is no such guarantee. A C compiler could actually call f() first,
then call h() and g() (in either order), then multiply, then add.

I think (without any real proof) that if one talks about "binding"
instead of "precedence", then shows how a parse tree works, it
helps people de-couple the concept of compile-time parse-tree
binding from that of run-time execution order.

In any case:

(It should indeed be 222.)
So in the first two cases you get the value q pointed to and then
increment q. In the last case you increment q and then get the value it
points to. So p1 points to p[0], p2 points to p[1], then you skip p[2] and
p3 points to p[3].

For:

p1 = *q++;

(and likewise for p2), you could actually "increment q" first, then
"get the value q pointed to before the increment", as if you had
written instead:

q++; p1 = q[-1];

or even the rather obfuscated:

p1 = (++q)[-1];

A C compiler might even generate the same machine code for all
three of these source code patterns.

C makes only these promises in the expression:

p1 = *q++;

- q will be incremented eventually; this will be visible some time
between "the previous sequence point" and "the next sequence
point".

- The value q had before the increment will be an operand to the
unary "*" operator.

- The unary "*" operator will find the object the pointer points
to.

- The value of that object (i.e., *q) will be obtained and, at
some point, be stored into the object named "p1". This store
will be visible some time between "the previous sequence
point" and "the next sequence point".

- The semicolon terminating this statement is a sequence point
(the "next" one as far as all of the above goes).

The sequence point from the semicolon is where the action stops.
All of the changes piled up -- "increment q", "find value of *(q
before increment)", and "store new value into p1" must all finish.
But any order these occur in is invisible, and if you write code
in which the order might *be* visible, you get no guarantees. In
some cases -- like f() + g() * h(), where each function prints "f()
called\n" and "g() called\n" and "h() called\n" -- the effect is
"unspecified behavior". Here nothing "bad" can happen, but the
output may occur in any order. In other cases, like "a = i++;"
-- the effect is "undefined" behavior. With undefined behavior
all bets are off; arbitrarily bad things may happen (including
the example someone had earlier of "void main()" nearly frying
the computer monitor).

In this case, nothing depends on any underlying order, so the
code is correct:
 
M

Mark A. Odell

It is, I think, better to say "++ binds more tightly" than "++
has higher precedence". In some sense these are the same thing,
but in another important way, they are very different.

I agree, bind would have been the better term.
 
K

Kevin Goodsell

Bo said:
hi:

please take a look at the following code:

int p[4]={111, 222, 333, 444}, *q = p, p1, p2, p3;

p1 = *q++;
p2 = *(q++);
p3 = *(++q);


what is value of p2? I think it should be 333. however, the result of p2
is 222.

what is wrong here?

thanks,

bo

You seem to be making the common mistake of believing that the
parentheses will somehow force complete evaluation of the increment
before anything outside of the parenthesis is considered. In fact,
parentheses do not change order of evaluation, they only override
precedence. Overriding precedence can sometimes have the effect of
changing order of evaluation, but this is not such a case.

Checking a precedence chart, you should be able to determine that in the
expression

*q++

the ++ binds more tightly than the *. You probably also know,
intuitively, that using parens to clarify this fact should not change
the meaning of the expression. The following expression is exactly the
same - the parens are redundant.

*(q++)

And the reason you know this, intuitively, is that you've seen it in
other, less confusing cases. You know these two expressions are equivalent:

a + b * c

a + (b * c)

-Kevin
 
G

glen herrmannsfeldt

Chris Torek wrote:

(snip)
The word "precedence" contains the word "precede", which means "to
go in front of" or "to be earlier than". People seem to read things
into this that are not there. For instance, in "f() + g() * h()",
one can say that "*" has "higher precedence" than "+". The assumption
people make is that g() and h() will get called first -- but there
is no such guarantee. A C compiler could actually call f() first,
then call h() and g() (in either order), then multiply, then add.
I think (without any real proof) that if one talks about "binding"
instead of "precedence", then shows how a parse tree works, it
helps people de-couple the concept of compile-time parse-tree
binding from that of run-time execution order.

I agree that precedence has other meanings, but it seems that by
now it has been used for this meaning long enough to keep.

Since early languages such as Fortran and Algol didn't have
operators with side effects, that problem didn't come up.

Functions could have side effects, but maybe they didn't worry
about that. As the word has been used with this meaning
for many years, it seems to me too late to change it.

-- glen
 

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

No members online now.

Forum statistics

Threads
474,122
Messages
2,570,717
Members
47,283
Latest member
VonnieEwan

Latest Threads

Top