1函数void* memmove(void* dest, void* sour, size_t num);
可以将地址sour的拷贝给地址dest并且向后延申至num个字节。与函数memcpy有相同的作用,但是memmove可以处理的源内存块和⽬标内存块是重叠的情况,简单来说就是当处理对象是数组是memmove可以实现数组的自我拷贝。像:
由图中代码可以看出memmove实现了数组arr的自我拷贝。而memcpy就不可以(少数编译器可以)。
memmove的实现:
下面是一段可以实现memcpy的代码,因两着很相似所以尝试使用。
void* my_memmove(void* arr2, void* arr, size_t bit)
{
if(bit>0)
{
*(char*)arr2 = *(char*)arr;
((char*)arr2)++;
((char*)arr)++;
bit--;
my_memmove(arr2, arr, bit);
}
return (char*)arr2-1;
}
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
my_memmove(arr+3, arr, 16);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
但使用这段代码来将蓝色部分变成红色部分时,
我们期望的运行结果是”1 2 3 1 2 3 4 8 9 10“但实际是:
经过画图我们可以看出这是从前向后排后面的数字被前面的覆盖掉了,所以我们采用从后向前赋值的方式。但是当这样写时,想要将红色化为蓝色部分时又会出现覆盖的问题,而这时我们就需要从前向后排。
总结:
经过上面的分析可以得出:当要修改的地址大于源地址时我们需要从后向前排,而相反我们则需要从前向后排,注意当两者不存在交集时可以直接从后向前排、从后向前亦可。
所以对代码修正得:
void* my2_memmove(void* arr2, void* arr, size_t num)
{
if (num > 0)
{
*(char*)arr2 = *(char*)arr;
arr2 = (char*)arr2 - 1;
arr = (char*)arr - 1;
num--;
my2_memmove(arr2, arr, num);
}
return (char*)arr2 - 1;
}
void* my_memmove(void* arr2, void* arr, size_t num)
{
if (num > 0 && arr2 < arr)
{
*(char*)arr2 = *(char*)arr;
arr2 = (char*)arr2 + 1;
arr = (char*)arr + 1;
num--;
my_memmove(arr2, arr, num);
}
if (num >= 0 && arr2<arr)
{
return (char*)arr2 - 1;
}
arr = (char*)arr + num - 1;
arr2 = (char*)arr2 + num - 1;
return my2_memmove(arr2, arr, num);
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr, arr+3, 4 * sizeof(int));
my_memmove(arr2 + 3, arr2, 4 * sizeof(int));
int i = 0;
printf("arr:");
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
printf("\narr2:");
for (i = 0; i < 10; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
由图我们得到了”1 2 3 1 2 3 4 8 9 0“这个运行结果。