【C语言进阶(7)】内存函数 —— 使用方法 + 模拟实现

news2024/12/22 20:08:13

文章目录

  • 前言
  • Ⅰ 内存函数
    • ⒈memcpy
    • ⒉memmove
    • ⒊memcmp
    • ⒋memset
  • Ⅱ 模拟实现
    • ⒈模拟实现 memcpy
    • ⒉模拟实现 memmove
    • ⒊模拟实现 memcmp
    • ⒋模拟实现 memset

前言

内存操作函数的优势

  • 字符串函数只能操作字符串的内容,局限性很大。
  • 内存函数可以操作任意类型的数据,因为是直接对内存进行操作。

函数引用头文件

  • <string.h>

Ⅰ 内存函数

⒈memcpy

内存拷贝函数

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

函数参数

  • destination:指向要粘贴的目标空间的起始地址,类型转换为 void* 类型的指针。
  • source:指向要被拷贝的源头空间的起始地址,类型转换为 const void* 类型的指针。
  • num:要拷贝的字节数。

函数功能

  • 从 source 指向的目标空间拷贝 num 个字节的内容到 destination 的内存位置
  • memcpy 在遇到 \0 时不会停止。
  • 如果 source 和 destination 有任何内存上的的重叠,复制的结果都是未定义的。
  • strcpy 只能拷贝的对象只能是字符串,而 memcpy 直接拷贝内存中得内容,就使得 memcpy 能拷贝的数据类型变得更多。

返回值

  • 目标空间的起始地址

函数用例

#include <stdio.h>
#include <string.h>

int main()
{
	int i = 0;
	int arr1[10] = { 0 };
	int arr2[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr2) / sizeof(arr2[0]);

	memcpy(arr1, arr2, sz * sizeof(arr2[0]));
	//从 arr2 中拷贝 10 * 4 个字节的内容到 arr1 去

	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr1[i]);
	}
	putchar('\n');

	return 0;
}

在这里插入图片描述

不能处理内存重叠的情况

  • 如果源空间和目标空间在内存中出现重叠情况的话,拷贝的内容就会出现重叠的情况。
  • 此时就只能使用 memmove 函数了。

在这里插入图片描述
在这里插入图片描述

  • 可能会有人使用 memcpy 去尝试重叠拷贝,发现能够正确处理这种情况。
  • 在 C 语言中,memcpy 只处理不重叠的拷贝。在 VS 中,一旦在使用 memcpy 拷贝时发现重叠的情况,会自动将 memcpy 替换成 memmove

⒉memmove

处理内存重叠的情况

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

函数功能

  • 和 memcpy 的差别就是 memmove 函数处理的源内存块和目标内存块是可以重叠的。
  • 如果源空间和目标空间出现重叠,就得使用 memmove 函数处理。

函数用例

在这里插入图片描述

⒊memcmp

内存比较函数

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

函数功能

  • 比较 ptr1 和 ptr2 所指向空间的前 num 个字节的内容

函数返回值

  • 函数的返回值和 strcmp 的情况一样,在前 num 个字节里:
函数返回值说明
0ptr1 和 ptr2 所指向的两块空间的内容完全一致
< 0在两块空间中首次出现不相等的数据时,ptr1 指向的数据小于 ptr2 的
> 0在两块空间中首次出现不相等的数据时,ptr1 指向的数据大于 ptr2 的

函数用例

在这里插入图片描述

⒋memset

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

函数功能

  • 将 ptr 指向的空间的前 num 个字节的内容设置成给定的 value

函数用例

在这里插入图片描述

内存设置函数

Ⅱ 模拟实现

⒈模拟实现 memcpy

void* my_memcpy(void* dest, const void* sour, size_t num)
{
	assert(dest && sour);

	void* start = dest;					//保留目标空间的起始地址

	for (int i = 0; i < num; i++)		//总共拷贝 num 个字节的内容
	{
		*(char*)dest = *(char*)sour;	//一次拷贝一个字节的内容过去
		dest = (char*)dest + 1;			//让 dest 指向下一个字节的位置	
		sour = (char*)sour + 1;			//让 sour 指向下一个字节的位置
	}

	return start;						//返回目标空间的起始地址
}

⒉模拟实现 memmove

实现思路

  • 内存重叠的时候要避免一开始就把重叠部分的数据给修改。
  • 所以当两块空间产生重叠的时候就有两种处理方法了。
    1. 从 sour 末尾向前拷贝数据到 dest
    2. 从 sour 靠头向后拷贝数据到 dest

1. 从后向前拷贝

  • 当 dest 的起始位置落在 sour 指向空间的右边时可以让 sour 使用从后向前拷贝的方法。
  • 如:dest[4] = sour[4] ——> dest[3] = dest[3] ——> dest[2] = sour[2] …… 从尾开始向前拷贝。

在这里插入图片描述

