C语言内存函数
目录
- memcpy(Copy block of memory)使用和模拟实现
- memcpy的模拟实现
- memmove(Move block of memory)使用和模拟实现
- memmove的模拟实现:
- memset(Fill block of memory)函数的使用
- 扩展
- memcmp(Compare two blocks of memory)函数的使用
感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接
🐒🐒🐒个人主页
🥸🥸🥸C语言
🐿️🐿️🐿️C语言例题
🐣🐓🏀python
memcpy(Copy block of memory)使用和模拟实现
代码格式:
void * memcpy ( void * destination, const void * source, size_t num );
memcpy使用要点:
1:函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置
2:这个函数在遇到 ‘\0’ 的时候并不会停下来
3:如果source和destination有任何的重叠,复制的结果都是未定义的
4:由于不知道程序猿会传入什么样的指针,所以我们用void * 表示各种类型的指针,因此我们用void*后可以传入int * ,char * …类型的指针
此外我们还有区分 strcpy和memcpy,一个是拷贝字符,一个是拷贝内存,memcpy拷贝是针对不重叠的拷贝)
我们解释一下重叠的含义:
int main()
{int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };memcpy(arr+2, arr , 16);return 0;
}
这就是拷贝重叠,arr+2是表示的&a[2],arr是数组名表示首元素的地址,我们用一个图来说明

首先我们将a[0]=0,a[1]=1分别替换a[2]=2,a[3]=3,由于传进去的是地址,所以是永久改变,此时我们的a[2]和a[3]都发生了变化,但是a[2]和a[3]还没有去替换a[4]和a[5]
当我们用a[2]和a[3]去替换a[4]和a[5]时,a[2]和a[3]已经变成了0和1,所以替换a[4]和a[5]的结果也是0和1
只不过有些编译器的结果并不是这样的(比如VS),因为VS中的memcpy约等于memmove,唯一的解释就是程序猿在实现memcpy时的编写不同,所以代码的结果就不同,但是大多数编译器都是前面的结果
代码示例:
#include <stdio.h>
#include <string.h>
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[10] = { 0 };memcpy(arr2, arr1, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr2[i]);}return 0;
}
代码解析:
这里有两个int类型的数组,arr2中的元素全是0,我们将arr1中的元素复制到arr2中
由于我们传入的arr2和arr1都是数组的数组名,也就是数组首元素的地址,传入的字节数为20,因为一个数组中的元素大小为4个字节,所以相当于传入5个元素到arr2中
之后就从arr2中第一个元素0开始改变,总共改变5个元素,打印的结果如下

memcpy的模拟实现
void* my_memcpy(void* dest, const void* src, size_t sz)
{assert(dest && src);while (sz--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}return dest;
}int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[10] = { 0 };my_memcpy(arr2, arr1, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr2[i]);}return 0;
}
代码解析:
因为是拷贝的内存,但是数组中的元素是整形元素,如果我们拷贝的内存大小不是4的倍数(一个整形大小为4个字节),比如7,那么可能就无法拷贝进去
因此我们需要将传入的数组元素地址进行强制类型转换成char,只有这样才能一个字节一个字节的拷贝, * (char)dest = * (char*)src是将dest和src强制转换为char*类型的指针,再解引用,将src的一个字节拷贝给dest**
而dest = (char)dest + 1和src = (char)src + 1都是将两个数组强制类型转换,再通过+1跳到下一个字节,这样我们就可以保证每一个字节都能够拷贝**
错误代码示例1:
void* my_memcpy(void* dest,const void* src, size_t sz)
{assert(dest && src);while (sz--){*(char*)dest = *(char*)src;(char*)dest++;(char*)src++;}return dest;
}
错误代码示例2:
void* my_memcpy(void* dest,const void* src, size_t sz)
{assert(dest && src);while (sz--){*(char*)dest = *(char*)src;dest = ++(char*)dest ;src = ++(char*)src ;}return dest;
}
错误1具体原因其实我也没有搞懂,错误2只能在某些编译器下可以正常运行,但不是全部,因此就算作错误
memmove(Move block of memory)使用和模拟实现
代码格式:
void * memmove ( void * destination, const void * source, size_t num );
memmove使用要点:
1:和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的
2:如果源空间和目标空间出现重叠,就得使用memmove函数处理
代码示例:
#include <stdio.h>
#include <string.h>
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };memmove(arr1 + 2, arr1, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr1[i]);}return 0;
}
代码解析:
这里只有一个数组arr1,我们传入的地址为arr1+2和arr1,分别表示数组第三个元素的地址(&arr1[3]),和数组首元素的地址

