模拟实现memmove函数
分析
- 试看这样一道题
int arr[6] = {1,2,3,4,5,6};
将数组前4个元素复制到后4个元素上,即将数组变为
{1,2,1,2,3,4}
将数组还原为初始在将后四个元素复制到三个元素上,即为
{3,4,3,4,5,6}
说到拷贝我们一定会想到上一篇博客中模拟的memcpy函数
但是用memcpy函数后输出的结果是这样的
void *my_memcpy(void *dest, void *src, size_t count)
{
void *ret = dest;
assert(dest != NULL);
assert(src != NULL);
while (count)
{
*(char*)dest = *(char*)src;
dest = (char*)dest +1;
src = (char*)src +1;
count--;
}
return ret;
}
int main()
{
int arr[6] = {1,2,3,4,5,6};
memcpy(arr+2, arr, 16); //将数组前4个元素复制到后4个元素上
for (int i = 0; i<6; i++)
{
printf("%d",arr[i]);
}
return 0;
}
结果:
我们期待的结果 121234
实际结果 121212
分析:
- 拷贝目标和源有重叠部分!
- 我们将前两个元素拷贝后3,4就变成了1,2,这样3,4就丢失了,在拷贝三和四的位置时实际拷贝的又是1,2。
- 我们想到一个解决方法就是倒着拷贝,这样就不会丢失3,4。但是倒着拷贝如果想实现题目中的第二种境况时又会发生丢失。
- 也就是说,既有需要从前向后拷贝的情况也有从后向前拷贝的情况。
进一步分析:
- 如何区别有重叠时从前向后还是从后向前的两种情况
- 在没有重叠时从前向后还是从后向前均可
我们只需分析重叠时
重叠时关键在于目标与源的前后关系当 目标在源之后 (即题目第一种情况) 从后向前
- 当 目标在源之前 (即题目第二种情况) 从前向后
代码实现
void *my_memmove(void *dest, void *src, size_t count)
{
void *ret = dest;
assert(dest != NULL);
assert(src != NULL);
if (dest>src) //目标在源之前
{
while (count)
{
*(char*)dest = *(char*)src;
dest = (char*)dest +1;
src = (char*)src +1;
count--;
}
}
else //目标在源之后
{
while (count--)
{
*((char*)dest+count) = *((char*)src+count);
}
}
return ret;
}
int main()
{
int arr1[6] = {1,2,3,4,5,6};
memmove(arr1+2, arr1, 16);
for (int i = 0; i<6; i++)
{
printf("%d ",arr1[i]);
}
printf("\n");
int arr2[6] = {1,2,3,4,5,6};
memmove(arr2, arr2+2, 16);
for (int i = 0; i<6; i++)
{
printf("%d ",arr2[i]);
}
return 0;
}
输出结果:
1 2 1 2 3 4
3 4 5 6 5 6