I'm trying to understand how the parentheses affects the precedence in an expression:
int arr[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
auto b = arr;
std::cout << *(++b) << std::endl;
// output : 1
In this code I get the expected output but if I change it to:
std::cout << *(b++) << std::endl;
// output 0
I get 0 as output. Because of the parentheses I though b++ will be evaluated first and then de-referencing will occur. It seems I was wrong, then I removed the parentheses completely and test with *++b and *b++ and get the same results.Does that mean the parentheses don't affect the precedence on this kind of expressions ? And why are the results of this two expressions are equivelant:
*(b + 1)
*(++b)
But it's not the case with *(b++) ?
It does evaluate the b++ first. b++ increments b and returns the previous value of b, before the increment happened. The result of b++ and the value of b afterwards are different. Think of it as (using int instead of int * because a reference-to-pointer makes the signature ugly):
int postfix_increment(int &x) {
int result = x;
x = x + 1;
return result;
}
(Except that using the incremented value before the next sequence point is undefined behavior.)
If you introduce a temporary variable for the result of the parenthesis, to make sure it's evaluated first, it may be easier to see the difference:
int *tmp = b++;
// At this point, b == tmp + 1!
std::cout << *tmp << std::endl;
*(b++) is equivalent to storing the old pointer, incrementing the pointer and dereferencing the old pointer
int* post_increment(int* b)
{
int* old = b;
++b;
return old;
}
It is an instructive exercise to write a thin iterator wrapper around a plain pointer. When writing user-defined iterators, the above post_increment() function is usually written an overloaded operator++(int). The int argument is purely to distinguish it from the pre-increment operator operator++(). In addition, you'd need an overloaded operator*() to dereference an iterator.
*(b+1) works because you do math. Math takes parentheses into account. Only after Math is done, the expression gets evaluated.
*(++b) works because you increment before evaluation (prefix increment).
*(b++) doesn't work because you increment after evaluation (postfix increment).
Related
From What does an assignment return? :
An assignment expression has the value of the left operand after the assignment
and this code:
#include <iostream>
using namespace std;
int main() {
int a[5] = { 0,1,2 };
int* a_ptr = a;
int b = (*a_ptr++ = 3); //int *b won't compile
cout << b << endl; //3
}
What is the left operand of = when evaluating (*a_ptr++ = 3) ?
What's the definition of an operand? In my mind, an operand is an identifier or name which is aptr.
int b = (*a_ptr++ = 3); is grouped as int b = (*(a_ptr++) = 3);. Note that the parentheses are superfluous; you could have written
int b = *a_ptr++ = 3;
which in many ways makes the result more obvious, since the right-to-left associativity of = is such that the 3 carries over to the value of b.
a_ptr++ is an expression equal to a_ptr but it will point to the second element of the array a once the whole statement completes. Since you don't make use of that incremented pointer, the ++ is a red-herring, so the statement simplifies to
int b = *a_ptr = 3;
whereupon it's clear that *a_ptr = 3 has the effect of setting the first element of the array a to 3 and is an expression equal to 3, which is assigned to b.
The left operand is *a_ptr++. As per the operator precedence, it's evaluated as
*(a_ptr++)
where the post-increment is sequenced as a side effect, after the execution of the statement. The value of the operand is the result of the statement. So, it's equivalent to
int b = (*a_ptr = 3);
a_ptr++;
That said, in general, Operands are expressions or values on which an operator operates or works. So, it can be
a variable (ex: var, as in int var)
a literal (5 or '"Hello"')
an expression (like *a_ptr++)
If I have this code:
int A[5] = { 2, 1, 3, 55 };
int *p = A;
cout << ++(*p);
the result is 3 and the value of the first position of A is 3 also, why?
I mean, by hierarchy of operators () is more hierarchical than ++, then we would need operate *p first:
++(*p) => ++(2) => 3
with any change in A vector?
*p is not just "2", it's an lvalue, i.e. this "2" has a well-defined location.
The value at this location is modified by the ++ operator - by definition of the ++ operator.
If you don't want to modify the value, use + 1 instead: *p + 1.
In C/C++, lvalue is a value with a defined location in memory. This value can be changed - by an assignment, incremented, decrement.
For example,
int x = 0;
x = 1; // ok, x is an lvalue, assignment changes the value from 0 to 1
int *p = &x;
*p = 2; // ok, *p is an lvalue, assignment changes the value from 1 to 2
In contrast, an rvalue is a value without a defined location - for example, a result of an arithmetic operation. This value can't be assigned, incremented or decremented (it doesn't mean it can't be used in a larger expression).
For example,
int x = 0, y = 1;
(x + y) = 3; // compilation error, (x + y) is an rvalue
2++; // compilation error, 2 is an rvalue
Here's a pretty simple article explaining lvalues / rvalues: https://eli.thegreenplace.net/2011/12/15/understanding-lvalues-and-rvalues-in-c-and-c
The ++(*p) is the same as ++p[0] and ++A[0] All change the first element of the array.
Why ++(*p) changes the pointer value
It does not. The pointer value is value kept in the p. It is called "address" or "reference". It does not change.
It's worth noting the overuse of '*' in C++ which usually confuses novices.
Here:
int *p = A;
'*' means you are declaring p as a variable that can store a memory address (a pointer), and assigning the address of the first position of A (it's the same as &(A[0]) ).
Here:
++(*p)
' *' means you are looking into 'p' content (derreferencing the address of 'p' which is the same as the address of 'A[0]'). Then the '++' increments the value which reflects both.
Just to confirm, after this assignment (int *p = A;) print the values of 'p', 'A' and '&A[0]'.
I stumbled upon https://en.cppreference.com/w/cpp/language/operator_precedence
On the chart, I see that post-increment operator (++) is way above assignment operator (=).
However, I know that
int a[] = {10,20};
int* b = &a[0];
*(b++) = 5;
cout << a[0] << endl; // 5
cout << a[1] << endl; // 20
cout << *b << endl; // 20, now points to a[1]
I always take it for grant that post-increment happens after the assignment operator. However, if I follow the operation precedence chart, then isn't post-increment suppose to happen before = operation? Isn't the answer suppose to be a={10, 5} rather than a={5, 20}?
"Precedence" is misleading. It has little to do in general with evaluation order (what happens first), but instead determines what is the operand of each operator for the purpose of evaluation. But let's examine your example.
*(b++) = 5;
This means that 5 is to be assigned to the lvalue on the left. And since C++17, we know that 5 is evaluated entirely before *(b++). Prior to that, they could be evaluated in any order.
Now, b++ has the meaning of "increment b, but evaluate to its previous value". So b++ may cause the increment to happen prior to the assignment taking place, yes, but the value of (b++) is the address before the increment happened. And that is why b is updated to point at the next element, while modifying the current one, in one expression.
Post increment (b++) increments b, then returns the previous value of b.
Pre increment (++b) increments b, then returns the new value of b.
To get the behavior you're expecting, change from post-increment to pre-increment.
For example:
#include <iostream>
int main() {
int a[] = {10, 20};
int *b = &a[0];
*(++b) = 5;
std::cout << a[0] << std::endl;
std::cout << a[1] << std::endl;
std::cout << *b << std::endl;
}
Yields the following output:
10
5
5
Table is Correct. And there is no confusion for the result.
Just remember the fact that post increment(PI) or decrement(DI), perform +1 or -1 update after the current statement containing PI or DI.
*(b++) = 5;
1st b++ will take place first as it is in parentheses. but b didn't move next yet. As compiler always remember in post operations that it would perform it after the current statement. so it is like:
*b = 5; // a[0]=5; compiler remembered b=b+1; to be executed.
so now b = b+1;
hence b is now pointing at a[1];
What is the order of evaluation in ++*ptr++? Does it change when pointers and lvalues are involved in the operation?
If the precedence of a++ is higher than *a or ++a, then why is ++*a++ evaluated as first returning the incremented value then changing the pointer, rather than changing the pointer, then incrementing the value at the location.
Refrence for Precedence: https://en.cppreference.com/w/cpp/language/operator_precedence
arr = {9, 99, 999 };
int *ptr = arr;
std::cout << ++*ptr++ << '\t';
std::cout << *ptr;
I expected the output to be 100 100, but the actual output was 10 99.
The postfix increment a++ increments the pointer ptr, but returns the copy of ptr before the operation (see difference between prefix/postfix).
So it can be rewritten (as noted in Quimby's answer) as ++(*(ptr++)) and goes like:
ptr++ : increments ptr so that it points to 99, but returns another pointer that still points to 9
*ptr++ : dereferences, evaluates to 9
++*ptr++ : increments the value pointed to by the copied pointer, meaning increments 9 and returns 10
Here the logic behind pre/post increment/decrement is explained well:
Pre-increment and pre-decrement operators increments or decrements the value of the object and returns a reference to the result.
Post-increment and post-decrement creates a copy of the object, increments or decrements the value of the object and returns the copy from before the increment or decrement.
From: https://en.cppreference.com/w/cpp/language/operator_incdec
Postfix operators have higher precedence that prefix so they BIND tighter/first so: ++*ptr++ is the same as ++(*(ptr++)) which boils down to what operand works on what. So postfix ++ will be applied to your 'ptr' pointer but 'after' first std::cout line. Prefix ++ will work on dereferenced ptr so this all is the same as:
int arr[] = {9, 99, 999 };
int *ptr = arr;
++(*ptr); // 9+1=10
std::cout << *ptr << '\t';
ptr++; // now ptr points to 99
std::cout << *ptr;
In short, because ++*ptr++ is rewritten as ++(*(ptr++))
The rules in the link are quite clear:
The postfix ++ has highest precedence => ++*(ptr++)
The prefix ++ and * have the same precedence and they are right-associative => ++(*(ptr++))
The expression can also be split into individual statements like this:
arr = {9, 99, 999 };
int *ptr = arr;
int *ptr2 = ptr++;//ptr2 still points to the first element
int val = *ptr2; // 9
int incVal= ++val; // 10
Hopefully it's clear that the ptr now points to the second element of the array and the result of the expression is the incremented value.
Since you are using a single dimensional array
++*ptr referred to increment in pointer ptr to 0 elements of array, after incrementing the output for this will be 10
The postfix ++ has highest precedence => ++*(ptr++)
I'm trying something very simple, well supposed to be simple but it somehow is messing with me...
I am trying to understand the effect of ++ on arrays when treated as pointers and pointers when treated as arrays.
So,
int main()
{
int a[4] = { 1, 4, 7, 9 };
*a = 3;
*(a+1) = 4;
*++a = 4; //compiler error
}
1: So at *(a+1)=4 we set a[1]=4; //Happy
But when *++a = 4;, I'd expect pointer a to be incremented one since ++ is precedent to * and then * kicks in and we make it equal to 4. But this code just does not work... Why is that?
Another problem:
int main()
{
int* p = (int *)malloc(8);
*p = 5;
printf("%d", p[0]);
*++p = 9; //now this works!
printf("%d", p[1]); //garbage
printf("%d", p[0]); //prints 9
}
2: Now *++p = 9; works fine but it's not really behaving like an array. How are two different? This is just incrementing p, and making it equal to 9. If I print p[0], it now prints 9 and I see that though can't access it via p[0] anymore, *(p-1) shows 5 is still there. So indexing a pointer with [0], where exactly does it point to? What has changed?
Thanks a lot all experts!
The array names is not modifiable lvalue so operation ++ is not applied hence ++a that try to modify a is compilation time error (where a is array name).
Note *(a + 1) and *a++ are not same, a + 1 is a valid instruction as it just add 1 but doesn't modify a itself, Whereas ++a (that is equvilent to a = a + 1) try to modify a hence error.
Note 'array names' are not pointer. Pointers are variable but array names are not. Of-course when you assign array name to a pointer then in most expressions array names decays into address of first element. e.g.
int *p = a;
Note p points to first element of array (a[0]).
Read some exceptions where array name not decaying into a pointer to first element?
An expression a[i] is equivalent to *(a + i), where a can be either a pointer or an array name. Hence in your second example p[i] is valid expression.
Additionally, *++p is valid because because p is a pointer (a variable) in second code example.
int a[4] = { 1, 4, 7, 9 };
int *pa=a;
There is one difference between an array name and a pointer that must be kept in mind. A pointer is a variable, sopa=a and pa++ are legal. But an array name is not a
variable; constructions like a=pa and a++ are illegal
int* p = (int *)malloc(8);
Don't cast result of malloc()
Use index with pointer
p[1]=9; // p[1]==*(p+1)