【C语言】memmove()函数(拷贝重叠内存块函数详解)
🦄个人主页:修修修也
🎏所属专栏:C语言
⚙️操作环境:Visual Studio 2022
目录
一.memmove()函数简介
1.函数功能
2.函数参数
1>.void * destination
2>.onst void * source
3>.size_t num
3.函数返回值
4.函数头文件
二.memmove()函数的具体使用
1.使用memmove()函数完成拷贝整型数组数据(目的地与源重叠)
2.使用memmove()函数完成拷贝字符数组数据(目的地与源重叠)
三.模拟实现memmove()函数功能
🎏实现思路
1.函数参数及返回值设定逻辑
📌函数参数:
📌函数返回值:
2.函数功能实现逻辑
1.情况一(两个内存块不重叠)
2.情况二(两个内存块有重叠)
🎏代码编写
🎏运行测试
1.测试my_memmove()函数的逆序拷贝
2.测试my_memmove()函数的顺序拷贝
结语
一.memmove()函数简介
我们先来看一下cplusplus.com - The C++ Resources Network网站上memmove()函数的基本信息:
1.函数功能
可以看到,memmove()函数的功能是:
从源头指向的内存块拷贝固定字节数的数据到目标指向的内存块,并且源头的内存块与目标内存块可以重叠.(最后一点是memmove()与memcpy最大的区别)
2.函数参数
该函数一共有三个参数,分别是:
void * memmove ( void * destination, const void * source, size_t num );
1>.void * destination
第一个参数的类型是无类型指针(void*),它指向拷贝的目的地内存块,它的作用是为函数提供目的地的内存块起始地址,以便函数能够准确地将内容拷贝到我们需要的内存空间.
2>.onst void * source
第二个参数的类型是被const修饰(const修饰的指针,const在*左边表示指针指向的内容不可修改,const在*右边表示指针的指向不可修改)的无类型指针(void*),它指向拷贝数据的来源内存块,它的作用是为函数提供拷贝源头内存块起始地址,以便函数能够准确找到拷贝的源头进行拷贝.
3>.size_t num
第三个参数的类型是size_t(无符号整形),它表示要拷贝数据的字节数,它的作用是告诉函数需要拷贝的字节数是多少,以便函数精准的拷贝该数目字节数空间的内容到目的地.
3.函数返回值
函数的返回值类型是无类型指针(void*),它的作用是在函数运行结束后返回拷贝后的目的地内存块的起始地址.
4.函数头文件
该函数包含在头文件<string.h>中.
二.memmove()函数的具体使用
memmove()函数的使用场景是:
当我们想拷贝一个整型数组/结构体/枚举常量等strcpy()函数无法拷贝的数据,并且目的地内存块和源头内存块可能会有重叠的时候,我们可以考虑使用memmove()函数来完实现这一诉求,当然,想要使用memmove()函数拷贝字符串数据或者拷贝目的地内存块和源头内存块不重叠也是可以的.(但是会有些杀鸡用牛刀的感觉哈哈哈)
下面是拷贝时源内存块与目标内存块重叠的情况示意图:
1.使用memmove()函数完成拷贝整型数组数据(目的地与源重叠)
因为拷贝目的地内存块与源内存块不重叠的情况我们已经在memcpy()函数部分详细展示过了,因此在memmove()函数部分我们将着重展示它的内存块重叠时的使用情况.
如下,我们使用memmove()函数将arr数组中的1,2,3,4,5拷贝到3,4,5,6,7的位置上去:
分别给memmove()函数传入三个参数:
拷贝目的地地址(即arr+2),拷贝来源地址(即arr),拷贝字节数(即sizeof(arr[0])*5).
/* memmove 使用测试 */
#include <stdio.h>
#include <string.h>int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };memmove(arr+2, arr, sizeof(arr[0])*5); //sizeof(arr[0])计算的结果是arr数组中一个元素的字节大小,乘5代表5个for (int i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}
在vs编译器中运行查看结果:
可以看到memmove()函数成功的将arr数组中的1,2,3,4,5拷贝到了3,4,5,6,7的位置上.
2.使用memmove()函数完成拷贝字符数组数据(目的地与源重叠)
如下,我们使用memmove()函数将str数组的" very useful"拷贝到" useful......"的位置上去:
分别给memmove()函数传入三个参数:
拷贝目的地地址(即str+20),拷贝来源地址(即str+15),拷贝字节数(即11).
/* memmove 使用测试 */
#include <stdio.h>
#include <string.h>int main()
{char str[] = "memmove can be very useful......";memmove(str + 20, str + 15, 11);//使用memmove()函数拷贝内存块重叠字符串printf("%s\n", str);return 0;
}
在vs编译器中运行查看结果:
可以看到memmove()函数成功的将str数组的" very useful"拷贝到了" useful......"的位置上.
三.模拟实现memmove()函数功能
🎏实现思路
1.函数参数及返回值设定逻辑
📌函数参数:
void * destination
因为memmove()函数要实现的是内存空间的拷贝,所以在使用memmove()函数时我们难免会遇到拷贝不同类型数据的可能,因此在这里我们需要将目的地的地址类型设置为无类型指针(void*),以便函数后续可以处理任意类型的数据.
const void * source
将来源地址的类型设置为无类型指针(void*)的原因与目的地的原因相同,都是便于函数可以处理任意类型的数据.
而给来源的地址指针加上const的原因是防止拷贝的过程中将来源的内容不慎修改,在*指针左侧加上const就可以使const修饰的指针指向的内容变成常量.
size_t num
因为要拷贝的字节数恒为非负数,因此字节数的类型是无符号整形(size_t).
📌函数返回值:
void*
函数返回值设置为void*的原因同目的地及来源地相同,都是便于函数可以在处理完任意类型的数据后可以返回目的地的地址.
2.函数功能实现逻辑
在讲实现逻辑之前,我们先分情况讨论一下在拷贝数据时,我们可能遇到的几种情况:
注:以下演示中,*src指针指向源头起始内存块,*dest指针指向目标起始内存块.
1.情况一(两个内存块不重叠)
这种情况下内存空间的拷贝逻辑是较为简单的,不论是数据从前向后拷贝还是从后向前拷贝,结果都是正确的.
例如这种情况:
或是这种情况:
2.情况二(两个内存块有重叠)
这种情况就比较复杂了,同样分两种情况,如图:
当源头指针在前时,只能从源头内存块的后端向前端移动拷贝:
拷贝逻辑示意图(序号代表拷贝次序):
当目的地指针在前时,只能从源头内存块的前端向后端移动拷贝:
拷贝逻辑示意图(序号代表拷贝次序):
分析清楚上面四种不同的情况,我们就可以在代码的编写中对不同情况进行分情况讨论了.
当然这里的分情况是十分灵活的,你可以四种情况各分一种,也可以按拷贝模式来分,从前向后拷的算一种,从后向前拷的算另一种.
除了两个必须按固定方式拷贝的情况之外,剩下两种情况无论按哪种方式拷贝都行.
那么我们在这里就选择一种最简单也最容易理解的方式来模拟实现memmove()函数吧.
即如果源头指针在前(小),从后向前拷贝;目的地指针在前(小),从前向后拷贝
数据在内存中的存储示意图:
🎏代码编写
清楚了不同情况的拷贝逻辑后,代码的编写就只需要按上面说的分两种情况就好了,以及,函数在实现时的其他需要注意的点我都标注在注释中了.
综上,my_memmove()函数的完整实现代码如下:
//模拟实现my_memmove()函数void* my_memmove(void* destination, const void* source, size_t num)
{assert(destination); //防止源头或目的地指针为NULLassert(source);void* ret = destination;if (source < destination) //内存中数据的存储是由低地址到高地址的{//从后向前拷贝while (num--) //以num为20为例,在num进入while循环之后,就立刻--,变成19了{*((char*)destination + num ) = *((char*)source + num );//这时source+num刚好指向的是源头内存块的最后一个字节}}else{while (num--){//从前向后拷贝*((char*)destination) = *((char*)source);++((char*)destination); ++((char*)source);//这里使用后置++的话一定要给(char*)destination整体带上括号//否则后置++的优先级比(char*)的强制类型转换的优先级高,//导致指针类型还是void*时就进行++操作,这是在C标准中是不允许的}}return ret;
}
🎏运行测试
1.测试my_memmove()函数的逆序拷贝
如下,我们使用my_memmove()函数将arr数组的1,2,3,4,5拷贝到3,4,5,6,7的位置上去:
即按照前面提到的这种情况进行拷贝:
vs2022测试运行结果:
可以看到my_memmove()函数成功的将arr数组中的1,2,3,4,5拷贝到了3,4,5,6,7的位置上.
2.测试my_memmove()函数的顺序拷贝
如下,我们使用my_memmove()函数将arr数组的3,4,5,6,7拷贝到1,2,3,4,5的位置上去:
即按照前面提到的这种情况拷贝:
vs2022中测试运行结果:
可以看到my_memmove()函数成功的将arr数组中的3,4,5,6,7拷贝到了1,2,3,4,5的位置上.
结语
希望这篇memmove()函数的介绍到能对大家有所帮助,欢迎大佬们留言或私信与我交流.
最后的最后,感谢这位大佬指出了我在memcpy()函数阶段模拟实现的不足,因为和他的交流,才促成了这篇博客的产生:
学海漫浩浩,我亦苦作舟!关注我,大家一起学习,一起进步!
相关文章推荐
【C语言】memcpy()函数
【C语言】memset()函数
【C语言】strcpy()函数
【C语言】strlen()函数
【C语言】rand()函数(如何生成指定范围随机数)
【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序
C语言内存相关库函数思维导图:
相关文章:

【C语言】memmove()函数(拷贝重叠内存块函数详解)
🦄个人主页:修修修也 🎏所属专栏:C语言 ⚙️操作环境:Visual Studio 2022 目录 一.memmove()函数简介 1.函数功能 2.函数参数 1>.void * destination 2>.onst void * source 3>.size_t num 3.函数返回值 4.函数头文件 二.memmove()函数…...
04-流媒体-ffmpeg.c源码分析
ffmpeg.c是一个使用ffmpeg库的参考代码,实现了视频格式转换的功能,类似于我们常用的格式工产,源代码的的目录是: ffmpeg-4.2.2/fftools/ffmpeg.c 和前面的ffplay一样,我们分析其源代码,主要只是为了让读者了解ffmpeg.c此文件的大概流程,并且熟悉常用的ffmpeg库的API。 下…...
迭代器 Iterator
迭代器是一种设计模式,它用于遍历集合或容器中的元素,能够访问集合的元素而无需关心集合的内部结构: 特点: 封装集合访问:迭代器封装了对集合元素的访问,通过迭代器访问集合中的元素,而无需了…...

掌握CSS Flexbox,打造完美响应式布局,适配各种设备!
🎬 江城开朗的豌豆:个人主页 🔥 个人专栏 :《 VUE 》 《 javaScript 》 📝 个人网站 :《 江城开朗的豌豆🫛 》 ⛺️ 生活的理想,就是为了理想的生活 ! 目录 ⭐ 专栏简介 📘 文章引言 基…...

