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

在这里插入图片描述
前言

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


内存函数的应用

  • 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

在这里插入图片描述

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

day05_用户管理minIO角色分配(页面制作,查询用户,添加用户,修改用户,删除用户,用户头像,查询所有角色,保存角色数据)

文章目录 1 用户管理1.1 页面制作1.2 查询用户1.2.1 需求说明1.2.2 后端接口需求分析SysUserSysUserDtoSysUserControllerSysUserServiceSysUserMapperSysUserMapper.xml 1.2.3 前端对接实现思路sysUser.jssysRole.vue 1.3 添加用户1.3.1 需求说明1.3.2 页面制作1.3.3 后端接口…

C语言题目:指针

1. 下面代码的结果是&#xff1a; #include <stdio.h> int i; int main() {i--;if (i > sizeof(i)){printf(">\n");}else{printf("<\n");}return 0; }答案&#xff1a;> 解析&#xff1a; i作为全局变量且在未赋值的情况下初始值为1&…

每日一练:LeeCode-701、二叉搜索树中的插入操作【二叉搜索树+DFS+全搜】

本文是力扣 每日一练&#xff1a;LeeCode-701、二叉搜索树中的插入操作【二叉搜索树DFS全搜】学习与理解过程&#xff0c;本文仅做学习之用&#xff0c;对本题感兴趣的小伙伴可以出门左拐LeeCode。 给定二叉搜索树&#xff08;BST&#xff09;的根节点 root 和要插入树中的值 …

看视频,学习使用MindOpt APL 建模语言编码数学规划问题,练习语法,实战拿奖品

活动介绍 活动名称&#xff1a;看视频&#xff0c;补充代码&#xff0c;拿精美礼品 活动规则&#xff1a; 浏览视频学习MAPL&#xff0c;完善“例题”。需要完善的内容&#xff1a;补充约束条件、读取csv表格数据&#xff0c;将决策变量的取值输出为csv表格&#xff0c;验证一…

pyuic生成py文件到指定文件夹

pyuic生成py文件到指定文件夹 关于如何在pycharm配置外部工具的方法这里不做赘述&#xff0c;本文主要说明&#xff0c;如何利用pyuic将ui文件生成到指定的项目目录中。 前提条件&#xff1a;已配置的pyuic工具可以正常使用生成文件到目录中。 一、打开外部工具配置页面 打开…

Java注解之@PathVariable,一文掌握@PathVariable注解知识(2)

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

Office/WPS 好用的PPT插件-智能选择布局

软件介绍 PPT大珩助手是一款全新设计的Office PPT插件&#xff0c;它是一款功能强大且实用的PPT辅助工具&#xff0c;能够轻松帮助您修改、优化和管理幻灯片。凭借丰富的功能和用户友好的界面&#xff0c;PPT大珩助手能够助力您打造出精美而专业的演示文稿。我们致力于为用户提…

“平民化”非结构数据处理

在全球信息产业高速发展的背景下&#xff0c;IDC预测&#xff0c;2018 到 2025 年之间&#xff0c;全球产生的数据量将会从 33 ZB 增长到 175 ZB&#xff0c; 复合增长率27%&#xff0c;其中超过 80%的数据都会是处理难度较大的非结构化数据&#xff0c;如文档、文本、图形、图…

【数据分享】2000~2023年MOD15A2H 061 叶面积指数LAI数据集

各位同学们好&#xff0c;今天和大伙儿交流的是2000~2013年MOD15A2H 061 LAI数据集。如果大家有下载处理数据等方面的问题&#xff0c;您可以私信或评论。 Myneni, R., Y. Knyazikhin, T. Park. MODIS/Terra Leaf Area Index/FPAR 8-Day L4 Global 500m SIN Grid V061. 2021, d…

RK3568平台开发系列讲解(基础篇)互斥锁实验

🚀返回专栏总目录 文章目录 一、互斥锁二、驱动案例沉淀、分享、成长,让自己和他人都能有所收获!😄 一、互斥锁 互斥锁为资源引入一个状态:锁定或者非锁定。某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将…

C++ //练习 10.7 下面的程序是否有错误?如果有,请改正。

