An array can decay to pointer to its first element. In your example plain a will decay to &a[0]. And for any array or pointer a and index i, the expression a[i] is exactly equal to *(a + i).
Also, if you lay out your array how it would look like in memory, it would be
+---------+---------+
| a[0][0] | a[0][1] |
+---------+---------+
Now armed with this information, we can start transforming the expressions in your printf call.
Lets start with *(a + 0):
- Because the equivalence,
*(a + 0) becomes a[0].
- Because
a[0] is an array, it will decay to a pointer to its first element, i.e. &a[0][0].
So the first argument is equal to &a[0][0], i.e. a pointer to a[0][0].
Then lets take a + 0.
- The expression
a + 0 is equal to &*(a + 0).
- Because the array/pointer equivalence
&*(a + 0) becomes &a[0].
&a[0] is a pointer to the first element of a, which happens to begin at the same position in memory as a[0][0].
This of course means that the pointer &a[0] and &a[0][0] both are pointing to the same locations, and the output would be equal. However the types of those two pointers are very different:
- The type of
&a[0][0] is a pointer to an int, i.e. int *
- The type of
&a[0] is a pointer to an array of two int elements, i.e. int (*)[2]