玩转内存修改函数——【C语言】

在上篇博客中,我们学习了字符串函数,针对一些字符串我们可以做出一系列操作。接下来我们将学习一些内存修改函数(#inlcude<string.h>),让我们一起走进mempy、memmove、memcmp函数中。


目录

mempcy函数​编辑

memmove函数

memcmp函数


mempcy函数

通过函数原型,我们可以看出返回值和一些指针参数类型都是void*类型,这就说明此函数不仅仅局限于字符串,针对整型数组、结构体数组等等都可以实现,size_t num参数单位是字节,因为前面指针的类型为void* ,我们并不知道传入数组的元素类型,所以第三个参数的单位为字节就能对很多数据类型进行拷贝。

memcpy函数是复制内存块的函数,函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。

1.参数:destianation指针是接收一个任何类型的数组首元素地址,用作目标。

source指针也是接收同种类型的指针变量,用作拷贝内容。

size_t num是要拷贝的字节数。

2.返回值:返回目标的指针。

3.这个函数在遇到 '\0' 的时候并不会停下来该函数不检查中的任何终止空字符 - 它总是准确地复制字节

4.如果source和destination有任何的重叠,复制的结果都是未定义的。

 接下来对memcpy函数的引用:

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

将arr1中的40个字节内存内容拷贝到arr2中去。arr2中有20个0,但是只拷贝10个arr1中的元素,所以arr2中有前10个元素将被arr1中的内容覆盖,结果如下: 接下来我们进行对memcpy函数的模拟实现:

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

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

我们创建一个my_memcpy函数,仿照memcpy函数原型来建立自定义函数的原型。因为返回值为目标数组的首元素指针,所以我们先创建一个void*指针对目标数组进行标记。然后使用while循环,进行逐字节赋值。因为memcoy函数可以针对任何种类的数组,所以我们应该将void*类型指针全部强制类型转换为最小单位char*类型的指针,这样就可以兼容所有种类的数组。当赋值完成后进行指针加1操作(对于void*类型的指针,我们不能对其进行++操作,所以我们只能写成dest = (char*)dest + 1;的形式)。当num--到0时,证明已经全部赋值完毕,跳出循环返回最初指针即可。

下面是我们运行的结果:

与我们最初使用memcpy函数所得到的结果相同。

接下来我们又有一个问题,我们可以使用memcpy函数将一个数组中的内容,拷贝到自己中吗 ?说更通俗点:有一个整型数组int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };将arr1中的1,2,3,4,5放到3,4,5,6,7的位置上面吗?

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

我们想的到最终arr1中的内容: 1,2,1,2,3,4,5,8,9,10但结果如何呢?

 那为什么会是这样呢?

那我们应该怎么做才能完成刚才的内容呢?这就要使用memmove函数来完成了!!


memmove函数

 memmove函数是将移动内存块的函数,将字节的值从指向的位置复制到目标指向的内存块。复制就像使用了中间缓冲区一样,允许目标重叠。

1.返回值和参数与mempy函数相同,我们可以参照上面进行理解。

2.指针和目标指针指向的对象的基础类型与此函数无关;结果是数据的二进制副本。
该函数不检查中的任何终止空字符 - 它总是准确地复制字节
为避免溢出,目标参数和参数指向的数组的大小应至少为字节

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

 接下来让我们使用memmove函数完成上面的问题:

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

 很丝滑的完成了刚才的问题。

现在让我们对memmove函数进行模拟实现:

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


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

 创建一个my_memmove函数,仿照memmove原型完成自定义函数的参数。但是我们应该怎么完成函数体呢?

刚才使用最基本的从前向后复制,就得不到想要的结果,如果从后向前复制则可以得到想要数组。有写情况我们又需要从前向后复制,所以我为大家总结一下:

所以我们得分情况来完成自定义函数体,当dest指针<src指针时,里面的内容与my_memcpy内容相同。当dest指针>src指针时,我们继续利用while循环,利用从后向前复制才能完成。 在每次解引用前加上nun字节数即可指针从后往前访问,while判断条件为num--,在判断是否结束时也可以挪动指针,一举两得。最后返回目标数组的首元素地址即可。唯一与my_memcpy函数不同的时必须分类讨论。

运行结果如下:

 此函数模拟完成!

针对以上两个函数,看到这里都会有个疑问,是不是memcpy函数可以干的事memmove函数都可以办到。那肯定的。所以memmove函数的作用肯定是高于mempy函数的!!!


