了解内存函数

 ✨✨欢迎👍👍点赞☕️☕️收藏✍✍评论

个人主页:秋邱'博客

所属栏目:C语言

前言 

 内存函数不止malloc、calloc、realloc、free还有memcpy、memmove、memset、memcmp前四个的头文件是<stdlib.h>,后四个的头文件是<string.h>


1.0 memcpy()

函数声明:

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

destination:指向要复制内容的目标数组的指针,类型转换为void*类型的指针。

source:指向被复制的目标数组的指针,类型转换为const void*类型的指针。(const指针内容不能被修改)

num:字节个数。

返回值:返回一个类型的指针。

注意: 

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

1.1 函数使用

int main()
{int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[20] = { 0 };int num = sizeof(arr1) / sizeof(arr1[0]);MyMemcpy(arr1, arr2, num * sizeof(int));for (int i = 0; i < num; i++){printf("%d ", arr2[i]);}return 0;
}

打印结果:

1.2 模拟实现

前面对memcpy进行了使用,发现memcpy就是将原内存拷贝到目标内存去的一个函数。

这里用void*来接收指针的地址,因为并不清楚传入函数的是声明类型,所以用void*来接收(void*可以接收任意类型

#include<stdio.h>
void* my_memcopy(void* dest,const void* src, size_t num)
//const这里是拷贝,只需要原地址空间的数据,并不需要修改
{void* ret = dest;while (num--){*(char*)src = *(char*)dest;//将原地址的数据放入目的地址src = (char*)src + 1;//对src和dest为(char*)+1跳过一个字节dest = (char*)dest + 1;}return ret;
}
int main()
{int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[20] = { 0 };int num = sizeof(arr1) / sizeof(arr1[0]);my_memcopy(arr1, arr2, num * sizeof(int));for (int i = 0; i < num; i++){printf("%d ", arr2[i]);}return 0;
}

分析:

dest和src均为void*类型,在解引用需要将它们转化为(char*),因为在函数拷贝过程中,并不清楚传入的是int*还是char*等类型,这就需要char*一个一个字节的搬运。

强制类型转换只是临时的,下一次的使用还是原来的类型,也就是dest和src下一次使用还是void*的类型。src = (char*)src + 1将src强换为(char*)赋给src。

开辟一个void*的函数,来存dest的初始地址,最后返回。

对于重叠的内存,交给memmove来处理。


2.0 memmove()

memmove的destination和source相同的

函数声明:

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

destination:指向要复制内容的目标数组的指针,类型转换为void*类型的指针。

source:指向被复制的目标数组的指针,类型转换为const void*类型的指针。(const指针内容不能被修改)

num:字节个数。

返回值:返回一个类型的指针。

2.1 函数使用

int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };//代码1memmove(arr+2, arr, sizeof(int)*5);//代码2memmove(arr, arr+2, sizeof(int)*5);for (int i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}

打印结果:

 代码1

代码2

可以看到,代码1和代码2的打印结果不同,这跟dest在前还是在后有关系,到模拟实现的时候就要分情况来讨论。 

2.2 模拟实现

2.2.1 分析

 2.2.1.1 dest在前,src在后,且有重叠(dest < src)

前向后遍历:3 4 5 6 7 6 7 8 9 10 √

后向前遍历:7 6 7 6 7 6 7 8 9 10 ×

很明显,从前向后遍历才是正确的。

2.2.1.2 src在前,dest在后,且有重叠(dest > src)

前向后遍历:1 2 1 2 1 2 1 8 9 10  ×

后向前遍历:1 2 1 2 3 4 5 8 9 10  √

2.2.1.3 无重叠

前向后遍历=后向前遍历:1 2 3 4 5 1 2 3 4 5

前向后遍历=后向前遍历:5 6 7 8 9 10 5 6 7 8 9 10

使用第三种情况已经被第一二种情况包括了,就不需要拿出来分析了。 只需要讨论前两种就行了。

void* my_memmove(void* dest, const void* src, size_t num)
{void* ret = dest;if (dest < src)//dest在前,src在后{while(num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}}else{//src在前,dest在后dest = (char*)dest + num-1;src = (char*)src + num-1;while (num--){*(char*)dest = *(char*)src;dest = (char*)dest - 1;//指向末尾src = (char*)src - 1;//指向末尾}}return ret;
}
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };my_memmove(arr+2, arr, sizeof(int)*5);for (int i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}

dest在前,src在后,且有重叠(dest < src)这个情况跟memcpy的写法一样,只需用if判断dest是否小于src即可。else里只需要将,src里的数据一个字节一个字节的放进dest就可以了。


3.0 memset()

函数声明:

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

ptr:指向需要被放置的指针。

value:该值作为int类型传递,但函数使用该值的unsigned char转换来填充内存块。

num:字节个数。

返回值:返回一个类型的指针。

3.1 函数使用

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

打印结果:

 

3.2 模拟实现

