From the C++ (2017) Standard (7.2 Array-to-pointer conversion)
1 An lvalue or rvalue of type “array of N T” or “array of unknown
bound of T” can be converted to a prvalue of type “pointer to T”. The
temporary materialization conversion (7.4) is applied. The result is
a pointer to the first element of the array.
Thus let's assume that you have an array like this
T A[N1][N2]...[Nn];
where T
is some type and [N1][N2]...[Nn]
is an informal record of dimensions of the array. Then this declaration can be written also like
T ( A[N1] )[N2]...[Nn];
To declare a pojnter to the first element of the array all you beed is to substitute ( A[N1] )
for ( *ptr )
in the declaration.
T ( A[N1] )[N2]...[Nn];
T ( *ptr )[N2]...[Nn] = A;
For example taking the declaration from the question
int A[2][3];
you can rewrite it like
int ( A[2] )[3];
Now it is easy to declare a pointer to the first element of the array
int ( *ptr )[3] = A;
Dereferencing the pointer you get the first "row" of the type int[3]
of the two-dimensional array
On the other hand, if you have a declaration of an array of pointers like
int * A[3];
which can be rewritten like
int * ( A[3] );
then to get a declaration of a pointer you can write
int * ( *ptr ) = A;
that is the same as
int **ptr = A;
So dereferencing the pointer you will get an object of the type int *
that is in turn a pointer.
So for this declaration
int ( *ptr )[3] = A;
the pointed object is a one-dimensional array. For example you can write
std::cout << sizeof( *ptr ) << std::endl;
and you will get a value that is equal to sizeof( int[3] )
that is equal to 3 * sizeof( int )
As for this declaration
int * A[3];
int **ptr = A;
the pointed object is a pointer of the type int *
. If to write for this pointer
std::cout << sizeof( *ptr ) << std::endl;
then you will get a value that is equal to sizeof( int * )
Let's consider this code snippet
int **ptr = new int *[2];
for( int i = 0; i < 2; i++ ) ptr[i] = new int[3];
In the first statement there is dynamically allocated a one-dimensional array of the type int *[2]
.
Then in the loop there are dynamically created 2 arrays of the type int[3]
and pointers to first elements of the arrays are assigned to elements of the previously allocated one-dimensional array.
So in whole there are dynamically allocated 3 arrays: one of the type int *[2]
and two of the type int [3]
. That is there are allocated three separate extents of memory.
Instead you could write
int ( *ptr )[3] = new int[2][3];
In this case there is allocated dynamically only one two-dimensional array and the declared pointer ptr
points to the first "row" of the array. That is there is allocated only one extent of memory.