【C语言进阶篇】C语言内存函数

目录

1.memcpy函数及其模拟实现

    1.1 memcpy函数的使用

    1.2 memcpy函数的模拟实现

2.memmove函数及其模拟实现

    2.1 memmove函数的使用

    2.2 memmove函数的模拟实现

3.memset函数

4.memcmp函数


1.memcpy函数及其模拟实现
    1.1 memcpy函数的使用

  memcpy函数是用来拷贝内存的函数,其拷贝的方式为一个字节一个字节地拷贝,使用时需要包含 <string.h> 的头文件。上面的 size_t num 参数的作用就是接收我们输入的想要拷贝的字节数;destination的意思是目的地,void* destination 参数是拷贝存放的目的地;source是起源的意思,const void* source就是我们所要拷贝的数据的起始地。两个接收地址的变量用 void* 类型来定义,说明可以接收不同类型的地址。来看看具体使用:

  这里我们将 arr 数组里20个字节的内存拷贝到 arr1 数组中去,因为arr数组的类型为int型,每个元素的大小为4个字节,因此,拷贝20个字节的内容相当于拷贝了 arr 中5个元素进 arr1 中。

  需要注意的是,如果 arr1 数组中本身有元素,在拷贝的时候,拷贝过去的元素会覆盖掉 arr1 中原有的元素:

  操作字符串:

    1.2 memcpy函数的模拟实现

  下面我们来自己动手模拟实现一下memcpy函数:

//模拟实现memcpy函数
void* my_memcpy(void* dest, const void* src, size_t num)
{void* ret = dest;//这一步是为了保存dest最开始指向的地址,因为在后续循环里的操作里,//dest的地址已经跑到后面去了,不指向最开始的地址while (num--)//这里是总共循环的次数,需要拷贝多少个字节就循环多少次{*(char*)dest = *(char*)src;// 因为dest与src都是void*类型,没法直接解引用操作,又因为// memcpy函数是一个字节一个字节拷贝的,因此我们在这进行拷贝操作的时候//将dest与src都强制类型转换为char*类型,这样就可以达到一个字节一个字节拷贝的目的了dest = (char*)dest + 1;src = (char*)src + 1;//这里的操作是在拷贝完一个字节以后,dest与src的地址都+1//去找下一个字节地址,进行下一个字节的拷贝}return ret;
}int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int arr1[10] = { 0 };my_memcpy(arr1, arr, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr1[i]);}return 0;
}
2.memmove函数及其模拟实现
    2.1 memmove函数的使用

  memmove函数的作用和memcpy函数几乎一样,使用时也需要包含<string.h>的头文件但是memcpy函数相比于memmove函数来讲有一个缺陷,下面来看一段代码:

这里我们想要将 arr 数组中 1,2,3,4,5 的数据拷贝到 arr 数组中 3,4,5,6,7 的位置,那么结果按理来说应该最后输出打印的是 1,2,1,2,3,4,5,8,9,10。但实际上跟我们想的一样吗?

没错,想的和我们就是一样的,可能这个时候就有人想说我在水字数了。哎!此言差矣。虽然在这里最后输出的结果和我们设想的是一样的,但是,这仅是在VS编译器环境下一样而已,换做别的编译器,可能最后输出的就是下列结果:

为什么可能输出这个结果呢?我们来画图理解:

那么我们如果想要在一个数组里实现我们想要的效果,该怎么办呢?

  这就需要用到memmove函数了,memmove函数就可以专门用来处理这种拷贝内存与存放内存有重叠的情况:

在VS编译器中,memcpy函数也能够完成memmove的作用,我们不妨大胆猜测,在VS中memcpy函数的实现是和memmove函数一样的。

    2.2 memmove函数的模拟实现

  下面我们来手动模拟实现一下memmove函数。

  在模拟实现memmove函数之前,我们需要搞清楚memmove函数的原理,memmove函数的模拟实现相较于memcpy函数更为复杂,我们来逐个讨论:
 

  如何避免在拷贝内存的时候将后面需要拷贝的内存给改变呢?就像上面所说的改为 1,2,1,2,1,2,1,8,9,10 的情况。这时候我们可以想到,将内存从后往前拷贝不就行了,就像这样:

  ② 

  用从前往后的方法就可以达到我们上面的目的,但是,这里又会出现一个新的问题,如果我需要拷贝的内存在存放的内存后面呢,就像下面这种情况:

  这种情况从前往后存还适用吗?我们画图来探究一下:
  

  显然,这个时候再采用从后往前的方法就不行了。既然从前往后不行,那我们从前往后可行吗?画图探究下:

可以发现,这种情况从前往后拷贝存储是可行的,那么除了这两种情况还有别的情况吗?没有了,需要拷贝的内存拷贝内存目的地重复的情况一共就三种:  ① 需要拷贝的内存拷贝内存目的地前并且两者有重复部分   ② 需要拷贝的内存拷贝内存目的地后并且两者有重复部分  ③ 两者完全重复 。而第三种情况不管怎么拷贝都能达到我们的目的,因此,在模拟实现memmove函数时,我们只需要考虑前两种情况即可。下面来看代码:

  