memmove的模拟实现:
在实现之前我们先理解一下思路:
memmove的实现其实有一种比较简单的方法,就是我们只需要创造一个和arr一模一样的数组brr,由于是两个不同的数组,内存地址是不同的,只是数组元素是相同的,这样我们就解决重叠的问题了

但是我们能不能只通过arr自身而不去创造brr去实现memmove呢?

如图:我们需要将绿色方框中的元素拷贝到红色方框中的元素,可以像这样拷贝,我们先将a[4]=3拷贝到a[6]=5中,然后将a[3]=2拷贝到a[5]=4中…这样就可以避免重叠拷贝,造成拷贝元素不是我们想要的情况了
而如果我们需要将图中绿色方框中的元素拷贝到前面红色方框的元素呢?

其实方式都是一样的
综上如果我们只用数组arr而不创造数组brr的话,我们需要考虑到两种情况,一个是往前拷贝,一个是往后拷贝,所以针对情况我们就一定会用到if语句
具体实现代码如下:
void* my_memmove(void* dest, const void* src, size_t sz)
{assert(dest && src);void* ret = dest;//记录dest启始地址if (dest < src)//从前向后{for (int i = 0; i < sz; i++){*(char*)dest = *(char*)src;dest = (char*)+1;src = (char*)src + 1;}}else//从后向前{while (sz--){*((char*)dest + sz) = *((char*)src + sz);}}return ret;
}
代码解析:
* (char * )dest = * (char*)src是将dest和src强制转换为char*,方便后续可以一个字节一个字节的拷贝
dest = (char*)+1和src = (char*)src + 1是将两个数组都强转后向后移动一个字节
由于while(sz–)是先判断sz是否=0,判断完后再执行后置减减,然后在通过 *((char *)dest + sz) = * ((char * )src + sz)确定需要拷贝的数组和要拷贝数字的位置,我们用一个图来说明:
我们需要将绿色方框中的元素拷贝进红色方框中去,下面是各元素的16进制表示


memset(Fill block of memory)函数的使用
代码格式:
void * memset ( void * ptr, int value, size_t num );
memset使用要点:
1:memset是用来设置内存的,将内存中的值以字节为单位设置成想要的内容
代码示例:
#include <stdio.h>
#include <string.h>
int main()
{char str[] = "hello world";memset(str, 'x', 6);printf("%s",str);return 0;
}
代码解析:
memset中我们传入的

扩展
memset是以字节为单位设置内存的,为了方便理解我们看一个代码
int main()
{int arr[10] = { 0 };memset(arr, 1, 40);for (int i = 0; i < 10; i++){printf("%d\n", arr[i]);
}return 0;
}
运行结果如图:

我们调试看一下内存

这是以16进制的方式存储的,在还没有执行memset时内存存储的每个字节都是0

而执行memset后我们可以看到每隔一个字节都会有一个0变成1,因此我们通过这个就比较容易理解以字节为单位设置内存这句话了
所以memset最好还是设置char类型的数组
memcmp(Compare two blocks of memory)函数的使用
代码格式:
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
memcmp使用要点:
1:比较从ptr1和ptr2指针指向的位置开始,向后的num个字节
2:memcmp是比较两个内存块
返回值如下

