First of all - as others have pointed out - you need to use the correct format specifiers, and cast to these values to pointers.
Now as to why all of them give same value.
Here x is an array. And the type of its elements are unsigned int[3]
. i.e. x
is an array
of unsigned int[3]
arrays.
First, x + 3
gives the address of fourth element in your array. That is the
address of {10, 11, 12}
. The address of this array in memory will be the address of its first element in memory. That is the address of 10
in memory. Note that this value is int (*) [3]
, i.e. address of an unsigned int[3] array
.
Second, * (x + 3)
is equivalent to x[3], which is the fourth element, which is unsigned int[3]
.
It is the array {10, 11, 12}
. This value is pointing to the first element of
array {10, 11, 12}
. That is, this value is pointing to 10
. Note that this value is unsigned int[3]
.
Third *(x+2) + 3
: Here *(x + 2)
is equivalent to x[2]
which is an unsigned int[3]
, which is {7, 8, 9}
array ,
and when you do a + 3
you are again getting the address of 10
. Note that this value is unsigned int[3]
.
So, you see in all three cases your result is the same address in memory, i.e. the address where 10
is stored - even though you are representing different things at different time; unsigned int (*)[3]
at first, and unsigned int[3]
at second and third.