简体   繁体   English

C/C++ 中指针数组上的 memmove 是如何工作的?

[英]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.这些 arrays 充满了价值。 And I want to shift some arrays (the Ni last ones).我想转移一些 arrays (最后的 Ni)。 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*));

Are there any differences between these 2 lines?这两条线有什么区别吗?

Yes, they are very different.是的,它们非常不同。 And the second is leaking memory.第二个是泄漏 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) (注意:我将 N-1 更改为 N,因为我认为这是一个错误)

The allocated memory now looks like:分配的 memory 现在看起来像:

在此处输入图像描述

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.您将垂直数组中的双指针复制到 position 向上。 Like:喜欢:

在此处输入图像描述

So it's very different operations that the 2 code blocks do.因此,这两个代码块执行的操作非常不同。

And the memmove is bad as it leaks memory.而且memmove很糟糕,因为它泄漏了 memory。

The first copies M numbers N-1-i times, and the second copies N-1-i pointers once.第一个复制M个数字N-1-i次,第二个复制N-1-i个指针一次。
That is, if double and double* are the same size, the first copies M times as much memory as the second.也就是说,如果doubledouble*大小相同,则第一个复制的 memory 是第二个复制的M倍。
(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.复制指针或复制元素。

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:噗,这在技术上有很大的不同,但是让我们删除sizeof(double*)和演员表:

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: &Arr[i]等于&*(Arr + i)等于Arr + i ,所以:

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: *(a + i)等于a[i] ,所以我们可以:

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 :由于i + j在两边并且j0开始,我们可以从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] .现在这会将指针值(!)从Arr[j + 1]复制到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论文 arrays 价值满满

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.理智并假设N > 1 ,则Arr[N - 1]未初始化。 So, accessing in the above loops Arr[j + 1] for the last loop when j = N - 2 is accessing uninitialized value.因此,当j = N - 2访问最后一个循环时,在上述循环中访问Arr[j + 1]正在访问未初始化的值。 And the loop for(int k = 0; k < M; k++) Arr[j][k] = Arr[j + 1][k];循环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.取消引用Arr[j + 1][k]中未初始化的指针并且是未定义的行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM