This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Could anyone explain these undefined behaviors (i = i++ + ++i , i = i++, etc…)
#include<stdio.h>
int main()
{
char a[]="Hello";
char *p=a;
while(*p)
++*p++; //Statement 2
printf("%s",a);
int x=10;
++x++; //Statement 1
return 0;
}
When i compile this code i get an l-value Required error in Statement 1, which i can understand. How is that statement 2 does not produce an error even though i intend to do the same thing? Can someone shed light?
Both pre-increment and post-increment produce rvalues and rvalues can't be modified.
So ++x++ (statement 1) is clearly a constraint violation and compiler gives error.
But it's not the case with the statement 2. Though p++ produces an rvalue which its value can't be modified, it can be dereferenced. Alternatively if you do ++p++ this would be equivalent to the ++x++ case and would give an error. Because here the pointer itself is modified.
So it's equivalent to: ++(*p++).
(Note that the brackets are only for understanding and it's not required. The expression ++*p++ is well-defined.)
What happens is:
The post-increment p++ evaluates to the old value of p, in this example &a[0], and the stored value of p is incremented.
*p++ gives the value p pointed to before the increment, in this example a[0].
The final pre-increment increments that value, so a[0] becomes I (probably, could be something else on EBCDIC machines).
When the incremented values of p and a[0] are stored is unspecified, but both must have been stored at the next sequence point (the terminating ;).
Quoting from ISO C99 standard :
6.5.2.4 Postfix increment and decrement operators
Constraints
1
The operand of the postfix increment or decrement operator shall have qualified or
unqualified real or pointer type and shall be a modifiable lvalue.
For this case :
++*p++; //Statement 2
postfix ++ has higher precedence and prefix ++ and * has same precedence and right to left associativity. It means at first step it's incrementing the pointer not it's value.
So it will give you the next address of that type. And then value (which is actually *p) is incremented. So ,In this case no constraint violation.
It's same as ++(*(p++)).
For other case below:
int x=10;
++x++; //Statement 1
In the above case of variable(not pointer) ++(Either postfix or prefix increment or decrement) give you the rvalue ,then applying ++ or -- on rvalue is constraint violation.++ or -- operand should be an lvalue . See the Standard quote written above. Hence giving error.
#include<stdio.h>
int main()
{
char a[]="Hello";
char *p=a;
while(*p)
++*p++; //Statement 2
printf("%s",a);
int x=10;
++x=x++; //Statement 1
return 0;
}
//this code will fetch same error due to the simultaneous pre and post increment.
because it cannot assign and increment simultaneously it require a value to perform increment on it.
Related
I am learning C language and quite confused the differences between ++*ptr and *ptr++.
For example:
int x = 19;
int *ptr = &x;
I know ++*ptr and *ptr++ produce different results but I am not sure why is that?
These statements produce different results because of the way in which the operators bind. In particular, the prefix ++ operator has the same precedence as *, and they associate right-to-left. Thus
++*ptr
is parsed as
++(*ptr)
meaning "increment the value pointed at by ptr,". On the other hand, the postfix ++ operator has higher precedence than the dereferrence operator *. Thefore
*ptr++
means
*(ptr++)
which means "increment ptr to go to the element after the one it points at, then dereference its old value" (since postfix ++ hands back the value the pointer used to have).
In the context you described, you probably want to write ++*ptr, which would increment x indirectly through ptr. Writing *ptr++ would be dangerous because it would march ptr forward past x, and since x isn't part of an array the pointer would be dangling somewhere in memory (perhaps on top of itself!)
Hope this helps!
The accepted answer is not correct. It's not the case that the postfix ++ operator has the same precedence as dereference/indirection *. The prefix and postfix operators have different precedence, and only the prefix operator has the same precedence as dereference/indirection.
As the precedence table shows, postfix ++ has a higher precedence than dereference/indirection *. So *ptr++ gets evaluated as *(ptr++). ptr++ evaluates to the current value of ptr; it increments ptr only as a side effect. The value of the expression is the same as the current value of ptr. So it won't have any effect on the value stored at the pointer. It will merely dereference the pointer (i.e., get the current value stored there, which is 19), then advance the pointer. In your example there is no defined value stored at the new position of ptr, so the pointer is pointing to garbage. Dereferencing it now would be dangerous.
Also as the table shows, prefix ++ has the same precedence as dereference/indirection *, but because of right-left associativity, it gets evaluated as ++(*ptr). This will first dereference the pointer (i.e., get the value stored at the address pointed to) and then increment that value. I.e., the value will now be 20.
The accepted answer is correct about the effects of the two, but the actual mechanism is different from the one given there.
As templatetypedef says, but you should provide the parenthesis around *ptr to ensure the outcome. For instance, the following yields 1606415888 using GCC and 0 using CLang on my computer:
int x = 19;
int *ptr = &x;
printf("%d\n", *ptr++);
printf("%d\n", *ptr);
And you expected x to be 20. So use (*ptr)++ instead.
#include<stdio.h>
void increment(int *p) {
*p = *p + 1;
}
void main() {
int a = 1;
increment(&a);
printf("%d", a);
}
for above if I run above code it prints 2
but if I replace *p = *p + 1; with *p++;
it is printing 1.Why is it so?...
operator precedence...
When writing *p++ you get these operations:
p++ is evaluated (later p will get incremented)
the original value of p is returned (since this is a suffix ++, if it was prefix, the value returned would have been p+1... )
dereference of the the pointer p and since p earlier pointed to 1, that's what you get
If you take a look at the precedence table for operators you will see that the postfix increment has a higher precedence than dereference. This means that *p++ will actually be grouped as *(p++).
You should use parenthesis to explicit what you are trying to do, in this case (*p)++ or ++(*p).
To answer this question consult the table of C operator precedence: operator + has lower precedence than dereference operator *, while increment operator ++ has higher precedence.
That is why ++ is applied to the pointer, while + 1 is applied to the result of pointer dereference.
Read about operator precedence. Check what happens when you do (*p)++.
Note: You may also try doing *(p++). But this will invoke undefined behaviour UB.
In the first case *p=*p+1; the control adds one to the value at *p by 1 and then stores the result in *p. This actually uses a temporary variable during program runtime which you are not able to see. Now,the value at the temporary instance is incremented and finally stored in *p.
In the second case, *p++; a sequence point concept comes.
According to C standard an object's stored value can be modified only once (by evaluation of expressions) between two sequence points.
A sequence point occurs:
at the end of full expressions
at the &&,|| and ?: operators.
at a function call (after evaluation of arguments,just before the actual call)
In *p++;, since the expression is modified only after the sequence point is encountered, *p is unable to store the modified value of itself.
what is the order of precedence for pre ++, post ++ and * ? how these expression are parsed in VS 08 compiler.
void main(){
int arr[] ={34,11,43};
int *ptr = arr;
printf("%d",++*ptr++);
printf("%d",++ptr++);
}
explain the l value expression. i want to understand why ++*ptr++ is a valid expression, while ++ptr++ is giving error.
error: '++' needs l-value
The precedence is ++(*(ptr++)) and ++(ptr++) respectively.
ptr++ is an rvalue, because the language definition says so. (rvalue means that you can use the value but you cannot attempt to refer to the memory location where this value might be stored).
The ++ operator updates the value stored in a memory location, therefore it can only be applied to an lvalue. So ++(ptr++) is a constraint violation.
However, * can be applied to rvalues and the result is an lvalue (i.e. an expression that designates a memory location). So ++ can be applied to *ptr++ .
++p++
Says: pre-increment p and post-increment p (in unspecified order). Even if it were allowed it would invoke undefined behavior due to modifying p more than once before encountering a sequence point.
Anyway, the increment operators, post- and pre-, return an rvalue. An rvalue is the value of an expression. It has no location to write to and can be thought as an intermediate value.
*p++
This expression initially results in an lvalue, *p. That location can be written to, so it is incremented by the pre-increment and then p itself is incremented. The increment results in an rvalue, but you are not attempting to modify it.
In C programming preincrement and predecrement operators return an rvalue which essentially tells you that it is a result and not a place to make an assignment. In C++ programming the preincrement and predecrement operators return an lvalue where you can perform further assignments.
A statement like,
int i=10;
++i=5;
is syntactiacally valid in C++. But in C it is a syntax error.
Even in C++ the postincrement and postdecrement operators return an rvalue. Thus the following statement will give you a syntax error in both C and C++.
int i=10;
i++=5;
I am learning C language and quite confused the differences between ++*ptr and *ptr++.
For example:
int x = 19;
int *ptr = &x;
I know ++*ptr and *ptr++ produce different results but I am not sure why is that?
These statements produce different results because of the way in which the operators bind. In particular, the prefix ++ operator has the same precedence as *, and they associate right-to-left. Thus
++*ptr
is parsed as
++(*ptr)
meaning "increment the value pointed at by ptr,". On the other hand, the postfix ++ operator has higher precedence than the dereferrence operator *. Thefore
*ptr++
means
*(ptr++)
which means "increment ptr to go to the element after the one it points at, then dereference its old value" (since postfix ++ hands back the value the pointer used to have).
In the context you described, you probably want to write ++*ptr, which would increment x indirectly through ptr. Writing *ptr++ would be dangerous because it would march ptr forward past x, and since x isn't part of an array the pointer would be dangling somewhere in memory (perhaps on top of itself!)
Hope this helps!
The accepted answer is not correct. It's not the case that the postfix ++ operator has the same precedence as dereference/indirection *. The prefix and postfix operators have different precedence, and only the prefix operator has the same precedence as dereference/indirection.
As the precedence table shows, postfix ++ has a higher precedence than dereference/indirection *. So *ptr++ gets evaluated as *(ptr++). ptr++ evaluates to the current value of ptr; it increments ptr only as a side effect. The value of the expression is the same as the current value of ptr. So it won't have any effect on the value stored at the pointer. It will merely dereference the pointer (i.e., get the current value stored there, which is 19), then advance the pointer. In your example there is no defined value stored at the new position of ptr, so the pointer is pointing to garbage. Dereferencing it now would be dangerous.
Also as the table shows, prefix ++ has the same precedence as dereference/indirection *, but because of right-left associativity, it gets evaluated as ++(*ptr). This will first dereference the pointer (i.e., get the value stored at the address pointed to) and then increment that value. I.e., the value will now be 20.
The accepted answer is correct about the effects of the two, but the actual mechanism is different from the one given there.
As templatetypedef says, but you should provide the parenthesis around *ptr to ensure the outcome. For instance, the following yields 1606415888 using GCC and 0 using CLang on my computer:
int x = 19;
int *ptr = &x;
printf("%d\n", *ptr++);
printf("%d\n", *ptr);
And you expected x to be 20. So use (*ptr)++ instead.
int val = 5;
printf("%d",++val++); //gives compilation error : '++' needs l-value
int *p = &val;
printf("%d",++*p++); //no error
Could someone explain these 2 cases? Thanks.
++val++ is the same as ++(val++). Since the result of val++ is not an lvalue, this is illegal. And as Stephen Canon pointed out, if the result of val++ were an lvalue, ++(val++) would be undefined behavior as there is no sequence point between the ++s.
++*p++ is the same as ++(*(p++)). Since the result of *(p++) is an lvalue, this is legal.
The expression ++val++ is the same as (++val)++ (or perhaps ++(val++), anyway it's not very relevant). The result of the ++ operator is not the variable, but the value, and you can't apply the operator to a value.
The expression ++*p++ is the same as ++(*(p++)). The result of p++ is the value, but the result of *(p++) is a memory location, which the ++ operator can be applied to.
also note that you're changing the address of the pointer by
int k = ++*p++;
int j = ++val++; //gives compilation error
That because you cannot pre-increment an rvalue. ++val++ is interpreted as ++(val++) because post-increment operator has higher precedence than pre-increment operator. val++ returns an rvalue and pre-increment operator requires its operand to be an lvalue. :)
int k = ++*p++; //no error
++*p++ is interpreted as ++(*(p++)), which is perfectly valid.