This is normal, if not for any other reason, because char can use all other types in accordance with the standard. Multidimensional arrays are also allocated as an adjacent block, so for starters it is a one-dimensional array in memory.
We know that tab1 splits into a pointer to the first element of an adjacent multidimensional array (which is an array) and distinguishes this array pointer to char* (which can be any alias) should be good.
When in doubt, you can always do &tab1[0][0] . Again, since we know that allocated memory is contiguous.
EDIT
If it was an integer array ( int tab1[3][3] ), then the story is slightly different. As far as I understand before C++17 , the standard says that a pointer to the correct type of an object is valid regardless of how it got its value. This means that casting to int* must be accurate, because we know that the address received by tab1 matches the address of the first element.
However, after C++17 this guarantee was removed, so this behavior is likely to be undefined.
See THIS question for more details .
For this reason, I always recommend using &tab1[0][0] , which will always be valid.
Galik source share