I am confused about working of the below statement:
*ptr++->str
First ++ operator is applied to ptr which returns rvalue. Next operator is -> has to be applied. Doesn't -> operator require lvalue?
Doesnt -> operator require lvalue?
No. See section 6.5.2.3 of the C99 standard:
The first operand of the -> operator shall have type ‘‘pointer to qualified or unqualified
structure’’ or ‘‘pointer to qualified or unqualified union’’, and the second operand shall
name a member of the type pointed to.
...
A postfix expression followed by the -> operator and an identifier designates a member
of a structure or union object. The value is that of the named member of the object to
which the first expression points, and is an lvalue.
And that's all it says on the matter.
This could be a possible definition for the struct.
#include <stdio.h>
struct fuzz {
char *str;
} stuff = {"Hi there!"} ;
struct fuzz *ptr = &stuff;
int main()
{
char ch='#';
printf("Before: p=%p, ch=%c\n", (void*) ptr, ch);
ch = *ptr++->str;
printf("After: p=%p, ch=%c\n", (void*) ptr, ch);
return 0;
}
Output:
Before: p=0x601020, ch=#
After: p=0x601028, ch=H
And the output proves that the pointer expression is an lvalue. Modifyable, if str would not point to a string constant.
Related
#include <stdio.h>
void main ()
{
int* p = NULL;
printf("%d", *p);
}
It prints:
Exception thrown: read access violation.
p was nullptr.
NULL pointers may not be dereferenced.
Doing so invokes undefined behavior, which in this case manifested in your program crashing.
This is documented in section 6.5.3.2p4 of the C standard:
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. 102)
102) Thus, &*E is equivalent to E (even if E is a null pointer), and
&(E1[E2]) to ((E1)+(E2)). It is always true that if E is a
function designator or an lvalue that is a valid operand of
the unary & operator,
*&E is a function designator or an lvalue equal to E. If
*P is an lvalue and T is the name of an object pointer type,
*(T)P is an lvalue that has a type compatible with that to which T points.
Among the invalid values for dereferencing a pointer
by the unary
* operator are a null pointer, an address inappropriately aligned for the type of object pointed to, and the address of an object after
the end of its lifetime.
If you want to print the pointer itself, pass it to printf without dereferencing it and use the %p format specifier:
printf("%p\n", (void *)p);
The behaviour of int* p = NULL; *p; is undefined.
If you want to print out the address of p, then use "%p" as the format specifier, and drop the dereference:
printf("%p", (void*)p);
The cast to (void*) is required in order to match exactly the format specifier.
I can easily remove this error by replacing&(name+0) by &name[0] or just name, but why I'm getting this error??
#include<stdio.h>
#include<string.h>
void print(char *c)
{
while(*c != '\0')
{
printf("%c",*c);
c++;
}
printf("\n");
}
int main(void)
{
char name[]="Hello World!";
print(&(name+0)); //ERROR here
return 0;
}
Use of
print(&(name+0)); //ERROR here
seems to be a result of some misunderstanding.
First things first - why is it a syntactic error?
(name + 0) does not evaluate to an lvalue. Hence, you cannot take the address of the value of that expression.
A simple way to decide whether something is an lvalue or not is to ask yourself: Can I use it on the LHS of an assignment operator? In your case, you have to ask: Can I use
(name + 0) = <something>;
The answer is "no".
If you want to pass the address of the first element of name to print, you can use couple of methods.
print(&(name[0])); // Explicitly get the first element's address.
print(name); // The array decays to the address of the first element.
To quote the C11 standard in section 6.3.2.1 subsection 1:
An lvalue is an expression (with an object type other than void) that
potentially designates an object; if an lvalue does not designate an
object when it is evaluated, the behavior is undefined. When an object
is said to have a particular type, the type is specified by the lvalue
used to designate the object.
In this case, you've got the expression (name + 0). While name itself designates an object and is therefore an lvalue, the result of the addition in that expression does not designate an object, but rather a value, and is not an lvalue and thus ineligible for the unary & operator.
The &(name+0) is not equivalent to &name[0]. &name[0] is the same as &(*(name + 0)). Note the indirection, when you are using the subscript operator it's the same as offsetting the pointer and dereferencing it.
#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]
The following excerpt is from Harbinson, Steele C: A Reference Manual (5th Edition). According to the book the two assignments to p are equivalent.
7.5.6 Address Operator
int a[10], *p;
p = a; p = *&a;
Yet, according to the C faq Question 6.12 a is of type pointer to int whereas &a is of type pointer to array of int.
So we should get a type error in the second assignment p = *&a because we are trying to assign an array of int to a pointer.
Why is the assignment p = *&a correct?
Quoting C11, chapter §6.5.3.2, Address and indirection operators,
The unary * operator denotes indirection. [....] If the operand has type ‘‘pointer to type’’, the result has type ‘‘type’’. [....]
So, for p = *&a;,
&a is a pointer to "array of ints".
*&a is an array type.
Now, when used in RHS of assignment, an array type decays to pointer to the first element of the array, an int *.
Quoting C11, chapter §6.3.2.1
Except when it is the operand of the sizeof operator, the _Alignof operator, or the
unary & operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. [...]
Hence, there's no warning/ error reported.
When *& comes together then it is not evaluated. p = *&a; is equivqlent to p = a;. * and & nullify the effects of each other.
I have a question about lvalue and rvalue:
void * p;
typedef struct
{
int a;
int b;
} TypeA;
&(TypeA*)p; // here it complains lvalue required as unary '&' operand
why the (TypeA*)p gives a rvaule?
p is an object of type "pointer to void"; if you cast the value in p to type "pointer to TypeA" you no longer have an 'object': you have just a 'value'.
'Values' (like 42) have no address.
/* wrong code; this does not work */
int *p = &42; /* values do not */
void *q = &(0xDEADBEEF); /* have addresses */
Casting returns r-value and unary & needs a l-value as its operand.
Address-of Operator: &
The operand of the address-of operator can be either a function designator or an l-value that designates an object that is not a bit field and is not declared with the register storage-class specifier.
(TypeA*)p
This statement is going to type cast and return a value that needs to be assigned to a variable. so you can not directly use & on it since the return is a value which will not have a adress.