内存函数(C语言)

内存函数

以下函数的头文件:string.h

  • 针对内存块进行处理的函数

memcpy

函数原型:

void* memcpy(void* destination, const void* source, size_t num);目标空间地址                源空间地址
  • num,被拷贝的字节个数

  • 返回目标空间的起始地址

  • 从source函数向后拷贝num字节个数据到目标空间

  • 目标空间地址和源空间地址有重叠部分,有重叠内存的拷贝,结果是未定义的

  • C语言标准规定:memcpy可以不负责有重叠内存的拷贝

    • 而vs编译器的库函数也可以实现重叠内存的拷贝。
#include <stdio.h>
#include <string.h>
int main()
{int arr1[20] = { 1, 2, 3, 4, 5, 6 };int arr2[20] = { 0 };memcpy(arr2, arr1, sizeof(int) * 5);for (int i = 0; i < 5; i++){printf("%d ", arr2[i]);}return 0;
}

在这里插入图片描述

通过函数原型也发现,这个memcpy函数是一个函数参数,函数返回类型都是void无符号类型,这是说明该函数是一个,泛型函数,它可以接收任意类型的参数,使同一个函数能用于多种类型的数据

该用例说明了,将数组arr1从第一个元素开始的20个字节拷贝到arr2中。

模拟memcpy函数

void* my_memcpy(void* dest, const void* src, size_t num)
{void* ret = dest;assert(dest && src);while(num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}return ret;
}

该函数是泛型函数,在返回类型和参数上要保持一致,后面的size_t num参数用来接收拷贝的字节个数。

能够进行任意数据类型的拷贝,这里只能将源空间一个一个字节拷贝到目标空间里,而void类型不是4个字节,所以将,dest和src强制类型转换为char类型,这样每循环一次就拷贝一个字节的内容,然后让指针dest和src向后走一个字节。

(char*)dest++;dest = *(char*)dest + 1;的区别:

c/c++里的强制类型转换,是临时的,(char*)dest++;试图将一个 void *类型的dest强制类型转换,然后++,语法是有问题的,对 (char *)dest使用++,实际上是 (char* dest) = dest + 1;,将无符号类型的指针赋给 char *类型的指针编译器会报错的
在这里插入图片描述

最后将目标空间的起始地址返回即可。

使用assert断言是因为,目标空间和源空间都不能为空,否则就是对空指针解引用,加一条assert是代码具有更好的健壮性。

memmove

函数原型:

void* memmove(void* destination, const void* source, size_t num);
  • 负责重叠内存的拷贝
  • 用法与memcpy相同。
  • memmove可以是memcpy的替代,它支持更多的使用场景,重叠内存的拷贝。

模拟memmove函数

俩个函数的功能及其相似,它们在实现上的不同,模拟memcpy函数是,对字节进行拷贝时,是将source里的字节从前向后一个一个拷贝的,如图:

source里一共有12个字节,模拟的memcpy函数将从数字2开始的第一个字节,一个一个拷贝到目标空间里。
在这里插入图片描述

在这里插入图片描述

若两快空间重叠时会发生哪些情况:

  • dest指针大于source指针,目标空间与源空间重叠,但目标空间起始地址小于源空间,此时针对情况一,如上图橘色与蓝色重叠部分
  • dest指针小于source指针,目标空间与源空间重叠,但目标空间起始地址大于源空间,此时针对情况二,如上图绿色与蓝色重叠部分

情况一:

  • 当使用从前向后一个一个字节的拷贝时, 0 被拷贝为 2,1 被拷贝为 3,2 被拷贝为 4,结果与预期相符和,所以当目标空间与源空间重叠,但目标空间起始地址小于源空间时,采用从前向后一个字节一个字节的拷贝。

在这里插入图片描述

