Why is arr and &arr the same?
Solution 1
They're not the same. They just are at the same memory location. For example, you can write arr+2
to get the address of arr[2]
, but not (&arr)+2
to do the same.
Also, sizeof arr
and sizeof &arr
are different.
Solution 2
#include <cassert>
struct foo {
int x;
int y;
};
int main() {
foo f;
void* a = &f.x;
void* b = &f;
assert(a == b);
}
For the same reason the two addresses a
and b
above are the same. The address of an object is the same as the address of its first member (Their types however, are different).
arr
_______^_______
/ \
| [0] [1] [2] |
--------------------+-----+-----+-----+--------------------------
some memory | | | | more memory
--------------------+-----+-----+-----+--------------------------
^
|
the pointers point here
As you can see in this diagram, the first element of the array is at the same address as the array itself.
Solution 3
The two have the same value but different types.
When it's used by itself (not the operand of &
or sizeof
), arr
evaluates to a pointer to int
holding the address of the first int
in the array.
&arr
evaluates to a pointer to array of three int
s, holding the address of the array. Since the first int
in the array has to be at the very beginning of the array, those addresses must be equal.
The difference between the two becomes apparent if you do some math on the results:
arr+1
will be equal to arr + sizeof(int)
.
((&arr) + 1)
will be equal to arr + sizeof(arr)
== arr + sizeof(int) * 3
Edit: As to how/why this happens, the answer is fairly simple: because the standard says so. In particular, it says (§6.3.2.1/3):
Except when it is the operand of the sizeof 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.
[note: this particular quote is from the C99 standard, but I believe there's equivalent language in all versions of both the C and C++ standards].
In the first case (arr
by itself), arr
is not being used as the operand of sizeof, unary &, etc., so it is converted (not promoted) to the type "pointer to type" (in this case, "pointer to int").
In the second case (&arr
), the name obviously is being used as the operand of the unary &
operator -- so that conversion does not take place.
Solution 4
The address is the same but both expressions are different. They just start at the same memory location. The types of both expressions are different.
The value of arr
is of type int *
and the value of &arr
is of type int (*)[3]
.
&
is the address operator and the address of an object is a pointer to that object. The pointer to an object of type int [3]
is of type int (*)[3]
Solution 5
They are not the same.
A bit more strict explanation:
arr
is an lvalue of type int [3]
. An attempt to use
arr
in some expressions like cout << arr
will result in lvalue-to-rvalue conversion which, as there are no rvalues of array type, will convert it to an rvalue of type int *
and with the value equal to &arr[0]
. This is what you can display.
&arr
is an rvalue of type int (*)[3]
, pointing to the array object itself. No magic here :-) This pointer points to the same address as &arr[0]
because the array object and its first member start in the exact same place in the memory. That's why you have the same result when printing them.
An easy way to confirm that they are different is comparing *(arr)
and *(&arr)
: the first is an lvalue of type int
and the second is an lvalue of type int[3]
.
Related videos on Youtube
ragnarius
Updated on June 04, 2022Comments
-
ragnarius almost 2 years
I have been programming c/c++ for many years, but todays accidental discovery made me somewhat curious... Why does both outputs produce the same result in the code below? (
arr
is of course the address ofarr[0]
, i.e. a pointer toarr[0]
. I would have expected&arr
to be the adress of that pointer, but it has the same value asarr
)int arr[3]; cout << arr << endl; cout << &arr << endl;
Remark: This question was closed, but now it is opened again. (Thanks ?)
I know that
&arr[0]
andarr
evaluates to the same number, but that is not my question! The question is why&arr
andarr
evaluates to the same number. Ifarr
is a literal (not stored anyware), then the compiler should complain and say thatarr
is not an lvalue. If the address of thearr
is stored somewhere then&arr
should give me the address of that location. (but this is not the case)if I write
const int* arr2 = arr;
then
arr2[i]==arr[i]
for any integeri
, but&arr2 != arr
.-
ragnarius about 12 years@David Schwartz, If I had written int* arr2 = new int[3], then &arr2 would have been stored in a variable. Maybe arr is a literal constant? But if one take the address of a constant (e.g. &123) then the compiler complains (123 is not an lvalue). The compiler did not complain when I took the address of arr.
-
ragnarius about 12 yearsI do not think it is a duplicate!
-
-
Mooing Duck about 12 yearsIt's good to note that
(&arr)+2
will compile, and maybe even run, but it's undefined behavior, and will not give youarr[2]
. -
Jerry Coffin about 12 years@MooingDuck: Where do you (think you) see anything related to the address of a pointer? (hint: there's no such thing here). There's no promotion involved here either.
-
ragnarius about 12 yearsI tried it, but &f.x != &f.y . So the address of an object is only the same as the address of its FIRST member...
-
Mooing Duck about 12 years
int(*)[3]
is convertable to anint**
A pointer to an array is convertable to a pointer to a pointer. -
Mooing Duck about 12 yearsyou state that
arr
"yields" a pointer toint
, which is ambiguous, and possibly misleading. -
Mooing Duck about 12 years@ragnarius: The address of the array is the same as the address of the first element of the array. Has nothing to do with the members of the elements.
-
R. Martinho Fernandes about 12 years@ragnarius: that's exactly what I said.
-
ragnarius about 12 yearsTo bad my question was closed. I know that and array, when type casted to an int, has the same value as the address of the first element. But this was not my question..
-
Xeo about 12 years@Mooing: That is wrong,
int (*)[3]
is not convertible toint**
. The pointer-to-array needs the exact size of the inner dimension to know how far to step: ideone.com/iDkB7. -
ragnarius about 12 yearsI am not sure I understand your quote. We are discussing the unary & operator and your quote says that "Except it is the [...] unary & operator...".
-
InQusitive over 2 yearsThis answer is more clearer than the accepted answer.