C语言之内存函数篇(3)

目录

memcpy

memcpy的使用

memcpy的模拟实现

NO1.

NO2. 

memcpy可否实现重叠空间的拷贝

my_memcpy 

memcpy 

memmove 

memmove

memmove模拟实现

分析

代码

memset

memset的使用

memcmp

memcmp的使用 

<0

=0

>0 


今天我们继续介绍几个重要的内存操作函数。🙂🙂🙂

在前面一章我们学过strcpy,strcmp等字符串函数,那这里我们来学习与它们功能类似的内存函数。

还是从参数,返回值,头文件,模拟实现等方面来讲解 

  • 注意是void* ,什么类型都🆗
  • 模拟实现必须要会 
  • size_t num代表的是字节

memcpy

memcpy - C++ Reference 

 memcpy与strcpy是类似的,但是strcpy仅仅用在字符串拷贝上,内存中的数据,不仅仅是字   符,还有整型,浮点型等等,这里就要用到我们的memcpy

void * memcpy ( void * destination, const void * source, size_t num );
  • memcpy是库函数,从source的位置开始向后拷贝num个字节的数据到desitination的内存位置
  •  C语言标准值规定,memcpy来实现不重叠的内存的拷贝。memcpy达到60分可以实现功能
  •  在我们VS2022这个环境中,memcpy也可以实现重叠内存的拷贝。此时memcpy达到100分
  • 头文件#include<string.h>
  • 参数size_t num是拷贝的字节个数
  • 参数const void * source 是拷贝的字节的起始位置(const防止source修改,void*类型)
  • 参数void * destination 是拷贝到的空间的起始位置(void*类型)
  • 返回类型void *
  • void*类型表示可以接收任何类型的数据,但是不能 解引用 哦
  • 这个函数在遇到 '\0' 的时候并不会停下来。
  • 如果source和destination有任何的重叠,复制的结果都是未定义的 
  • memcpy的模拟实现

memcpy的使用

#include<stdio.h>
int main()
{int a[] = { 0 };int b[] = { 6,7,8,9,10 };//5✖4void* p = memcpy(a, b, 20);int i = 0;for (i = 0; i < 5 ;i++){printf("%d ", a[i]);}return 0;
}

  • 这下无论是什么类型的数据都可以从一个空间拷贝到另外一个空间里去。 

memcpy的模拟实现

#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* destination, const void* source, size_t num)//记住num是字节的个数
{assert(dest && src);void* ret = destination;while (num--){*((char*)destination) = *((char*)source);(char*)destination = (char*)destination + 1;(char*)source = (char*)source + 1;}return ret;
}
int main()
{int a[20] = { 0 };int b[] = { 1,2,3,4,5 };//5✖4void* p = my_memcpy(a, b, 20);int i = 0;for (i = 0; i < 5 ;i++){printf("%d ", a[i]);}return 0;
}

NO1.

有同学说可以直接一个整型一个整型的拷贝过去,但是问题在于编写库函数的程序员并不会知道我们需要拷贝怎样的类型数据,所以这里我们又可以用到回调函数当时使用的一个方法 

回调函数------->

C语言之指针进阶篇(3)_唐棣棣的博客-CSDN博客

 

NO2. 

*((char*)destination) = *((char*)source);
(char*)destination++;
(char*)source++;

 那有同学这样写可以吗?

 答:当然是不可以的啦。其实关于前置和后置++我们都尽量少去使用。  因为副作用很多。我们也不清楚它的能使用的情况是怎样一回事,所以尽量少用。这里不能使用的原因是:destinationsource强制转化后,再去++,强制转化已经失效了,++时destinationsource已经变成void*类型的啦

++(char*)destination;
++(char*)source;

 虽然以上写法可能可以,但是会存在无法编译的问题。

还有同学问就不能直接++? 

 答:当然不行。回调函数我们那篇博文我们已经讲解过 void*类型的指针变量不能解引用和            计算++ --等等。

memcpy可否实现重叠空间的拷贝

当我们学习了上面memcpy的知识了,有人就动了动自己的小脑袋。🙂🙂

memcpy真的不能实现重叠内存的拷贝吗?

my_memcpy 

#include<stdio.h>
void* my_memcpy(void* destination, const void* source, size_t num)//记住num是字节的个数
{void* ret = destination;while (num--){*((char*)destination) = *((char*)source);destination = (char*)destination + 1;source = (char*)source + 1;}return ret;
}
int main()
{int b[] = { 1,2,3,4,5 };//把1 2 3拷贝到3 4 5void* p = my_memcpy(b+2, b, 12);int i = 0;for (i = 0; i < 5 ;i++){printf("%d ", b[i]);}return 0;
}

