C语言之内存函数

C语言之内存函数

文章目录

  • C语言之内存函数
    • 1. memcpy 使⽤和模拟实现
      • 1.1 memcpy 函数的使用
      • 1.3 memcpy的模拟实现
    • 2. memmove 使⽤和模拟实现
      • 2.1 memmove 函数的使用
      • 2.2 memmove的模拟实现
    • 3. memset 函数的使用
    • 4. memcmp 函数的使⽤

1. memcpy 使⽤和模拟实现

函数声明如下:

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

memcpy函数和strncpy函数很相似,

  1. 只不过strncpy函数只能处理字符数组,而memcpy函数可以处理任意类型的数据
  2. strncpy函数会在目标字符数组结尾添加’\0’,而memcpy函数则不会
  3. 都在string.h库函数中

1.1 memcpy 函数的使用

代码一:
将arr1中的1 2 3 4 5 拷贝到arr2中

#include <stdio.h>
#include <string.h>
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[20] = { 0 };memcpy(arr2, arr1, 5*sizeof(int));int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr2[i]);}return 0;
}

代码运行结果如下:
在这里插入图片描述

memcpy函数有三个参数

  1. 参数一为需要拷贝的目标地址
  2. 参数二为拷贝数据来源的地址
  3. 参数三为需要拷贝的字节大小
    在上述代码中,传给了memcpy函数20个字节的大小
    因为整型是4个字节,所以只会拷贝前5个数据

代码二:
将arr1中的4 5 6 7 8拷贝到arr2中

#include <stdio.h>
#include <string.h>
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[20] = { 0 };memcpy(arr2, arr1+3, 5*sizeof(int));int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr2[i]);}return 0;
}

在这里插入图片描述

代码三:
将arr1中的字符串拷贝到arr2中

#include <stdio.h>
#include <string.h>
int main()
{char arr1[] = "Hello \0World!";char arr2[20] = { 0 };memcpy(arr2, arr1, 13);int i = 0;for (i = 0; i < 13; i++){printf("%c", arr2[i]);}return 0;
}

代码运行结果如下:
在这里插入图片描述
memcpy函数在拷贝数据时,遇到\0时不会停下来

代码四:
将arr中的 1 2 3 4 5 拷贝到arr中4 5 6 7 8的位置上

#include <stdio.h>
#include <string.h>
int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };memcpy(arr + 3, arr, 5 * sizeof(int));int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}

在这里插入图片描述

由于空间重叠了,当改dest的第三个元素时,src的第三个元素已经被改成了1,使用dest第三个元素为1,第四个同理,为2,所以使用memcpy无法拷贝重复的空间

在VS2022中可以实现
在这里插入图片描述
但是
C语言中规定:
memcpy拷贝的就是不重复的数据
重复的数据交给memmove

在VS2022中,memcpy是可以拷贝重复部分的数据的,在C语言中规定的memcpy功能可能只有60分,但是VS2022中可能将其提升到了100分

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

1.3 memcpy的模拟实现

void *memcpy(void *dest, const void *src, size_t n);

思路:

  1. 由于memcpy要处理不同类型的数据,所以第一个参数和第二个参数得是void类型的,void类型的指针可以接收任意类型的地址
  2. 由于不确定传进来的是什么数据,只知道需要拷贝多少字节,在函数内部可以将其强制类型转换为char*类型的指针,一个字节一个字节拷贝
  3. 函数返回值为dest的地址,所以为void*

实现代码如下:

#include <stdio.h>
#include <assert.h>void* my_memcpy(void* dest, const void* src, size_t num)
{char* ret = dest;assert(dest && src); //assert断言,判断传入的地址是否为空指针while (num--)   //一个字节一个字节拷贝{*(char*)dest = *(char*)src; //void*类型不能解引用,并且需要一个字节一个字节的拷贝,所以强制类型转换为char*类型dest = (char*)dest + 1; //强制类型转换是临时的,再次强制类型转换并+1找到下一个需要交换的地址src = (char*)src + 1;}return ret;  //返回dest的地址
}int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[20] = { 0 };my_memcpy(arr2, arr1, 5 * sizeof(int));int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr2[i]);}return 0;

2. memmove 使⽤和模拟实现

函数声明如下:

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

• 和memcpy的差别就是memmove函数处理的源内存块和⽬标内存块是可以重叠的

• 如果源空间和⽬标空间出现重叠,就得使⽤memmove函数处理。

2.1 memmove 函数的使用

将arr中的 1 2 3 4 5 拷贝到arr中4 5 6 7 8的位置上

#include <stdio.h>
#include <string.h>
int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };memcpy(arr + 3, arr, 5 * sizeof(int));int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}

代码运行结果如下:
在这里插入图片描述

2.2 memmove的模拟实现

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

思路:

  1. 由于memmove也要处理不同类型的数据,所以第一个参数和第二个参数得是void类型的,void类型的指针可以接收任意类型的地址
  2. 由于不确定传进来的是什么数据,只知道需要拷贝多少字节,在函数内部可以将其强制类型转换为char*类型的指针,一个字节一个字节拷贝
  3. 函数返回值为dest的地址,所以为void*
  4. dest 和 src 会有两种关系
    1.dest 在 src 左边
    2.dest 在 src 右边

