C语言-------内存函数

前面向大家介绍了C语言中的字符函数和字符串函数,今天再向大家介绍一下类似的函数————

C语言中的内存函数。

1. memcpy函数的使用和模拟实现

memcoy函数是一种通过内存来复制内容的一种函数,以字节为基本单位进行,斌并且是一个可以复制任何类型数据的函数。

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

上面代码就是memcpy函数的一个基本形式。 

用法解释:destination是一个指向目标空间的 void* 类型的指针,source是一个指向源空间(提供复制的内容的对象)的指针。num是一个无符号整形的参数,单位是字节。

意思就是从source指向的位置开始向后复制num个字节的内容复制destination指向的位置。

使用时注意事项:

1. memcpy函数进行内容的复制时,遇到源空间的 '\0' 不会停止。

2. memcpy函数进行内容复制时的基本单位是字节

3. memcpy函数使用时,最好不要涉及到目标空间和源空间共同覆盖的空间,否则复制的结果都是未定义的。

老样子,上代码。

int main()
{int arr1[] = { 1,2,3,4,5 };int arr2[5] = { 0 };printf("复制前arr2数组为:");int i = 0;for (i = 0; i < 5; i++){printf("%d ", arr2[i]);}printf("\n");memcpy(arr2, arr1, 3 * sizeof(arr1[0]));//3*sizeof(arr1[0])是指将从arr1开始复制直到到达12个字节printf("复制后arr2数组为:");for (i = 0; i < 5; i++){printf("%d ", arr2[i]);}return 0;}

memcpy函数的模拟实现

void my_memcpy(void* dest, const void* src, int num) //设置成void* 型指针是为了接受任何类型的数据
{while (num--){*(char*)dest = *(char*)src;//因为void*指针无法直接进行解引用,我们将其转换成char*型的dest = (char*)dest + 1;src = (char*)src + 1;}
}
int main()
{int arr1[] = { 1,2,3,4,5 };int arr2[10] = { 0 };my_memcpy(arr2, arr1, 20);for (int i = 0; i < 10; i++){printf("%d ", arr2[i]);}return 0;
}

以上就是memcpy函数的模拟实现

有人看了代码就疑惑了,为什么偏偏实现函数功能是将指针强制转换成char*的呢?

其实就是为了方便操作

本质上是将要复制的内容转换为一个一个字节复制过去,而char*型的指针一次就只能操作一个字节,就实现了通过一个一个字节来复制内容。 

运行如下图

实现模拟之后,我们再来解释一下为什么操作的空间最好不要有重叠。

void my_memcpy(void* dest, const void* src, int num) 
{while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}
}
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10};my_memcpy(arr1+3, arr1, 20);for (int i = 0; i < 10; i++){printf("%d ", arr1[i]);}return 0;
}

 通过画图我们知道,按照上面代码操作,4和5的空间是共同覆盖的,所以当进行到复制半路的途中,4和5就会被改为1和2了,然而4和5也是后面要复制的内容,但是4和5已经提前被改为1和2了,所以后面的复制操作也是会有影响的。

运行代码

但是这种效果是通过我们模拟实现的。

如果我们真使用上memcpy函数时,memcpy函数还是会正常实现复制的。

这说明VS中memcpy函数已经具备了处理空间重叠的问题。但我们如果以后遇到的空间是重叠的,最好不要使用memcpy函数。

所以C语言就为我们提供了一个处理空间重叠的函数------memmove函数

2. memmove函数的使用和模拟实现 

其实memmove函数和memcpy函数的用法是差不多的,不同点在于memmove函数是专门设计来处理目标空间和源空间重叠的问题的。

需要注意的是:memmove函数处理的基本单位也是字节。

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

上代码

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

 

运行代码发现,memmove函数在处理目标空间和源空间重叠时,是可以正常将源空间的内容复制到目标空间的。

所以每当我们在复制内容时,遇到目标空间和源空间重叠的问题时,必须使用memmove函数。

memmove函数的模拟实现

在模拟实现memmove函数遇到的情况比较多也比较复杂。我们 一 一 来分析。

第一种情况

如上图,当dest和src指向的空间没有重叠时,我们只需要把src里面要复制的内容从前向后或者从后向前拷贝到目标空间中去。

第二种情况

如图,当src指向的空间于dest指向的空间有重叠部分时,并且src在dest的左边时,我们依次将src指向的内容从前向后拷贝到dest指向的空间时,我们会发现这样拷贝时,我们会将后面要拷贝的4和5变成了1和2,这样要拷贝4和5时就无法拷贝了,因为4和5应经提前被替换成1和2了,已经没有4和5了。

 所以这时候我们要改变一下,将src里面的内容从后向前拷贝。

