1、memcpy
memcpy函数是C/C++语言中的一个用于内存复制的函数,声明在 string.h 中(C++是 cstring)。其原型是:
void * memcpy ( void * destination, const void * source, size_t num );
其中,destination表示的是要拷贝到的目标起始地址,source表示要拷贝内容的起始地址,num表示要拷贝的字节数。函数的作用为:将 num个bytes 的值从 source 指向的位置直接复制到destination 指向的内存块。
模拟实现:我们可以看到,destination和source指针的类型均为void*类型,也就是说传入的指针变量不知道它的具体类型。这其实很容易理解,在对内存块进行拷贝的时候,由于情况很多,比如:这次需要拷贝整型内容,下次需要拷贝字符型内容,过几天又需要拷贝结构体类型的内容,所以在函数设计的时候要增大函数的普适性,在这里的指针类型就使用void*类型来接收指针。
函数的第三个参数是num,它表示要拷贝的字节数量,内存块的最小单位为字节正好与之对应大小的数据类型为char类型。所以我们不考虑具体操作的原数据是什么类型,即不需要考虑原来数据占有几个字节,我们将这些数据全部拆成一个个独立的字节数据进行搬移。那么在使用指针的时候只需要将其强制类型转换成char*类型进行循环赋值即可。下面是函数的实现:
void* my_memcpy(void* dest, const void* src, size_t num)
{assert(dest && src);size_t i = 0;void* ret = dest;for (i = 0; i < num; i++)//每次搬移一个字节{*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}return ret;
}
在指针加一的时候进行要注意,不能直接写成(char*)dest++,这是因为(char*)dest是临时的在进行++操作的时候,dest依旧是void*类型。让我们来测试一下
#include <stdio.h>int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int sz1 = sizeof(arr1) / sizeof(arr1[0]);int arr2[10] = 0;my_memcpy(arr2, arr1, sizeof(int) * 3);//拷贝三个数字int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr2[i]);}return 0;
}
运行结果:
上述的函数已经能实现绝大多数的内存拷贝问题,但是存在一种可能程序可能会报错,假设源地址内存块 与 目标地址内存块发生重叠,再拷贝的过程中会破坏掉源地址内存块的数据,导致后面的拷贝发生拷贝的是错误的数据。画个图来看一下具体问题:
发生错误的原因就是在拷贝过程中对源地址空间的数据进行了破坏,这种破坏是算法导致的,可以改变策略来应对这种问题。我们可以看到上面算法拷贝的顺序从源地址空间的起始向源地址空间的末尾进行拷贝,那我们 可以改变拷贝的顺序,从右向左拷贝:
还会有一种情况,交叠的部分在src的左侧时我们采取的策略依然是从左到右的拷贝顺序:
其实,做出这些策略的调整的核心思想就是:源地址空间的数据在拷贝过程中不能被破坏。
下面让我们重新审视这个问题进行总结,我们将dest空间看成一个运动的方框,src空间是静止不动的。 当dest<src时拷贝的顺序为从左往右,当dest>src时从右往左进行拷贝。一般在处理这种有交集的问题时,我们使用的是memmove函数。
2、memmove
有了在memcpy中的过渡部分,我们来模拟实现一下memmove。代码如下:
#include <assert.h>void* my_memmove(void* dest, const void* src, size_t num)
{assert(dest && src);size_t i = 0;void* ret = dest;int temp = num;for (i = 0; i < num; i++){if (dest < src){//从左往右拷贝*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}else{//从右往左拷贝*((char*)dest+ temp -1)=*((char*)src + temp - 1);temp--;}}return ret;
}
所谓的从左往右这个方向指的是 从src的左边还是右边开始拷贝。
3、两者的区别
他们的作用是一样的,唯一的区别是,当内存发生局部重叠的时候,memmove保证拷贝的结果是正确的,memcpy不保证拷贝的结果的正确。