void* my_memset(void* ptr, int value, size_t num)
{void* ret = ptr;//while(num--)//{//	*(char*)ptr = (char)value;//	ptr = (char*)ptr + 1;//}for (int i = 0; i < num; i++){*(char*)ptr = (char)value;ptr = (char*)ptr + 1;}return ret;
}
int main()
{char ptr[] = "hello world";my_memset(ptr, 'x', 6);printf("%s", ptr);return 0;
}

分析: 这个函数的实现比较简单,给定一个指针ptr开始,逐个字节地将值(char*)value设置到后续的内存位置,循环执行num次。


4.0 memcmp()

函数声明:

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

ptr1:指向内存块的指针。

ptr2:指向内存块的指针。

num:字节个数。

 返回值:

返回值意思(如果作为unsigned char值计算)
<0ptr1的值小于ptr2的值
=0ptr1的值等于ptr2的值
>0ptr1的值大于ptr2的值

4.1 模拟实现

int memcmp(const void* ptr1, const void* ptr2, size_t num)
{if (*(char*)ptr1 > *(char*)ptr2)return 1;else if (*(char*)ptr1 < *(char*)ptr2)return -1;else{ptr1 = *(char*)ptr1 + 1;ptr2 = *(char*)ptr2 + 1;}return 0;
}
int main()
{char arr1[] = "Hello Qiu";char arr2[] = "Hello qiu";int ret = memcmp(arr1, arr2, sizeof(arr1));if (ret > 0)printf("'%s' is greater than '%s'.\n", arr1, arr2);else if (ret < 0)printf("'%s' is less than '%s'.\n", arr1, arr2);elseprintf("'%s' is the same as '%s'.\n", arr1, arr2);return 0;
}

将传入的指向用void*接收,ptr1和ptr2一个字节一个字节的进行比较,若ptr1大,则返回大于0的值;ptr1相等ptr2,且*ptr1+1、*ptr2+1直到全部比完相同,返回0;ptr2大,返回小于0的值。


感谢各位大佬莅临,如有错误欢迎指出,共同学习进步。 

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

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

相关文章

【C++】-【QT】类库使用-001

1主窗口创建 1.1【makefile】配置 1 源码 QT widgetsSOURCES main.cpp2 图示 1.2源码 1 源码 #include <QWidget> #include <QApplication>using namespace std;int main(int argc,char *argv[]) {QApplication a(argc,argv);QWidget w;w.show();return a…

YOLOv8改进 | 独家创新篇 | 利用MobileNetV4的UIB模块二次创新C2f(全网独家首发)

一、本文介绍 本文给大家带来的改进机制是利用MobileNetV4的UIB模块二次创新C2f&#xff0c;其中UIB模块来自2024.5月发布的MobileNetV4网络&#xff0c;其是一种高度优化的神经网络架构&#xff0c;专为移动设备设计。它最新的改动总结主要有两点&#xff0c;采用了通用反向瓶…

C语言:指针(1)

1. 内存和地址 内存划分为⼀个个的内存单元&#xff0c;每个内存单元的⼤⼩取1个字节。 计算机中常⻅的单位&#xff08;补充&#xff09;&#xff1a; ⼀个⽐特位可以存储⼀个2进制的位1或者0 C语⾔中给地址起了新的名字叫&#xff1a;指针。 内存单元的编号地址指针。 1.…

介绍 ffmpeg.dll 文件以及ffmpeg.dll丢失怎么办的五种修复方法

ffmpeg.dll 是一个动态链接库文件&#xff0c;属于 FFmpeg运行库。它在计算机上扮演着非常重要的角色&#xff0c;因为它提供了许多应用程序和操作系统所需的功能和组件。当 ffmpeg.dll 文件丢失或损坏时&#xff0c;可能会导致程序无法正常运行&#xff0c;甚至系统崩溃。下面…

树莓派4b红外检测

1.红外检测连接图 2.红外检测工作原理 红外传感器的工作原理类似于物体检测传感器。该传感器包括一个红外LED和一个红外光电二极管&#xff0c;因此通过将这两者结合起来&#xff0c;可以形成一个光耦合器。 红外LED是一种发射红外辐射的发射器。该LED看起来与标准LED相似&a…

嫦娥六号近月制动成功,建立月球基地又迈进一步!

嫦娥六号探测器在近月制动的关键时刻&#xff0c;北京航天飞行控制中心内弥漫着紧张而庄重的氛围。每一个航天科技工作者都屏息以待&#xff0c;他们的眼神中充满了期待与自豪。随着一系列精妙绝伦的指令如同琴弦上的音符般流畅地奏响&#xff0c;嫦娥六号探测器在万众瞩目的目…

排序算法(Java版)

目录 1、直接插入排序2、希尔排序3、直接选择排序4、堆排序5、冒泡排序6、快速排序6.1 递归实现6.2 非递归实现 7、归并排序7.1 递归实现7.2 非递归实现 8、性能分析 今天我们学习一种算法&#xff1a;排序算法&#xff08;本文的排序默认是从小到大顺序&#xff09;&#xff0…

红帽为 Red Hat OpenShift AI 扩大与 Elasticsearch 向量数据库的合作