void* my_memmove(void* dest, const void* src, size_t num)
{if (dest > src)//拷贝内存在拷贝存放的内存的前面,并且有内存叠加{dest = (char*)dest + num - 1;//将dest和src分别指向各自的最后一个字节src = (char*)src + num - 1;while (num--)//将内容一个字节一个字节进行拷贝{*(char*)dest = *(char*)src;dest = (char*)dest - 1;src = (char*)src - 1;}}else{while (num--)//拷贝内存在拷贝存放的内存的后面,并且有内存叠加{*(char*)dest = *(char*)src;//直接从第一个字节拷贝dest = (char*)dest + 1;src = (char*)src + 1;}}
}int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };my_memmove(arr+2, arr, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}
3.memset函数

  memset函数顾名思义就是用来设置内存,将需要设置的内存中的值按照字节来设置成想要的内容,使用时也需要包含<string.h>的头文件

  

这里我们用memset函数将字符串s的前三个字节的内容改为了字符 ' x '。 

4.memcmp函数

memcmp函数是用来比较内存的,用法与strcmp函数十分相似,不同的是,strcmp函数是专门用来比较字符串的函数,而memcmp函数则可以用来比较各种类型。

这里的意思就是:当所比较的两个字符串,前一个大于后一个则返回一个大于0的数,反之则返回小于0的数,相等则返回0

这里我们调用的memcmp的时候,将 与 s1 进行比较,如果 s1 ,则返回一个大于0的数,反之,则返回小于0的数,如果相等,则返回0。这里 的第一个字符是a,而 s1 的第一个字符是b,在第一个字符就判断出了大小,后面也不用判断了,直接返回了小于0的数。

                                                       创作不易,点个赞再走呗,求求啦~😊

               

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

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

相关文章

mysql 索引(为什么选择B+ Tree?)

索引实现原理 索引&#xff1a;排好序的数据结构 优点&#xff1a;降低I/O成本&#xff0c;CPU的资源消耗&#xff08;数据持久化在磁盘中&#xff0c;每次查询都得与磁盘交互&#xff09; 缺点&#xff1a;更新表效率变慢&#xff0c;&#xff08;更新表数据&#xff0c;还要…

数据的响应式:实现动态数据驱动的技巧

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

洛谷P1100 高低位交换

#先看题目 题目描述 给出一个小于 的非负整数。这个数可以用一个 32 位的二进制数表示&#xff08;不足 32 位用 0 补足&#xff09;。我们称这个二进制数的前 16 位为“高位”&#xff0c;后 16 位为“低位”。将它的高低位交换&#xff0c;我们可以得到一个新的数。试问这…

​关于robotframework,app,appium的xpath定位问题及常用方法​

关于类似的帖子好像很多&#xff0c;但是没有找到具体能帮我解决问题的办法。还是自己深究了好久才基本知道app上面的xpath定位和web上的不同点&#xff1a; 先放一个图&#xff1a; A&#xff0c;先说说不用xpath的场景&#xff0c;一般是用于存在id或者name。可能没有看到na…

UI 学习 三 可访问性 UX

设计、交流和实现不同领域内容的易访问性决策&#xff0c;涉及到一系列考虑因素&#xff0c;以达到更容易访问的产品体验。 Material使用的框架借鉴了WCAG标准和行业最佳实践&#xff0c;以帮助任何人预测、计划、记录和实现可访问体验。 下面描述的三个阶段有助于将可视化UI…

Verilog——信号类型

Verilog HDL 的信号类型有很多种&#xff0c;主要包括两种数据类型&#xff1a;线网类型 (net type) 和寄存器类型 &#xff08; reg type &#xff09;。在进行工程设计的过程中也只会使用到这两个类型的信号。 4.1 信号位宽 定义信号类型的同时&#xff0c;必须定义好信号…

使用决策树模型绘制混淆矩阵、ROC曲线、特征变量重要性排序图

大家好&#xff0c;我是带我去滑雪&#xff01; 决策树模型可以处理各种类型的特征&#xff08;连续型、离散型、类别型等&#xff09;&#xff0c;不需要对特征进行过多的预处理工作&#xff0c;因此非常适合初步探索数据。通过绘制混淆矩阵、ROC曲线和特征变量重要性排序图&a…

基于java+springboot+vue实现的高校自习室预约系统(文末源码+Lw+ppt)23-428

摘 要 高校自习室预约系统采用B/S架构&#xff0c;数据库是MySQL。网站的搭建与开发采用了先进的java进行编写&#xff0c;使用了springboot框架。该系统从两个对象&#xff1a;由管理员和学生来对系统进行设计构建。主要功能包括&#xff1a;个人信息修改&#xff0c;对用户…