FlutterUnit 周边 | 收录排序算法可视化
theme: cyanosis 1. FlutterUnit 更新:排序算法可视化 排序算法可视化是用视图层表现出算法执行过程中排序的过程,感谢 编程的平行世界 在 《十几种排序算法的可视化效果,快来看看!👀》》 一文中提供的算法支持。我进行…...

代码随想录Day30 贪心05 LeetCode T435无重叠区间 T763划分字母区间 T56 合并区间
LeetCode T435 无重叠区间 题目链接:435. 无重叠区间 - 力扣(LeetCode) 题目思路: 这题思路和昨天的打气球类似,我们需要按照左区间或者右区间进行排序,然后哦判断第i个区间的左端点和第i-1个区间的右端点的大小关系,,如果大于等于,那么就无需操作,一旦…...

发展高质量存储力,中国高科技力量聚浪成潮
中国信息通信研究院指出,在全球数字化转型与产业变革的浪潮下,算力正在成为改变全球竞争格局的关键力量。而根据最新的《算力基础设施高质量发展行动计划》,算力是集信息计算力、数据存储力和网络运载力于一体的新型生产力。当前,…...

修改svc的LoadBalancer的IP引发的惨案
文章目录 背景修改externalIPs的操作api-server报错日志挽救教训 背景 k8s集群没有接外部负载均衡,部署istio的时候ingressgateway一直pending。 于是手动修改了这个lb svc的externalIP,于是k8s就崩了,如何崩的,且听我还道来。 …...
2520. 统计能整除数字的位数
2520. 统计能整除数字的位数 class Solution {public int countDigits(int num) {int res 0;int o num;while (num > 0) {if (o % (num % 10) 0) {res 1;}num num / 10;}return res;} }...
BeanUtils.copyProperties的用法
常见场景 我们如果有两个具有很多相同属性名的JavaBean对象a和b,想把a中的属性赋值到b,例如 接口中将接收到的前端请求参数XxxReqVo,我们想把这个入参转化为XxxQuery对象作为数据库的查询条件对象 传统做法是手动set,即 XxxQuery xxxQuer…...

