内存函数(C语言)

内存函数

以下函数的头文件:string.h

  • 针对内存块进行处理的函数

memcpy

函数原型:

void* memcpy(void* destination, const void* source, size_t num);目标空间地址                源空间地址
  • num,被拷贝的字节个数

  • 返回目标空间的起始地址

  • 从source函数向后拷贝num字节个数据到目标空间

  • 目标空间地址和源空间地址有重叠部分,有重叠内存的拷贝,结果是未定义的

  • C语言标准规定:memcpy可以不负责有重叠内存的拷贝

    • 而vs编译器的库函数也可以实现重叠内存的拷贝。
#include <stdio.h>
#include <string.h>
int main()
{int arr1[20] = { 1, 2, 3, 4, 5, 6 };int arr2[20] = { 0 };memcpy(arr2, arr1, sizeof(int) * 5);for (int i = 0; i < 5; i++){printf("%d ", arr2[i]);}return 0;
}

在这里插入图片描述

通过函数原型也发现,这个memcpy函数是一个函数参数,函数返回类型都是void无符号类型,这是说明该函数是一个,泛型函数,它可以接收任意类型的参数,使同一个函数能用于多种类型的数据

该用例说明了,将数组arr1从第一个元素开始的20个字节拷贝到arr2中。

模拟memcpy函数

void* my_memcpy(void* dest, const void* src, size_t num)
{void* ret = dest;assert(dest && src);while(num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}return ret;
}

该函数是泛型函数,在返回类型和参数上要保持一致,后面的size_t num参数用来接收拷贝的字节个数。

能够进行任意数据类型的拷贝,这里只能将源空间一个一个字节拷贝到目标空间里,而void类型不是4个字节,所以将,dest和src强制类型转换为char类型,这样每循环一次就拷贝一个字节的内容,然后让指针dest和src向后走一个字节。

(char*)dest++;dest = *(char*)dest + 1;的区别:

c/c++里的强制类型转换,是临时的,(char*)dest++;试图将一个 void *类型的dest强制类型转换,然后++,语法是有问题的,对 (char *)dest使用++,实际上是 (char* dest) = dest + 1;,将无符号类型的指针赋给 char *类型的指针编译器会报错的
在这里插入图片描述

最后将目标空间的起始地址返回即可。

使用assert断言是因为,目标空间和源空间都不能为空,否则就是对空指针解引用,加一条assert是代码具有更好的健壮性。

memmove

函数原型:

void* memmove(void* destination, const void* source, size_t num);
  • 负责重叠内存的拷贝
  • 用法与memcpy相同。
  • memmove可以是memcpy的替代,它支持更多的使用场景,重叠内存的拷贝。

模拟memmove函数

俩个函数的功能及其相似,它们在实现上的不同,模拟memcpy函数是,对字节进行拷贝时,是将source里的字节从前向后一个一个拷贝的,如图:

source里一共有12个字节,模拟的memcpy函数将从数字2开始的第一个字节,一个一个拷贝到目标空间里。
在这里插入图片描述

在这里插入图片描述

若两快空间重叠时会发生哪些情况:

  • dest指针大于source指针,目标空间与源空间重叠,但目标空间起始地址小于源空间,此时针对情况一,如上图橘色与蓝色重叠部分
  • dest指针小于source指针,目标空间与源空间重叠,但目标空间起始地址大于源空间,此时针对情况二,如上图绿色与蓝色重叠部分

情况一:

  • 当使用从前向后一个一个字节的拷贝时, 0 被拷贝为 2,1 被拷贝为 3,2 被拷贝为 4,结果与预期相符和,所以当目标空间与源空间重叠,但目标空间起始地址小于源空间时,采用从前向后一个字节一个字节的拷贝。

在这里插入图片描述

情况二:

  • 对应情况二使用从前向后一次拷贝字节时,将源空间内容拷贝到密目标空间,此时 4 被拷贝为 2 , 5 被拷贝为 3 , 6被拷贝为2。

  • 与预期结果并不相符和,预期拷贝后的结果时 0 1 2 3 2 3 4。

  • 实际结果为,0 1 2 3 2 3 2。

