Reputation: 19
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
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:
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:
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:
So it's very different operations that the 2 code blocks do.
And the memmove
is bad as it leaks memory.
Upvotes: 1
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
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