memcmp函数

 memcmp函数是比较两个内存块,这里与strcmp函数有一些相似,都是比较两个数组是否相同,返回值的情况相同。但不同的是memcmp可以比较的类型更多,该函数在找到空字符后不会停止比较,而strcmp会停止。

PTR1

指向内存块的指针。

PTR2

指向内存块的指针。

数字

要比较的字节数。

它是通过比较内存中存储的数据进行一个字节一个字节的比较。

 举个使用memcmp函数的例子:

int main(void)
{
	int arr1[10] = { 1,2,1,4,5,6 };
	int arr2[10] = { 1,2,257 };
	int ret = memcmp(arr1, arr2, 9);
	printf("%d\n", ret);

	return 0;
}

比较arr1与arr2中前9个字节是否相同?

 arr1中前10个字节的存储内容

arr2中前10个字节存储内容 

因为我们比较的是前9个字节的内容,所以是全部相同的,应该返回输出的值为0; 如果我们比较前10个字节,应该输出的就为-1; 

以上就是我对内存修改函数的全部认识,希望各位大佬在评论区给予我宝贵意见! 

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

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

相关文章

kaggle新赛:学生摘要评估大赛赛题解析(NLP)

赛题名称&#xff1a;CommonLit - Evaluate Student Summaries 赛题链接&#xff1a; https://www.kaggle.com/competitions/commonlit-evaluate-student-summaries/ 赛题背景 摘要写作是所有年龄段学习者的一项重要技能。总结可以增强阅读理解能力&#xff0c;特别是在第二…

12. 一些开发中遇到的SQL问题

文章目录 一些开发中遇到的SQL问题1. sql报11090错误,原因可能是以下错误&#xff0c;在&#xff1f;占位符后有一个空格2. 占位符&#xff1f;的位置不能是表名&#xff0c;否则会无法进行预编译3. mysql中desc是关键字&#xff0c;如果字段名称为desc会报错4. 数据库中时间格…

[JavaScript游戏开发] 2D二维地图绘制、人物移动、障碍检测

系列文章目录 第一章 2D二维地图绘制、人物移动、障碍检测 文章目录 系列文章目录前言一、列计划1.1、目标1.2、步骤 二、使用步骤2.1、准备素材(图片)&#xff1a;草坪、人物(熊猫)、障碍(石头)2.2、初始化布局(表格)&#xff0c;边距设置为0&#xff0c;无边框&#xff0c;设…

【java】【基础1】数据类型运算符

目录 一、数据类型&#xff08;4大类8种&#xff09; 1.1类型转换 1、自动类型转换 2、表达式的自动类转换 3、强制类型转换 二、运算符 2.1基本算术运算符 2.2自增自减运算符 2.3赋值运算 2.4关系运算符 2.5逻辑运算符 2.6三元运算符 2.7运算符的优先级 三、API文档&am…

机械设计制造及其自动化专业向PLC方向发展的可行性

是的&#xff0c;机械设计制造及其自动化专业往PLC&#xff08;可编程逻辑控制器&#xff09;方向发展是可行的。PLC是一种用于控制和自动化各种机械设备和工业过程的计算机控制系统。它被广泛应用于工业自动化领域&#xff0c;包括制造业、能源行业、交通运输等。 我这里刚好…

uniapp引入echarts

作为前端在开发需求的时候经常会遇到将数据展示为图表的需求&#xff0c;之前一直用的HBuilder的图表插件uCharts&#xff0c;使用方法可以参考我的另一篇博客&#xff1a;uniapp 中使用图表&#xff08;秋云uCharts图表组件&#xff09; 但是最近发现uCharts很多功能都需要付…

基于单片机的智能路灯控制系统人体感应灯光控制系统的设计与实现

功能介绍 以51单片机作为主控系统&#xff1b;LCD1602液晶显示当前时间、年月日、时分秒&#xff1b;按键看看有设置自动手动模式&#xff1b;3路红外探头用来感应当前3个区域是否有人&#xff1b;按键可以设置当前时间、开启和关闭教室灯光时间&#xff1b;在手动模式下&#…

需求条目化与自动估算强强联合 助力软件估算自动化

痛点&#xff1a; 需求是产品的源头&#xff0c;是项目规模估算的基石。而传统的软件规模估算是由项目成员手工进行&#xff0c;对人员能力、经验、方法都有一定的要求&#xff0c;但是效果不好而且耗时费力&#xff0c;不能保持规模估算的一致性。 而导致这些问题的原因&#…

leetcode 101.对称二叉树