情况一:
在这里插入图片描述

上述情况,虽然有重叠的空间,但是还是可以拷贝,实现方式和memcpy一样

情况二:

在这里插入图片描述

在上述代码中,出现了重叠的空间,如果正序交换的话,后面的内容被覆盖了,无法交换,所以我们换种方式交换,逆序交换
在这里插入图片描述
这样交换,内容就不会被覆盖了

实现代码如下:

#include <stdio.h>
#include <assert.h>
void* my_memcpy(char* dest, const char* src, size_t num)
{char* ret = dest; assert(dest && src);   //assert断言if (dest < src)   //当dest在src左边时{while(num--)      //逻辑和memcpy一致{*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}}else             //dest在src右边{while (num--)  //一个字节一个字节拷贝{*((char*)dest + num) = *((char*)src + num); //找到最后一个字节然后拷贝 num--之后找到倒数第二个字节拷贝}}
}
int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };my_memcpy(arr + 3, arr, 5 * sizeof(int));int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}

3. memset 函数的使用

函数声明如下:

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

memset是⽤来设置内存的,将内存中的值以字节为单位设置成想要的内容
第一个参数是需要修改的地址
第二个参数是设置成什么内容
第三个参数是要设置的大小

#include <stdio.h>
#include <string.h>
int main()
{char arr[] = "abcdefghi";memset(arr, 'x', 5);printf("%s\n", arr);return 0;
}

代码运行结果:
xxxxxfghi

将前5个字节的元素改成了x

4. memcmp 函数的使⽤

函数声明如下:

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

和strncmp相似
都是⽐较从ptr1和ptr2指针指向的位置开始,向后的num个字节
返回值如下:
如果ptr1大于ptr2则返回一个大于零的值
如果ptr1小于ptr2则返回一个小于零的值
如果ptr1等于ptr2则返回一个零
在这里插入图片描述

#include <stdio.h>
#include <string.h>
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[] = { 1,2,3,4,9 };int ret = memcmp(arr1, arr2, 16);if (ret > 0)printf("大于\n");else if (ret < 0)printf("小于");elseprintf("等于\n");return 0;
}

代码运行结果:
等于

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

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

相关文章

《已解决: ImportError: Keras requires TensorFlow 2.2 or higher 问题》

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页: &#x1f405;&#x1f43e;猫头虎的博客&#x1f390;《面试题大全专栏》 &#x1f995; 文章图文并茂&#x1f996…

qt-C++笔记之不使用ui文件纯C++构建时控件在布局管理器作用下的默认位置和大小实践

qt-C笔记之不使用ui文件纯C构建时控件在布局管理器作用下的默认位置和大小实践 code review! 文章目录 qt-C笔记之不使用ui文件纯C构建时控件在布局管理器作用下的默认位置和大小实践1.ChatGPT解释2.ChatGPT——resize()和move()详解3.默认大小和位置——示例运行一4.默认大小…

excel表中慎用合并单元格,多用跨列居中

如下一个excel例表&#xff1a; 要将首行居中&#xff0c;最好的办法如下&#xff1a; 1、选中首行单元格 2、按下ctrl1&#xff0c;调出“设置单元格格式”&#xff0c;选中“对齐”&#xff0c;在“水平对齐”中选择“跨列居中” 3、完成任务 这样居中的好处是&#xff1a;可…

【NeRF】3、MobileR2L | 移动端实时的神经光场(CVPR2023)

论文&#xff1a;Real-Time Neural Light Field on Mobile Devices 代码&#xff1a;https://github.com/snap-research/MobileR2L 出处&#xff1a;CVPR2023 贡献&#xff1a; 设计了一套移动端实时的 R2L 网络结构 MobileR2L&#xff0c;在 iphone13 上渲染一张 1008x756…

RC-MVSNet:无监督的多视角立体视觉与神经渲染--论文笔记(2022年)

RC-MVSNet&#xff1a;无监督的多视角立体视觉与神经渲染--论文笔记&#xff08;2022年&#xff09; 摘要1 引言2 相关工作2.1 基于监督的MVS2.2 无监督和自监督MVS2.3 多视图神经渲染 3 实现方法3.1 无监督的MVS网络 Chang, D. et al. (2022). RC-MVSNet: Unsupervised Multi-…

帮管客CRM SQL注入漏洞复现

0x01 产品简介 帮管客CRM是一款集客户档案、销售记录、业务往来等功能于一体的客户管理系统。帮管客CRM客户管理系统&#xff0c;客户管理&#xff0c;从未如此简单&#xff0c;一个平台满足企业全方位的销售跟进、智能化服务管理、高效的沟通协同、图表化数据分析帮管客颠覆传…

【深度学习实验】图像处理(二):PIL 和 PyTorch(transforms)中的图像处理与随机图片增强

文章目录 一、实验介绍二、实验环境1. 配置虚拟环境2. 库版本介绍 三、实验内容0. 导入需要的工具包1. PIL图像处理a. 生成绿色和蓝色图像b. 缩放和合成图像c 在合成图像上添加文字d. 展示并保存图像 2. PIL随机图像增强a. 定义随机图像增强函数b. 实验结果展示 3. PyTorch&…