2. 从前向后拷贝

  • 如果使用从后向前拷贝的话,上面那种情况 dest 的起始位置落在 sour 指向空间的右边很容易就能解决。
  • 但是如果 dest 的起始位置落在 sour 指向空间的左边就不是那么一回事了。

在这里插入图片描述

判断拷贝方式

  • 根据 dest 的落点来判断使用(从后向前 / 从前向后)的拷贝方式。
  • dest 的落点可以划分成三个部分
    1. dest 起始位置落在 sour 指向的空间:从 sour 的开头(从前向后)拷贝到 dest。
    2. dest 起始位置落在 sour 指向的空间:从 sour 的末尾(从后向前)拷贝到 dest。
    3. dest 起始位置落在 sour 指向的空间:从 sour 的末尾(从后向前)拷贝到 dest。

在这里插入图片描述

代码实现方法

  • 当 dest 的起始位置落在 sour 的各个区域时,可以选择的划分方式。

    1. 法 1:1 区和 3 区选择(从前向后)拷贝,2 区选择(从后向前)拷贝。
    2. 法 2:2 区和 3 区选择(从后向前)拷贝,1 区选择(从前向后)拷贝。
  • 个人推荐使用法 2,因为只需要判断 dest 的起始地址在 sour 的起始地址的左右方向即可。

法 2 展示代码

void* my_memmove(void* dest, const void* sour, size_t num)	
{
	assert(dest && sour);				

	void* start = dest;

	if (dest < sour)					//dest 落在 sour 左边,选择 前 -> 后
	{
		for (int i = 0; i < num; i++)	//从前向后拷贝就是模拟实现 memcpy 里的那段代码
		{
			*(char*)dest = *(char*)sour;
			dest = (char*)dest + 1;
			sour = (char*)sour + 1;
		}

		return start;
	}
	else								//dest 落在 sour 右边,选择 后 -> 前	
	{								
		while (num--)					//从 sour 指向空间的最后一个字节开始向前拷贝
		{
			*((char*)dest + num) = *((char*)sour + num);
		}
	}

	return start;						//返回目标空间的起始地址
}

⒊模拟实现 memcmp

int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{
	assert(ptr1 && ptr2);

	while (num--)							//比较两块空间的前 num 个字节
	{
		if (*(char*)ptr1 == *(char*)ptr2)	//当前字节相等时继续比较下一对字节
		{
			ptr1 = (char*)ptr1 + 1;
			ptr2 = (char*)ptr2 + 1;
		}
		else								//出现不相等时返回两对字节之间的差值
		{
			return *(char*)ptr1 - *(char*)ptr2;
		}
	}

	return 0;
}

⒋模拟实现 memset

void* my_memset(void* ptr, int value, size_t num)
{
	assert(ptr);

	char* start = ptr;

	for (int i = 0; i < num; i++)
	{
		*((char*)ptr + i) = (char)value;
	}

	return start;
}

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

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

相关文章

Kali 安装浩劫(Havoc Command and Control Framework)

拉取 github 上的项目到本地进入 Havoc 目录 git clone https://github.com/HavocFramework/Havoc.git cd Havoc下载基于 Kali 的一系列软件 sudo apt install -y git build-essential apt-utils cmake libfontconfig1 libglu1-mesa-dev libgtest-dev libspdlog-dev libboost…

改进YOLO系列:7.添加CA注意力机制

添加CA注意力机制 1. CA注意力机制论文2. CA注意力机制原理3. CA注意力机制的配置3.1common.py配置3.2yolo.py配置3.3yaml文件配置1. CA注意力机制论文 论文题目:Coordinate Attention for Efficient Mobile Network Design 论文链接:Coordinate Attention for Effi…

400电话系统的数据分析和优化对企业的发展和增长有什么具体的好处?

对企业而言&#xff0c;通过400电话系统的数据分析和优化可以带来以下具体好处&#xff0c;促进企业的发展和增长&#xff1a; 优化客户满意度&#xff1a;通过数据分析和优化&#xff0c;企业可以更好地了解客户的需求和偏好&#xff0c;针对性地提供个性化的服务。这将提升客…

如何评估分类模型的好坏

如何评估分类模型的好坏 评估分类预测模型的质量&#xff0c;常用一个矩阵、三条曲线和六个指标。 一个矩阵&#xff1a;混淆矩阵&#xff1b;三条曲线&#xff1a;ROC曲线、PR曲线、KS曲线&#xff1b;六个指标&#xff1a;正确率Acc、查全率R、查准率P、F值、AUC、BEP值、KS…

「快学Docker」Docker容器安全性探析

「快学Docker」Docker容器安全性探析 引言容器安全性威胁Docker容器安全性目录容器镜像安全性主机与容器隔离访问控制运行时监控与防御网络安全性Docker容器安全性最佳实践 总结 引言 在当今快速发展的软件开发和部署领域&#xff0c;容器化技术已经成为一种不可或缺的工具。然…

Zotero文件同步方案:Zotero + Koofr + GooleDrive/OneDrive

