Reputation: 183
Expression 1: *p++;
where p
is a pointer to integer.
p
will be incremented first and then the value to which it is pointing to is taken due to associativity(right to left). Is it right?
Expression 2: a=*p++;
where p
is a pointer to integer.
Value of p
is taken first and then assigned to a
first then p
is incremented due to post increment. Is it right?
Upvotes: 12
Views: 2389
Reputation: 643
v = i++;
: i
is returned to the equality operation and then assigned to v
. Subsequently, i
is incremented (EDIT: technically it's not necessarily executed in this order). Thus v
has the old value of i
. I remember it like this: ++
is written last and therefore happens last.v = ++i;
: i
is incremented, and then returned to be assigned to v
. v
and i
has the same value.for(int i=0; i<n; i++)
is the same as for(int i=0; i<n; ++i)
. The latter is sometimes automatically preferred because it tends to be faster for some objects.*
has lower precedence than ++
so *p++
is the same as *(p++)
. Thus in this case p
is returned to *
which dereferences it. Then the address in p
is incremented by one element. *++p
increments the adress of p first, then dereferences it.v = (*p)++;
sets v equal to the old value pointed to by p
and then increments it, while v = ++(*p);
increments the value pointed to by p
and then sets v
equal to it. The address in p
is unchanged.Example: If,
int a[] = {1,2};
then
int v = *a++;
and
int v = *++a;
will both leave a
incremented, but in the first case v
will be 1 and in the latter it'll be 2.
Upvotes: 1
Reputation: 283893
*p++;
wherep
is a pointer to integer.
p
will be incremented first and then the value to which it is pointing to is taken due to associativity (right to left). Is it right?
No. In a post-increment, the value is copied to a temporary (an rvalue), then the lvalue is incremented as a side effect.
a=*p++;
wherep
is a pointer to integer.Value of
p
is taken first and then assigned toa
first thenp
is incremented due to post increment. Is it right?
No, that's not correct either. The increment of p
might happen before the write to a
. What's important is that the value being stored in a
was loaded using the temporary copy of the prior value of p
.
Whether that memory fetch occurs before the memory write with the new value of p
isn't specified, and any code that relies on the order is undefined behavior.
Any of these sequences are allowed:
p
into temporary THEN increment p
, THEN load value at address indicated in temporary THEN store loaded value to a
p
into temporary THEN load value at address indicated in temporary (this value itself is placed in a temporary) THEN increment p
THEN store loaded value to a
p
into temporary THEN load value at address indicated in temporary THEN store loaded value to a
THEN increment p
Here are two code examples that are undefined behavior because they rely on the order of side effects:
int a = 7;
int *p = &a;
a = (*p)++; // undefined behavior, do not do this!!
void *pv;
pv = &pv;
void *pv2;
pv2 = *(pv++); // undefined behavior, do not do this!!!
The parentheses do not create a sequence point (or sequenced before relationship, in the new wording). The version of the code with parentheses is just as undefined as the version without.
Upvotes: 0
Reputation: 134396
First of all, let me tell you that, neither associativity nor order of evaluation is actually relevant here. It is all about the operator precedence. Let's see the definitions first. (emphasis mine)
Precedence : In mathematics and computer programming, the order of operations (or operator precedence) is a collection of rules that reflect conventions about which procedures to perform first in order to evaluate a given mathematical expression.
Associativity: In programming languages, the associativity (or fixity) of an operator is a property that determines how operators of the same precedence are grouped in the absence of parentheses.
Order of evaluation : Order of evaluation of the operands of any C operator, including the order of evaluation of function arguments in a function-call expression, and the order of evaluation of the subexpressions within any expression is unspecified, except a few cases. There's mainly two types of evaluation: a) value computation b) side effect.
Post-increment has higher precedence, so it will be evaluated first.
Now, it so happens that the value increment is a side effect of the operation which is sequenced after the " value computation". So, the value computation result, will be the unchanged value of the operand p
(which again, here, gets dereferenced due to use of *
operator) and then, the increment takes place.
Quoting C11
, chapter §6.5.2.4,
The result of the postfix
++
operator is the value of the operand. As a side effect, the value of the operand object is incremented (that is, the value 1 of the appropriate type is added to it). See the discussions of additive operators and compound assignment for information on constraints, types, and conversions and the effects of operations on pointers. The value computation of the result is sequenced before the side effect of updating the stored value of the operand. [.....]
The order of evaluation in both the cases are same, the only difference is, in the first case, the final value is discarded.
If you use the first expression "as-is", your compiler should produce a warning about unused value.
Upvotes: 18
Reputation: 311126
Postfix operators have higher priorities than unary operators.
Thus this expression
*p++
is equivalent to the expression
*( p++ )
According to the C Standard (6.5.2.4 Postfix increment and decrement operators)
2 The result of the postfix ++ operator is the value of the operand. As a side effect, the value of the operand object is incremented (that is, the value 1 of the appropriate type is added to it). See the discussions of additive operators and compound assignment for information on constraints, types, and conversions and the effects of operations on pointers. The value computation of the result is sequenced before the side effect of updating the stored value of the operand.
So p++
yields the original value of the pointer p
as the result of the operation and has also a side effect of incrementing the operand itself.
As for the unary operator then (6.5.3.2 Address and indirection operators)
4 The unary * operator denotes indirection. If the operand points to a function, the result is a function designator; if it points to an object, the result is an lvalue designating the object. If the operand has type ‘‘pointer to type’’, the result has type ‘‘type’’. If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined
So the final result of the expression
*( p++ )
is the value of the object pointed to by the pointer p
that also is incremented due to the side effect. This value is assigned to the variable a
in the statement
a=*p++;
For example if there are the following declarations
char s[] = "Hello";
char *p = s;
char a;
then after this statement
a = *p++;
the object a
will have the character 'H'
and the pointer p
will point to the second character of the array s that is to the character 'e'
.
Upvotes: 9
Reputation: 782508
Associativity is not relevant here. Associativity only matters when you have adjacent operators with the same precedence. But in this case, ++
has higher precedence than *
, so only precedence matters. Because of precedence, the expression is equivalent to:
*(p++)
Since it uses post-increment, p++
increments the pointer, but the expression returns the value of the pointer before it was incremented. The indirection then uses that original pointer to fetch the value. It's effectively equivalent to:
int *temp = p;
p = p + 1;
*temp;
The second expression is the same, except it assigns the value to another variable, so that last statement becomes:
a = *temp;
Upvotes: 5
Reputation: 24788
The expression
*p++
is equivalent to
*(p++)
This is due to precedende (i.e.: the postfix increment operator has higher precedence than the indirection operator)
and the expression
a=*p++
is for the same reason equivalent to
a=*(p++)
In both cases, the expression p++
is evaluated to p
.
Upvotes: 3