代码示例:
int main()
{int arr1[] = { 1,2,3,4,5,6,7 };//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00...int arr2[] = { 1,2,3 };//01 00 00 00 02 00 00 00 03 00 00 00int a = memcmp(arr1, arr2, 12);printf("%d", a);return 0;
}
代码结果如下:

但如果我们稍微改一下代码呢?
int main()
{int arr1[] = { 1,2,3,4,5,6,7 };//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00...int arr2[] = { 1,2,3,0x11223304 };//01 00 00 00 02 00 00 00 03 00 00 00 04 33 22 11int a = memcmp(arr1, arr2, 13);printf("%d", a);return 0;
}
可以看到我们将arr2中添加了一个16进制的元素0x11223304 ,并且在memcmp中我们将比较的12个字节改为13个字节,结果如下

结果是0,从这里我们也可以看出,memcmp也是将数组中的元素用16进制来表示,再通过一个字节一个字节的比较,方式有点像前面的memset
相关文章:
C语言内存函数
目录 memcpy(Copy block of memory)使用和模拟实现memcpy的模拟实现 memmove(Move block of memory)使用和模拟实现memmove的模拟实现: memset(Fill block of memory)函数的使用扩展 memcmp(Compare two blocks of memory)函数的使用 感谢各位大佬对我的支持,如果我的文章对你有…...
【Docker】Docker-compose及Consul多容器编排工具
使用一个Dockerfile模版文件可以定义一个单独的应用容器,当需要定义多个容器时就需要编排 docker swarm(管理跨节点) 编排工具——docker compose Dockerfile可以让用户管理一个单独的应用容器;而Compose则允许用户在一个模板&…...
Unity网络同步方案帧同步和状态同步
网络同步方案 介绍开始我们使用的状态同步(实时状态同步)后来采用的帧同步 状态同步优点缺点 帧同步顺序执行追帧重连优点缺点 总结 这两年做的都是帧同步和状态同步的项目,正好最近有时间总结一下什么是帧同步和状态同步,之前在做…...
【Monorepo实战】pnpm+turbo+vitepress构建公共组件库文档系统
Monorepo架构可以把多个独立的系统放到一起联调,本文记录基于pnpm > workspace功能,如何构建将vitepress和组件库进行联调,并且使用turbo进行任务顺序编排。 技术栈清单: pnpm 、vitepress 、turbo 一、需求分析 1、最终目标…...
CentOS 编译安装Redis
一、编译配置hiredis.h C来操作redis数据库。通过hiredis接口来实现,目前只能在Linux环境使用。 下载hiredis.h hiredis的下载地址为:https://github.com/redis/hiredis 解压并编译hiredis [rootlocalhost source_code]# pwd /usr/local/source_…...
可拓展的低代码全栈框架
尽管现在越来越多的人开始对低代码开发感兴趣,但已有低代码方案的局限性仍然让大家有所保留。其中最常见的担忧莫过于低代码缺乏灵活性以及容易被厂商锁定。 显然这样的担忧是合理的,因为大家都不希望在实现特定功能的时候才发现低代码平台无法支持&…...
C++11 智能指针
目录 智能指针 异常导致执行流乱跳 智能指针解决问题 auto_ptr unique_ptr sharded_ptr weak_ptr 智能指针 由于C11引入异常之后,执行流乱跳,所以导致之前 malloc/new 的空间很容易没有被释放,导致内存泄露问题。 所以这时候&#x…...
二、WebGPU阶段间变量(inter-stage variables)
二、WebGPU阶段间变量(inter-stage variables) 在上一篇文章中,我们介绍了一些关于WebGPU的基础知识。在本文中,我们将介绍阶段变量(inter-stage variables)的基础知识。 阶段变量在顶点着色器和片段着色…...
【Linux】31个普通信号
文章目录 1.每种信号的含义2.两种不能被忽略的信号3.两种不能被捕捉的信号 1.每种信号的含义 信号编号信号名信号含义1SIGHUP如果终端接口检测到一个连接断开,则会将此信号发送给与该终端相关的控制进程,该信号的默认处理动作是终止进程。2SIGINT当用户…...
Mac电脑交互式原型设计 Axure RP 8汉化最新 for mac
Axure RP 8是一款专业且快速的原型设计工具,主要用于定义需求、规格、设计功能和界面。这款工具主要适用于用户体验设计师、交互设计师、业务分析师、信息架构师、可用性专家和产品经理等职业。 Axure RP 8的主要特性包括能够快速设计出应用软件或Web网站的线框图、…...
在线免费无时长限制录屏工具 - 录猎在线版
需要录屏的小伙伴注意啦,想要长时间录制又不想花钱的,可以看下这款在线版录屏软件 —— 录猎在线版,一个录屏软件所需要的基本功能它都有,设置录制范围、录制的声音来源、摄像头也能录制的。同时它是支持Windows和Mac系统的&#…...
c语言文件操作详解:fgetc,fputc,fgets,fputs,fscanf,,fprintf,fread,fwrite的使用和区别
前言:在对于c语言的学习中,我们为了持续使用一些数据,为了让我们的数据可以在程序退出后仍然保存并且可以使用,我们引入了文件的概念和操作,本文旨在为大家分享在文件操作中常用的输入输出函数的使用方式和技巧&#x…...
Harmony装饰器
1、装饰器 装饰器是用于装饰类、结构、方法以及变量,并赋予其特殊的含义。如: Component表示自定义组件Entry表示该自定义组件为入口组件State表示组件中的状态变量,状态变量变化会触发UI刷新。 2 、语法范式 Builder/BuilderParam&#…...
如何加快Chrome谷歌浏览器下载速度?
用Chrome打开chrome://flags/...
使用kubectl连接远程Kubernetes(k8s)集群
使用kubectl连接远程Kubernetes集群 环境准备下载kubectl下载地址 安装kubectl并处理配置文件Windows的安装配置安装kubectl拉取配置文件安装kubectl拉取配置文件kubectl命令自动补全 Linux的安装配置安装kubectl拉取配置文件kubectl命令自动补全 环境准备 你需要准备一个Kube…...
Kubernetes革命:云原生时代的应用编排和自动化
文章目录 什么是Kubernetes以及为何它备受欢迎?云原生应用和K8s的关系Kubernetes的核心概念:Pods、Services、ReplicaSets等部署、扩展和管理应用程序的自动化容器编排的演进:Docker到Kubernetes实际用例:企业如何受益于K8s的应用…...
mysql.mongoDb,neo4j数据库对比
#Mysql与MongoDb和Neo4j的一些对比 主要区别 MySQL: 1.MySQL是一种关系型数据库管理系统(RDBMS),广泛用于处理结构化数据。 2.它支持SQL语言,具备成熟的事务处理和数据一致性能力。 3.MySQL适用于大多数传统的基于表…...
unity使用UniStorm 5.1.0.unitypackage增加天气
添加天天气组件unistorm 然后添加一个player 导入包会报错,需要修改代码 using UnityEngine; using UnityEngine.PostProcessing;namespace UnityEditor.PostProcessing {[CustomPropertyDrawer(typeof(UnityEngine.PostProcessing.MinAttribute))]sealed class MinDrawer : …...
Flink实现kafka到kafka、kafka到doris的精准一次消费
1 流程图 2 Flink来源表建模 --来源-城市topic CREATE TABLE NJ_QL_JC_SSJC_SOURCE ( record string ) WITH (connector kafka,topic QL_JC_SSJC,properties.bootstrap.servers 172.*.*.*:9092,properties.group.id QL_JC_SSJC_NJ_QL_JC_SSJC_SOURCE,scan.startup.mode …...
Outlook屏蔽Jira AI提醒
前言:最近不知道为什么jira上的ai小助手抽风,一周发个几千封邮件…导致我现在都不想在邮箱里面跟找垃圾一样找消息了。实在忍无可忍,决定屏蔽AI小助手,方法很简单,follow me~~ 第一步:双击打开电脑版Outloo…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
