If you look at the memory layout of a 1D array such as
int array[5];
it will make sense.
array
|
V
+---+---+---+---+---+---+
| | | | | | |
+---+---+---+---+---+---+
array[0]
|
V
+---+---+---+---+---+---+
| | | | | | |
+---+---+---+---+---+---+
Address of array
|
V
+---+---+---+---+---+---+
| | | | | | |
+---+---+---+---+---+---+
Address of array[0]
|
V
+---+---+---+---+---+---+
| | | | | | |
+---+---+---+---+---+---+
i.e. &array == &array[0] == array decayed to a pointer
With a pointer declared as:
int (*ptr)[5] = &array;
ptr == &array
*ptr == array decayed to a pointer == &array[0] == &array
That's why you see the same value printed when you use:
printf("%p, %p", *ptr, ptr);