DNA序列修正——HashMap应用

题目链接&#xff1a;1.DNA序列修正 - 蓝桥云课 (lanqiao.cn) 利用HashMap的特性&#xff0c;将字母匹配转换成数字匹配 A T 0 1 C G 1 2 3 另外&#xff0c;Java中没有交换&#xff08;swap&#xff09;函数&#xff0c;需要自己进行编写。 程序代码&#xff1a; pac…

【电路笔记】-MOSFET作为开关

MOSFET 作为开关 文章目录 MOSFET 作为开关1、概述2、MOSFET特性曲线2.1 截住区域2.2 饱和区域3、MOSFET作为开关的示例4、功率MOSFET电机控制5、P沟道MOSFET作为开关6、互补MOSFET作为开关电机控制器当 MOSFET 在截止区和饱和区之间工作时,MOSFET 是非常好的电子开关,用于控…

mybatis项目中配置sql提示

2023版的idea好像内置了这个功能。 第一步&#xff1a; 第二步&#xff1a;第一步完成后user会爆红&#xff0c;这时我们需要连接数据库。

TypeScript中的 K、T 、V

文章目录 前言泛型类型链接关系K、T、V 含义自动类型推断泛型的应用场景容器类和数据结构函数和方法接口和类类型约束和扩展常用的工具类型 前言 在 TypeScript 的泛型里经常会碰到一些字母&#xff0c;比如 K、T、V&#xff0c;是不是觉得很奇怪&#xff1f; 泛型类型 图中的…

ChatGPT提示词方法的原理

关于提示词&#xff0c;我之前的一些文章可以参考&#xff1a; 【AIGC】AI作图最全提示词prompt集合&#xff08;收藏级&#xff09;https://giszz.blog.csdn.net/article/details/134815245?ydrefereraHR0cHM6Ly9tcC5jc2RuLm5ldC9tcF9ibG9nL21hbmFnZS9hcnRpY2xlP3NwbT0xMDExL…

力扣● 583. 两个字符串的删除操作 ● 72. 编辑距离 ● 编辑距离总结篇

● 583. 两个字符串的删除操作 注意审题&#xff1a; 给定两个单词 word1 和 word2 &#xff0c;返回使得 word1 和 word2 相同所需的最小步数。 每步 可以删除任意一个字符串中的一个字符。 删除最少的字符使两者相同&#xff0c;说明留下来的就是最大公共子序列。不要求…

13 秒插入 30 万条数据,这才是 Java 批量插入正确的姿势!

本文主要讲述通过MyBatis、JDBC等做大数据量数据插入的案例和结果。 30万条数据插入插入数据库验证 实体类、mapper和配置文件定义 User实体 mapper接口 mapper.xml文件 jdbc.properties sqlMapConfig.xml 不分批次直接梭哈 循环逐条插入 MyBatis实现插入30万条数据 J…

代码资源集合

代码资源 通信QPSKOQPSKMSK信道编码GMSK 雷达LFM及干扰技术LFM射频噪声干扰噪声调幅干扰噪声调频干扰噪声调相干扰固定移频干扰间歇采样干扰 SAR成像RD算法CS算法wk算法 SAR干扰技术射频噪声干扰调幅噪声干扰调频噪声干扰调相噪声干扰噪声卷积干扰乘积干扰移频干扰 DOA估计功率…

电学基础知识

目录 电流 前言 电流的产生 电流的单位安培&#xff08;A&#xff09; 电路和电池 开路和闭路 电灯泡原理 对电池容量的理解 毫安时 毫瓦时 直流电和交流电 AC交流电 DC直流电 直流电和交流电对比 电压 对电器的电压和电流的理解 电阻 电压电阻电子的关系 欧…

python--剑指offer--中等--07. 重建二叉树

输入某二叉树的前序遍历和中序遍历的结果&#xff0c;请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 例如&#xff0c;给出 前序遍历 preorder [3,9,20,15,7] 中序遍历 inorder [9,3,15,20,7] 返回如下的二叉树&#xff1a; 3/ 9 20 / 15 7 …

47.全排列II

// 定义一个Solution类&#xff0c;用于解决给定不重复整数数组的全排列问题 class Solution {// 初始化结果集&#xff0c;用于存放所有不重复的全排列组合List<List<Integer>> result new ArrayList<>();// 初始化路径变量&#xff0c;用于暂存当前递归生…

Vulnhub靶机:Kioptrix_Level1.3

一、介绍 运行环境&#xff1a;Virtualbox 攻击机&#xff1a;kali&#xff08;192.168.56.101&#xff09; 靶机&#xff1a;Kioptrix_Level1.3&#xff08;192.168.56.109&#xff09; 目标&#xff1a;获取靶机root权限和flag 靶机下载地址&#xff1a;https://www.vul…