如上图,当我们将src指向的内容依次从后向前拷贝到dest指向的目标空间时,我们会发现这样就能正常复制内容。

第3种情况

 

这时我们发现当空间有重叠时,并且src在dest的右边时,我们将src里面的内容依次从前向后拷贝的dest指向的空间时,是可以正常运行的。

总结: 

1.当 src在  1  区域时,也就是在dest的左边时,我们将src指向的内容从后向前拷贝。(src<dest)

2.当src在  2 和 3 区域时,也就是在dest的右边时,我们将src指向的内容从前向后拷贝。(src>dest)

代码实现

void my_memmove(void* dest, void* src, int num)
{if (src > dest){//从前向后拷贝while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src+1;}}else{while (num--){//num- -的同时,也样dest和src向后退了 *((char*)dest + num) = *((char*)src + num);}}
}
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int sz = sizeof(arr1) / sizeof(arr1[0]);my_memmove(arr1 + 2, arr1, 20);int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr1[i]);}return 0;
}

运行代码

 

3.memset函数的使用

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

memset函数是用来设置内存的,将内存中的值以字节为单位设置成想要的内容。

解释memset的3个参数

1.ptr 是一个void* 类型的指针,其指向的是被修改内容空间的起始位置。

2.value是我们要设置的内容。

3.num 是表示从ptr指向的起始位置开始向后有多少个字节的内容需要改变。

老样子,上代码感受

int main()
{char arr[] = "hallo bit";memset(arr, 'x', 5 * sizeof(arr[0]));printf("%s", arr);return 0;
}

 

4.memcmp函数的使用

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

memcmp函数是用来比较ptr1指向的内容和ptr2指向的内容后num个字节的内容的大小。

       返回值              *ptr1-*ptr2
          >0             >0
           0                ==0
            <0               <0

我们还是直接通过代码感受一下

int main()
{char* str1 = "abcd";char* str2 = "abce";int ret=memcmp(str1, str2, 4);printf("%d\n", ret);if (ret > 0){printf("str1>str2");}else if (ret < 0){printf("str1<str2");}else{printf("str1==str2");}
}

运行代码 

 

完结,感谢大家的观看。 

 

 

 

 

 

 

 

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

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

相关文章

git可视化工具

Gitkraken GitKraken 是一款专门用于管理和协作Git仓库的图形化界面工具。它拥有友好直观的界面&#xff0c;使得Git的操作变得更加简单易用&#xff0c;尤其适合那些不熟悉Git命令行的开发者。GitKraken提供了丰富的功能&#xff0c;如代码审查、分支管理、仓库克隆、提交、推…

如何使用CSS构建一个瀑布流布局

如何使用CSS构建一个瀑布流布局 瀑布流布局是一种常见的网页布局方式&#xff0c;其中元素以不同的大小排列&#xff0c;且行与列之间没有不均匀的间隙。在瀑布流布局中&#xff0c;即使某一行或列中的元素较短&#xff0c;下一个元素也会占据空间。 如何实现瀑布流布局 实现…

多线程下载图片等待图片下载完代码实现

Future 实现方式 import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorServic…

java框架学习——反射概述及简易版框架搭建

前言&#xff1a; 整理下学习笔记&#xff0c;打好基础&#xff0c;daydayup!!! 反射 反射&#xff08;Reflection&#xff09;&#xff1a;加载类&#xff0c;并允许以编程的方式解剖类中的各种成分&#xff08;成员变量&#xff0c;方法&#xff0c;构造器等&#xff09; 1&…

C++之类和对象(上)

目录 1.面向过程和面向对象初步认识 2.类的引入 3.类的定义 4.类的访问限定符及封装 4.1访问限定符 4.2 类的两种定义方式 第一种&#xff1a; 第二种&#xff1a; 4.3封装 5.类的实例化 6.类对象模型 1.面向过程和面向对象初步认识 C语言是面向过程的&#xff0c;…

【ARM 嵌入式 C 文件操作系列 20 -- 文件删除函数 remove 详细介绍】

请阅读【嵌入式开发学习必备专栏 】 文章目录 文件删除函数 remove 文件删除函数 remove 在 C 语言中&#xff0c; 可以使用 remove 函数来删除一个文件&#xff0c;但在删除之前 可能想确认该文件是否存在。 可以使用 stat 函数来检查文件是否存在。 以下是如何实现这个功能…

出门一笑, “栈” 落江横 (Java篇)

本篇会加入个人的所谓‘鱼式疯言’ ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人…

03-自媒体文章发布

