探究一下:使用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是需要实现重叠部分内存拷贝的!!


相关文章
|
6月前
|
编译器 C语言 C++
【C语言】memset()函数(内存块初始化函数)
【C语言】memset()函数(内存块初始化函数)
84 0
|
30天前
|
程序员 编译器 C语言
C中的 malloc 和C++中的 new 有什么区别
在C语言中,`malloc`函数用于在运行时分配内存,返回指向所分配内存的指针,需显式包含头文件 `&lt;stdlib.h&gt;`。而在C++中,`new`不仅分配内存,还对其进行构造初始化,且直接使用类型声明即可,无需额外包含头文件。`new`还支持数组初始化,能更好地融入C++的面向对象特性,而`malloc`仅作为内存分配工具。使用完毕后,`free`和`delete`分别用于释放`malloc`和`new`分配的内存。
49 21
|
5月前
|
编译器
拷贝对象时编译器的一些优化
拷贝对象时编译器的一些优化
|
4月前
|
机器学习/深度学习 算法 搜索推荐
|
6月前
|
存储 前端开发 编译器
【C语言】memmove()函数(拷贝重叠内存块函数详解)
【C语言】memmove()函数(拷贝重叠内存块函数详解)
95 1
普通函数中的this指向问题解决方案_this
普通函数中的this指向问题解决方案_this
37 0
|
存储 算法 编译器
【c语言技能树】函数的创建与销毁 --函数栈帧
以下内容可能乍一看有点费解,但在我讲的过程中再看就很容易理解啦,
254 0
学C的第五天(初识指针,内存产生内存单元地址过程,指针函数介绍和其大小;结构体补充)-1
13*指针: 13.1 -- 内存: 内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的。 【32位操作系统的内存由32根地址线产生的高低电位(1/0), 划分为2的32次方个地址(编号\指针),一个地址为一个字节, 等于8比特。】
|
程序员
拷贝函数的优化
拷贝函数的优化
58 0