情况二:

  • 对应情况二使用从前向后一次拷贝字节时,将源空间内容拷贝到密目标空间,此时 4 被拷贝为 2 , 5 被拷贝为 3 , 6被拷贝为2。

  • 与预期结果并不相符和,预期拷贝后的结果时 0 1 2 3 2 3 4。

  • 实际结果为,0 1 2 3 2 3 2。

在这里插入图片描述

可以发现,使用从前向后一起拷贝字节时,源空间的内容覆盖掉,它还没有拷贝就已经被覆盖了,并将其放置在目标空间的最后一个位置。解决这种办法也很好理解,既然从前向后拷贝不行,那我们从后向前拷贝不久可以了。这样就避免了,还没有将源空间的数据拷贝到目标空间就被覆盖的情况。

将source指针和destination指针向后偏移num个字节 (char*)dest + num (char*)src + num,这样它两就指向最后一个字节,从后向前拷贝,每拷贝完一个字节后 num–

在这里插入图片描述

void* my_memmove(void* dest, const void* src, size_t num)
{void* ret = dest;assert(dest && src);if(dest > src)//后向前{while(num--){*((char*)dest + num) = *((char*)src + num);}}else{while(num--){*(char*)dest = *(char*)src;dest = *(char*)dest + 1;src = *(char*)src + 1;}}return ret;
}

当dest > src时,从后向前,第一步将dest和src偏移到最后一个位置, (char*)dest + num (char*)src + num,然后进行赋值 ,

*((char *)dest ) = *((char *)src );,其代码内讲多块内容合并在一起操作,通过控制num大小,来控制了dest和src偏移的位置,而循环结束的条件的num为0,这样就有了一条很精简的代码。

memset

函数原型:

void* memset(void* ptr, int value, size_t num);被填充空间    改变的内容 设置的字节个数       

memset,是用来设置内存的,将内存以字节为单位,

  • 将每个字节设置为 value的内容

很朴素的用法,没有过多的变化,但结果往往会让人出乎意料~。

int main()
{int arr1[20] = { 1, 2, 3, 4, 5, 6 };int arr2[20] = { 0 };memset(arr2, 9, 5);memset(arr1, 8, 5);for (int i = 0; i < 6; i++){printf("%d ", arr1[i]);}printf("\n");for (int i = 0; i < 5; i++){printf("%d ", arr2[i]);}return 0;
}

这不是一个使用的案例,通过运行代码能够发现数组arr1和arr2的结果相当的大,这是因为memset是在字节上设置内容,这里的第一条memset语句,将数组arr2里的五个字节内容,都放置了一个数字9,而内存里的 09 09 09 09实际上是16进制数,0x09090909,所以在打印的结果上会很大。

数字arr1的结果,同数组arr2一样,即使在传递的数组这块内容已经放的有值,memset还会将其覆盖。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

这里以字符串为例,字符串的大小是一个字节,这里我试图将字符数组arr1里的前三个字节内容置为x。

int main()
{char arr1[10] = "abcdef";memset(arr1, 'x', 3);return 0;
}

在这里插入图片描述

观察结果,memset函数指哪打哪~,也没有在最后一个x后多余的放置 '\0'

memcmp

函数原型:

int memcmp(const void* ptr1, const void* ptr2, size_t num);

比较字节大小:

  • ptr1 > ptr2 返回大于0
  • ptr1 < ptr2 返回小于0
  • 等于返回 0
  • num是指比较字节个数

memcmp函数与字符串函数里的strncmp功能很类似,前者是通过比较字节大小,后者是比较字符大小。

int main()
{int arr1[] = { 1, 2, 5 };int arr2[] = { 1, 2, 6 };printf("%d \n", memcmp(arr1, arr2, 8));return 0;
}

arr1前12个字节:

01 00 00 00 02 00 00 00 05 00 00 00

arr2前12个字节

01 00 00 00 02 00 00 00 06 00 00 00

试图比较前8个字节的大小时,返回的结果是0,每个字节上的内容都是相等的,而 memcmp(arr1, arr2, 9);,比较前9个字节大小时,将返回小于0的数字, 06 > 05 。

