1、memcpy函数
1.1memcpy函数的基本介绍
要讨论memmove,那memcpy自然是不能忽略的,这两个函数的功能非常相似,或者说memmove是memcpy的升级版本。我们打开MSDN可以看到这个函数的的头文件是memory.h或是string.h。参数分别是目标地址,源地址和需要拷贝的长度,返回类型是void*。
这个函数的作用我们也可以看出这个函数的作用和strcpy很相似,不同的是strcpy只能拷贝字符串。而memcpy是可以拷贝任何类型的数据的。
1.2、memcpy的缺点
但是这个函数也有一些问题。比如我想要拷贝的的目标地址和源地址是一个同一个数组,而且有重叠的情况下就会发生内容覆盖。就像这样。
我想把34567的内容拷贝到现在的56789的位置,因为56的位置已经被覆盖成了34,那么我们在使用memcpy就会导致这样的情况。
所以就有了memmove这个函数的出现。
2、memmove 函数
2.1、memmove函数的基本介绍
我们再来看看MSDN对于memmove这个函数的解释
memmove实现的功能跟memcpy一样但是不同的是memmove解决了前面说的问题。那我要怎么去实现这个函数呢?
3、memcpy函数的模拟实现
我们 要实现memcpy只要将每个字节的内容拷贝到目标位置就行所以说可以借助for循环和强制转换为(char*)类型的指针(由于char*类型的指针解引用的访问权限是一个字节)。
void* my_memcpy(const void* src, void* dst, size_t len)
{
assert(src && dst);
int* ret = dst;
for (int i = 0; i < len; i++)
{
*(char*)dst = *(char*)src;
((char*)dst)++;
((char*)src)++;
}
return ret;
}
由于src源地址的内容是不需要改变的所以说我们可以加上const保护。
再加上assert进行断言防止函数使用时传入空指针
非常的容易。
4、memmove函数的模拟实现
还是这个数据,我们要怎么去解决覆盖问题呢?我们可以从后往前拷贝也就是
7->9 6->8 5->7 4->6 3->5
这样就可以解决这个问题,但是如果目标空间在源空间的前面呢?如果还是使用从后往前拷贝的方法,就会把前面的内容覆盖了。就像这样
那么我们可以进行分类讨论,也就是借助if条件语句。
我们发现这是一个分界点,
如果dst在src的前面那就使用从前向后拷贝的方法
如果dst在src的后面那就使用从后向前拷贝的方法
我们就可以用dst-src去判断前后关系,但是由于我们的dst和src都是无类型的指针,所以说要先进行强制类型转换,在进行运算。
所以我们就可以写出下面的部分
如果dst在src的前面,也就是 (char*)dst - (char*)src < 0 ,那就使用从前向后拷贝的方法
如果dst在src的后面,也就是 (char*)dst - (char*)src > 0 ,那就使用从后向前拷贝的方法
void* my_memmove(void* dst, const void* src, size_t len)
{
int ret = dst;
if ((char*)dst - (char*)src < 0)
{
for (int i = 0; i < len; i++)
{
(char*)dst = *(char*)src;
((char*)src)++;
((char*)dst)++;
}
}
else
{
for (int i = len - 1; i >= 0; i--)
{
*((char*)dst + i) = *((char*)src + i);
}
}
return ret;
}
memmove就可以很好地实现出来了