初识C语言·内存函数

1 memcpy的使用和模拟实现

紧接字符串函数,出场的是第一个内存函数memcpy。前面讲的字符串函数是专门干关于字符串的事的,而这个函数可以干strcpy一样的事,但是区别就是它碰到\0也会继续复制。

函数的头文件是string,返回类型是void*,参数有两个,一个是目的地地址,一个是源的地址,还有一个是整型,这个整型代表的是要复制多少个字节,返回值是目的地的地址,因为源的值是不能被修改的,所以用const修饰,因为参数是void*,所以在一会儿模拟实现的时候我们就要强制转化成char*的,毕竟是修改字节。

先看一段简单的代码。

int main()
{int arr1[10] = { 1,2,9,4,5,6,7,8,9,10 };int arr2[10] = { 0 };memcpy(arr2, &arr1[4], 9);for (int i = 0; i < 10; i++){printf("%d ", arr2[i]);}return 0;
}

这串代码的意思就是从arr1[4]开始给arr2复制,复制9个字节,还是很好理解的,那如果不是在一个空间呢?比如我把arr1[4]的位置给arr1开始复制,会不会报错呢?答案是可能会。

如果目的地和源的内存有任何重叠的话,复制的结果都是未定义的,也就是说mencpy的行为是不可预测的,咱也不知道它会干啥,像这样。

int main()
{char str[] = "Hello, World!";memcpy(str + 7, str, 7);printf("%s\n", str);return 0;
}

结果是未知的,所以重叠的部分就不应该用mencpy了。

好了,我们现在就模拟实现一下memcpy函数。

主函数开始,传两个地址和一个整型过去,因为复制的是字节,所以我们可以使用字节数当作循环变量,for while循环都可以,因为参数都是泛型指针,所以有必要强制转化为char*指针,转化之后就是复制了,这里有个需要注意的点就是不能直接*(char*)p1++,这样系统会报错的,我们就可以换一个思路,如下。

当然,返回的地址需要用一个临时变量存起来,最后返回就行了,因为返回的是泛型指针,所以临时变量的指针类型也是void*。

void my_memcpy(void* p2, const void* p1, size_t num)
{void* ret = p2;for ( ; num > 0; num--){*(char*)p2 = *(char*)p1;(char*)p2 = (char*)p2 + 1;(char*)p1 = (char*)p1 + 1;}return ret;
}
int main()
{srand((unsigned int)time(NULL));int arr1[10] = { 1,2,9,4,5,6,7,8,9,10 };int arr2[10] = { 0 };int num = rand() % 40 + 1;my_memcpy(arr2, arr1, num);for (int i = 0; i < 10; i++){printf("%d ", arr2[i]);}return 0;
}

读者可以自行实验一下。


2 memmove的使用和模拟实现

memcpy是不能让同一块空间复制的,但是menmove就可以,它和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。

先上代码实验一下。

int main()
{char arr[] = "Hello world!";memmove(arr, arr + 1, 3);printf("%s", arr);return 0;
}

最后的结果就是elllo world!,内存重叠了在memmove这里是没有任何问题的,但是在vs里面尝试对重叠的空间使用memcpy可能是不会报错的,这与vs有关,我们先不用在意。

现在讨论模拟实现memmove。

我们首先想为什么使用内存函数需要考虑空间是否重叠,这是因为如果重叠了就会导致内存复制的时候复制过去上一次复制留下的元素,那么解决方案是什么?是单独拿一块空间出来存储要存放的元素吗?这个实际上可以,但是不免会浪费挺多空间。较好的办法就是改变复制的顺序,如下。

假定红色区域是来源,绿色和蓝色部分是目的地,均有重叠,因为重叠无非就是前面重叠或者是后面重叠,所以有两种情况

第一种情况,绿色情况,假如从前往后复制,即从5开始复制是没有问题的,因为重叠部分5复制的时候9没有发生改变,如果是从后往前复制,即从9开始复制,那么最后复制5的时候,5已经发生了改变,复制就会出错。

第二种情况,蓝色情况,假如从前往后复制,即从5开始复制,那么在复制13那个位置的时候。9已经发生了改变,变成了5,所以复制会出错,同理,后往前复制就不会出错。

可以总结一个小规律:复制的方向取决于重叠的部分,只需要保证在复制的时候,重叠的部分还没有被复制就行,所以一共就两种情况。

void my_memmove(void* p1, const void* p2, size_t num)
{void* ret = p2;if (p1 < p2)//前往后{while (num){*(char*)p1 = *(char*)p2;(char*)p1 = (char*)p1 + 1;(char*)p2 = (char*)p2 + 1;num--;}}else//后往前{(char*)p2 = (char*)p2 + num - 1;(char*)p1 = (char*)p1 + num - 1;while (num){*(char*)p1 = *(char*)p2;(char*)p1 = (char*)p1 - 1;(char*)p2 = (char*)p2 - 1;num--;}}return ret;
}
int main()
{char str1[100] = "Hello world!";//Hehellworldmy_memmove(str1 + 2, str1, 4);printf("%s", str1);return 0;
}