cmp(arr1, arr2, 8));
return 0;
}
arr1前12个字节:

01 00 00 00 02 00 00 00 05 00 00 00

arr2前12个字节

01 00 00 00 02 00 00 00 06 00 00 00

试图比较前8个字节的大小时,返回的结果是0,每个字节上的内容都是相等的,而 memcmp(arr1, arr2, 9);,比较前9个字节大小时,将返回小于0的数字, 06 > 05 。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/377384.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在 PostgreSQL 里如何实现数据的实时监控和性能瓶颈的快速定位?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01;&#x1f4da;领书&#xff1a;PostgreSQL 入门到精通.pdf 文章目录 在 PostgreSQL 里如何实现数据的实时监控和性能瓶颈的快速定位一、数据实时监控的重要性二、PostgreSQ…

【C语言初阶】探索编程基础:深入理解分支与循环语句的奥秘

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ ⏩收录专栏⏪&#xff1a;C语言 “ 登神长阶 ” &#x1f921;往期回顾&#x1f921;&#xff1a;C语言入门 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀分支与循环语句 &#x1f4d2;1.…

聚类分析方法(三)

目录 五、聚类的质量评价&#xff08;一&#xff09;簇的数目估计&#xff08;二&#xff09;外部质量评价&#xff08;三&#xff09;内部质量评价 六、离群点挖掘&#xff08;一&#xff09;相关问题概述&#xff08;二&#xff09;基于距离的方法&#xff08;三&#xff09;…

element-plus 按需导入问题 404等问题

场景 新开一个项目&#xff0c;需要用element-plus这个ui库&#xff0c;使用按需引入。 这是我项目的一些版本号 "element-plus": "^2.7.6","vue": "^3.2.13","vue-router": "^4.0.3",过程&#xff08;看解决方法…

Unity发布webgl之后修改StreamingAssets 内的配置文件读取到的还是之前的配置文件的解决方案

问题描述 unity发布webgl之后&#xff0c;修改在StreamingAssets 中的配置信息&#xff0c;修改之后读取的还是之前的配置信息 读取配置文件的代码IEnumerator IE_WebGL_LoadWebSocketServerCopnfig(){var uri new System.Uri(Path.Combine(Application.streamingAssetsPath…

种田游戏扎堆,但玩家还有钱建设家园吗?

2024年暑期档&#xff0c;模拟经营游戏成为细分领域变化最为显著的一环。 6月26日泡泡玛特的《梦想家园》、7月10日《波西亚时光》手游版上线、还有心动跳跃整整研发了10年的《心动小镇》也将于7月17日上线。 事实上&#xff0c;从数量上看&#xff0c;模拟经营游戏并非小众品…

springboot 程序运行一段时间后收不到redis订阅的消息

springboot 程序运行一段时间后收不到redis订阅的消息 问题描述 程序启动后redis.user.two主题正常是可以收到消息的&#xff0c;发一条收一条&#xff0c;但是隔一段时间后&#xff1b;就收不到消息了&#xff1b; 此时如果你手动调用发送另外一个消息订阅redis.user.two2&…

代码随想录第50天|单调栈

739. 每日温度 参考 思路1: 暴力解法 思路2: 单调栈 使用场合: 寻找任一个元素的右边或者左边第一个比自己大或者小的元素位置, 存放的是遍历过的元素 记忆: 单调栈是对遍历过的元素做记录, 一般是对栈顶的元素 nums[mystack.top()] 做赋值操作的 如果想找到右边的元素大于左…

电脑文件误删除如何恢复?Top12电脑数据恢复软件汇总合集!(图文详解)

电脑文件误删除如何恢复&#xff1f;在日常使用电脑过程中&#xff0c;我们经常会遇到意外删除文件的情况。可能是因为按错了按键、误操作了鼠标&#xff0c;或者意外格式化了存储设备。这些情况都可能导致重要的文件不小心被删除。但是不用担心&#xff0c;有许多专业的数据恢…

