int a = 30;
int& b = (&a)[15];
std::cout << b << std::endl;
I print it , find that this is a random value that doesn't make any sense
What kind of grammar is int& b = (&a)[15]
int& b is a variable. Its name is b and its type is reference to int. type variable_name = expression is syntax for defining and initialising a variable.
& is a unary operator. For fundamental types, it is the addressof operator. Thus &a gives the address of the object referred by a. [] is the subscript operator. It adds the integer operand to the pointer operand, and indirects through the resulting pointer. In this case the pointer operand is a pointer to a, so the result is a reference to the fifteenth sibling of a. b is initialised to refer to that sibling.
Edit:
int a = 30;
Given this context, there is no fiftheenth sibling, and so the behaviour of the program is undefined.
Related
First example
int a = 0;
auto && b = ++a;
++a;
cout << a << b << endl;
prints 22
Second example
int a = 0;
auto && b = a++;
++a;
cout << a << b << endl;
prints 20
Question:
Why in first example ++a in 3rd line also increments b, and why there is no such behavior in second example?
Update: New question arised.
Because pre-increment (++a) first increments the value of a, stores the result, and then returns the reference to a. Now a and b effectively point to the same object.
Post-increment (a++), however, first stores the current value of a in a temporary, increments a, and returns this temporary - to which your rvalue ref points. a and b point to different objects, more specifically - b is a temporary holding the value of a prior to incrementing.
This is the reason why it's encouraged to use ++it over it++ for iterators and other complex objects that define increment / decrement: the latter creates a temporary copy and thus may be slower.
The difference is that ++a is an lvalue, however a++ is not. This is specified by C++14 [expr.pre.incr]/1:
The operand of prefix ++ is modified by adding 1 [...] The
operand shall be a modifiable lvalue. [...] The result is the updated operand; it is an lvalue
and [expr.post.incr]/1:
[...] The result is a prvalue.
Now we consider auto && b = ++a; . ++a is an lvalue. auto&& is a forwarding reference. Forwarding references can actually bind to lvalues: the auto may itself deduce to a reference type. This code deduces to int &b = ++a;.
When a reference is bound to an lvalue of the same type, the reference binds directly, so b becomes another name for a.
In the second example, auto && b = a++;, a++ is a prvalue. This means it doesn't have an associated address and it's no longer any relation to the variable a. This line has the same behaviour as ++a; auto && b = (a + 0); would.
Firstly, since a++ is a prvalue, auto&& deduces to int&&. (i.e. auto deduces to int). When a reference of non-class type is bound to a prvalue, a temporary object is copy-initialized from the value. This object has its lifetime extended to match the reference.
So b in the second case is bound to a different object from a, a "temporary" int (which is not really so temporary, since it lasts as long as b does).
The reference binding rules are in [dcl.init.ref].
In the second case (post-increment) b actually references the temporary created for (a++), so the increments do not affect b.
I want to know what is the different between *&aPtr and &*aPtr if replaced * & and & * ?
int a;
int *aptr;
a = 7;
aptr=&a;
cout << &* aPtr<< *&aPtr<< endl;
They have the same value, but *&aPtr is an lvalue that refers to aPtr whereas &*aPtr is a prvalue that has the same value as aPtr.
If the types are primitives (integers, characters, booleans etc.), then they will yield the same value.
A difference may occure if the operators & and * are overloaded for specific class. in this case, depending on the implementation alone - there might be a difference.
One other thing: a corner case can occure if T* t actually points to null:
int* i = nullptr;
*&i; //ok, first takes the address of i, then dereference it, yielding a null pointer again
&*i //wrong, dereference a null pointer, yielding undefined behavior
These unary operators & and * group right to left.
So in this expression
&*aPtr
at first operator * is applied and you get lvalue of a after that operator & is applied and you get rvalue of pointer to a.
Its value is the same as the initial value of aPtr. However you may not write for example
&*aPtr = &a;
while you may write
aPtr = &a;
In this expression
*&aPtr
at first operator & is applied that yields the address of variable aPtr itself. After that operator * is applied and you get again aPtr.
The difference between this expression and the above expression is that you may write
*&aPtr = &a;
because expression *&aPtr yields lvalue of aPtr.
I’m studying about pointers. It’s quite confusing—maybe because I’m new. I have a question that what *(&a) indicates in the following short program.
On line 7, I know *(&a) means “value at address of variable a,” but on line 13, what does *(&a)=5 mean? When I assign &a=5, the compiler gives an error along the lines of “lvalue required as left operand of assignment,” but when I assign the value in *(&a), then it compiles with no error.
#include <stdio.h>
int main()
{
int *p, a = 2, b;
b = *(&a); // line 7
printf("%d", b);
p = &a;
printf("%d", p);
*(&a) = 5; // line 13
printf("%d", a);
return 0;
}
Given an int a; then &a gives you the address of a which is an int *. Given an int *p; the expression *p gives you the int that p is pointing to. So *(&a) is the value behind the address of a which is a. In other words *(&a) does the same as just a.
There are times when this is sort of useful. Given a std::vector<int>::iterator it; you can get a pointer to the int the iterator points to by dereferencing the iterator to get the int and then take the address, so you get &(*it).
This is covered in § 5.3.1 [expr.unary.op]:
1 The unary * operator performs indirection: the expression to which
it is applied shall be a pointer to an object type, or a pointer to a
function type and the result is an lvalue referring to the object or
function to which the expression points. If the type of the expression
is “pointer to T,” the type of the result is “T.”
and:
2 The result of each of the following unary operators is a prvalue.
3 The result of the unary & operator is a pointer to its operand.
Since &a yields a prvalue, &a = 5 is invalid, because &a is not an lvalue. Only modifiable lvalues can appear on the left hand of the built-in assignment operator.
On the other hand, *(&a) yields an lvalue (making it assignable).
&a will return a pointer to a, or the memory address where a is located. The dereference operator * returns the value of the data pointed to by the address. Consider the following code.
int foo = 3;
int* bar = &foo; /// bar points to foo.
printf( "%d\n", *bar ); /// will print 3
printf( "%d\n", *(&foo) ); /// will also print 3
The variable bar points to the memory address where foo is located. By using the dereference operator, you get the value stored in memory at the address contained in bar. The last example combines the two, you get a pointer to foo and immediately dereference it, which returns the value stored in foo
For example:
int x[100];
void *p;
x[0] = 0x12345678;
x[1] = 0xfacecafe;
x[3] = 0xdeadbeef;
p = x;
((int *) p) ++ ;
printf("The value = 0x%08x", *(int*)p);
Compiling the above generates an lvalue required error on the line with the ++ operator.
The cast creates a temporary pointer of type int *. You can't increment a temporary as it doesn't denote a place to store the result.
In C and C++ standardese, (int *)p is an rvalue, which roughly means an expression that can only occur on the right-hand side of an assignment.
p on the other hand is an lvalue, which means it can validly appear on the left-hand side of an assignment. Only lvalues can be incremented.
The expression ((int *) p) treats the pointer stored inside the variable p is a pointer to int. If you want to treat the variable itself as a pointer to int variable (and then increment it), use a reference cast:
((int *&) p) ++ ;
Thanks to larsmans for pointing to the right direction.
I took the liberty of digging deeper into this. So for future reference, according to sections 6.5.2.4 and 6.5.4 of the C99 standard (http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf):
6.5.2.4 Postfix increment and decrement operators
Constraints
The operand of the postfix increment
or decrement operator shall have
qualified or unqualified real or
pointer type and shall be a modifiable
lvalue....
6.5.4 Cast operators
..
..
[Footnote] 89) A cast
does not yield an lvalue. Thus, a cast
to a qualified type has the same
effect as a cast to the unqualified
version of the type.
Note: This only applies to C. C++ may handle casts differently.
You can get the intended result with
p = (int*)p + 1;
Using the increment operator on a dereferenced pointer to p, which is an lvalue, also works:
(*(int**)&p)++;
However, the latter is not portable, since (void*)p might not have the same representation as (int*)p.
Rvalue expression ((int *) p) creates and temporary of type int* on which operator ++ cannot be applied.
++ requires an lvalue as its operand.
As #FredOverflow mentions lvalues and rvalues have very little to do with assignment.
Arrays are lvalues still they cannot be assigned to because they are non-modifiable.
std::string("Prasoon") is an rvalue expression still it can occur on the left side of assignment operator because we are allowed to call member functions( operator = in this case) on temporaries.
Take this piece of code:
int a;
int *pointer = &a;
int **b = &(&(*pointer));
Would the above set b to the address of pointer or not?
The reason I ask is because *pointer gives the value of a, and the reference of that is the address of a. Is this treated as just the address of a, or is it also treated as pointer.
Does this make sense? Could I do:
&(*pointer) = a;
No. In C, you can only get a pointer to a storage area (which means a variable, an array element, or another pointer; they call those "l-values"), not to any expression. You cannot get a pointer to an expressions that has no defined storage area (like an addition, or the result of a function call). It should be noted however that C++ messes these rules with references, but for the sake of clarity, I'll leave it out.
Pointers aren't magical: in the end, they're just integers. Therefore, when you get the pointer of a pointer, it's just like you were getting the pointer of an integer. It has no more repercussions.
For instance, if you get the pointer to a in your code, you're just copying this address in another variable. Nothing keeps you from changing said variable:
int a;
int* p = &a;
p = NULL;
And doing this, you a will remain unaltered. All you can change about a is its value. Its address is immutable. Anything else would imply that &a = NULL (or any other pointer value) would work, which doesn't.
int **b = &(&(*pointer));
This doesn't, or shouldn't compile.
You can only take the address of an l-value. (See below for a description)
C++03 S5.3.1-2:
The result of the unary & operator is
a pointer to its operand. The operand
shall be an lvalue or a qualifiedid.
In the first case, if the type of the
expression is “T,” the type of the
result is “pointer to T.” In
particular, the address of an object
of type “cv T” is “pointer to cv T,”
with the same cv-qualifiers. For a
qualified-id, if the member is a
static member of type “T”, the type of
the result is plain “pointer to T.” If
the member is a nonstatic member of
class C of type T, the type of the
result is “pointer to member of class
C of type
...and the reference of that is the address of a...
Also you are using the term reference wrong here. & is a symbol that is used for different things. one of those things is to declare references, an unrelated thing is the address of unary operator. The later is not called a reference.
Does this make sense? Could I do: &(*pointer) = a;
An address of a variable, and hence &(*pointer) or equivalently &a are r-values.
You can't assign anything to an r-avlue. Ignoring things like const you can consider an r-value something that must appear on the right hand side. An l-value is kind of like left hand side but really it means it can be stored in a storage location (the difference is because a const object for example can't appear on the left hand side but it is still considered an l-value).
You can't take the address of something twice, so the above code probably won't even compile (have you tried that? What happened?).
In your expression:
*ptr is a lvalue
&(*ptr) is a rvalue
&(&(*ptr)) is an ill-formed expression as you are trying to take the address of an rvalue which is not allowed in C++.
Furthermore,
&(*pointer) = a;
is ill-formed, because the type of the lhs expression is 'int *' where type of rhs expression is 'int'. C++ does not allow converting an 'int' to 'int *'
Would the above set b to the address of pointer or not?
No, it won't. &(*pointer) is the address of a, which is just a number (an r-value), and you can't take the address of or assign to an r-value. So both &(&(*pointer)) and &(*pointer) = a will not compile.
The address of pointer is simply &pointer, so what will work is int **b = &pointer;.
1.No, and that make compile error at int **b = &(&(*pointer));
2.Set b to the address of pointer: int **b = &pointer;
3.&(*pointer) = a; -> NO you cant. &something is constant cant be changed, must be *pointer = a; or pointer = &a;