模拟实现memmove函数(主要解决重叠拷贝问题)

简介: 本篇博客是基于模拟实现memcpy库函数这篇文章写的在本文开始之前,希望大家能读一下memmove函数跟memcpy函数功能大致相同,所以我们在实现memmove函数时可以用模拟memcpy函数代码进行改进

本篇博客是基于模拟实现memcpy库函数这篇文章写的

在本文开始之前,希望大家能读一下

memmove函数跟memcpy函数功能大致相同,所以我们在实现memmove函数时可以用模拟memcpy函数代码进行改进

分析并解决问题

本文主要实现的细节就是如何解决目标地址和拷贝内容的地址重叠拷贝的问题

下面我们分两个方面解决这个问题

1、当src<dest时


当我们的拷贝内容地址小于目标地址时,该如何拷贝呢?


如果是从低地址向高地址拷贝,那当“4”就会被拷贝为“1”,所以低地址向高地址拷贝这种方法行不通。


而从高地址向低地址拷贝时,“4”拷贝给“7”、“3”拷贝给“6”、“2”拷贝给“5”、“1”拷贝给“4”,这样就“4”就可以在改变之前把值拷贝给“7”。


所以当src<dest时,选从高地址向低地址拷贝

a1a0495678adffebd6e3ba460c21a727_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aiB5aiB5rKB5rKB,size_20,color_FFFFFF,t_70,g_se,x_16.png

2、当src>dest时

当我们的拷贝内容地址小于目标地址时,我们可以直接从低地址向高地址拷贝,而反过来就不行。

fb17014d8376f5df02f8f892ebf06f4e_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aiB5aiB5rKB5rKB,size_20,color_FFFFFF,t_70,g_se,x_16.png


模拟函数具体实现步骤  

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)就能指向各自的末尾了。

4b459b7da0d855f1e4c24fde944b0912_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aiB5aiB5rKB5rKB,size_20,color_FFFFFF,t_70,g_se,x_16.png


加入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;
}

76a2643be370267ae1a9c173141cf5ce_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aiB5aiB5rKB5rKB,size_20,color_FFFFFF,t_70,g_se,x_16.png

相关文章
|
8月前
|
安全 C++
内存函数 memcpy 和 memmove 的讲解和模拟实现
内存函数 memcpy 和 memmove 的讲解和模拟实现
37 0
|
1月前
|
存储 前端开发 编译器
【C语言】memmove()函数(拷贝重叠内存块函数详解)
【C语言】memmove()函数(拷贝重叠内存块函数详解)
48 1
|
1月前
|
编译器 C++
memmove函数和memcpy函数的模拟实现
memmove函数和memcpy函数的模拟实现
13 1
|
8月前
|
存储 安全
memcpy和memmove函数的介绍和模拟实现
memcpy和memmove函数的介绍和模拟实现
|
10月前
模拟实现库函数memcpy--复制内存块。详细理解内存重叠及精准复制问题
模拟实现库函数memcpy--复制内存块。详细理解内存重叠及精准复制问题
|
10月前
|
SoC
模拟实现库函数strcpy,对strcpy的进一步理解(深刻理解重叠问题,防止内存与源重叠)
模拟实现库函数strcpy,对strcpy的进一步理解(深刻理解重叠问题,防止内存与源重叠)
|
10月前
|
SoC
模拟实现库函数strcat--将源字符串的副本追加到目标字符串(理解内存重叠问题)
模拟实现库函数strcat--将源字符串的副本追加到目标字符串(理解内存重叠问题)
|
11月前
|
程序员
拷贝函数的优化
拷贝函数的优化
45 0
|
编译器 C语言
C语言之函数栈帧的创建与销毁讲解(1)(一)
C语言之函数栈帧的创建与销毁讲解(1)