Jeecgboot vue3的选择部门组件JSelectDept如何实现只查询本级以及子级的部门

jeecgboot vue3的文档&#xff1a;地址 JSelectDept组件实现了弹窗然后选择部门返回的功能&#xff0c;但部门是所有数据&#xff0c;不符合需求&#xff0c;所以在原有代码上稍微改动了一下 组件属性值如下&#xff1a; 当serverTreeDatafalse的时候&#xff0c;从后端查询…

【Git的基本操作】版本回退 | 撤销修改的三种情况 | 删除文件

目录 5.版本回退 5.1选项hard&后悔药 5.2后悔药&commit id 5.3版本回退的原理 6.撤销修改 6.1情况一 6.2情况二 6.3情况三 ​7.删除文件 Git重要能力之一马&#xff0c;版本回退功能。Git是版本控制系统&#xff0c;能够管理文件历史版本。本篇以ReadMe文件为…

Web前端开发

1. 介绍 本文将覆盖Web前端开发的方方面面&#xff0c;包括HTML、CSS、JavaScript三大基础知识&#xff0c;vue3框架以及项目实战&#xff0c;帮助读者从零开始掌握前端开发。 2. Web前端开发基础 2.1 HTML5 2.1.1 什么是HTML5 HTML&#xff08;HyperText Markup Language…

Paddle 打包部署

PaddleOCR 打包部署exe 心酸历程 PaddleOCR部署exe模式PaddleOCR安装到本地(稍后有时间再写)PaddleOCR打包过程异常问题记录&#xff01;&#xff01;&#xff01;&#xff01;No such file or directory: D:\\py_project\\paddleOCR\\dist\\paddleOCR\\_internal\\paddleocr\\…

Spring中的适配器模式和策略模式

1. 适配器模式的应用 1.1适配器模式&#xff08;Adapter Pattern&#xff09;的原始定义是&#xff1a;将一个类的接口转换为客户期望的另一个接口&#xff0c;适配器可以让不兼容的两个类一起协同工作。 1.2 AOP中的适配器模式 在Spring的AOP中&#xff0c;使用Advice&#…

使用Elasticsearch Python SDK 查询Easysearch

随着数据分析需求的不断增长&#xff0c;能够高效地查询和分析大数据集变得越来越重要。Elasticsearch作为一种强大的分布式搜索和分析引擎&#xff0c;被广泛应用于各种场景。Easyearch 支持原生 Elasticsearch 的 DSL 查询语法&#xff0c;确保原业务代码无需调整即可无缝迁移…

记录些MySQL题集(1)

Innodb 是如何实现事务的&#xff1f; InnoDB是MySQL数据库的一个存储引擎&#xff0c;它支持事务处理。事务处理是数据库管理系统执行过程中的一个逻辑单位&#xff0c;由一个或多个SQL语句组成&#xff0c;这些语句要么全部执行&#xff0c;要么全部不执行&#xff0c;是一个…

idea修改全局配置、idea中用aliyun的脚手架,解决配置文件中文乱码

idea修改全局配置 idea中用aliyun的脚手架&#xff0c;创建springBoot项目 解决配置文件中文乱码

C判断一个点在三角形上

背景 鼠标操作时&#xff0c;经常要判断是否命中显示控件&#xff0c;特开发此算法快速判断。 原理 三角形三等分点定理是指在任意三角形ABC中&#xff0c;可以找到三个点D、E和F&#xff0c;使得线段AD、BE和CF均等分三角形ABC。 这意味着三个等分点分别位于三个边界上&…

Maven学习笔记——如何在pom.xml中通过坐标为项目导入jar包

注意&#xff1a;我们只导入了一个jar包坐标&#xff0c;但右边项目中确多出来了好几个jar包&#xff0c;这是因为我们导入的该jar包所依赖其他jar包&#xff0c;maven自动帮我们导入了进来

【网络运维的重要性】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…