Your example is messy, but pointer arithmetic is messy in general, disrespectful to types. Your example does not make sense from a type theory point of view.
arr
points to the first element of the array. Note that arr[i]
is equivalent to *(arr+i)
. arr
is a 4-elements array of type int
.
p
is a pointer to a 4-element array of type int
.
You assign to p
the address of &arr
, which has the same address as arr
(but the type is different, see below).
Then you print it out and this means:
arr
is the address of the first element of the array
&p
is the address of p
p
is the address of &arr
(whole array), which is the address of arr
, which is the address of the first element in the array
*p
is the address of arr
, which is the address of the first element in the array
**p
is trying to dereference *p
, which is dereferencing arr
, which actually is the first element of the array
After you increment p++
: arr
and &p
don't change, the rest does
We have already emphasized that in most cases, the name of an array is
converted into the address of its first element; one notable exception
being when it is the operand of sizeof, which is essential if the
stuff to do with malloc is to work. Another case is when an array name
is the operand of the & address-of operator. Here, it is converted
into the address of the whole array. What's the difference? Even if
you think that addresses would be in some way ‘the same’, the critical
difference is that they have different types. For an array of n
elements of type T, then the address of the first element has type
‘pointer to T’; the address of the whole array has type ‘pointer to
array of n elements of type T’; clearly very different. Here's an
example of it:
int ar[10];
int *ip;
int (*ar10i)[10]; /* pointer to array of 10 ints */
ip = ar; /* address of first element */
ip = &ar[0]; /* address of first element */
ar10i = &ar; /* address of whole array */