So pointers are not integers. Sure, you can convert them to integers by casting them to an integer type, or add integers to them to slide them around. But they are not integers.
Pointers are like mathematical vectors over the integers, if you have done any linear algebra.
p1-p2
is the distance between p1
and p2
, the integer required to add to p2
to reach p1
.
When you add an integer to a pointer, you have to pay attention to the type of the pointer. If the pointer is to an object of size 4, each time you add 1 to a pointer its numerical address increases by 4, not 1.
The same thing is true when you subtract two pointers.
The key part here is that the numerical value of the address in memory matters, but the type matters just as much to understand what happens.
The second strange thing going on here is that arrays decay into pointers to their first element at the drop of a hat. They, however, are not pointers to their first element, they just convert into them very easily.
So when we do this:
(&a)[1]
we are taking the address of a
. The address of a
is a pointer of type int(*)[7]
. It is a pointer to an array, not a pointer to the first element of the array. The difference is in the type of the pointer. And that 7 is important.
We then use []
on the pointer. If you have a pointer or array p
and a value v
, p[v]
is defined to be *(p+v)
. This leads to humor if you do v[p]
, but that isn't important.
Let pa
represent (&a)
. Then pa[1]
is going to be *(pa + 1)
.
Now, pa
is a pointer-to-an-array (not a pointer-to-the-first-element of the array). So +1 adds the full size of the array (sizeof(int)*7) to the numeric value.
So pa+1
is a pointer to one-past-the-end of a
, and is of type pointer-to-array.
We then dereference, and get the non-existent array of size 7 right after the end of the array a
.
Then we subtract a
.
(&a)[1]-a
This is where pointer decay kicks in. There is no -
operation on arrays, but there is a -
operation on pointers. So the C language helpfully decays each of these arrays into pointers to their first element.
The pointer to the first element of a
is &a[0]
.
The pointer to the first element of the array of size 7 immediately after the end of a
is ... &a[7]
.
Both of these pointers are of type int*
. When you subtract two int*
s, you get their numeric pointer value, divided by sizeof(int)
. In this case, this is easy -- 7.
This might be easier if we looked at this:
(&a)[1]-(&a)[0]
or
*(&a+1)-*(&a+0)
&a
is a pointer to the array a
of type "pointer to array of size 7". We add 1 to it, getting the pointer to the array afterwards in one case, and zero in the other case.
We then go down back to being arrays, and subtract. Subtraction triggers decay to pointer-to-first-element, so we get a pointer to the element right after the end of a, and a pointer to the first element of a.
&a[7]-&a[0]
which is
&*(a+7)-&*(a+0)
Now &*
does nothing to things that are already pointers (which they are at that point), so:
(a+7)-(a+0)
The question then becomes, how much do you have to add to a+0
to reach a+7
. The answer, not surprisingly, is 7
:
(a+7) = (a+0)+7
and that is what is displayed.