Explaining the "length trick"
int arr[5] {1,2,3,4,5};
int len = *(&arr + 1) - *&arr; //5
&arr
is the address of the array, of type int(*)[5]
. &arr + 1
is a one-past-the-end pointer for this array. Dereferencing it results in int[5]
, which is implicitly convertible to int*
(array-to-pointer conversion). The result of this expression is a one-past-the-end pointer for the elements of the array, of type int*
. We can subtract this from *&arr
or just arr
to obtain the length of the array.
// shorter version of the trick above
int len = *(&arr + 1) - arr;
Note that both versions dereference a one-past-the-end pointer, so they are undefined behavior! You're just seeing a "works on my machine" effect.
There are much more readable and correct ways to obtain the length of an array, such as:
std::size(arr)
(since C++17)
sizeof(arr) / sizeof(*arr)
(C-style, avoid if possible)
Other Questions
which means that (&arr + 1) == *(&arr + 1)
and *&arr == &arr
, but if i do
int len = (&arr + 1) - &arr; //1
the result is 1, not 5. I'm totally confused here.
Both of these equations would fail to compile, you cannot say that *&arr == &arr
. Note that a pointer to an array and a pointer to the first element of the array represent the same address, but they are different pointers. Performing + 1
on them will take differently sized steps depending on the type of the pointer.
The result is 1
because one is a pointer to the array arr
, and one is a one-past-the-end pointer to the array arr
. The difference between them is obviously 1
, because they're one step apart. Converting to an int*
is crucial for the original trick to work.
int* p = arr;
int (*ptr)[5] = &arr;
Here, the first line is performing array-to-pointer conversion implicitly, and the second line is taking the address of the array.
These two pointers represent the same address, but they have a different type and cannot be compared or converted between one another.
int *p = &arr; // error
int (*ptr)[5] = arr; // error
The first line attempts to convert an int(*)[5]
to an int*
implicitly, which is not allowed.
The second line tries to do the opposite, which is also not allowed.
Once again, the original trick works because we are dereferencing the pointer to the array, which gives us an int[5]
, which can be converted to int*
:
int (*ptr)[5] = &arr;
int *p = *ptr;