memmove函数和memcpy函数的模拟实现

简介: memmove函数和memcpy函数的模拟实现

首先我们来了解memmove函数和memcpy函数的使用

memmove函数

他的函数所需参数如下

1.函数memcpy从source的位置开始向后复制num个字节的数据destination 指向的内存位置。

2.这个函数在遇到 ‘\0’ 的时候并不会停下来。

3.如果source和destination有任何的重叠,复制的结果都是未定义的

void * memcpy ( void * destination, const void * source, size_t num );

我们要注意,这里的num是以字节为单位的,而不是元素个数,并且由于这里我们不知道memmove所移动的内容是什么数据类型,所以移动的目的和源头都用void来定义,由于memmove函数还需有返回目的的起始地址,所以函数类型定义为void**。

下面我们就可以对memmove函数进行模拟实现

我们定义此模拟实现函数为my_memmove

我们定义数组

arr[]={1,2,3,4,5,6,7}

我们想要将数组中数字3,4,5放入1,2,3的位置中,也就是说src中的内容从前向后移动到det中,反之,如果采用从后向前将不会达到我们想要的下图的数组,移动后的数组内容如下图所示

我们将数组移动的内容进行分析,此时det在src的前面,我们可以先将数字3放入arr[0],然后一次放入4,5

下面来看另外一种情况,就是如果det在src的后面呢,该如何移动呢

这个时候我们就会发现从前向后的方法并不适用与这种情况了,我们可以采用从后向前的方式,若依旧采用从前向后的方式的话,会是这种效果

这个时候我们就可以开始构思函数了

由于函数最终需要返回det的起始地址,所以我们定义一个void* ret=det放入函数中,并且采用断言保证不为空指针

void my_memmove(void* det, void* src, size_t size)
{ 
        assert(det && src);
        void* ret = det;
}

接下来分析当det在src前面是的移动方式

由于不知道数据的类型,并且size的单位是字节,但是当数据的类型是int的时候,循环进行是该如何移动呢,我们就可以将det的指针类型强制转化为char*指针,就可以进行字节“++”操作了

if (det < src)//从前往后移动
  {
    int i = 0;
    for (i = 0; i < size; i++)
    {
      *(char*)det = *(char*)src;//强制类型转换
      arr1 = (char*)det + 1;
      arr2 = (char*)src + 1;
    }

反之,我们就写出det在src之后的部分

while (size--)
    {
      *((char*)det + size) = *((char*)src + size);
    }

到这里,memmove的模拟实现就完成了,我们还要记得返回ret,也就是det的起始地址

完整函数代码如下

void my_memmove(void* det, void* src, size_t size)
{
  assert(det && src);
  void* ret = det;
  if (det < src)//从前往后移动
  {
    int i = 0;
    for (i = 0; i < size; i++)
    {
      *(char*)det = *(char*)src;
      arr1 = (char*)det + 1;
      arr2 = (char*)src + 1;
    }
  } 
  else
  {
    while (size--)
    {
      *((char*)det + size) = *((char*)src + size);
    }
  }
  return ret;
}

memcpy函数

相对于memmove函数,memcpy的功能就没有怎么完整了,memmove和memcpy的差别就是memmove函数处理的源内存块和⽬标内存块是可以重叠的,所以,如果源空间和⽬标空间出现重叠,就得使⽤memmove函数处理。但是,有一些编译器的memcpy也可以处理重叠的的情况,就比如vs。

memcpy的模拟实现和memmove的差别不大

代码如下

void * memcpy ( void * det, const void * src, size_t size)
{
 void * ret = det;
assert(arr1 && arr2);
 while (size--) {
 *(char *)dst = *(char *)src;
 dst = (char *)dst + 1;
 src = (char *)src + 1;
 }
 return(ret);
}

大家可以发现,memcpy函数的模拟实现就是memmove函数模拟实现的一部分,就是只采用了从前向后的方式进行内存更改,所以这里我就不做过多的解释了,大家自行理解。

好了,今天的分享就到这里了!

相关文章
|
前端开发 JavaScript API
Ajax技术的秘密揭秘:异步传输,高效交互
Ajax技术的秘密揭秘:异步传输,高效交互
|
SQL 人工智能 分布式计算
基于阿里云PAI平台搭建知识库检索增强的大模型对话系统
基于原始的阿里云计算平台产技文档,搭建一套基于大模型检索增强答疑机器人。本方案已在阿里云线上多个场景落地,将覆盖阿里云官方答疑群聊、研发答疑机器人、钉钉技术服务助手等。线上工单拦截率提升10+%,答疑采纳率70+%,显著提升答疑效率。
|
10月前
|
Linux UED iOS开发
|
SQL 存储 数据安全/隐私保护
MyBatis-Plus演绎:数据权限控制,优雅至极!
项目使用mybaits-plus,所以在mybaits-plus的基础上增加数据权限的过滤 mybaits-plus自带数据权限支持,但由于系统数据权限相对复杂,通过查看文档发现好像并不适用,且原项目版本低,所以最终还是通过自己的方式实现
1690 1
MyBatis-Plus演绎:数据权限控制,优雅至极!
|
数据库 微服务
GTS事务执行过程
【8月更文挑战第25天】
220 4
|
Linux 网络安全 开发工具
LDAP学习笔记之五:LDAP客户端实现系统帐号验证
LDAP学习笔记之五:LDAP客户端实现系统帐号验证
|
人工智能 数据可视化 算法
实例解读:Python量化分析在投资中的应用
实例解读:Python量化分析在投资中的应用
|
人工智能 监控 算法
计算机在公共卫生领域的应用
计算机在公共卫生领域的应用
|
存储 小程序 Java
基于SpringBoot+Redis的前后端分离外卖项目-苍穹外卖微信小程序端(九)
基于SpringBoot+Redis的前后端分离外卖项目-苍穹外卖微信小程序端(九)
|
Kubernetes 开发者 Docker
Docker工程化发展以及实践讲解
Docker 是一种容器技术,可以让开发者在一个隔离的环境中运行和部署应用程序,从而提高应用程序的可移植性、安全性和效率。但是仅仅使用 Docker 并不能保证应用程序的可靠性、可扩展性和可维护性,为了实现这些目标,Docker 的使用也需要进行一些工程化改造。因此也就有了本文,本文中博主将给大家介绍 Docker 工程化的发展以及实践方式。
139 2