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))