【进阶C语言】内存函数(详解)

news2024/11/25 16:04:09

在这里插入图片描述
前言

上一期讲的函数都是和字符串相关的,但是我们在操作数据的时候,不仅仅是操作字符串的数据,还得需要内存函数的应用


内存函数的应用

  • 1. memcpy
    • 1.1 memcpy的介绍
    • 1.2 memcpy的使用
    • 1.3 模拟实现memcpy库函数
    • 1.4 我想在1,2后面打印1,2,3,4,5会怎么样?
  • 2. memmove
    • 2.1 memmove的介绍
    • 2.2 memmove的使用
    • 2.3 模拟实现memmove库函数
  • 3. memcmp
    • 3.1 memcmp的介绍
    • 3.2 memcmp的使用
  • 4. memset
    • 4.1 memset的介绍
    • 4.2 memset的使用

1. memcpy

1.1 memcpy的介绍

void * memcpy ( void * destination, const void * source, size_t num );
  1. 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
  2. 这个函数在遇到 ‘\0’ 的时候并不会停下来。
  3. 如果source和destination有任何的重叠,复制的结果都是未定义的。

1.2 memcpy的使用

用代码举例:

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[8] = { 0 };
	//把arr1中的前5个数据拷贝到arr2中
	memcpy(arr2, arr1, 20);//strcpy不能用,它只针对字符串拷贝,而上面的是整型数据
	return 0; 
}

在这里插入图片描述
试试浮点型看看可不可以:

int main()
{
	float arr1[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
	float arr2[8] = { 0 };
	//把arr1中的前5个数据拷贝到arr2中
	memcpy(arr2, arr1, 12);
	return 0; 
}

在这里插入图片描述

从中发现memcpy它并不在乎整型还是浮点型,所以叫他内存拷贝

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

在分析一下上面的信息:
void* – 通用类型的指针,可以接受任意类型数据的地址,但是这种指针不能直接解引用和加减运算!
memcpy函数的设计者,不知道未来程序员使用memcpy拷贝什么类型的数据!
size_t num 表示拷贝多少个字节

1.3 模拟实现memcpy库函数

//memcpy函数返回的是目标空间的起始地址
#include <assert.h>

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;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[8] = { 0 };
	//把arr1中的前5个数据拷贝到arr2中
	my_memcpy(arr2, arr1, 20);
	return 0; 
}

调试监视结果如下:

在这里插入图片描述

1.4 我想在1,2后面打印1,2,3,4,5会怎么样?

#include <assert.h>

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;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	//   你先打印  1 2 1 2 3 4 5 8 9 10
	//   结果却是  1 2 1 2 1 2 1 8 9 10
	
	my_memcpy(arr1 + 2, arr1, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
}

在这里插入图片描述
红色框框:目标空间
绿色框框:想要拷贝的原数据

结论:
所以我们发现:在内存重叠的时候,使用memcpy可能会出现意想不到的结果
建议在内存重叠的情况,使用memmove函数.

2. memmove

2.1 memmove的介绍

void * memmove ( void * destination, const void * source, size_t num );
  1. 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
  2. 如果源空间和目标空间出现重叠,就得使用memmove函数处理。

2.2 memmove的使用

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	//   你先打印  1 2 1 2 3 4 5 8 9 10
	//   结果却是  1 2 1 2 3 4 5 8 9 10
	//说明没有问题
	
	memmove(arr1 + 2, arr1, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
}

代码结果:
在这里插入图片描述

2.3 模拟实现memmove库函数

在这里插入图片描述
红色框框:目标空间
蓝色框框:想要拷贝的原数据
在这里插入图片描述
当dest在src前面,也就是dest的地址更低,src的地址更高的时候
在这里插入图片描述
整个图片概念图:
在这里插入图片描述
从而有两种方案,综合比较,B方案效果更好
在这里插入图片描述
B方案图片解释:
在这里插入图片描述
代码样子:

if (dest < src)
{


	//前->后



}
else
{

	//后->前


}

完整版代码:

//memcpy函数返回的是目标空间的起始地址
#include <assert.h>

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

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

总结:
C语言:memcpy拷贝不重叠的内存
重叠的就交给memmove
memmove > memcpy 100 60
VS:100 100

3. memcmp

3.1 memcmp的介绍

int memcmp ( const void * ptr1,  const void * ptr2,  size_t num );
  1. 比较从ptr1和ptr2指针开始的num个字节
  2. 返回值如下:在这里插入图片描述

3.2 memcmp的使用

int main()
{
	int arr1[] = { 1,2,3,4,5 };//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00
	int arr2[] = { 1,2,3,4,6 };//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 06 00 00 00
	int ret = memcmp(arr1, arr2, 17);
	printf("%d\n", ret);
}