自媒体文章发布 1)自媒体前后端搭建 1.1)后台搭建 ①&#xff1a;资料中找到heima-leadnews-wemedia.zip解压 拷贝到heima-leadnews-service工程下&#xff0c;并指定子模块 执行leadnews-wemedia.sql脚本 添加对应的nacos配置 spring:datasource:driver-class-name: com…

23年蓝桥杯省赛 动态规划DP

动态规划 就是:给定一个问题&#xff0c;我们把它拆成一个个子问题&#xff0c;直到子问可以直接解决。然后把子问题的答案保存起来&#xff0c;以减少重量计算&#xff0c;再根据子问题答察反推&#xff0c;得出问解的一种方法。 题目&#xff1a; 这天&#xff0c;一只蜗牛…

QT串口接收数据并进行波形显示(含源码)

**使用QT在串口调试助手基础上实现波形显示&#xff08;含源码&#xff09; 评论比较多留言需要源码的&#xff0c;逐个发邮箱比较麻烦也不能及时回复&#xff0c;现将源码上传至链接&#xff08;无需积分下载&#xff09;https://download.csdn.net/download/m0_51294753/877…

mysql 8.0 常用函数大全总结,并列出实例

MySQL 8.0提供了丰富的内置函数&#xff0c;这些函数可以大致分为几个类别&#xff1a;字符串函数、数值函数、日期和时间函数、比较函数、逻辑函数、控制流函数等。以下是20个常用的MySQL函数及其简单的使用示例&#xff1a; 1. **CONCAT()**: 字符串连接函数。 - 示例&am…

设计一个可扩展的Python Web框架:并发、性能与安全性考量

设计一个可扩展的Python Web框架&#xff1a;并发、性能与安全性考量 一、引言 随着Web应用的日益复杂和需求的不断增长&#xff0c;一个可扩展的Web框架变得至关重要。在Python生态系统中&#xff0c;虽然存在诸多优秀的Web框架&#xff0c;但设计一个符合自身需求且具备高度…

云服务器4m带宽是什么意思?

云服务器配置4M带宽是什么意思&#xff1f;4M代表该台云服务器的网络传输速度为4Mbps&#xff0c;一般指该台云服务器的公网出方向带宽&#xff0c;即从云服务器下载的公网带宽&#xff0c;4M带宽下载速度为512KB/秒&#xff0c;云服务器吧yunfuwuqiba.com整理常见的云服务器公…

Java之过滤器Filter、拦截器Interceptor与面向切面AOP

Java之过滤器Filter、拦截器Interceptor与面向切面AOP Filter的使用 Component WebFilter(urlPatterns {"/*"}) public class CustomFilter implements Filter {Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain cha…

cJSON(API的详细使用教程)

我们今天来学习一般嵌入式的必备库&#xff0c;JSON库 1&#xff0c;json和cJSON 那什么是JSON什么是cJSON&#xff0c;他们之间有什么样的关联呢&#xff0c;让我们一起来探究一下吧。 JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&…

C和C++内存管理

目录&#xff1a; 一&#xff1a;C和C内存分布 二&#xff1a;C动态内存管理方式 三&#xff1a;C动态内存管理方式 四&#xff1a;operator new与operator delete函数 五&#xff1a;new和delete的实现原理 六&#xff1a;定位new表达式(placement-new) 七&#xff1…

使用YOLOv8训练自己的【目标检测】数据集

文章目录 1.收集数据集1.1 使用开源已标记数据集1.2 爬取网络图像1.3 自己拍摄数据集1.4 使用数据增强生成数据集1.5 使用算法合成图像 2.标注数据集2.1确认标注格式2.2 开始标注 3.划分数据集4.配置训练环境4.1获取代码4.2安装环境 5.训练模型5.1新建一个数据集yaml文件5.2预测…

了解IP地址的基本概念和修改步骤

在数字化时代&#xff0c;IP地址作为网络设备的唯一标识&#xff0c;其重要性不言而喻。无论是为了提升网络性能&#xff0c;还是出于隐私保护的需求&#xff0c;修改IP地址都是网络使用者可能遇到的操作。虎观代理将详细介绍如何修改IP地址&#xff0c;并探讨在修改过程中需要…

python+flask+django文献文件资料搜索系统

后端&#xff1a;python 前端&#xff1a;vue.jselementui 框架&#xff1a;django/flask Python版本&#xff1a;python3.7 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat 开发软件&#xff1a;PyCharm 本系统在设计过程中&#xff0c;很好地发挥了该开发方式的优…

刷题DAY45 | 70-爬楼梯(进阶) LeetCode 322-零钱兑换 279-完全平方数

70 爬楼梯&#xff08;进阶&#xff09; 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬至多m (1 < m < n)个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 注意&#xff1a;给定 n 是一个正整数。 输入描述 输入共一行&#xff0c;包含两个正整数&…