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.
Related
I'm wondering how to actually evaluate the following statement , what does it exactly do ?
*ptr1++ = *ptr2++;
Does it firstly assign the value of that the pointer is pointing at and then increments ?
Is it the same as writing the following ;
*ptr1 = *ptr2
ptr1++;
ptr2++;
Does the equal sign actually have higher precedence than the increment sign (++) ?
Thanks for the help.
There's no need to introduce temporal relationships (like "firstly" and "then") to understand the meaning of this statement. In fact, describing it in terms of "firstly", "secondly" and such would be misleading.
Operator precedence tells us that it should be interpreted as
*(ptr1++) = *(ptr2++);
i.e. it tells us that in both cases ++ applies to pointers, not to pointed values. That's all operator precedence tells us, no more. Operator precedence and associativity does not define order of evaluation (and actually have nothing to do with it).
The fact that postfix form of ++ is used means that the result of ptr1++ subexpression is the old, original, non-incremented pointer value (same for ptr2++). So, the unary * operators are applied to the original pointer values.
This tells us that the assignment operator copies data stored at the location originally pointed by ptr2 to the location originally pointed by ptr1.
Side-effects of this statement (produced by ++ operators) increment both pointers. It does not matter when exactly that happens.
Again, this does not mean that * operators are applied and data is copied "firstly" and pointers are incremented "afterwards". The compiler is free to do it in any order, as long as the required semantics is satisfied. It may compile it into code you suggested in your question, or into something completely different. E.g.
old_ptr1 = ptr1;
ptr1 = ptr1 + 1;
*old_ptr1 = *ptr2;
ptr2 = ptr2 + 1;
According to C Operator Precedence I would say yes and no, the results are equivalent, the sequence of the operations might not be.
quote from the C Operator Precedence
When parsing an expression, an operator which is listed on some row will
be bound tighter (as if by parentheses) to its arguments than any operator
that is listed on a row further below it.
For example, the expression *p++ is parsed as *(p++), and not as
(*p)++.
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.
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?
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.
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'.
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;
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.
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.
When you don't use the returned value, they do the same (although different implementations may yield different performance in some cases). E.g. in for loops, 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.
*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?
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++; 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?
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:
Copy p into temporary THEN increment p, THEN load value at address indicated in temporary THEN store loaded value to a
Copy 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
Copy 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.
#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.
I have an int pointer (i.e., int *count) that I want to increment the integer being pointed at by using the ++ operator. I thought I would call:
*count++;
However, I am getting a build warning "expression result unused". I can: call
*count += 1;
But, I would like to know how to use the ++ operator as well. Any ideas?
The ++ has equal precedence with the * and the associativity is right-to-left. See here. It's made even more complex because even though the ++ will be associated with the pointer the increment is applied after the statement's evaluation.
The order things happen is:
Post increment, remember the post-incremented pointer address value as a temporary
Dereference non-incremented pointer address
Apply the incremented pointer address to count, count now points to the next possible memory address for an entity of its type.
You get the warning because you never actually use the dereferenced value at step 2. Like #Sidarth says, you'll need parenthesis to force the order of evaluation:
(*ptr)++
Try using (*count)++. *count++ might be incrementing the pointer to next position and then using indirection (which is unintentional).