代码结果:
在这里插入图片描述

4. memset

4.1 memset的介绍

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

将 ptr 指向的内存块的第一个字节数设置为指定值(解释为无符号字符)。

4.2 memset的使用

int main()
{
	char arr[] = "hello world";//以字节为单位来进行设置的
		memset(arr, 'x', 5);
		printf("%s\n", arr);
}

代码结果:
在这里插入图片描述
注意:memset是以字节为单位来进行设置的!!
什么意思呢?

int main()
{
	int arr[10] = { 0 };
	//01 01 01 01
	memset(arr, 1, sizeof(arr));//这种写法无法将数据的每个元素设置为1
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%x ", arr[i]);
	}
}

体会代码结果:

这种写法无法将数据的每个元素设置为1

在这里插入图片描述

如果这份博客对大家有帮助,希望各位给恒川一个免费的点赞作为鼓励,并评论收藏一下,谢谢大家!!!
制作不易,如果大家有什么疑问或给恒川的意见,欢迎评论区留言。

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

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

相关文章

Ubuntu开启SSH免密登录

Ubuntu开启SSH免密登录 要实现SSH免密登录&#xff0c;首先需要准备一组公钥和私钥。将公钥放到服务器上&#xff0c;将私钥放到客户机上。当客户机连接服务器时&#xff0c;服务器会根据自身的公钥校验客户机的私钥&#xff0c;如果校验通过则允许连接。 一、创建密钥 在客…

(Linux)Centos7.*版本安装配置Java环境、Tomcat、Nginx并打包部署SSM框架web系统

目录 一、准备软件与安装包 (一)、必须的软件 1、点击下载Xshell 2、点击下载FileZilla (二)、准备安装包 1、点击下载JDK1.8Linux版本 2、点击下载Nginx 3、点击下载Tomcat 二、关于FileZilla软件的使用说明 (一)、FileZilla软件的打开和说明 (二)、配置服务器地…

什么是FIFO?

同步FIFO和异步FIFO 1、FIFO定义 FIFO是英文First In First Out的缩写&#xff0c;是一种先进先出的数据缓存器&#xff0c;他与普通存储器的区别是没有外部读写地址线&#xff0c;这样使用起来非常简单&#xff0c;但缺点就是只能顺序写入数据&#xff0c;顺序的读出数据&am…

C++修炼之筑基期第三层——拷贝构造函数

文章目录 &#x1f490;专栏导读&#x1f490;文章导读&#x1f337;拷贝构造函数的概念&#x1f337;拷贝构造函数的特性 &#x1f490;专栏导读 &#x1f338;作者简介&#xff1a;花想云&#xff0c;在读本科生一枚&#xff0c;致力于 C/C、Linux 学习。 &#x1f338;本文…

Rocky9/Centos stream9 修改静态ip,修改网卡。

目录 需求&#xff1a; 修改ipv4地址为10.10.10.10 子网掩码为255.255.255.0 网关为10.10.10.254 dns为本机ip 当前版本&#xff1a; 前言&#xff1a; 正文&#xff1a; 后续其他方法拓展。 本人新建立一个QQ shell群&#xff0c;感兴趣的可以加入&#xff1a;637257233 …

瑞数5.5逆向笔记(纯扣算法)

瑞数5解密 首先看请求,请求返回202大概率是(瑞数3,4).返回412是瑞数5 还可以看后缀值 MmEwMD4xxxxx 就是4代瑞数&#xff0c;bX3Xf9nD5xxxxx 就是5代瑞数 区别4带上来有1-2个无限debugger,这个直接过掉就好,还会有一个假cookie,5带没有 1.meta content 动态的每次请求都会变…

IDEA如何运行SSM项目(超详细图解)

&#x1f4d6;本篇超级详细案例截图教学 IDEA如何运行SSM(Maven工程)项目&#xff0c;图片点击可放大仔细看 1、查看项目 项目里面一般会包含项目源码、数据库、环境配置教程、运行教程。 项目介绍文件有的是.md文件&#xff0c;这个需要记事本或者typora打开&#xff0c;wor…

【瑞吉外卖开发笔记】

瑞吉外卖开发笔记 源码地址 一、业务开发Day01 1、软件开发整体介绍 软件开发流程 角色分工 软件环境 2、瑞奇外卖项目介绍 项目介绍 产品原型展示 技术选型 功能架构 角色 3、环境搭建 开发环境搭建 数据库环境搭建 运行对应db_reggie.sql文件Maven项目搭建 新建Springb…

毫米波雷达(mmWave)基本原理

