All of the expressions a
, &a
and &a[0]
will yield the same address1 - the address of the array is the same as the address of its first element:
+---+
a: | 1 | a[0]
+---+
| 2 | a[1]
+---+
The difference is in the types of the expressions. a
has type int [2]
, but unless it is the operand of the sizeof
or unary &
operators, it "decays" to type int *
and the value of the expression will be the address of the first element2. &a[0]
has type int *
, and &a
has type int (*)[2]
(pointer to 2-element array of int
).
This is why it didn't work when you wrote
int *ptr = &a; // int * = int (*)[2]
The types aren't compatible. It would have worked if you had written
int *ptr = a; // int * = int *
Again, a
has type int [2]
, but unless it's the operand of the sizeof
or unary &
operators, it "decays" to type int *
and its value is the address of the first element - in this context, it's identical to writing &a[0]
.
- Not accounting for any type conversion - on platforms like x86 and x86-64,
int *
and int (*)[2]
have the same size and representation, but that's not guaranteed everywhere.
- This is important - an array expression is not a pointer. It will be converted to a pointer as necessary, but there's no separate pointer object that explicitly points to the first element of the array.