作者&#xff1a;来自 Elastic Aditya Tripathi 红帽和 Elastic 今天宣布开展合作&#xff0c;以便在 Red Hat OpenShift AI 上集成 Elasticsearch 向量数据库。 Red Hat OpenShift 用户现在可以通过红帽生态系统目录实施 Elasticsearch 以进行向量搜索和检索增强生成 (RAG) 应…

Flink DataSink介绍

介绍 Flink DataSink是Apache Flink框架中的一个重要组件&#xff0c;它定义了数据流经过一系列处理后最终的输出位置。以下是关于Flink DataSink的详细介绍&#xff1a; 概念&#xff1a;DataSink主要负责对经过Flink处理后的流进行一系列操作&#xff0c;并将计算后的数据结…

Hive Transaction事务表(含实现原理)

Hive Transaction事务表 在Hive中&#xff0c;事务表&#xff08;Transactional Tables&#xff09;允许用户执行事务性操作&#xff0c;包括ACID&#xff08;原子性、一致性、隔离性、持久性&#xff09;特性。事务表是在Hive 0.14版本引入的&#xff0c;并且在后续版本中不断…

wangEditor富文本编辑器与layui图片上传

记录&#xff1a;js 显示默认的wangEditor富文本编辑器内容和图片 <style>body {background-color: #ffffff;}.layui-form-select dl{z-index:100000;} </style> <div class"layui-form layuimini-form"><div class"layui-form-item"…

【Android项目】“追茶到底”项目介绍

没有多的介绍&#xff0c;这里只是展示我的项目效果&#xff0c;后面会给出具体的代码实现。 一、用户模块 1、注册&#xff08;第一次登陆的话需要先注册账号&#xff09; 2、登陆&#xff08;具有记住最近登录用户功能&#xff09; 二、点单模块 1、展示饮品列表 2、双向联动…

缓存雪崩、击穿、击穿

缓存雪崩&#xff1a; 就是大量数据在同一时间过期或者redis宕机时&#xff0c;这时候有大量的用户请求无法在redis中进行处理&#xff0c;而去直接访问数据库&#xff0c;从而导致数据库压力剧增&#xff0c;甚至有可能导致数据库宕机&#xff0c;从而引发的一些列连锁反应&a…

【vue+vue-treeselect】根据指定字段,如isLeaf(是否末级节点),设置只允许末级节点可以选

1、当项目有特殊要求&#xff0c;必须根据某个字段的值去判断&#xff0c;是否节点可以选&#xff0c;即使已经是末级节点了&#xff0c;还是需要根据字段判断是否禁用 &#xff08;1&#xff09; :flat"true"一定要设置 (2)获取数据源的时候&#xff0c;设置下禁用…

【进程间通信】共享内存

文章目录 共享内存常用的接口指令利用命名管道实现同步机制总结 System V的IPC资源的生命周期都是随内核的。 共享内存 共享内存也是为了进程间进行通信的&#xff0c;因为进程间具有独立性&#xff0c;通信的本质是两个不同的进程看到同一份公共资源&#xff0c;所以共享内存…

【web网页制作】html+css旅游家乡河南开封主题网页制作(4页面)【附源码】

HTMLCSS家乡河南主题网页目录 &#x1f354;涉及知识&#x1f964;写在前面&#x1f367;一、网页主题&#x1f333;二、页面效果Page1 首页Page2 开封游玩Page 3 开封美食Page4 留言 &#x1f308; 三、网页架构与技术3.1 脑海构思3.2 整体布局3.3 技术说明书 &#x1f40b;四…

centos8.5 安装 redis 7.2.4 详细步骤

1 下载Index of /releases/ (redis.io) 通过xftp等方式上传到服务器&#xff0c;安装依赖包 yum install gcc gcc-c make tcl -y [rootlocalhost software]# ll total 3308 -rw-r--r--. 1 root root 3386861 May 3 21:56 redis-7.2.4.tar.gz [rootlocalhost software]# ll…

CoPilot 产品体验:提升 OpenNJet 的控制管理和服务提供能力

文章目录 前言系统架构介绍CoPilot 配置CoPilot 插件规范 体验 CoPilot 实例CoPilot: Broker 实例CoPilot: Ctrl 实例 开发其他语言编写的 CoPilot目标主要思路具体实现执行 go 程序代码 功能扩展总结 前言 CoPilot 是 OpenNJet 的一个重要组成部分&#xff0c;它在 Master-Wo…

O2OA开发平台前端源码级二次开发(Vue3,React)

在使用O2OA进行项目定制化开发时&#xff0c;我们可以开发新的前端组件&#xff08;x_component&#xff09;以扩展O2OA来实现更多的业务。这种新增前端组件或者前端业务的开发通常会配合后端自定义应用实现的服务来完成系统内数据的交互。在当系统默认的界面不符合系统UI/UE设…

C++之大数运算

溪云初起日沉阁 山雨欲来风满楼 契子✨ 我们知道数据类型皆有范围&#xff0c;一旦超出了这个范围就会造成溢出问题 今天说说我们常见的数据类型范围&#xff1a; 我们平时写代码也会遇到数据类型范围溢出问题&#xff1a; 比如 ~ 我们之前写的学生管理系统在用 int类型 填写…