本篇博客是基于模拟实现memcpy库函数这篇文章写的
在本文开始之前,希望大家能读一下
memmove函数跟memcpy函数功能大致相同,所以我们在实现memmove函数时可以用模拟memcpy函数代码进行改进
分析并解决问题
本文主要实现的细节就是如何解决目标地址和拷贝内容的地址重叠拷贝的问题
下面我们分两个方面解决这个问题
1、当src<dest时
当我们的拷贝内容地址小于目标地址时,该如何拷贝呢?
如果是从低地址向高地址拷贝,那当“4”就会被拷贝为“1”,所以低地址向高地址拷贝这种方法行不通。
而从高地址向低地址拷贝时,“4”拷贝给“7”、“3”拷贝给“6”、“2”拷贝给“5”、“1”拷贝给“4”,这样就“4”就可以在改变之前把值拷贝给“7”。
所以当src<dest时,选从高地址向低地址拷贝
2、当src>dest时
当我们的拷贝内容地址小于目标地址时,我们可以直接从低地址向高地址拷贝,而反过来就不行。
模拟函数具体实现步骤
1、第一步给模拟函数起名
在模拟函数之前我们要先给我们的函数起个名字,就叫my_memmove
然后把目标空间地址、要拷贝内容空间地址、字节数传入进去
2、第二步写模拟函数主体
这一步我们要模仿着memmove函数原型,来写我们的模拟函数
3、实现具体功能
具体功能我分为两种,一种是从前往后拷贝,另一种是从后往前拷贝
从前往后拷贝比较简单
我们可以直接用模拟实现memcpy函数中的代码
while (count--) { *(char*)dest = *(char*)src; dest = (char*)dest + 1; src = (char*)src + 1; }
然后是从后往前拷贝
我们如何分别找到dest和src所指向空间的末尾呢?
如下图,我们如果把dest所指向空间的起始位置设为0的话,那么下图的末尾就是dest+15,而总字节长度为16,所以我们也可以把dest或src加上(count-1)就能指向各自的末尾了。
加入count为20个字节,那在while循环中先判断count是否大于0,大于就count--进入循环体,所以就循环count次 。
while (count--) { *((char*)dest + count) = *((char*)src + count); }
两种拷贝实现完后加上if条件判断,当src小于dest时,从后往前拷贝,当src大于dest时从前往后拷贝。
同时我们也不要忘了,要拷贝一下目标地址的起始位置,因为函数要返回目标空间起始地址
void* my_memmove(void* dest, const void* src, size_t count) { char* ret = (char*)dest; if (dest < src) { while (count--) { //从先向后 *(char*)dest = *(char*)src; dest = (char*)dest + 1; src = (char*)src + 1; } } else { //从后向前 while (count--) { *((char*)dest + count) = *((char*)src + count); } } return ret; }
最后为了函数的健壮性,避免用户传递空指针,我们可以用assert判断一下dest和src的是否为空指针(在使用assert()函数时,别忘了引用头文件#include<assert.h>)
assert(dest && src);
代码实现
#include<stdio.h> #include<assert.h> void* my_memmove(void* dest, const void* src, size_t count) { assert(dest && src); char* ret = (char*)dest; if (dest < src) { while (count--) { //从先向后 *(char*)dest = *(char*)src; dest = (char*)dest + 1; src = (char*)src + 1; } } else { //从后向前 while (count--) { *((char*)dest + count) = *((char*)src + count); } } return ret; } int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 }; int arr2[10] = { 1,2,3,4,5,6,7,8,9,10 }; //dest>src情况 my_memmove(arr1 + 3, arr1, 16); //dest<src情况 my_memmove(arr2 + 3, arr2 + 5, 16); return 0; }