This is actually very interesting and, the more you learn about C++ the more completely irrelevant you find it becomes in all but rare situations.
int arr2d[3][2] = {
{1, 2},
{3, 4},
{5, 6}
};
So here you have an identifier arr2d and that identifier has a type:
array of arrays
Now the type array in C++ relates to a contiguous block of objects. So you have a contiguous block of contiguous blocks.
However, when you use the identifier in an expression the rules of C++ say it decays into a pointer to the first element of the array for which it is type array (there is a subtle distinction between an array and a type called "array").
So when you do this:
auto a = arr2d;
Well the identifier a is now a pointer because arr2d has decayed into a pointer to the first element of the 2D Array you originally created. But what is the type of the pointer?
It is a pointer to the first element of an array of arrays. But the first element of an array of arrays is an array - so it is a pointer to an array. How is that written in C++ syntax?
Like this:
int (*)[2]; // see the right-left-rule
C++ syntax can be a dark art and none of it quite so dark as the declaration of types. The complexity of it is hidden for simple situations like an int but shows its metal when things get complicated.
int (*)[2]; // see the right-left-rule
This means a pointer (now go right) to an array of 2 elements (now go left) of type int.
C++ types are declared onion like, unwrapping right to left to allow a unified syntax capable of declaring anything from an int to a function returning a function pointer to a function that returned a pointer to an array of function pointers... etc.
See: right-left-rule.
Incidentally you could avoid decaying to a pointer to array by using this syntax:
auto a = &arr2d; // get the address of the whole 2D array
Your IDE should show something like:
int (*)[3][2]; // pointer to array-of-array-of-int
You would access it like this:
(*a)[0][0] = 1; // dereference pointer to access 2D array it points to
But I suspect a better remedy to your problem is to use std::array. That will behave more predictably.
std::array<std::array<int, 2>, 3> arr2d = {{
{1, 2},
{3, 4},
{5, 6}
}};
auto a = &arr2d;
Now a is type std::array<std::array<int, 2>, 3>*