Say I initialise arrays and variables as such:
int arr1d[3] = { 1, 2, 3 };
int* arrptr = arr1d;
int (*ptr1d)[3] = &arr1d;
int arr2d[2][3] = { {1, 2, 3}, {4, 5, 6} };
int (*ptr2d)[3] = arr2d;
So, arr1d
is an array of 3 integers. Under the hood, arr1d
is a pointer to the first element of the array, i.e. &arr1d[0]
. Hence, we can assign arr1d
to int* arrptr
.
ptr1d
points to an array of 3 integers. arr1d
is an int*
pointing to &arr1d[0]
, but why is &arr1d
of type int (*)[3]
? Naively, I thought that writing &arr1d
simply gave us an address to assign to the pointer. Is this is something specific to pointers to arrays?
Apparently, arr2d
is of type int (*)[3]
(which I learned from this post). Both ptr2d
and *ptr2d
have the same value, so why is that second dereference even necessary? My thoughts are that it may be because ptr2d
is of type int (*)[3]
(pointer to array of 3 ints), *ptr2d
is of type int*
(pointer to an int), and so **ptr2d
ultimately gets us the first value of the first array, 1. So we're not dereferencing here to walk along addresses as we see in many diagrams, we're dereferencing to access underlying types. Is this correct? Does this explain why the type of &arr1d
is also int (*)[3]
(we're going "up a level"?)
Thank you.
int arr1d[3] = { 1, 2, 3 };
So, arr1d is an array of 3 integers.
Correct.
Under the hood, arr1d is a pointer to the first element of the array, i.e. &arr1d[0]
It is unclear what you mean by "under the hood", but in the C++ language an array is an array. It is not a pointer type. Saying that arr1d
is &arr1d[0]
is wrong. If you mean in machine code, then it is wrong because machine code has neither types nor variables.
Hence, we can assign
arr1d
toint* arrptr
.
We can assign arr1d
to int* arrptr
because an array type is implicitly convertible to a pointer to its element type. And the result of this conversion is indeed same value and type as &arr1d[0]
. This conversion is called decaying.
Naively, I thought that writing
&arr1d
simply gave us an address to assign to the pointer.
&arr1d
simply does give us an address that can be assigned to a pointer. So, you thought correctly.
but why is
&arr1d
of typeint (*)[3]
?
The type of arr1d
is array of 3 integers i.e. int[3]
. Taking its address gives you a pointer to array of 3 integers i.e. int (*)[3]
).
Is this is something specific to pointers to arrays?
The unary &
always gives a pointer to the operand (except in case of class types for which the operator has been overloaded in which case it gives whatever the overload returns; overloading unary &
is rare). It is called the addressof operator.
Of course, &
gives you a pointer to an array only when operand is an array. Other times it gives some other pointer type.
int (*ptr2d)[3] = arr2d;
Apparently,
arr2d
is of typeint (*)[3]
(which I learned from this post).
You learned wrongly. The type of arr2d
is int[2][3]
. int[3]
is the type of the element of arr2d
and thus int (*)[3]
is the pointer type to which the array type decays; a pointer to element of that array.
*ptr2d
is of typeint*
(pointer to an int)
Wrong. *ptr2d
is of type int[3]
(array of 3 int). This array does implicitly convert to pointer to its first element, which has the type int*
.