Zotero文件同步方案&#xff1a;Zotero Koofr GooleDrive/OneDrive 背景知识ZoteroKoofrGoogleDrive/OneDrive配置步骤注意事项参考资料 觉得文章有收获&#xff0c;欢迎关注公众号鼓励一下作者呀~ 在学习的过程中&#xff0c;也搜集了一些量化、技术的视频及书籍资源&#x…

【业务功能篇83】微服务SpringCloud-ElasticSearch-Kibanan-docke安装-应用层实战

五、ElasticSearch应用 1.ES 的Java API两种方式 Elasticsearch 的API 分为 REST Client API&#xff08;http请求形式&#xff09;以及 transportClient API两种。相比来说transportClient API效率更高&#xff0c;transportClient 是通过Elasticsearch内部RPC的形式进行请求…

Win11安装VMware中的镜像的下载

首先&#xff0c;下载好VMware之后需要许可证&#xff0c;在VMware选择许可证填上即可&#xff08;可以解决一部分VMware创建虚拟机过程中出现的问题&#xff09;。 百度网盘自取&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/17gBySqoPi2HeGJJlalp-VQ 提取码&…

学信息系统项目管理师第4版系列01_导读

2023年对于信息系统项目管理师&#xff08;以下简称“高项”&#xff09;的考生来说真是命运多舛的一年&#xff0c;上半年改大纲换教材&#xff0c;下半年改机考换考法&#xff0c;真是一言难尽啊。 不过&#xff0c;“天要下雨&#xff0c;娘要嫁人”&#xff0c;该考试拿证…

Linux:Nginx服务与搭建

目录 一、Nginx概述 二、Nginx三大作用&#xff1a;反向代理、负载均衡、动静分离 三、Nginx和Apache 3.1Nginx和Apache的差异 3.2Nginx和Apache的优缺点比较 四、编译安装niginx 五、创建Nginx 自启动文件 六、Nginx的信号使用 6.1信号 七、升级 nginx1.18 nginx1.2…

java 里面 long 转换int内存分析

了解补码知识点 要将补码转换为十进制&#xff0c;需要确定补码的符号位。如果补码的符号位为1&#xff0c;则表示为负数&#xff0c;否则表示为正数。 假设我们有一个补码为1 0110 1011 1100 1101 1000 0011 1101 1100 0010 1101 1111 1101 1100 0001 1100 0011 0100 首先&a…

无涯教程-进程 - 组会话控制

在本章中&#xff0c;我们将熟悉进程组&#xff0c;会话和作业控制。 进程组(Process Groups ) - 进程组是一个或多个进程的集合&#xff0c;一个进程组由一个或多个共享相同进程组标识符(PGID)的进程组成。 会话(Sessions) - 它是各种进程组的集合。…

软考A计划-系统集成项目管理工程师-项目风险管理-下

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

开源哲学:自由、共享与合作

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

Spark最后一课

1.Spark的提交过程(YarnCluster) 1.命令输入脚本启动,启动submit任务 2.解析参数 看是cluster还是yarn单点模式 3.创建客户端YarnClusterApplication 4.封装提交命令交给RM 5.RM在NM上启动ApplicationMaster(AM) 注意AM消耗的资源都是container的 6.AM根据参数启动Driver并且…

使用Burp Suite进行Web应用渗透测试

使用Burp Suite进行Web应用渗透测试是一种常见的方法&#xff0c;可以帮助发现Web应用程序中的安全漏洞和弱点。 步骤&#xff1a; 准备工作&#xff1a; 首先&#xff0c;确保已经安装了Burp Suite&#xff0c;并配置浏览器以使用Burp Suite作为代理。 配置代理&#xff1a;…

Nvidia Jetson 编解码开发(7)Jetpack 4.x版本Multimedia API 硬件编码开发--输出端对接ROS publish

1.前言 Nvidia Jetson 编解码开发(6)Jetpack 4.x版本Multimedia API 硬件编码开发--输入端对接Camera V4L2采集_free-xx的博客-CSDN博客 基于上篇基于开发 需求: (1)2路Camera采集 + H265编码 (2)2路编码完的H265数据通过ROS 发布出去,上位机播放 2. 开发记录 2…

centos7根目录扩容

centos7根目录扩容 具体操作步骤欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如…

C++技能系列 - 编码规范(Google C++编程风格指南)

现在的一切都是为将来的梦想编织翅膀&#xff0c;让梦想在现实中展翅高飞。 Now everything is for the future of dream weaving wings, let the dream fly in reality. 编码规范&#xff08;Google C Style Guide&#xff09; 编码规范&#xff08;Google C Style Guide&am…

【每日一题】1267. 统计参与通信的服务器

【每日一题】1267. 统计参与通信的服务器 1267. 统计参与通信的服务器题目描述解题思路 1267. 统计参与通信的服务器 题目描述 这里有一幅服务器分布图&#xff0c;服务器的位置标识在 m * n 的整数矩阵网格 grid 中&#xff0c;1 表示单元格上有服务器&#xff0c;0 表示没有…