Why ++(*p) is not giving l-value required error? - c

#include <stdio.h>
int main()
{
int arr[] = {1, 2, 3, 4, 5};
int *p = arr;
++*p;
p += 2;
printf("%d", *p);
return 0;
}
Why is this code not giving any compile time error,My doubt is ++*p is evaluated as ++(*p) and *p will be constant value 1 ,when we do ++(1) which is not a l-value,why is compiler not giving an error?

*p will be constant value [...]
No, it is the same as arr[0].
So
++(*p);
is the same as
++(p[0]);
is the same as
++(arr[0]);
which is a perfectly valid statement.

Object pointer dereferencing does not itself produce the value to which the pointer points. Instead it produces an lvalue that refers to that value. In the words of the standard:
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".
(C2011, 6.5.3.2/4; emphasis added)
Unary * is thus among a class of operators that can be considered to operate on the identity of an object, as opposed to on its value. The & operator and and some uses of the sizeof operator can also be considered to be in this category.

*p will be constant value
No, it won't. *p is a[0] when you do int *p = arr;. a[0] is not a constant value, and since they are the same, *p is not a constant value either.
As a result, this:
++(*p);
is equivalent to:
++(a[0]);
which increments the element at the first position of the array, as you can see clearly.
But looking back at ++(*p), one can see that:
*p dereferences the pointer, resulting in an l-value.
Then we have (*p), the l-value in parentheses.
++(*p) applies the pre-increment operator to an l-value, which is value, thus no compiler error should be generated.

Why ++(*p) is not giving l-value required error?
Dereference operator on a pointer yields a lvalue.
Therefore, *p is a lvalue and using pre-increment operator on it is valid.

Just note both the statements used by you :
++*p; // increments the value pointed by *p at that time `a[0]` by 1
p += 2; // increments the address p is storing by 2
And the reason there is no l-value required error is because in your statement :
++*p; // *p is not a constant, it is same as a[0]

Related

Why are lvalues converted to values in certain places and not others? [duplicate]

This question already has answers here:
Is *p an lvalue or rvalue
(3 answers)
Closed 7 months ago.
Consider this code:
int x = 99;
int * p = &x;
*p = *p + 1;
Why do the *p on the left side and right side of the = operator differ?
How does the compiler know to use the left *p to be the object x and the right *p to be the value of x?
Specifically, if the compiler evaluates *p to be the value of x, why does the *p on the left side not evaluate to 99, creating an erroneous assignment to a literal: 99 = 99 + 1;?
Similarly, if the compiler evalues *p to be the object x (assuming that that is what the left operand of the = operator expects), why does not the *p on the right hand side also evaluate to the object x?
The result of the dereference operator * is an lvalue. It references an object (not just a value) that can be assigned to.
This means that *p is an lvalue denoting the object that p points to, specifically x.
When an lvalue is used in an expression such as *p + 1 or x + 1, the lvalue is converted to a value and is no longer an lvalue. This conversion does not happen when the lvalue is the left operand of the assignment operator.
This conversion is detailed in section 6.3.2.1p2 of the C standard:
Except when it is the operand of the sizeof operator, the _Alignof
operator, the unary & operator, the ++ operator, the --
operator, or the left operand of the . operator or an assignment
operator, an lvalue that does not have array type is converted to the
value stored in the designated object (and is no longer an lvalue);
this is called lvalue conversion
So the expression *p = *p + 1 is effectively the same as *p = 99 + 1. The same goes for x = x + 1.
C and C++, like many languages, distinguish between L-values and R-values. These terms refer to the way an expression is treated when it's on the left or right side of an assignment.
There are a number of intricacies, but for the purpose of answering your question simply, an L-value refers to a location, while an R-value is any general value (like the amount in a numeric type, or all the contents of a structure).
So when you write:
L-value = R-value
it means to copy the R-value into the location described by the L-value.
The simplest case is an ordinary variable assignment:
x = x + 1;
On the right side, x is an R-value; we get the number 99 from it, add 1 to that, producing the value 100. On the left side, x is an L-value that refers to the memory address of the variable, and we store 100 in that location.
It's no different when you replace x with *p.

In C for postfix and prefix operator, operand should be an lvalue, so what actually lvalue means for a pointer variable in case of these operators?

