-1

With one dimensional arrays (or integers for example) I know how to create pointers both for allocation in the heap and in the stack

-Pointer in the stack and array in the stack

int a[3];
int *ptr=a;

-Pointer in the stack and array in the heap

int *ptr=new int[3];

But for matrix (for example 3x2) the pointer can be created as an array of pointers int (*A)[3] or as a double pointer int **A.

I would like to know the main difference between these two way to create a pointer to a multidimensional array.

In particular I've seen the array of pointers used to create pointer to a matrix array stored in the stack as:

int A[2][3];
int (*ptr)[3]=A;

And I've seen the double pointer used for matrices allocated in the heap

int **ptr= new *[3];
for(int i=0; i<=3; i++) int ptr[i]=new [2];

But is it also possible to use the array of pointer for the heap and the double pointer for the stack?

And again, more generally, what are the main difference between the array of pointers and the double pointer?

trincot
  • 317,000
  • 35
  • 244
  • 286
Gianolepo
  • 155
  • 7
  • 2
    This sort of question pops up once a week on SO. What did you find when you searched for it? – StoryTeller - Unslander Monica Dec 05 '17 at 10:24
  • [This post](https://stackoverflow.com/questions/42094465/correctly-allocating-multi-dimensional-arrays) details array internals in C. There are obvious differences (some of the technique cannot be applied to C++), but the general gist of memory layout is the same. – StoryTeller - Unslander Monica Dec 05 '17 at 10:26
  • For matrices I usually prefer to have an one-dimensional array (btw. that is what `int a[2][3]` normally does under the hood AFAIK), the performance is much better because of the contiguous memory (compared to separate allocation of each row or column with `int *a[2]`). Also, for the same reason (dcache performance) it does matter whether your matrix is row-major or column-major and how you iterate it then. – EmDroid Dec 05 '17 at 10:32
  • e.g. https://stackoverflow.com/questions/33746434/double-pointer-vs-array-of-pointersarray-vs-array / https://stackoverflow.com/questions/33491687/difference-between-double-pointer-and-array-of-pointers / many more – underscore_d Dec 05 '17 at 10:34
  • 1
    Possible duplicate of [Difference between double pointer and array of pointers](https://stackoverflow.com/questions/33491687/difference-between-double-pointer-and-array-of-pointers) – underscore_d Dec 05 '17 at 10:35
  • `int (*A)[3]` isn't an array of pointers. It is a pointer to an array of length 3. – juanchopanza Dec 05 '17 at 10:36

1 Answers1

1

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.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335