【RabbitMQ 实战】12 镜像队列
一、镜像队列的概念 RabbitMQ的镜像队列是将消息副本存储在一组节点上,以提高可用性和可靠性。镜像队列将队列中的消息复制到一个或多个其他节点上,并使这些节点上的队列保持同步。当一个节点失败时,其他节点上的队列不受影响,因…...

PyCharm社区版安装
PyCharm社区版安装 到中国官网下载 https://www.jetbrains.com/zh-cn/pycharm/download/?sectionwindows 首次创建项目,会自动下载安装Python 3.9 社区版的区别 社区版的区别...

【LeetCode每日一题合集】2023.10.16-2023.10.22(只出现一次的数字Ⅲ)
文章目录 260. 只出现一次的数字 III⭐(异或)🐂2652. 倍数求和解法1——枚举模拟解法2—— O ( 1 ) O(1) O(1)容斥原理相似题目——1201. 丑数 III(二分查找容斥原理) 2530. 执行 K 次操作后的最大分数解法1——贪心优…...

尚硅谷大数据项目《在线教育之实时数仓》笔记003
视频地址:尚硅谷大数据项目《在线教育之实时数仓》_哔哩哔哩_bilibili 目录 第7章 数仓开发之ODS层 P015 第8章 数仓开发之DIM层 P016 P017 P018 P019 01、node001节点Linux命令 02、KafkaUtil.java 03、DimSinkApp.java P020 P021 P022 P023 第7章 数…...

【Linux】部署单体项目以及前后端分离项目(项目部署)
一、简介 以下就是Linux部署单机项目和前后端分离项目的优缺点,希望对你有所帮助。 1、Linux部署单机项目: 优点: 1.简化了系统管理:由于所有服务都在同一台机器上运行,因此可以简化系统管理和维护。 2.提高了性能&a…...

设计模式之门面模式
前言 什么是门面模式 门面模式是一种结构型设计模式,它提供了一个统一的接口,用来访问子系统中的一群接口。它定义了一个高层接口,让子系统更容易使用。这种模式常用于将一个复杂的子系统封装成一个简单的接口,使得客户端可以方…...

Postman的使用
Postman的使用 Postman断言Postman常用断言1、断言响应状态码2、断言包含某个字符串3、断言JSON数据4、Postman断言工作原理 Postman关联Postman自动关联创建环境 3、Postman参数化CSV文件JSON文件1、用例集的导入导出2、环境导出 Postman断言 让Postman工具代替人自动判断预期…...

QGIS008:QGIS拓扑检查、修改及验证
摘要:本文介绍使用QGIS拓扑检查器和几何图形检查器检查图层的拓扑错误,修改拓扑错误,并对修改后的图层进行错误验证。 实验数据: 链接:https://pan.baidu.com/s/1Vy2s-KYS-XJevqHNdavv9A?pwdf06o 提取码:…...
安装DBD-Oracle报错处理
cd DBD-Oracle-1.83 perl Makefile.PL make && make install make编译报错如下: /bin/ld: 找不到 -lnsl collect2: 错误:ld 返回 1 make: *** [Makefile:524:blib/arch/auto/DBD/Oracle/Oracle.so] 错误 1 [rootlocalhost DBD-Ora…...
【机器学习】KNN算法-鸢尾花种类预测
KNN算法-鸢尾花种类预测 文章目录 KNN算法-鸢尾花种类预测1. 数据集介绍2. KNN优缺点: K最近邻(K-Nearest Neighbors,KNN)算法是一种用于模式识别和分类的简单但强大的机器学习算法。它的工作原理非常直观:给定一个新数…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...

label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...

MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...

Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...