In C for postfix and prefix operator, operand should be an l value, so if cp = &ch; and assume that address of ch is 1000 and address of cp is 5000 so ++cp should be 5001 or 1001 ?
This doubt arises because lvalue of cp is location of cp(5000) and rvalue of cp is value at 5000, "that is 1000". So if ++ operator works on lvalue then it should increment 5000 and not the 1000(because it's an rvalue)?
Thanks in advance.
If you have for example these two declarations
char ch = 'A';
char *cp = &ch;
Then this expression ++cp increases the value stored in the variable cp. The value is the address of the variable ch So after the increment the value stored in the variable cp will point to the memory that is after the memory occupied by the variable ch.
The unary operator ++ can change a value of an lvalue expression. You may not for example to write
char ch = 'A';
`++&ch;`
because the expression &ch yields a value of the address.
It is the same as to write
++3;
instead of
int x = 3;
++x;
According to the C11 standard(ISO-IEC-9899-2011)--6.3.2.1 Lvalues, arrays and function designators: HTML_version pdf_version
Except when it is the operand of the sizeof operator, the unary & operator, the ++
operator, the -- operator, or the left operand of the . operator or an assignment operator,
an lvalue that does not have array type is converted to the value stored in the designated
object (and is no longer an lvalue); this is called lvalue conversion.
Actually, the result of & operator is rvalue and the result of * operator is lvalue, so:
int *p1; //variable p1 is a lvalue
int num = 314; //variable num is a lvalue
p1 = &num; //num is still a lvalue, and keep it that way
int *p2 = p1 + 1; //p1 is still a lvalue, but will become a rvalue through lvalue conversion

why foo((&i)++) gives Lvalue required error. There is no array associated

I understand a few things about Lvalue but I don't understand how the below code gives an error:
#include<stdio.h>
void foo(int *);
int main()
{
int i=10;
foo((&i)++);
}
void foo(int *p)
{
printf("%d",*p);
}
6:13: error: lvalue required as increment operand
foo((&i)++);
^
x++ results following steps.
1) read the value of x in to register.
2) increment the value of x
3) write the incremented value back to x (which means you are changing the value of x by '1')
But what you are trying to do is (&i)++ which means the following.
1) read address of i into register
2) increment the address by 1
3) write the incremented value in to address again? How you can change the address?
If you want to send the integer which is stored in next address to foo(), you need to increment as below.
int *p = &i + 1;
foo(p);
But that may result in undefined behavior because you know only address of i where i value is stored. Once you increment the address, you will get next address and it may contain some junk value.
There is an attempt to apply the unary operator & to a temporary object that is evaluated as the expression (&i)++. You may not apply the operator to a temporary object.
C Standard (6.5.3.2 Address and indirection operators):
1 The operand of the unary & operator shall be either a function designator, the result of a [] or unary * operator, or an lvalue that designates an object that is not a bit-field and is not declared with the register storage-class specifier.

Is a dereferenced pointer a valid lvalue?

Assuming the definition:
int i = 10;
int *p = &i;
Why is *p a valid lvalue here:
*p+=10;
Shouldn't *p evaluate to the value of the int stored at &i, ie. 10, and hence generate a "Not an lvalue" error?
An lvalue is an expression that refers to a region
of storage that can be manipulated.
*p is such an expression that refers to a region of storage. This is different than say 10+=10; because 10 doesn't refer to a region of storage like a variable would.
C11 6.5.3.2p4:
Semantics
...
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
I.e. with
int i = 10;
int *p = &i;
the result of *p is an lvalue that designates the object i.
Therefore *p += 10 works, as it is an lvalue.
Now, if an lvalue were used in a context where the object itself is needed, it would be converted to the value stored in the designated object. This is called the lvalue conversion, and the resulting value of course isn't an lvalue anymore (C11 6.3.2.1p2).
I believe you are confused with the definition of p. p is, in fact, a variable of type pointer to int, and its value is initialized to the address of i.
Nonetheless, *p is a valid lvalue as well - a valid expression to a storage location.
In very simple words, pointers point to an object (in a general, non OOP sense), not to the contents of that object. So yes, a dereferenced pointer is a valid lvalue.
In very low level terms. A pointer is nothing but a memory address, a dereferenced pointer is the memory at that address.
Shouldn't *p evaluate to the value of the int stored at &i, ie. 10, and hence generate a "Not an lvalue" error?
In simple words,
* means "value at address".
*p means "value at address given by the value of p".
*p = 10; means "set 10 as the value at address given by the value of p".
lvalue is an expression that refers to an object stored somewhere in the memory. *p is also an expression that refers to an object stored at location p.

Explanation of ++val++ and ++*p++ in C

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.

Resources