在这里插入图片描述

可以发现,使用从前向后一起拷贝字节时,源空间的内容覆盖掉,它还没有拷贝就已经被覆盖了,并将其放置在目标空间的最后一个位置。解决这种办法也很好理解,既然从前向后拷贝不行,那我们从后向前拷贝不久可以了。这样就避免了,还没有将源空间的数据拷贝到目标空间就被覆盖的情况。

将source指针和destination指针向后偏移num个字节 (char*)dest + num (char*)src + num,这样它两就指向最后一个字节,从后向前拷贝,每拷贝完一个字节后 num–

在这里插入图片描述

void* my_memmove(void* dest, const void* src, size_t num)
{void* ret = dest;assert(dest && src);if(dest > src)//后向前{while(num--){*((char*)dest + num) = *((char*)src + num);}}else{while(num--){*(char*)dest = *(char*)src;dest = *(char*)dest + 1;src = *(char*)src + 1;}}return ret;
}

当dest > src时,从后向前,第一步将dest和src偏移到最后一个位置, (char*)dest + num (char*)src + num,然后进行赋值 ,

*((char *)dest ) = *((char *)src );,其代码内讲多块内容合并在一起操作,通过控制num大小,来控制了dest和src偏移的位置,而循环结束的条件的num为0,这样就有了一条很精简的代码。

memset

函数原型:

void* memset(void* ptr, int value, size_t num);被填充空间    改变的内容 设置的字节个数       

memset,是用来设置内存的,将内存以字节为单位,

  • 将每个字节设置为 value的内容

很朴素的用法,没有过多的变化,但结果往往会让人出乎意料~。

int main()
{int arr1[20] = { 1, 2, 3, 4, 5, 6 };int arr2[20] = { 0 };memset(arr2, 9, 5);memset(arr1, 8, 5);for (int i = 0; i < 6; i++){printf("%d ", arr1[i]);}printf("\n");for (int i = 0; i < 5; i++){printf("%d ", arr2[i]);}return 0;
}

这不是一个使用的案例,通过运行代码能够发现数组arr1和arr2的结果相当的大,这是因为memset是在字节上设置内容,这里的第一条memset语句,将数组arr2里的五个字节内容,都放置了一个数字9,而内存里的 09 09 09 09实际上是16进制数,0x09090909,所以在打印的结果上会很大。

数字arr1的结果,同数组arr2一样,即使在传递的数组这块内容已经放的有值,memset还会将其覆盖。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

这里以字符串为例,字符串的大小是一个字节,这里我试图将字符数组arr1里的前三个字节内容置为x。

int main()
{char arr1[10] = "abcdef";memset(arr1, 'x', 3);return 0;
}

在这里插入图片描述

观察结果,memset函数指哪打哪~,也没有在最后一个x后多余的放置 '\0'

memcmp

函数原型:

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

比较字节大小:

  • ptr1 > ptr2 返回大于0
  • ptr1 < ptr2 返回小于0
  • 等于返回 0
  • num是指比较字节个数

memcmp函数与字符串函数里的strncmp功能很类似,前者是通过比较字节大小,后者是比较字符大小。

int main()
{int arr1[] = { 1, 2, 5 };int arr2[] = { 1, 2, 6 };printf("%d \n", memcmp(arr1, arr2, 8));return 0;
}

arr1前12个字节:

01 00 00 00 02 00 00 00 05 00 00 00

arr2前12个字节

01 00 00 00 02 00 00 00 06 00 00 00

试图比较前8个字节的大小时,返回的结果是0,每个字节上的内容都是相等的,而 memcmp(arr1, arr2, 9);,比较前9个字节大小时,将返回小于0的数字, 06 > 05 。

cmp(arr1, arr2, 8));
return 0;
}
arr1前12个字节:

01 00 00 00 02 00 00 00 05 00 00 00

arr2前12个字节

01 00 00 00 02 00 00 00 06 00 00 00

