Check the types!!
Given the definition as int a[4][4];
a
is of type int [4][4]
- array of an array of 4 integers. It's not the same as int **
.
a[n]
is of type int [4]
- array of 4 integers. It's not the same as int *
a[n][m]
is of type int
. - integer.
Now, given the fact, that the address of the array is also the address of the first element in the array, the values are same, but they differ in types.
To check it visually
int a[4][4]
+-------+--------+-------+-----------+
| | | | |
|a[0][0]| a[0][1]| a[0][2] a[0][3] |
| | | | |
+------------------------------------+
| | | | |
|a[1][0]| | | |
| | | | |
+------------------------------------+
| | | | |
|a[2][0]| | | |
| | | | |
+------------------------------------+
| | | | |
| | | | |
| | | | |
| | | | |
+-------+--------+-------+-----------+
Then, quoting the C11
, §6.3.2.1
Except when it is the operand of the sizeof
operator, the _Alignof
operator, or the
unary &
operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. [...]
So, while passing an argument of type array as a function argument, it decays to the pointer to the first element of the array.
So, let's have a look.
a
, decays to &(a[0])
- the address of the first element of type int (*)[4]
.
*a
, which is the same as a[0]
, decays to an int *
, pointer to the first element.
**a
which is same as *(*a)
== *(a[0])
== a[0][0]
- that's the int
value at that index.
Now once again look carefully at the image above - do you see that the first element of int [0]
and int [0][0]
are basically residing at the same address? In other words, the starting address are the same.
That's the reason behind the output you see.