我们讨论的就是传过去的地址的大小是谁高,如果目的地的地址高于来源的地址,那么复制的方向就是从前往后,如果低于,那么复制的地址就是从后往前。特别要注意的是第二种情况,如果是从后往前,那么两个指针指向的位置都需要发生改变,所以需要先加上复制的字节数。第二种情况下,容易犯错的是指向的位置应该加字节数在建减一个1,这点可以自行实验一下。

memmove函数模拟实现就完成了。

可以这样理解,

memcpy可以实现的memmove都可以实现,唯一的区别只是内存空间不能重叠的问题。


3 memset的使用和模拟实现

在cplusplus中,memset的返回值void*,返回的是传进去的地址,参数有三个,泛型指针,存进去的值,设置的字节数。

这个函数的功能就是把内存中的值设置成自己想要的值,那有人问了,为什么第二个参数是int类型的,这是因为字符在计算机中实际上是以AscII值的形式读取的,所以参数类型是int类型。

int main()
{char arr1[100] = "abcdefg";memset(arr1,'*',6);printf("%s", arr1);return 0;
}

这是一个简单应用,那么现在模拟实现一下,模拟实现难度不大,每个字节设置一下就行了。

void* my_memset(void* p1, int tem, size_t num)
{void* ret = p1;while (num--){*(char*)p1 = tem;(char*)p1 = (char*)p1 + 1;}return ret;
}
int main()
{char arr1[100] = "abcdefg";my_memset(arr1, '*', 3);printf("%s", arr1);return 0;
}

4 memcmp的使用和模拟实现

根据cplusplus,memcmp的返回值是int类型的,实际上和strcmp一样,返回的值就是1 0 -1,strcmp是用来比较字符串的,memcmp就是用来比较内存的,比较的每个字节每个字节的比较的。

头文件还是string,参数有3个,分别是两块内存的地址和比较的字节数的大小,话不多说,看看简单的使用。

int main()
{char str1[100] = "abCdefg";char str2[100] = "abcdefg";int ret1 = memcmp(str1,str2,3);int ret2 = memcmp(str2, str1, 3);int ret3 = memcmp(str1, str2, 2);printf("%d\n", ret1);printf("%d\n", ret2);printf("%d\n", ret3);return 0;
}

所以字符串函数能做到的许多内存函数也是可以做到的,模拟实现和strcmp很是相似,这里就不模拟实现了,重点是memmove的使用和模拟实现。


感谢阅读!

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

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

相关文章

如何从 Keras 中的深度学习目录加载大型数据集

一、说明 数据集读取&#xff0c;使用、在磁盘上存储和构建图像数据集有一些约定&#xff0c;以便在训练和评估深度学习模型时能够快速高效地加载。本文介绍Keras 深度学习库中的ImageDataGenerator类等工具自动加载训练、测试和验证数据集。 二、ImageDataGenerator加载数据集…

2024.1.11

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);speechnew QTextToSpeech(this);id1startTimer(1000);//设置文本到中间ui->sys_label->setAlignment(Qt:…

20240107移远的4G模块EC20在Firefly的AIO-3399J开发板的Android11下调通能上网

20240107移远的4G模块EC20在Firefly的AIO-3399J开发板的Android11下调通能上网 2024/1/7 11:17 开发板&#xff1a;Firefly的AIO-3399J【RK3399】SDK&#xff1a;rk3399-android-11-r20211216.tar.xz【Android11】 Android11.0.tar.bz2.aa【ToyBrick】 Android11.0.tar.bz2.ab …

Java的Netty

1.基本概念介绍 有了Netty&#xff0c;你可以实现自己的HTTP服务器&#xff0c;FTP服务器&#xff0c;UDP服务器&#xff0c;RPC服务器&#xff0c;WebSocket服务器&#xff0c;Redis的Proxy服务器&#xff0c;MySQL的Proxy服务器等等。 Netty 是一个基于 Java 的高性能网络应…

红队打靶练习:BREACH: 1

信息收集 1、arp ┌──(root㉿ru)-[~/kali] └─# arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:69:c7:bf, IPv4: 192.168.110.128 Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan) 192.168.110.1 00:50:56:c0:00:08 …

RK3568驱动指南|第十篇 热插拔-第118章 使用udev挂载U盘和T卡实验

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

CTF-PWN-沙箱逃脱-【seccomp和prtcl-1】