试图比较前8个字节的大小时,返回的结果是0,每个字节上的内容都是相等的,而 memcmp(arr1, arr2, 9);,比较前9个字节大小时,将返回小于0的数字, 06 > 05 。

在这里插入图片描述

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

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

相关文章

Python与自动化脚本编写

Python与自动化脚本编写 Python因其简洁的语法和强大的库支持&#xff0c;成为了自动化脚本编写的首选语言之一。在这篇文章中&#xff0c;我们将探索如何使用Python来编写自动化脚本&#xff0c;以简化日常任务。 一、Python自动化脚本的基础 1. Python在自动化中的优势 Pyth…

1.31、基于长短记忆网络(LSTM)的发动机剩余寿命预测(matlab)

1、基于长短记忆网络(LSTM)的发动机剩余寿命预测的原理及流程 基于长短期记忆网络(LSTM)的发动机剩余寿命预测是一种常见的机器学习应用&#xff0c;用于分析和预测发动机或其他设备的剩余可用寿命。下面是LSTM用于发动机剩余寿命预测的原理和流程&#xff1a; 数据收集&#…

【Linux】 GCC/G++与Makefile使用

Linux GCC/G使用 GCC如何完成 格式&#xff1a;gcc [选项] 要编译的文件 [选项] [目标文件] 常用选项&#xff1a; -E&#xff1a;让gcc在预处理结束后停止编译过程&#xff0c;输出.i的C语言原始文件。-S&#xff1a;该选项只是进行编译而不是进行汇编&#xff0c;最终生成汇…

力扣144题:二叉树的先序遍历

给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,2,3]示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[]示例 3&#xff1a; 输入&#xff1a;root [1] 输出&am…

C++入门学习——初始化列表

概念 初始化列表&#xff1a;以一个冒号开始&#xff0c;接着是一个以逗号分隔的数据成员列表&#xff0c;每个"成员变量"后面跟一个放在括 号中的初始值或表达式 class Date { public://初始化列表Date(int year,int month,int day):_year(year),_month(month),_d…

[Windows] 油.管视频下载神器 Gihosoft TubeGet Pro v9.3.88

描述 对于经常在互联网上进行操作的学生&#xff0c;白领等&#xff01; 一款好用的软件总是能得心应手&#xff0c;事半功倍。 今天给大家带了一款高科技软件 管视频下载神器 无需额外付费&#xff0c;永久免费&#xff01; 亲测可运行&#xff01;&#xff01; 内容 目前主…

高德地图显示圆形区域并在区域边上标注半径

bug&#xff1a;循环创建三个圆形区域 &#xff0c;数组设置为[{raduis:500,color:“#FF0000”}]&#xff0c;然后循环取颜色会莫名其妙报错修改为 strokeColor: [“#FF0000”, “#1EE3C2”, “#3772E9”][i]即可 initAMap() {AMapLoader.load({key: "130cca3be68a2ff0fd5…

记VMware网络适配器里的自定义特定虚拟网络一直加载问题解决办法

1、问题描述 VMware网络适配器里的自定义特定虚拟网络一直加载问题&#xff1a; 在自定义&#xff1a;特定虚拟网络选择的时候 没有上图所示的三个选择&#xff0c;而是正在加载虚拟网络.... 如下图所示&#xff1a; 2、解决办法 2.1、原因分析&#xff1a; 是安装时候出现…

安防视频监控/视频汇聚EasyCVR平台浏览器http可以播放,https不能播放,如何解决?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台基于云边端一体化架构&#xff0c;兼容性强、支持多协议接入&#xff0c;包括国标GB/T 28181协议、部标JT808、GA/T 1400协议、RTMP、RTSP/Onvif协议、海康Ehome、海康SDK、大华SDK、华为SDK、宇视SDK、乐橙SDK、萤石云SD…

7.15洛谷蓝题

二分答案的两个模板&#xff1a; 1.最小值的最大化&#xff1a; #define _CRT_SECURE_NO_WARNINGS 1 #include<bits/stdc.h> #include<iostream> #include<algorithm> #include<cstring> #include<vector> #include<queue> #include<…

