Florian Aubin
Florian Aubin

Reputation: 19

How does memmove on array of pointers in C/C++ work?

I have an array of array like this :

double **Arr = malloc(N*sizeof(double*));
for(int j = 0; j < N-1; j++)
  Arr[j] = malloc(M*sizeof(double))

Theses arrays are full of values. And I want to shift some arrays (the N-i last ones). Are there any differences between these 2 lines ?

for(int j = i; j < N-1; j++)
  for(int k = 0; k < M; k++)
    Arr[j][k] = Arr[j+1][k];

or

memmove(&(Arr[i]), &(Arr[i+1]), (N-1-i)*sizeof(double*));

Upvotes: 1

Views: 952

Answers (3)

4386427
4386427

Reputation: 44246

Are there any differences between these 2 lines ?

Yes, they are very different. And the second is leaking memory.

Explanation:

After initialization like:

double **Arr = malloc(N*sizeof(double*));
for(int j = 0; j < N; j++)
  Arr[j] = malloc(M*sizeof(double))

(note: I changed the N-1 to N as I assumed it to be a mistake)

The allocated memory now looks like:

enter image description here

When you then do:

for(int j = i; j < N; j++)
  for(int k = 0; k < M; k++)
    Arr[j][k] = Arr[j+1][k];

You copy the doubles from a horizontal array to the horizontal array above. Like:

enter image description here

When you do:

memmove(&(Arr[i]), &(Arr[i+1]), (N-1-i)*sizeof(double*));

You copy the double-pointers in the vertical array one position up. Like:

enter image description here

So it's very different operations that the 2 code blocks do.

And the memmove is bad as it leaks memory.

Upvotes: 1

KamilCuk
KamilCuk

Reputation: 140880

Are there any differences between these 2 lines ?

Let's take:

memmove(&(Arr[i]), &(Arr[i+1]), (N-1-i)*sizeof(double*));

Basically what it does can be represented by copying byte-by-byte the specified amount of bytes from one pointer to another. So it can be written in this I hope correct code:

for (size_t j = 0; j < (N-1-i)*sizeof(double*); ++j) {
    *( ((char*)&Arr[i]) + j ) = *( ((char *)(&Arr[i + 1]) + j );

Puff, it makes a big technical difference, but let's remove sizeof(double*) and the casts:

for (size_t j = 0; j < N - 1 - i; ++j)
    *(&Arr[i] + j) = *(&Arr[i + 1] + j);

The &Arr[i] is equal to &*(Arr + i) which is equal to Arr + i, so:

for (size_t j = 0; j < N - 1 - i; ++j) {
    *(Arr + i + j) = *(Arr + i + j + 1);

The *(a + i) is equal to a[i], so we can:

for (size_t j = 0; j < N - 1 - i; ++j) {
    Arr[i + j] = Arr[i + j + 1];

As i + j is on both sides and j starts from 0, we could just start from i:

for (size_t j = i; j < N - 1; ++j) {
    Arr[j] = Arr[j + 1];

Now this copies the pointers values(!) from Arr[j + 1] into Arr[j]. This does something very different then copying the values that are pointed to by the pointers:

for(int j = i; j < N - 1; j++)
    for(int k = 0; k < M; k++)
         Arr[j][k] = Arr[j + 1][k];

On the other hand, the above code could be translated to:

for(int j = i; j < N - 1; j++)
    memcpy(Arr[j], Arr[j + 1], M * sizeof(double));
  //^^^^^^ or memove, but I guess not

Theses arrays are full of values

Your initialization routine that you have showed has this loop:

for(int j = 0; j < N-1; j++)
   Arr[j] = malloc(M*sizeof(double))

Being sane and assuming N > 1, then Arr[N - 1] is left uninitialized. So, accessing in the above loops Arr[j + 1] for the last loop when j = N - 2 is accessing uninitialized value. And the loop for(int k = 0; k < M; k++) Arr[j][k] = Arr[j + 1][k]; dereferences uninitialized pointer in Arr[j + 1][k] and is undefined behavior.

Upvotes: 0

molbdnilo
molbdnilo

Reputation: 66371

The first copies M numbers N-1-i times, and the second copies N-1-i pointers once.
That is, if double and double* are the same size, the first copies M times as much memory as the second.
(And is less cache-friendly.)

Simplifying to just two pointers:

 double *arr = malloc(M * sizeof(double));
 double *arr2 = malloc(M * sizeof(double));

the difference is the same as between

 for (int k = 0; k < M; k++) arr2[k] = arr[k];

and

arr2 = arr;

Which one you should use depends on what you're after; copying the pointers or copying the elements.

Upvotes: 0

Related Questions