文章目录 啥是seccomp#ifndef #define #endif使用使用格式 seccomp无参数条件禁用系统调用有参数条件禁用系统调用 prctl实例 seccomp_export_bpf 啥是seccomp 就是可以禁用掉某些系统调用&#xff0c;然后只能允许某些系统调用 #ifndef #define #endif使用 #ifndef #defin…

Day4Qt

1.头文件: #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTime>//时间类 #include <QTimer>//时间事件类 #include <QTimerEvent>//定时器类 #include <QTextToSpeech> namespace Ui { class Widget; }class Widget : publi…

JMeter 批量接口测试

一、背景 最近在进行某中台的接口测试准备&#xff0c;发现接口数量非常多&#xff0c;有6、70个&#xff0c;而且每个接口都有大量的参数并且需要进行各种参数验证来测试接口是否能够正确返回响应值。想了几种方案后&#xff0c;决定尝试使用JMeter的csv读取来实现批量的接口…

SFT会改善LLM性能,RLHF可能会损害性能

SFT&#xff08;Structured Fine-Tuning&#xff09;是一种模型优化技术&#xff0c;它通过在预训练的语言模型上进行有针对性的微调&#xff0c;以适应特定任务或领域。SFT可以提高性能的原因有几个&#xff1a; 领域自适应&#xff1a;预训练的语言模型通常在大规模通用语料库…

vscode 创建文件自动添加注释信息

随机记录 目录 1. 背景介绍 2. "Docstring Generator"扩展 2.1 安装 2.2 设置注释信息 3. 自动配置py 文件头注释 1. 背景介绍 在VS Code中&#xff0c;您可以使用扩展来为新创建的Python文件自动添加头部注释信息。有几个常用的扩展可以实现此功能&#xff0…

eChart显示时等比例缩放

eChart会在不同分辨率的显示器中显示&#xff0c;要求显示内容可以等比例缩放&#xff0c;transform的原点是内容的中心位置&#xff0c;直接使用transform.scale缩放会导致有些内容溢出屏幕 screen的左上角移动到屏幕的中心计算出比例&#xff0c;以screen左上角为原点&#…

leetcode-二进制求和

67. 二进制求和 class Solution:def addBinary(self, a: str, b: str) -> str:result carry 0for i in range(max(len(a), len(b))):a_bit a[-(i1)] if i < len(a) else 0b_bit b[-(i1)] if i < len(b) else 0sum_bit int(a_bit) int(b_bit) carryresult str…

Vue3:使用解构赋值来读取对象里的键-值对(值也是对象)

一、前言 在Vue3中&#xff0c;想要读取一个对象的“键—值”对&#xff08;值也是一个对象&#xff09;&#xff0c;数据格式如下&#xff1a; {1:{courseName: 课程1, study: 951526, visit: 3785553}&#xff0c;2:{courseName: 课程2, study: 181630, visit: 380830}&…

springboot+ipage分页频繁请求会报错 自动添加多一个limit

com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near LIMIT 500 at line 3 这个原因是因为springboot配置mysql的连接池太…

nginx sendfile

http模块中有一个sendfile指令&#xff0c;默认开启的 简单来说就是启用sendfile()系统调用来替换read()和write()调用&#xff0c;减少系统上下文切换从而提高性能&#xff0c; 当 nginx 是静态文件服务器时&#xff0c;能极大提高nginx的性能表现&#xff0c; 而当 nginx 是…

在线问卷调查的优势:提升数据收集与分析效率的关键要素

无论是在工作中还是学习中&#xff0c;我们经常会使用问卷调查法来解决一些问题。不过&#xff0c;问卷调查有两种形式——线上和线下&#xff0c;这两者之间有什么优势和不足呢&#xff1f; 纸质问卷&#xff1a; 1、优势&#xff1a; 我们在使用纸质问卷的时候&#xff0c;通…

十年磨一剑,写在美国比特币现货ETF获批后

出品&#xff5c;欧科云链研究院 作者&#xff5c;Hedy Bi 两天前&#xff0c;我们提出&#xff0c;对于比特币现货ETF市场。十年磨一剑&#xff0c;今天&#xff0c;这一里程碑终于到来。美国证监会&#xff08;SEC&#xff09;批准了11只比特币现货ETF&#xff0c;将会在芝…

【计算机网络】TCP原理 | 可靠性机制分析(三)

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【网络编程】【Java系列】 本专栏旨在分享学习网络编程、计算机网络的一点学习心得&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目…

气温如同过山车?探索气候变化对肠道微生物组的影响

谷禾健康 今年的天气&#xff0c;如此的奇怪&#xff1a; 短袖和羽绒服之间&#xff0c;只差了一个降温 忽冷忽热&#xff0c;气温仿佛过山车... 11月初多地气温破纪录&#xff0c;冬天集体迟到... 早穿皮袄午穿纱&#xff0c;每天不知道穿啥... 再不冷都不好意思过圣诞了... 好…