C Primer&#xff08;第5版&#xff09; 练习 10.7 练习 10.7 下面的程序是否有错误&#xff1f;如果有&#xff0c;请改正。 (a) vector<int>vec; list<int> lst; int i;while(cin>>i)lst.push_back(i);copy(lst.cbegin(), lst.cend(), vec.begin());(b) …

第三百七十三回

文章目录 1. 概念介绍2. 实现方法2.1 基本用法2.2 特殊用法 3. 示例代码4. 内容总结 我们在上一章回中介绍了"分享三个使用TextField的细节"相关的内容&#xff0c;本章回中将介绍如何让Text组件中的文字自动换行.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1.…

Redis性能攻略:Redis-benchmark工具与实用性能优化技巧

Redis作为一种高性能的内存数据库&#xff0c;广泛应用于各种业务场景。然而&#xff0c;随着业务规模的扩大和数据量的增长&#xff0c;Redis的性能问题逐渐凸显出来。为了提高Redis的性能&#xff0c;本文将深入探讨Redis性能优化方案&#xff0c;包括参数配置、数据结构、多…

华为HarmnyOS TypeScript基础语法快速入门

华为HarmnyOS TypeScript基础语法快速入门 一、JavaScript、TypeScript、ArkTS二、TypeScript基础语法1. 基础类型2. 条件语句3. 函数4. 类5. 模块6. 迭代器 一、JavaScript、TypeScript、ArkTS ArkTS是HarmonyOS优选的主力应用开发语言。它在TypeScript&#xff08;简称TS&am…

js方法 提前结束循环

http://t.csdnimg.cn/j0gkOhttp://t.csdnimg.cn/j0gkO 一、各种循环方法如何跳出整个循环&#xff1f; 对于forEach()方法&#xff0c;目前似乎没有比较优雅的跳出整个循环的方法&#xff0c;如果你实在要用forEach()方法并且需要在某种条件下跳出整个循环提高遍历效率&#x…

react路由基础

1.目录 A. 能够说出React路由的作用 B. 能够掌握react-router-dom的基本使用 C. 能够使用编程式导航跳转路由 D. 能够知道React路由的匹配模式 2.目录 A. React路由介绍 B. 路由的基本使用 C. 路由的执行过程 D. 编程式导航 E. 默认路由 F. 匹配模式 3.react路由介绍 现代…

[Vulnhub]靶场 Web Machine(N7)

kali:192.168.56.104 主机探测: arp-scan -l 靶机ip:192.168.56.104 端口扫描 nmap -p- 192.168.56.106 看一下web 目录扫描 gobuster dir -u http://192.168.56.106 -x html,txt,php,bak,zip --wordlist/usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt exp…

R语言数据可视化之美专业图表绘制指南(增强版):第1章 R语言编程与绘图基础

第1章 R语言编程与绘图基础 目录 第1章 R语言编程与绘图基础前言1.1 学术图表的基本概念1.1.1 学术图表的基本作用1.1.2基本类别1.1.3 学术图表的绘制原则 1.2 你为什么要选择R1.3 安装 前言 这是我第一次在博客里展示学习中国作者的教材的笔记。我选择这本书的依据是作者同时…

认识通讯协议——TCP/IP、UDP协议的区别,HTTP通讯协议的理解

目录 引出认识通讯协议1、TCP/IP协议&#xff0c;UDP协议的区别2、HTTP通讯协议的讲解 Redis冲冲冲——缓存三兄弟&#xff1a;缓存击穿、穿透、雪崩缓存击穿缓存穿透缓存雪崩 总结 引出 认识通讯协议——TCP/IP、UDP协议的区别&#xff0c;HTTP通讯协议的理解 认识通讯协议 …

【脑切片图像分割】MATLAB 图像处理 源码

1. 简单图像处理 加载图像 Brain.jpg&#xff0c;使用直方图和颜色分割成区域这些区域有不同的颜色。 这是一个更高级的问题&#xff0c;有多个解决它的方法。 例如&#xff0c;您可以计算具有特定数字的图像的直方图&#xff08;例如 16 - 32&#xff09;&#xff0c;找到直方…