浅谈内存函数以及模拟实现

1.memcpy

void * memcpy ( void * destination, const void * source, size_t num );

函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
这个函数在遇到 '\0' 的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是未定义的。

 

 接下来我们使用一下这个函数:

#include<string.h>
int main()
{int arr1[10] = { 0 };int arr2[] = { 1,2,3,4,5 };memcpy(arr1, arr2, 20);return 0;
}

 经过调试之后可以发现arr1里面存放了1,2,3,4,5,这个就是memcpy的基本用法。


2.模拟实现memcpy

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<string.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{assert(dest && src);while (num){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;num--;}
}
int main()
{int arr1[10] = { 0 };int arr2[] = { 1,2,3,4,5 };my_memcpy(arr1, arr2, 20);return 0;
}

src里面的内容是不会被改变的,所以使用const限制一下。num是拷贝的字节数,我们每次拷贝一个字节。先使用while循环,循环num次,每次num--,dest和src是void*的指针,我们强制类型转换为char*的指针,然后解引用,将src赋给dest,dest和src这时就应该往后走一个字节,因为强制类型转换是临时的,所以还是需要强制类型转换为char*,然后+1。

当我们想把1,2,3,4,5放到3,4,5,6,7的位置上时就会出现问题,当空间不重叠内存的时候使用memcpy是可以的,像这种不重叠内存的拷贝需要使用memmove。

int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };memcpy(arr + 2, arr, 20);return 0;
}

 3.memmove

void * memmove ( void * destination, const void * source, size_t num );

和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。

int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };memcpy(arr + 2, arr, 20);return 0;
}

 使用memmove的话就能很好的解决上面的问题。


4.模拟实现memmove

我们先来想一下,如果有一个数组:

int arr[]={1,2,3,4,5,6,7,8,9,10};

假如我们要把1,2,3,4,5拷贝到3,4,5,6,7这个位置上去,使得数组变成:

int arr[]={1,2,1,2,3,4,5,8,9,10};

那我们就需要先将5放在7的位置上,4放在6的位置上,以此类推,才能达到效果,也就是从后向前拷贝。

如果我们要把3,4,5,6,7拷贝到1,2,3,4,5这个位置上,就要先将3放到1的位置上,以此类推,也就是从前往后拷贝。

所以说拷贝的方式会根据需求而改变。

那么什么时候从前往后拷贝,什么时候从后往前拷贝呢?

还是用一个数组举例:

int arr[]={1,2,3,4,5,6,7,8,9,10};

如果dest这块空间在src这块空间的左边且重叠,也就是要把高地址的数据拷贝到低地址处,就需要从前往后拷贝。

如果dest这块空间在src这块空间的右边且重叠,也就是要把低地址的数据拷贝到高地址处,就需要从后往前拷贝。

如果dest这块空间和src这块空间不重叠,不管从前往后还是从后往前都是可以的,当然是在空间充足的情况下,不能越界。


 一开始我们还是需要保存起始位置的地址,用作返回值。使用if判断dest是否小于src,如果小于则进入for循环,循环sz次,这里的方法是跟上面的memcpy一样的。当dest>src时,我们使用while循环比较方便,因为我们从后向前拷贝是先将后面的数据开始,所以当我们将条件设置成sz--时,由于是后置--,也是循环sz次,但是*((char*)src + sz)就刚好能够拿出最后一个数据拷贝到*((char*)dest + sz),当然使用for循环也是可以的。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
void* my_memmove(void* dest,const void* src,size_t sz)
{assert(dest && src);void* ret = dest;if (dest < src)//从前向后{for (int i = 0; i < sz; i++){*(char*)dest = *(char*)src;dest = (char*)dest+1;src = (char*)src + 1;}}else//从后向前{while (sz--){*((char*)dest + sz) = *((char*)src + sz);}}return ret;
}
int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };my_memmove(arr, arr + 2, 20);for (int i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}

 


5.memset

void * memset ( void * ptr, int value, size_t num );

 这个函数就是将ptr指向的前num个字节的数据设置成指定的值(value),再把起始位置返回。

下面是memset的使用: 

int main()
{char arr[] = "hello world";memset(arr + 6, 'x', 3);printf("%s\n", arr);return 0;
}

 但是要注意的是num的单位是字节。如果我们想要把这个数组的内容设置成10个1,像下面这样就已经出错了,这样是把每个字节都设置成1,而不是整型。