redis实现消息延迟队列

业务场景 在很多软件系统功能中都会出现定时任务的业务场景,比如提前点单,比如定时发布动态,文章等而出现这样的的定时的任务为延迟队任务 代码模块 任务的持久化一般都需要建立一个任务表和任务日志表,避免宕机导致任务失效,先新建立一个数据库,创建基本的任务表和任务日志表…

【MOJO】Modular语言安装和测试

目录 一、Mojo介绍 Linux​ Mac 二、安装Mojo SDK 三、mojo代码测试 3.1、在 REPL 中运行代码​ 3.2、构建并运行 Mojo 源文件​ 运行mojo文件​ 构建可执行二进制文件​ 四、VSCode安装 一、Mojo介绍 在学习Rust语言的过程中无意发现了Modular语言&#xff0c;语言…

nginx基础篇学习

一、nginx编译安装 1、前往nginx官网获取安装包 下载安装包 2、解压 3、安装 进入安装包 安装准备&#xff1a;nginx的rewrite module重写模块依赖于pcre、pcre-devel、zlib和zlib-devel库&#xff0c;要先安装这些库 安装&#xff1a; 编译&#xff1a; 启动&#xff…

web前端之vue和echarts的堆叠柱状图顶部显示总数、鼠标悬浮工具提示、设置图例的显示与隐藏、label、legend、tooltip

MENU 效果图htmlJavaScripstyle解析 效果图 html <template><div><div><div id"idStackedColumnChart" style"width: 100%; height: 680px"></div></div></div> </template>JavaScrip export default {…

python-opencv轮廓检测(外轮廓检测和全部轮廓检测,计算轮廓面积和周长)

python-opencv轮廓检测&#xff08;外轮廓检测和全部轮廓检测&#xff0c;计算轮廓面积和周长&#xff09; 通过cv2.findContours&#xff0c;我们可以进行轮廓检测&#xff0c;当然也有很多检测模式&#xff0c;我们可以通过选择检测模式&#xff0c;进行外轮廓检测&#xff…

通过ros系统中websocket中发送sensor_msgs::Image数据给web端显示(二)

通过ros系统中websocket中发送sensor_msgs::Image数据给web端显示(二) mp4媒体流数据 #include <ros/ros.h> #include <signal.h> #include <sensor_msgs/Image.h> #include <message_filters/subscriber.h> #include <message_filters/synchroniz…

从零开始学习管道:管道程序的优化和文件描述符继承问题

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;Linux &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 本博客主要内容管道后续的完善&#xff0c;以及解决管道继承多个文件描…

【Amazon】基于Amazon提供的托管式EKS通过eksctl命令部署Kubernetes集群

文章目录 一、使用CloudFormation创建堡垒机二、安装AWS CLI命令行工具三、安装eksctl命令行工具四、创建集群角色4.1 集群服务角色创建4.2 集群节点组角色创建 五、创建 EKS集群六、登录EKS控制台七、参考链接 一、使用CloudFormation创建堡垒机 导航至CloudFormation&#xf…

python类和对象

1.使用对象组织数据 class Student:nameNone #记录名字 stu1Student() #创建对象 stu1.name"abc" #为对象属性赋值2.类的定义和使用 2.1成员方法的定义语法 传参的时候self是透明的&#xff0c;不用管 class Stu:nameNonedef sayHi(self):print(f"你好&#x…

【数据中台】开源项目(1)-LarkMidTable

LarkMidTable 是一站式开源的数据中台&#xff0c;实现中台的 基础建设&#xff0c;数据治理&#xff0c;数据开发&#xff0c;监控告警&#xff0c;数据服务&#xff0c;数据的可视化&#xff0c;实现高效赋能数据前台并提供数据服务的产品。 系统演示地址 &#xff1a; www.l…

Windows 7隐藏用户测试

请注意Window 7是在虚拟机上安装的&#xff0c;ip是192.168.0.108。 下边都是在虚拟机Window 7上操作&#xff0c;直到最后远程连接才在自己本机Windows 11上操作。 需要同时按下Windowsr,然后输入cmd&#xff0c;再点击确定。 在命令上里边输入net user可以显示一下用户。 …

C语言学习笔记之函数篇

与数学意义上的函数不同&#xff0c;C语言中的函数又称为过程&#xff0c;接口&#xff0c;具有极其重要的作用。教科书上将其定义为&#xff1a;程序中的子程序。 在计算机科学中&#xff0c;子程序&#xff08;英语&#xff1a;Subroutine, procedure, function, routine, me…

React 入门使用 (官方文档向 Part2)

文章目录 用 State 响应输入声明式地考虑 UI步骤 1&#xff1a;定位组件中不同的视图状态步骤 2&#xff1a;确定是什么触发了这些状态的改变步骤 3&#xff1a;通过 useState 表示内存中的 state步骤 4&#xff1a;删除任何不必要的 state 变量步骤 5&#xff1a;连接事件处理…