那问题到底出现在那里呢?

 

memcpy 

int main()
{int b[] = { 1,2,3,4,5 };//把1 2 3拷贝到3 4 5void* p = memcpy(b+2, b, 12);int i = 0;for (i = 0; i < 5 ;i++){printf("%d ", b[i]);}return 0;
}

 

综上所述:事实证明只是我们my_memcpy不可以。

 C语言标准值规定,memcpy来实现不重叠的内存的拷贝。memcpy达到60分可以实现功能

 在我们VS2022这个环境中,memcpy也可以实现重叠内存的拷贝。此时memcpy达到100分

 C语言标准值规定,memmove来实现重叠的内存拷贝。 

memmove 

使用memmove是否可以实现?

//当然可以
int main()
{int b[] = { 1,2,3,4,5 };//把1 2 3拷贝到3 4 5void* p = memmove(b+2, b, 12);int i = 0;for (i = 0; i < 5 ;i++){printf("%d ", b[i]);}return 0;
}

 

memmove

memmove - C++ Reference (cplusplus.com)

void * memmove ( void * destination, const void * source, size_t num );
  •  C语言标准值规定,memcpy来实现不重叠的内存的拷贝。memcpy达到60分可以实现功能
  •  在我们VS2022这个环境中,memcpy也可以实现重叠内存的拷贝。此时memcpy达到100分
  •  C语言标准值规定,memmove来实现重叠的内存拷贝。
  • memmove也是是库函数,类似memcpy,基本一致所不在详细介绍。
  • 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
  • 如果源空间和目标空间出现重叠,就得使用memmove函数处理。
  • memmove的模拟实现

memmove模拟实现

分析

代码

#include<stdio.h>
#include<strng.h>
#include<assert.h>
void* my_memmove(void* p1, void* p2,size_t num)
{assert(p1 && p2);void* ret = p1;//p1在p2的前面从后往前拷贝if (p1 < p2){while (num--){*(char*)p1 = *(char*)p2;p2 = (char*)p2 + 1;p1 = (char*)p1 + 1;}}//p1在p2的后面从后往前拷贝else{while (num--){*((char*)p1 + num) = *9(char*)p2 + num);}}return ret;
}
int main()
{char arr1[30] = "abcdef";void* ret = my_memmove(arr1, arr1+2,4);//4个字节printf("%s\n", ret);
}

memset

memset - C++ Reference (cplusplus.com)

void * memset ( void * ptr, int value, size_t num );
  • memset是库函数,是设置内存的,是以字节为单位设置内存的
  • 头文件#include<string.h>
  • 参数size_t num是设置的字节个数
  • 参数int value 是设置的字节
  • 参数void * ptr是设置的空间的起始位置(void*类型)
  • 返回类型void *
  •  void*类型表示可以接收任何类型的数据,但是不能 解引用 哦和计算++,--等
  • 准确来说memset更加适合char类型的变量,但是可以把整型设置全设为1
  • 注意char可以放到int里,int不能放到char里

memset的使用

#include<stdio.h>
#include<string.h>
int main()
{char arr[] = "tsqxgd.haha";memset(arr+6, 'x', 3);//再次强调是3个字节printf("%s\n", arr);
}

 

memcmp

memcmp - C++ Reference (cplusplus.com)

int memcmp ( const void * ptr1,const void * ptr2,size_t num );
  • memcmp是库函数,是比较内存的,是以字节为单位比较内存的
  • 比较从ptr1和ptr2指针开始的num个字节
  • 头文件#include<string.h>
  • 参数size_t num是设置的字节个数
  • 参数const void * ptr1 是比较的字节的起始位置(const防止source修改,void*类型)
  • 参数const void * ptr2 是比较的空间的起始位置(void*类型)
  •  void*类型表示可以接收任何类型的数据,但是不能 解引用 哦和计算++,--等
  • 返回类型int 
  •  返回值如下图:

memcmp的使用 

<0

#include<stdio.h>
#include<string.h>
int main()
{int arr1[] = { 1,2,3,4,5 };int arr2[] = { 1,2,3,4,6 };int ret = memcmp(arr1, arr2, 20);printf("%d\n", ret);
}

=0

#include<stdio.h>
#include<string.h>
int main()
{int arr1[] = { 1,2,3,4,5 };int arr2[] = { 1,2,3,4,6 };int ret = memcmp(arr1, arr2, 16);printf("%s\n", ret);
}

 