1. 引言 毫米波&#xff08;mmWave&#xff09;是一种特殊的雷达技术&#xff0c;它使用短波长的电磁波。雷达系统发射电磁波信号&#xff0c;然后其路径上的物体将它反射回去。通过捕捉反射信号&#xff0c;雷达系统可以确定目标的距离、速度和角度。毫米波雷达发射的信号波长…

函数(2)

文章目录 6. 函数的嵌套调用和链式访问6.1 嵌套调用6.2 链式访问 7. 函数的声明和定义7.1 函数声明7.2 函数定义 8. 函数递归8.1 什么是递归8.2 递归的两个必要条件8.3 递归与迭代 附&#xff1a; 6. 函数的嵌套调用和链式访问 6.1 嵌套调用 #include <stdio.h>int tes…

基于Python的学生成绩管理系统

末尾获取源码 开发语言&#xff1a;python 后端框架&#xff1a;django 数据库&#xff1a;MySQL5.7 开发软件&#xff1a;Pycharm 是否Maven项目&#xff1a;是 目录 一、项目简介 二、系统功能 三、系统项目截图 四、核心代码 4.1登录相关 4.2文件上传 4.3封装 一、项…

12.软考——数据流图

数据流图分层 数据字典 数据流图平衡原则 考试必问根据顶层数据流图补充0层数据流图中缺失的数据流图。 1.父图与子图之间的平衡 主要看系统和外部的联系是否缺失,比如上图数据管理中间件--------->前端应用中的处理后的操作结果这个数据流缺失。 2.子图内平衡 正常的加…

1123 Is It a Complete AVL Tree(72行代码+超详细注释)

1123 Is It a Complete AVL Tree 分数 30 全屏浏览题目 作者 CHEN, Yue 单位 浙江大学 An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; if at any time they differ by…

【原创】ChatGPT访问及内容安全技术设计

作者&#xff1a;黑夜路人 时间&#xff1a;2023/5/15 作为爆火的AIGC产品ChatGPT&#xff0c;以及类似的产品 Cluade、Bard、Newbing 等等&#xff0c;让大家趋之若鹜&#xff0c;如何把这些产品映射到自己的业务产品中&#xff0c;也是很多开发者需要面对的问题。 针对AIGC&…

Prompt工程师指南[从基础到进阶篇]:用于开发和优化提示,以有效地使用语言模型(LMs)进行各种应用和研究主题

Prompt工程师指南[从基础到进阶篇]&#xff1a;用于开发和优化提示&#xff0c;以有效地使用语言模型&#xff08;LMs&#xff09;进行各种应用和研究主题 Prompt工程是一种相对较新的学科&#xff0c;用于开发和优化提示&#xff0c;以有效地使用语言模型&#xff08;LMs&…

基于卷积的图像分类识别(二):ZFNet

本专栏介绍基于深度学习进行图像识别的经典和前沿模型&#xff0c;将持续更新&#xff0c;包括不仅限于&#xff1a;AlexNet&#xff0c; ZFNet&#xff0c;VGG&#xff0c;GoogLeNet&#xff0c;ResNet&#xff0c;DenseNet&#xff0c;SENet&#xff0c;MobileNet&#xff0c…

LitCTF2023 Reverse 题解及复现

文章目录 一.enbase641.main函数2.换表函数3. check函数4. 解题脚本: 二.snake1. 修复MagicNumber2. 反编译3. 解题脚本 三.For Aiur1. 注意点2. 解包3. 反编译4. 解题脚本 四.程序和人有一个能跑就行了1. fakeflag2. 真flag 五.debase641. encode函数2. 函数逻辑3. 根据程序逻…

PCIe事务层(详细)总结-PCIe专题知识(六)

目录 前言一、简介二、事务层数据传输三、数据格式四、其他相关链接1、PCIe物理层总结-PCIE专题知识&#xff08;一&#xff09;2、PCIe数据链路层图文总结-PCIe专题知识&#xff08;二&#xff09;3、PCIe物理层链路训练和初始化总结-PCIe专题知识&#xff08;三&#xff09;4…

SpringCloud:微服务保护之规则持久化

现在&#xff0c;sentinel的所有规则都是内存存储&#xff0c;重启后所有规则都会丢失。在生产环境下&#xff0c;我们必须确保这些规则的持久化&#xff0c;避免丢失。 1.规则管理模式 规则是否能持久化&#xff0c;取决于规则管理模式&#xff0c;sentinel支持三种规则管理…

基于卷积的图像分类识别(一):AlexNet

本专栏介绍基于深度学习进行图像识别的经典和前沿模型&#xff0c;将持续更新&#xff0c;包括不仅限于&#xff1a;AlexNet&#xff0c; ZFNet&#xff0c;VGG&#xff0c;GoogLeNet&#xff0c;ResNet&#xff0c;DenseNet&#xff0c;SENet&#xff0c;MobileNet&#xff0c…