Studying-代码随想录训练营day40| 198.打家劫舍、213.打家劫舍II、337.打家劫舍III

第40天&#xff0c;动态规划part07&#xff0c;动态规划经典题型“打家劫舍”(ง •_•)ง&#xff0c;编程语言&#xff1a;C 目录 198.打家劫舍 213.打家劫舍II 337.打家劫舍III 总结 198.打家劫舍 文档讲解&#xff1a;代码随想录打家劫舍 视频讲解&#xff1a;手…

【C++进阶学习】第七弹——AVL树——树形结构存储数据的经典模块

二叉搜索树&#xff1a;【C进阶学习】第五弹——二叉搜索树——二叉树进阶及set和map的铺垫-CSDN博客 目录 一、AVL树的概念 二、AVL树的原理与实现 AVL树的节点 AVL树的插入 AVL树的旋转 AVL树的打印 AVL树的检查 三、实现AVL树的完整代码 四、总结 前言&#xff1a…

JavaScript青少年简明教程:输入输出

JavaScript青少年简明教程&#xff1a;输入输出 JavaScript的输入输出情况相对复杂&#xff0c;因为它依赖于其运行的宿主环境&#xff08;如Web浏览器或Node.js&#xff09;来提供具体的输入输出机制。JavaScript的核心规范&#xff08;ECMAScript&#xff09;本身并不直接提…

C基础day9

一、思维导图 二、课后练习 1> 使用递归实现 求 n 的 k 次方 #include<myhead.h>int Pow(int n,int k) {if(k 0 ) //递归出口{return 1;}else{return n*Pow(n,k-1); //递归主体} }int main(int argc, const char *argv[]) {int n0,k0;printf("请输入n和k:&…

韩国coupang上线的卖家官网是什么?韩国电商有哪些平台?

根据Statista的调查报告&#xff0c;预计2024年电子商务市场收入将达到4.117亿美元。而韩国的电子商务市场是全球最具活力和创新性的市场之一&#xff0c;有数据显示2023年韩国电商市场规模已突破1700亿美元&#xff0c;全球排名第四。 韩国coupang上线的卖家官网是什么&#x…

Linux虚拟机扩展磁盘空间

文章目录 在VM上进行扩展新的磁盘空间进入虚拟机将扩展的磁盘空间分配给对应的分区 VM 下的Linux虚拟机提示磁盘空间不足&#xff0c;需要对其进行磁盘扩容&#xff0c;主要有以下两步&#xff1a; 在VM上进行扩展新的磁盘空间 先关闭虚拟机在VM的虚拟机设置处进行硬盘扩展 …

Redislnsight-v2远程连接redis

redis安装内容添加&#xff1a; Linux 下使用Docker安装redis-CSDN博客 点击添加 添加ip地址&#xff0c;密码&#xff0c;端口号 创建完成 点击查看内容&#xff1a;

Redis的单线程讲解与指令学习

目录 一.Redis的命令 二.数据类型 三.Redis的key的过期策略如何实现&#xff1f; 四.Redis为什么是单线程的 五.String有关的命令 Redis的学习专栏&#xff1a;http://t.csdnimg.cn/a8cvV 一.Redis的命令 两个基本命令 在Redis当中&#xff0c;有两个基本命令&#xff1…

记录些MySQL题集(3)

MySQL 分区技术深入解析 分区的基本概念 MySQL分区 是一种数据库优化的技术&#xff0c;它允许将一个大的表、索引或其子集分割成多个较小的、更易于管理的片段&#xff0c;这些片段称为“分区”。每个分区都可以独立于其他分区进行存储、备份、索引和其他操作。这种技术主要…

Docker初识及使用研究

公司使用docker&#xff0c;小组成员人人都是默默使用&#xff0c;也没讲解培训&#xff0c;真是搞笑。 记录自己独自研究及使用&#xff1a; 1)自己安装->失败-系统弄崩->安装成功 目录 1. Docker安装-初次安装失败2. Docker安装-初次安装成功 1. Docker安装-初次安装失…