>0 

#include<stdio.h>
#include<string.h>
int main()
{int arr1[] = { 1,2,3,4,7 };int arr2[] = { 1,2,3,4,6 };int ret = memcmp(arr1, arr2,20 );printf("%d\n", ret);
}

 

特别提醒:

只是在vs2022编译器下,才是0,1,-1这样的数值,

在其他编译器下可能就不是但是肯定是<0 >0 =0这样的范围的。 

✔✔✔✔✔最后,感谢大家的阅读,若有错误和不足,欢迎指正!

我知青山不复在,也知绿水难长流。

下篇博文我们总结各种函数的模拟实现。🆗🆗🆗🆗走的每一步都是算数的。

代码------→【gitee:唐棣棣 (TSQXG) - Gitee.com】

联系------→【邮箱:2784139418@qq.com】

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Celery结合flask完成异步任务与定时任务

Celery 常用于 web 异步任务、定时任务等。 使用 redis 作为 Celery的「消息代理 / 消息中间件」。 这里通过Flask-Mail使用qq邮箱延时发送邮件作为示例 pip install celery pip install redis pip install Flask-Mail1、使用flask发送邮件 使用 Flask-Mail 发送邮件需要进行…

【无标题】ICCV 2023 | CAPEAM:基于上下文感知规划和环境感知记忆机制构建具身智能体

文章链接&#xff1a; https://arxiv.org/abs/2308.07241 2023年&#xff0c;大型语言模型&#xff08;LLMs&#xff09;以及AI Agents的蓬勃发展为整个机器智能领域带来了全新的发展机遇。一直以来&#xff0c;研究者们对具身智能&#xff08;Embodied Artificial Intelligenc…

通过java向jar写入新文件

文章目录 原始需求分析实施步骤引入依赖核心编码运行效果 原始需求 有网友提问&#xff1a; 我想在程序中动态地向同一个jar包中添加文件&#xff0c;比如&#xff0c;我的可执行jar包是test.jar,我要在它运行时生成一些xml文件并将这些文件添加到test.jar中,请问如何实现&…

【分布式计算】三、虚拟化 Virtualization

1.什么是虚拟化 1.1.非虚拟化 我们首先来认识什么是非虚拟化   1.一台机器、一个操作系统、几个应用程序   2.应用程序可能会相互影响。   3.机器利用率较低&#xff0c;正常情况下低于25%。 关于X86平台&#xff1a; 1.服务器基础设施利用率低&#xff08;10-18%&#…

Linux驱动开发笔记

疑问 file_operation中每个操作函数的形参中inode的作用 file_operation定义了Linux内核驱动的所有的操作函数&#xff0c;每个操作函数与一个系统调用对应&#xff0c;对于字符设备来说&#xff0c;常用的函数有&#xff1a;llseek、read、write、pool等等&#xff0c;这些操…

阿里云七代云服务器实例、倚天云服务器及通用算力型和经济型实例规格介绍

在目前阿里云的云服务器产品中&#xff0c;既有五代六代实例规格&#xff0c;也有七代和八代倚天云服务器&#xff0c;同时还有通用算力型及经济型这些刚推出不久的新品云服务器实例&#xff0c;其中第五代实例规格目前不在是主推的实例规格了&#xff0c;现在主售的实例规格是…

【数据结构】堆,堆的实现,堆排序,TOP-K问题

大家好&#xff01;今天我们来学习数据结构中的堆及其应用 目录 1. 堆的概念及结构 2. 堆的实现 2.1 初始化堆 2.2 销毁堆 2.3 打印堆 2.4 交换函数 2.5 堆的向上调整 2.6 堆的向下调整 2.7 堆的插入 2.8 堆的删除 2.9 取堆顶的数据 2.10 堆的数据个数 2.11 堆的判…

内存函数的介绍和模拟实现

目录 1.memcpy的使用(内存拷贝) 2.memcpy的实现 3.memmove的使用&#xff08;内存拷贝&#xff09; 4.memmove的实现 5.memset 的使用&#xff08;内存设置&#xff09; 6.memcmp的使用&#xff08;内存比较&#xff09; 1.memcpy的使用(内存拷贝) void * memcpy ( void * …

整型提升——(巩固提高——字符截取oneNote笔记详解)

文章目录 前言一、整型提升是什么&#xff1f;二、详细图解1.图解展示 总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 整型提升是数据存储的重要题型&#xff0c;也是计算机组成原理的核心知识点。学习c语言进阶的时候,了解内存中数据怎么存&#…

