探究一下:使用memcpy函数能不能自己拷贝自己

简介: 探究一下:使用memcpy函数能不能自己拷贝自己

上篇博客,笔者详细的介绍了memcpy内存拷贝函数的使用及其模拟实现,到目前为止,引起了众多关注!


但是,仍有不少的读者对于笔者在上篇文章的最后所留的问题保持疑惑!!所以,笔者在此打算写一篇文章,来进行简单的解析,说明一下原因:


0a2653c851af460fa595bd959398a8f1.png


上面的问题,主要还是指:思考一下:对于数组:int  arr[]={1,2,3,4,5,6,7,8,9,10};能不能将1,2,3,4,5拷贝到3,4,5,6,7的位置??从而结果为:1,2,1,2,3,4,5,8,9,10呢???  这个答案是不能,但是为什么不可以呢??下面将是笔者的具体解析内容,请各位老铁仔细思考哟!!!


由于进行描写不是很方便,所以下面是笔者在画图板上面的内容!


2d65d23f6d4748949b924e4057485923.png


请大家仔细思考一下!!


由于在memcpy函数拷贝的时候,是按照字节来进行拷贝的!!所以,会进行一个一个int类型的拷贝,拷贝的数字将会覆盖原来的数字!所以,才会导致上面的结果!!请大家分析一下!就能得出上述结论!!


对于上述代码的实现过程为:


#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memcpy(void* dest, void* src, size_t num)
{
  void* ret = dest;
  assert(dest);
  assert(src);
  while (num--)
  {
  *(char*)dest = *(char*)src;
  dest = (char*)dest + 1;
  src = (char*)src + 1;
  }
  return ret;
}
int main()
{
  int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
  my_memcpy(arr1 + 2, arr1, 20);
  int i = 0;
  for (i = 0; i < 10; i++)
  {
  printf("%d ", arr1[i]);
  }
  return 0;
}

当然,这个代码,还是借用了memcpy内存拷贝的模拟实现!!所以还是希望各位老铁能够欣赏一下笔者的上篇博客!!


在上述代码里面:my_memcpy(arr1 + 2, arr1, 20);  arr1是指数组的首元素!!arr1+2是:指向数组的第三个元素!!


6de278e6d6694ce5bb08e7e842b7e74b.png


经过上面的画图分析过程,想必代码的运行结果也是显而易见的!!


12c3b7f3f8814309a195c64f051d4445.png


总结:当源头与目的地的空间有重合的部分,会被覆盖掉!!所以显得上面的代码,不是很合理!!


下面笔者来带领大家具体情况具体分析一下!!请仔细思考!


对于数组arr1[]={1,2,3,4,5,6,7,8,9,10}我们可以:从一下方面进行考虑:


1.将1,2,3,4,5放到3,4,5,6,7的位置 ,我们可以用从后往前放的方法来实现目地!!


第一步:将5放在7的位置,第二步:将4放在6的位置,第三步:将3放在5的位置……这样依次按照顺序来实现!!


34e8d716411043c08c7ffba9fbba23de.png


2.但是:对于所有的部分都进行这种从后往前放的顺序,又不一定都对! 就比如:将4,5,6,7,8放在1,2,3,4,5的位置处!


按照从后往前放的方式来进行思考的话:那么:第一步:将8放在5的位置,第二步:将7放在4的位置,第三步:将6放在3的位置,第四步:将5放在……(注意此时5的位置处,放置的不再是5了,已经被前面的8替代!!所以显得非常不合理!!)


92ba0822ed0b46e1ae72df8a17d3a45b.png


所以对于这种的拷贝情况,我们应该这样思考:从前往后放!!


d79b274929334152a6d38be91e2d1be3.png


经过上面的两个案列,想必各位老铁也能看出来:复杂!!


总结:有时候需要从前往后拷贝!!


           有时候需要从后往前拷贝!!


因此,笔者进行粗略的总结一下 :


dfc80ca9d8004e6c9ddc00e8448ffc6a.png


因此,对于memcpy函数的模拟实现的更加完整的代码为:


#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memcpy(void* dest, void* src, size_t num)
{
  void* ret = dest;
  assert(dest);
  assert(src);
  if (dest < src)
  {  //在这里:比较的是地址!!
  while (num--)
  {
    //从前往后
    *(char*)dest = *(char*)src;
    dest = (char*)dest + 1;
    src = (char*)src + 1;
  }
  }
  else
  {
  while (num--)
  {
    *((char*)dest + num) = *((char*)src + num);
    //从后往前
  }
  }
  return ret;
}
int main()
{
  int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
  my_memcpy(arr1 + 2, arr1, 20);
  int i = 0;
  for (i = 0; i < 10; i++)
  {
  printf("%d ", arr1[i]);
  }
  return 0;
}

上述代码的运行结果为:


0a2653c851af460fa595bd959398a8f1.png


其实,在C语言中,重叠部分的内存拷贝是交给:memmove函数实现的!!


因此对于memmove函数的模拟实现,便是将上面的代码,改改名字罢了!!在此,笔者就不再更改了!!


因此: memcpy只需要实现不重叠部分内存拷贝就可以了!


           memmove是需要实现重叠部分内存拷贝的!!


相关文章
|
10月前
|
存储 安全 C语言
深度剖析c语言程序 -- 函数栈帧的创建和销毁(纯肝货)-2
深度剖析c语言程序 -- 函数栈帧的创建和销毁(纯肝货)-2
102 0
|
10月前
|
存储 编译器 C语言
深度剖析c语言程序 -- 函数栈帧的创建和销毁(纯肝货)-1
深度剖析c语言程序 -- 函数栈帧的创建和销毁(纯肝货)-1
112 0
|
5月前
|
程序员 编译器 C语言
C中的 malloc 和C++中的 new 有什么区别
在C语言中,`malloc`函数用于在运行时分配内存,返回指向所分配内存的指针,需显式包含头文件 `&lt;stdlib.h&gt;`。而在C++中,`new`不仅分配内存,还对其进行构造初始化,且直接使用类型声明即可,无需额外包含头文件。`new`还支持数组初始化,能更好地融入C++的面向对象特性,而`malloc`仅作为内存分配工具。使用完毕后,`free`和`delete`分别用于释放`malloc`和`new`分配的内存。
92 21
|
10月前
|
存储 前端开发 编译器
【C语言】memmove()函数(拷贝重叠内存块函数详解)
【C语言】memmove()函数(拷贝重叠内存块函数详解)
129 1
|
存储
经常容易混淆的指针概念以及特殊指针
经常容易混淆的指针概念以及特殊指针
72 0
|
10月前
|
存储 安全 数据处理
C++系列十一:指针
C++系列十一:指针
|
C语言
C语言函数和指针的关系之二(未完)
C语言函数和指针的关系之二(未完)
54 0
|
C语言 C++
从汇编代码探究函数栈帧的创建和销毁的底层原理(一)
从汇编代码探究函数栈帧的创建和销毁的底层原理
|
存储 编译器
从汇编代码探究函数栈帧的创建和销毁的底层原理(二)
从汇编代码探究函数栈帧的创建和销毁的底层原理
|
存储 安全 编译器
C语言学习笔记—P17(函数栈帧的创建与销毁<超详解版>+图解+题例)
C语言学习笔记(函数栈帧的创建与销毁<超详解版>+图解+题例)
124 0
C语言学习笔记—P17(函数栈帧的创建与销毁<超详解版>+图解+题例)