int main()
{int arr[10] = { 0 };memset(arr, 1, 40);return 0;
}


6.memcmp

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

 memcmp这个函数就是比较两块空间的前num个字节的内容,如果一样则返回0,小于则返回<0,大于则返回>0。需要注意的是在比较时也是一对字节进行比较,和strcmp的区别就是strcmp是进行字符的比较,而memcmp是进行内存块的比较。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[] = { 1,2,3,4 };int ret=memcmp(arr1, arr2, 16);printf("%d ", ret);return 0;
}


今天的分享到这里就结束啦!谢谢老铁们的阅读,让我们下期再见。

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

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

相关文章

保姆级微服务部署教程

大家好&#xff0c;我是鱼皮。 项目上线是每位学编程同学必须掌握的基本技能。之前我已经给大家分享过很多种上线单体项目的方法了&#xff0c;今天再出一期微服务项目的部署教程&#xff0c;用一种最简单的方法&#xff0c;带大家轻松部署微服务项目。 开始之前&#xff0c;…

React 函数式组件和类式组件区别

React 中组件主要分为函数式组件和类式组件两种类型。 一、函数式组件 函数式组件 (也称无状态组件&#xff0c;没有内部状态state&#xff0c;16.8版本推出hooks后可使用useState来管理) 就是通过函数编写形式去实现一个React组件&#xff0c;是React中定义组件最简单的方式…

Linux虚拟机搭建RabbitMQ集群

普通集群模式&#xff0c;意思就是在多台机器上启动多个 RabbitMQ 实例&#xff0c;每台机器启动一个。创建的 queue&#xff0c;只会放在一个 RabbitMQ 实例上&#xff0c;但是每个实例都同步 queue 的元数据&#xff08;元数据可以认为是 queue 的一些配置信息&#xff0c;通…

自定义无边框窗口

效果&#xff1a; 可拖动拉伸 ui&#xff1a;设计如下 样式表&#xff1a;在ui CustomDialog 里设置的 #widget_title{background: #E6F1EB;border-top-left-radius: 20px;border-top-right-radius: 20px;}#widget_client{background-color: rgb(255, 255, 255);border-bottom…

react create-react-app v5配置 px2rem (不暴露 eject方式)

环境信息&#xff1a; create-react-app v5 “react”: “^18.2.0” “postcss-plugin-px2rem”: “^0.8.1” 配置步骤&#xff1a; 不暴露 eject 配置自己的webpack&#xff1a; 1.下载react-app-rewired 和 customize-cra-5 npm install react-app-rewired customize-cra…

十三、Django之添加用户(原始方法实现)

修改urls.py path("user/add/", views.user_add),添加user_add.html {% extends layout.html %} {% block content %}<div class"container"><div class"panel panel-default"><div class"panel-heading"><h3 c…

Jakob Jenkov 个人博客 JCE 部分(译文)

Java Cryptography API 使你能够在 Java 中加密和解密数据&#xff0c;以及管理密钥、签名、验证消息、计算加密哈希等等。Cryptography 属于经常被简称为 crypto&#xff0c;所以你有时候可能会看到 Java crypto 而不是 Java Cryptography&#xff0c;这两个术语是同一个意思。…

OSI七层网络模型

1. OSI模型 网络协议是网络中两台计算机之间传输数据的标准语言。各种计算机系统使用 OSI&#xff08;Open Systems Interconnection&#xff09;模型规定的标准相互通信。OSI 模型有七个抽象层&#xff0c;每个层都有不同的职责和协议。 下图显示了 OSI 模型中每一层的功能。…

【python海洋专题十四】读取多个盐度nc数据画盐度季节变化图

本期内容 读取多个盐度文件&#xff1b;拼接数据在画盐度的季节分布图Part01. 使用数据 IAP 网格盐度数据集 数据详细介绍&#xff1a; 见文件附件&#xff1a; pages/file/dl?fid378649712527544320 全球温盐格点数据.pdf IAP_Global_ocean_gridded_product.pdf 全球温…

Blender中的4种视图着色模式

Blender中有四种主要的视图着色模式&#xff1a;线框、实体、Look Dev和渲染。它们的主要区别如下&#xff1a; - 线框模式只显示物体的边缘&#xff08;线框&#xff09;&#xff0c;可以让您看到场景中的所有物体&#xff0c;也可以调整线框的颜色和背景的颜色。 - 实…

python实现UI自动化配置谷歌浏览器驱动

web端UI自动化执行在哪个浏览器&#xff0c;需要对应哪个浏览器的驱动。以谷歌浏览器为例&#xff0c;进行配置。一、查看谷歌浏览器版本 如下截图&#xff1a;我的谷歌浏览器版本是&#xff1a; 117.0.5938.150 二、下载对应版本谷歌浏览器驱动 首先可以从其他版本驱动地址中…

【AI】深度学习——人工智能、深度学习与神经网络

文章目录 0.1 如何开发一个AI系统0.2 表示学习(特征处理)0.2.1 传统特征学习特征选择过滤式包裹式 L 1 L_1 L1​ 正则化 特征抽取监督的特征学习无监督的特征学习 特征工程作用 0.2.2 语义鸿沟0.2.3 表示方式关联 0.2.4 表示学习对比 0.3 深度学习0.3.1 表示学习与深度学习0.3.…

【数据库系统概论】数据定义之基本表的定义/创建、修改和删除

前言 &#x1f6a9;定义/创建基本表语法示例 修改基本表语法示例 删除基本表语法示例 感谢 &#x1f496; 前言 &#x1f6a9; SQL支持数据库系统的三级模式结构&#xff0c;其模式、外模式和内模式中的基本对象有表、视图和索引&#xff0c;因此&#xff0c;SQL的数据定义功能…

云原生Kubernetes:K8S集群kubectl命令汇总

目录 一、理论 1.概念 2. kubectl 帮助方法 3.kubectl 子命令使用分类 4.使用kubectl 命令的必要环境 5.kubectl 详细命令 一、理论 1.概念 kubectl是一个命令行工具&#xff0c;通过跟 K8S 集群的 API Server 通信&#xff0c;来执行集群的管理工作。 kubectl命令是操…

智慧楼宇3D数据可视化大屏交互展示实现了楼宇能源的高效、智能、精细化管控

智慧园区是指将物联网、大数据、人工智能等技术应用于传统建筑和基础设施&#xff0c;以实现对园区的全面监控、管理和服务的一种建筑形态。通过将园区内设备、设施和系统联网&#xff0c;实现数据的传输、共享和响应&#xff0c;提高园区的管理效率和运营效益&#xff0c;为居…

Maven系列:第1篇:什么是maven?为什么需要它?

maven系列目标&#xff1a;从入门开始开始掌握一个高级开发所需要的maven技能。 这是maven系列第1篇。 为什么我们要学习maven? 学习某些技术&#xff0c;肯定是我们遇到了某些问题&#xff0c;而这些问题目前手头上没有很好的方案去解决&#xff0c;此时刚好有一种技术可以…

增强现实抬头显示AR-HUD

增强现实抬头显示&#xff08;AR-HUD&#xff09;可以将当前车身状态、障碍物提醒等信息3D投影在前挡风玻璃上&#xff0c;并通过自研的AR-Creator算法&#xff0c;融合实际道路场景进行导航&#xff0c;使驾驶员无需低头即可了解车辆实时行驶状况。结合DMS系统&#xff0c;可以…

一个rar压缩包如何分成三个?

一个rar压缩包体积太大了&#xff0c;想要将压缩包分为三个&#xff0c;该如何做到&#xff1f;其实很简单&#xff0c;方法就在我们经常使用的WinRAR当中。 我们先将压缩包内的文件解压出来&#xff0c;然后查看一下&#xff0c;然后打开WinRAR软件&#xff0c;找到文件&…

7个在Github上的flutter开源程序

阅读大量代码是提高开发技能的最佳方法之一。该开源项目是了解最佳实践、编码风格和许多其他主题的最佳场所。 软件开发最受欢迎的领域之一是跨平台移动应用程序开发。Flutter 是您可以使用的最流行的跨平台移动应用程序开发工具之一。今天&#xff0c;我们将了解 7 个开源 Flu…

2023年中国烹饪机器人市场发展概况分析:整体规模较小,市场仍处于培育期[图]

烹饪机器人仍属于家用电器范畴&#xff0c;是烹饪小家电的进一步细分&#xff0c;它是烹饪小家电、人工智能和服务机器在厨房领域的融合。烹饪机器人是一种智能化厨房设备&#xff0c;可以根据预设的程序实现自动翻炒和烹饪&#xff0c;是多功能料理机和炒菜机结合的产物。 烹…