今天跟大家分享两个内存操作函数的底层逻辑和模拟实现:
由于strcpy(字符拷贝函数)只能拷贝字符的局限性,我们需要运用memcpy(内存拷贝函数)来实现更多数据类型的拷贝,memmove也是同理。
对于函数原型的研究,我们通常参考cplusplus网站(推荐使用右上角旧版)cplusplus.comhttps://cplusplus.com/
首先是memcpy和memmove的原型:
void * memcpy ( void * destination, const void * source, size_t num );
void * memmove ( void * destination, const void * source, size_t num );
通过原型,我们可以看出对于未确定的数据类型,我们选择用void*类型的指针进行接收 并返回,这是mem类型函数的最基本原理(类似情况同理)。接下来用例子分析:
int arr1[20] = { 0 };
int arr2[20] = { 1,2,3,4,5,6,7,8,9 ,0};
我们需要将arr2中的(int)整型数据(拷贝多少看具体需求)拷贝到arr1当中,具体操作:
void* my_memcpy(void* dest,const void* src,size_t num)
{
assert(dest && src);//断言操作,确保程序健壮性(可参考cplusplus)
while (num--)
{
*(char*)dest = *(char*)src;dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
代码中有一个关键点--强制类型转换为char*类型,因为不确定我们具体要操作的数据类型是什么,所以我们只能一个字节一个字节地进行拷贝,那为什么不能是in类型或者其他类型呢?因为只有1个字节是最基础的,所有的数据类型都可以用char*(1个字节)的倍数来表示。剩下的就是最基本的数据传参,将arr2中的数据传入arr1中。
memmove可以看作是memcpy的一种特殊情况,
int arr1[20] = { 0 };
int arr2[20] = { 1,2,3,4,5,6,7,8,9 ,0};
memmove是发生在同一块空间的拷贝,也就是自己对自己的拷贝,如图:
我们需要将3,4,5,6,7拷贝进1,2,3,4,5中,如果从后往前拷贝,也就是7->5,6->4时,出现了内存的重叠,这就是memcpy和memmove的区别所在 。但是dest(目标地址)和src(传入地址)一定是如上图的先后顺序吗?所以我们需要对dest和src的地址先后进行讨论:
void* my_memmove(void* dest, const void* src, size_t sz)
{
if (dest < src)
{
//前->后
while (sz--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
//后->前
while (sz--)
{
*((char*)dest + sz) = *((char*)src + sz);
}
}
}
代码中有两个关键点--sz(拷贝字节数)和前后讨论
从前向后时,像memcpy一样依次拷贝;
从后向前时,
由于是一个字节一个字节从后向前拷贝,所以是从src+sz(个字节)开始向前拷贝。可以自己画图试试。
以上就是本期分享,
如有错误,敬请指正,谢谢大家!