首页 > 系统相关 >内存重叠以及memcpy和memmove函数详解

内存重叠以及memcpy和memmove函数详解

时间:2024-08-07 15:54:43浏览次数:17  
标签:src memmove dest 地址 详解 内存 拷贝 memcpy

内存重叠

当我们进行内存拷贝(memcpy函数)时或者在自己实现内存拷贝函数strcpy时,如果存在目标地址在原地址的范围内就造成了内存重叠。一开始看到这个名词的时候,确实有点难以理解,经过学习,我利用以下的例子来说明内存重叠问题。

首先,先介绍一下memcpy和memmove函数

memcpy和memmove函数

void *memcpy( void *dest, const void *src, size_t count );
void *memmove( void* dest, const void* src, size_t count );
  • memcpy和memmove函数都是用于从src拷贝count个字节到dest。
  • 但是,如果目标区域和源区域有重叠的话: memcpy不能够确保源串所在重叠区域在拷贝之前被覆盖,并且memcpy会出现错误。memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,复制后src内容会被更改, 当目标区域与源区域没有重叠则和memcpy函数功能相同。

memmove的处理措施:

(1)当源内存的首地址等于目标内存的首地址时,不进行任何拷贝。
(2)当源内存的首地址大于目标内存的首地址时,实行正向拷贝。
(3)当源内存的首地址小于目标内存的首地址时,实行反向拷贝。

接下来,借助于memcpy函数来说明内存重叠

memcpy(void *dest, void *src, size_t num)是将src指向的地址中的num个字节拷贝到dest目标地址中。假设我们需要拷贝六个字节到dest内存地址中,根据dest和src的关系,内存拷贝可以分为以下三类:

情况一:

目标地址与源地址没有任何重叠,即dest 地址> src地址 + 6或者dest 地址< src地址 - 6:
在这里插入图片描述
在这里插入图片描述

  • 这时,不会造成内存重叠,直接从左到右进行拷贝即可

情况二:

src地址 - 6< dest 地址< src地址:
在这里插入图片描述
这时即使会覆盖掉src的部分内存,但是并不会造成内存重叠。

情况三:

目标地址dest位于原地址的内存范围之内,即src 地址< dest 地址< src地址 + 6,这时进行内存拷贝,情况如下:
在这里插入图片描述
此时如果对src进行从左到右的内存拷贝,当该拷贝4的时候,此时原先src部分4的内存已经被1给覆盖掉了,就产生了拷贝错误。

解决:

  • 如果存在内存重叠,就从高地址进行拷贝
  • 自己实现的memcpy如下:
char *my_memcpy(char *dst, const char* src, int cnt)
{
	 assert(dst != NULL && src != NULL);
	 char *ret = dst;
	 /*内存᯿叠,从⾼地址开始复制*/
	 if (dst >= src && dst <= src+cnt-1)
	 {
		 dst = dst+cnt-1;
		 src = src+cnt-1;
		 while (cnt--)
		 {
			 *dst-- = *src--;
		 }
	 } 
	 else //正常情况,从低地址开始复制
	 {
		  while (cnt--)
		 {
			 *dst++ = *src++;
		 }
     }
	 return ret;
}

标签:src,memmove,dest,地址,详解,内存,拷贝,memcpy
From: https://blog.csdn.net/m0_73537205/article/details/140374579

相关文章

  • C语言 操作符详解
    目录一、操作符的分类二、二进制和进制转换 2.1二进制转十进制 2.2二进制转八进制 2.3二进制转十六进制 三、原码、反码、补码四、移位操作符4.1左移操作符​编辑 4.2右移操作符五、位操作符按位与:&按位或:|按位异或:^按位取反:~六、逗号表达式七、操作......
  • 超详细明了的C语言函数递归,望周知。(包含求n的阶乘顺序打印⼀个整数的每⼀位求第n个斐
    1.递归是什么?递归是学习C语⾔函数绕不开的⼀个话题,那什么是递归呢?递归其实是⼀种解决问题的⽅法,在C语⾔中,递归就是函数⾃⼰调⽤⾃⼰。写⼀个史上最简单的C语⾔递归代码#include<stdio.h>intmain(){printf......
  • 神经网络之卷积篇:详解边缘检测示例(Edge detection example)
    详解边缘检测示例卷积运算是卷积神经网络最基本的组成部分,使用边缘检测作为入门样例。在这个博客中,会看到卷积是如何进行运算的。在之前的博客中,说过神经网络的前几层是如何检测边缘的,然后,后面的层有可能检测到物体的部分区域,更靠后的一些层可能检测到完整的物体,这个例子中就是......
  • 4、Flink SQL 与 DataStream API 集成处理 Insert-Only 流详解
    处理Insert-Only流StreamTableEnvironment提供以下方法来从DataStream转换和转换到DataStream:fromDataStream(DataStream):将insert-only和任意类型的流转换为表,默认情况下不传播事件时间和水印。fromDataStream(DataStream,Schema):将insert-only和任意类型......
  • 深入解析:23种软件设计模式详解及其分类(创建型、结构型、行为型)附代码示例DEMO
    目录引言一、创建型模式1.简单工厂模式(SimpleFactoryPattern)2.抽象工厂模式(AbstractFactoryPattern)3.单例模式(SingletonPattern)4.建造者模式(BuilderPattern)5.原型模式(PrototypePattern)二、结构型模式1.适配器模式(AdapterPattern)2.桥接模式(BridgePatt......
  • HTTP报文:“请求报文“和“响应报文“详解
    在网络通信的世界里,HTTP协议扮演着至关重要的角色。它是客户端与服务器之间对话的语言,允许数据的请求和响应。本文将深入探讨HTTP报文的两个核心组成部分:请求报文和响应报文,揭示它们如何共同构建了网络通信的基础。......
  • 24-08-04 JavaSE java集合详解
    24-08-04JavaSE集合详解文章目录24-08-04JavaSE集合详解理解集合java集合的体系框架Collection类Collection接口的常用方法集合的遍历iterator迭代器增强for循环List类List类的常用方法List的三种遍历方法List的排序ArrayList类ArrayList类的注意事项Arraylist的......
  • C语言——一维二维数组详解
    文章目录数组数组的概念一维数组的创建和初始化数组创建数组的初始化数组的类型一维数组的使用数组下标数组元素的打印数组的输入sizeof计算数组元素个数一维数组在内存中的存储二维数组的创建二维数组的概念二维数组的创建二维数组的初始化不完全初始化完全初始化按......
  • JavaWeb中的Tomcat,Servlet详解
    JavaWebJavaWeb技术主要包括服务器技术(后端),如Tomcat,Servlet,JSP等待,以及客户端技术(前端)如HTML,CSS,JavaScript等等Web服务器Web服务器主要负责处理客户端发出的HTTP请求,并做出相应回应Web服务器:安装了服务器软件的计算机,只用于复杂处理请求,发出相应Web服务器......
  • 【Material-UI】按钮组件中的实验性API:Loading按钮详解
    文章目录一、LoadingButton组件概述1.组件介绍2.基本用法二、LoadingButton组件的高级用法1.自定义加载指示器2.图标与加载位置三、已知问题与解决方法1.Chrome翻译工具与LoadingButton的兼容性问题四、实用性与未来展望1.应用场景2.未来展望五、总结......