0

Codes are as follows:

#include <iostream>
using std::cout;

int main(int argc, char ** argv)
{
    int** p;
    int a[2][3]={{-1,-1,-1},
                 {-1,-1,-1}};
    int k=1;
    p = new int *[2];
    for(int i=0;i<2;i++) {
        p[i] = new int[3];
        for(int j=0;j<3;j++) {
            p[i][j] = k++;
        }
    }

    memcpy(a,p,2 * 3 * sizeof(int));
    for(int i=0;i<2;i++){
        for(int j=0;j<3;j++)
            cout<<a[i][j]<<" ";
        cout<<endl;
    }

    delete [] p;
    return 0;
}

Got unexpected results after running:

26573888 0 26573920
0   0   0

I think it copied addresses rather than values, so I changed the line memcpy(a,p,2 * 3 * sizeof(int)); to

memcpy(a,p[0],2 * 3 * sizeof(int));

And terminal printed out:

1 2 3
0 0 0

How to understand above results? Can anyone help me out?

GUESS
addresses of p[0][2] and p[1][0] are not continuous?

L. F.
  • 19,445
  • 8
  • 48
  • 82
Finley
  • 795
  • 1
  • 8
  • 26
  • 3
    Possible duplicate of [How are multi-dimensional arrays formatted in memory?](https://stackoverflow.com/questions/2565039/how-are-multi-dimensional-arrays-formatted-in-memory) – Aconcagua Oct 12 '19 at 10:35
  • What is the actual thing you want to achieve? Do you want to copy a static array into a dynamic one? Or do you just want to learn about memory layout? What is the purpose of your code? – Martin B. Oct 12 '19 at 10:41
  • Retracting close vote: Possible duplicate focuses only on multidimensional arrays without enlighting the difference to array of pointers sufficiently (how are *these* laid out in memory?). – Aconcagua Oct 12 '19 at 11:01

3 Answers3

0

You are mixing things...

This other question (and especially the accepted answer) explains it nicely. You have a static two-dimensional array and an int**.

These two look the same but aren't. The compiler knows which is which an so the one is laid out continuously and the other is not.

You can even see this in your code. Once you write

int a[2][3]={{-1,-1,-1},
             {-1,-1,-1}};

where the object is a chunk of memory denoted by a

But then you write

p = new int *[2];
for(int i=0;i<2;i++) {
    p[i] = new int[3];
    for(int j=0;j<3;j++) {
        p[i][j] = k++;
    }
}

where you have an object p. And then with the line p[i] = new int[3] you go on and make 2 seperate int[3] objects. These lie who knows where. And their addresses are assigned to the pointers p[i].

TL;DR: The type int[2][3] is fundamentally different from int** and these are not trivially interoperable.

Martin B.
  • 1,567
  • 14
  • 26
  • I understand what you mean but I wanted to emphasize the point that it is easily recognized that these two objects are different by the `new int[3]` line. I see that most of my answer is a recap of the other answer, I'll try to rewrite... – Martin B. Oct 12 '19 at 10:44
  • Reading the other question and answers again, I decided it's *not* a full duplicate, the other question indeed explains memory layout of multidimensional arrays nicely, but lacks emphasising the difference to arrays of pointers, so let's forget about my previous comment (deleted)... – Aconcagua Oct 12 '19 at 11:04
0

you have to do memcpy one per row to get the expected result:

memcpy(a[0], p[0], 3 * sizeof(int));
memcpy(a[1], p[1], 3 * sizeof(int));

The reason is rows are not contiguous.

Live on godbolt

Oblivion
  • 7,176
  • 2
  • 14
  • 33
0

What is the type of p[0]?

int*

What is the type of a[0]?

int[3]

a[0] decays to a pointer in appropriate context (e. g. when passing to a function as argument), but it is not one natively, totally in contrast to p[0], which is right from the start. You'll notice the difference if you e. g. compare the size of both (sizeof(a[0]) giving size of three ints, sizeof(p[0]) giving size of a pointer).

Array members always are just placed one after another contiguously, so for a, there are two arrays placed one after another:

a: { { -1, -1, -1 }, {-1, -1, -1 } }

For p actually exactly the same, each member following one after another contiguously; solely, this time, the members are true pointers (i. e. some address in memory). There are other arrays, but these are (necessarily) placed elsewhere:

p: { <pointer>, <pointer> }
         |          |
         V          |
       { 1, 2, 3}   |
                    V
                  { 4, 5, 6}

So in conclusion, your guess is correct.

Aconcagua
  • 24,880
  • 4
  • 34
  • 59