⭐️ 题目描述 &#x1f31f; leetcode链接&#xff1a;对称二叉树 思路&#xff1a; 这道题和 leetcode 100.相同的树 类似&#xff0c;是上一道的变形题。✨leetcode 100.相同的树 代码链接&#xff1a;【往期文章】leetcode 100.相同的树。这道题把根的左子树和右子树看作两…

CANoe如何配置Master/Slave模式

系列文章目录 文章目录 系列文章目录前言一、CANoe配置端口二、CANoe配置Master模式三、CANoe配置Slave模式前言 随着智能电动汽车的行业的发展,车载以太网的应用越来越广泛,最近很多朋友在问CANoe Master/Slave模式如何设置,车载以太网物理层也有一项是测试Master/Slave模式…

数据结构day5(2023.7.19)

一、Xmind整理&#xff1a; 双向链表的插入与删除&#xff1a; 二、课上练习&#xff1a; 练习1&#xff1a;单链表任意元素删除 /** function: 按元素删除* param [ in] * param [out] * return 返回堆区首地址*/ Linklist delete_by_data(datatype key,Linklist L) …

物联网(IoT):连接未来的万物之网

引言&#xff1a; 物联网&#xff08;Internet of Things&#xff0c;简称IoT&#xff09;是指通过各种智能设备和传感器&#xff0c;使物体能够互联互通、收集和共享数据的网络。随着科技的不断进步和智能设备的普及&#xff0c;物联网的应用呈现出爆发式增长&#xff0c;对各…

Leetcode-每日一题【109.有序链表转换二叉搜索树】

题目 给定一个单链表的头节点 head &#xff0c;其中的元素 按升序排序 &#xff0c;将其转换为高度平衡的二叉搜索树。 本题中&#xff0c;一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差不超过 1。 示例 1: 输入: head [-10,-3,0,5,9]输出: [0,-3,9,-…

Es存储和查询

基本概念 Cluster 集群&#xff0c;一个ES集群是由多个节点(Node)组成的&#xff0c;每个集群都有一个cluster name 作为标识&#xff0c; 在同一网段下的Es实例会通过cluster name 决定加入哪个集群下。 node 节点&#xff0c;一个ES实例就是一个node&#xff0c;一个机器可以…

SpringBoot(八)拦截器Interceptor

上篇介绍了Filter过滤器的使用&#xff0c;提起过滤器&#xff0c;就不得不再提起另外一个叫做拦截器的东西。两者的作用类似&#xff0c;都可以实现拦截请求的作用&#xff0c;但其实两者有着非常大的区别。本篇&#xff0c;我们就来学习下拦截器的使用。 如果你是新手&#x…

Java阶段五Day09

Java阶段五Day09 文章目录 Java阶段五Day09网关Gateway跨域的问题熔断限流组件sentinel微服务场景熔断降级限流降级 sentinel学习案例sentinel介绍重要的核心概念准备一个测试的工程定义资源定义规则sentinel运行原理本地文件定义规则整合nacos实现规则的远程读取规则的内容详解…

【广州华锐互动】AR远程巡检系统在设备维修保养中的作用

随着科技的不断发展&#xff0c;AR(增强现实)远程巡检系统在设备检修中发挥着越来越重要的作用。这种系统可以将AR技术与远程通信技术相结合&#xff0c;实现对设备检修过程的实时监控和远程指导&#xff0c;提高设备检修的效率和质量。 首先&#xff0c;AR远程巡检系统可以帮助…

Word字间距怎么调整?2023最新方法总结!

“作为一个Word新手&#xff0c;里面的好多功能我都没有弄清楚。今天正好写了一篇文章&#xff0c;但不知道应该怎么调整字间距。有朋友知道Word字间距怎么调的吗&#xff1f;快教教我&#xff01;” Word作为一个便捷的办公软件&#xff0c;让我们的工作更方便。学习好Word的使…

Unity自定义后处理——Vignette暗角

大家好&#xff0c;我是阿赵。   继续说一下屏幕后处理的做法&#xff0c;这一期讲的是Vignette暗角效果。 一、Vignette效果介绍 Vignette暗角的效果可以给画面提供一个氛围&#xff0c;或者模拟一些特殊的效果。 还是拿这个角色作为底图 添加了Vignette效果后&#xff0…

svn迁移到git实际操作

1.到svn项目目录右键选中gitbash打开窗口&#xff0c;执行获取用户并映射成git样式账号命令如下: svn log -q | awk -F | /^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" "$2" <"$2"163.cn>…