A 2D array is really an array of arrays.
The expression arr + 2
has type int (*)[2]
, while *(arr + 2)
has type int [2]
. When printing the former, you have a pointer so that value of the pointer is printed. In the latter case, you have an array which decays to a pointer to the first element. So *(arr + 2)
decays into arr + 2
, which is the same as the first expression.
Going into more detail on arr + 2
, arr
has type int [3][2]
. When you add an integer value to it, it decays to a pointer to the first member, so arr
decays to type int (*)[2]
, and arr + 2
also has that type, and points to the subarray containing { 3, 4 }
.
Also note that pointers should be printed with the %p
format specifier, and that the pointer must be casted to void *
, otherwise you invoke undefined behavior. In this case you were "lucky" that they happened to print the same thing.
To get the output of 3 you were expecting, you need to dereference one more time:
*(*(arr + 2))