孤举者难起,众行者易趋,openGauss 5.1.0版本正式发布!

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

华为云云耀云服务器L实例评测|云耀云服务器L实例搭建个人镜像站

华为云云耀云服务器L实例评测&#xff5c;云耀云服务器L实例搭建个人镜像站 一、云耀云服务器L实例介绍1.1 云耀云服务器L实例简介1.2 云耀云服务器L实例特点 二、Apache介绍2.1 Apache简介2.2 Apache特点 三、本次实践介绍3.1 本次实践简介3.2 本次环境规划 四、远程登录华为云…

SpringCloud Alibaba 入门到精通 - Sentinel

SpringCloud Alibaba 入门到精通 - Sentinel 一、基础结构搭建1.父工程创建2.子工程创建 二、Sentinel的整合SpringCloud1.微服务可能存在的问题2.SpringCloud集成Sentinel搭建Dashboard3 SpringCloud 整合Sentinel 三、服务降级1 服务降级-Sentinel2 Sentinel 整合 OpenFeign3…

【深度学习实验】卷积神经网络(三):自定义二维卷积层:步长、填充、输入输出通道

目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 三、实验内容 0. 导入必要的工具包 1. 步长、填充 a. 二维互相关运算&#xff08;corr2d&#xff09; b. 二维卷积层类&#xff08;Conv2D&#xff09; c. 模型测试 d. 代码整合 2. 输入输出通道 a…

Arcgis克里金插值报错:ERROR 999999: 执行函数时出错。 表名无效。 空间参考不存在。 ERROR 010429: GRID IO 中存在错误

ERROR 999999: 执行函数时出错。 问题描述 表名无效。 空间参考不存在。 ERROR 010429: GRID IO 中存在错误: WindowSetLyr: Window cell size does not match layer cell size. name: c:\users\lenovo\appdata\local\temp\arc2f89\t_t164, adepth: 32, type: 1, iomode: 6, …

智能合约漏洞,Dyna 事件分析

智能合约漏洞&#xff0c;Dyna 事件分析 1. 漏洞简介 https://twitter.com/BlockSecTeam/status/1628319536117153794 https://twitter.com/BeosinAlert/status/1628301635834486784 2. 相关地址或交易 攻击交易 1&#xff1a; https://bscscan.com/tx/0x7fa89d869fd1b89e…

算法通过村第十一关-位运算|青铜笔记|初始位运算

文章目录 前言1. 数字在计算中的表示拓展&#xff1a;为什么要有原码、反码和补码? 2. 位运算规则2.1 与、或、异或和取反2.2 位移运算2.3 位移运算和乘除的关系2.4 位运算的常用技巧 总结 前言 提示&#xff1a;我的父亲从我出生起便认识我&#xff0c;可他对我的了解却那么少…

西北主要河流水系(绿洲)流域(山区)及高程分类数据集(一)

最近收集整理的了西北地区主要河流水系&#xff08;绿洲&#xff09;流域&#xff08;山区&#xff09;及高程分类数据&#xff0c;&#xff0c;本次主要是新疆的河流水系&#xff08;绿洲&#xff09;流域&#xff08;山区&#xff09;及高程分类数据&#xff08;矢量&#xf…

ThemeForest – Canvas 7.2.0 – 多用途 HTML5 模板

ThemeForest 上的 HTML 网站模板受到全球数百万客户的喜爱。与包含网站所有页面并允许您在 WP 仪表板中自定义字体和样式的 WordPress 主题不同&#xff0c;这些设计模板是用 HTML 构建的。您可以在 HTML 编辑器中编辑模板&#xff0c;但不能在 WordPress 上编辑模板&#xff0…

机器人过程自动化(RPA)入门 7. 处理用户事件和助手机器人

在UiPath中,有两种类型的Robot用于自动化任何流程。一个是后台机器人,它在后台工作。它独立工作,这意味着它不需要用户的输入或任何用户交互。另一个是前台机器人,也被称为助理机器人。 本章介绍前台机器人。在这里,我们将了解自动化过程中通过简单按键、单击鼠标等触发事…

【Vue】数据监视输入绑定

hello&#xff0c;我是小索奇&#xff0c;精心制作的Vue系列持续发放&#xff0c;涵盖大量的经验和示例&#xff0c;如有需要&#xff0c;可以收藏哈 本章给大家讲解的是数据监视&#xff0c;前面的章节已经更新完毕&#xff0c;后面的章节持续输出&#xff0c;有任何问题都可以…