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

news2024/9/24 23:32:08

在上篇博客中,我们学习了字符串函数,针对一些字符串我们可以做出一系列操作。接下来我们将学习一些内存修改函数(#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; 

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

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

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

相关文章

leetcode刷题(轮转数组、买股票的最佳时机、买卖股票的最佳时机2、跳跃游戏、跳跃游戏2、最大子序列交替和、交替数字和、下降路径最小和)

目录 1、轮转数组 2、买卖股票的最佳时机 3、买卖股票的最佳时机② 4、跳跃游戏 5、跳跃游戏2 6、最大子序列交替和 7、交替数字和 8、下降路径最小和 1、轮转数组 class Solution():def rotate(self, nums, k):def reverse(i, j): #逆置数组while i < j:nums[i]…

Oracle Apex制作一个简单的交互式报表页面&页设计

目录 创建好一个菜单表 简单查询一下&#xff1a; 创建交互式报表 工作报表展示​编辑 菜单报表展示​编辑 页设计器 改变布局样式 修改标签内容 添加验证&#xff06;更改必填项 注意&#xff01; 在主页进行跳转 页跳转按钮 主页可以跳转到指定报表 面包屑 报表也可…

Clickhouse数据一致性和物化视图

Clickhouse 一、数据一致性的保证1.通过Group by对数据去重2.通过 FINAL 查询 二、物化视图1.物化视图与普通视图的区别2.优缺点3.基本语法 三、MaterializeMySQL引擎1.特点2.使用细则 四、常见问题排除分布式 DDL某数据节点的副本不执行数据副本表和数据不一致副本节点全量恢复…

【uniapp开发小程序】设置全屏的开屏广告、长按识别图片、点击跳转通话 拨打电话

设置全屏的开屏广告需求实现 效果图&#xff1a; 点击跳转其他小程序&#xff1a; uni.navigateToMiniProgram() 官方文档&#xff1a;uni.navigateToMiniProgram(OBJECT) | uni-app官网 // 示例代码 uni.navigateToMiniProgram({appId: ,path: pages/index/index?id123,ext…

Cilium核心技术-eBPF XDPTC介绍

eBPF 是一项革命性技术&#xff0c;它能在内核中运行沙箱程序&#xff08;sandbox programs&#xff09;&#xff0c; 而无需修改内核源码或者加载内核模块。 eBPF的一个重要特性是能够使用高级语言(如C)来实现程序。LLVM有一个eBPF后端&#xff0c;用于编辑包含eBPF指令的ELF文…

WEB:Web_php_unserialize

背景知识 反序列化函数及绕过 正则表达式及绕过 题目 源码解析&#xff08;参考链接在最后&#xff09; <?php class Demo { //定义一个类private $file index.php; //变量属性public function __construct($file) { //类方法$this->file $file; …

分布式锁与同步锁

什么是分布式锁 分布式锁是一种在分布式系统中用于协调多个节点访问共享资源的机制。在分布式系统中&#xff0c;由于存在多个节点并行执行任务&#xff0c;可能会出现竞争条件和数据不一致的问题。分布式锁通过约束同一时刻只有一个节点能够获得锁的方式&#xff0c;确保了对…

【计算机视觉】DINOv2(Facebook自监督视觉学习)的环境部署和使用代码示范(含源代码)

文章目录 一、导读二、环境部署三、使用示例 我的代码示范已经上传了Kaggle平台&#xff0c;具体的笔记地址为&#xff1a; https://www.kaggle.com/code/holmes0610/dinov2一、导读 DINOv2&#xff1a;在没有监督的情况下学习鲁棒的视觉特征 这是第一种训练计算机视觉模型的…

2023爱分析·AIGC厂商全景报告|爱分析报告

关键发现 通用大模型市场当前虽入局者众多&#xff0c;但终局将高度集中&#xff0c;未来将由5-6家厂商主导&#xff1b;应用层厂商及甲方企业应着眼终局&#xff0c;从大算力、巨量数据集、端到端AI工程化能力以及应用生态伙伴等维度综合考虑&#xff0c;慎重选择合作伙伴。 …

【LeetCode每日一题合集】2023.7.10-2023.7.16

文章目录 16. 最接近的三数之和排序 双指针 1911. 最大子序列交替和解法——动态规划 2544. 交替数字和&#xff08;简单模拟&#xff09;931. 下降路径最小和&#xff08;线性DP&#xff09;979. 在二叉树中分配硬币⭐⭐⭐⭐⭐&#xff08;dfs&#xff09;18. 四数之和&#…

[JAVA]程序逻辑控制,输入输出

&#x1f349;内容专栏&#xff1a;【JAVA】 &#x1f349;本文脉络&#xff1a;程序逻辑控制&#xff0c;if语句&#xff0c;switch循环&#xff0c;while循环&#xff0c;for循环&#xff0c;do while循环输入输出&#xff0c;例子 &#x1f349;本文作者&#xff1a;Melon_西…

Python:基于matplotlib与mayavi的3D可视化

文章目录 &#xff08;1&#xff09;基于matplotlib的3D可视化&#xff08;2&#xff09;基于mayavi的3D可视化&#xff08;2.1&#xff09;立方体&#xff08;2.2&#xff09;体素体 3D可视化是一种用于呈现三维数据的方法&#xff0c;它可以帮助我们更好地理解和分析复杂的空…

搭建 Java 部署环境,部署 Web 项目到 Linux

为了进行部署&#xff0c;把写好的 java web 程序放到 Linux 上&#xff0c;需要先把对应的依赖的软件 (环境) 搭建好&#xff0c;安装一些必要的软件程序 JDKTomcatMySqL jdk 直接使用包管理器进行安装(基于yum安装) 一、yum 1、认识 yum yum (Yellow dog Updater, Modified…

随机产生50个55以内的不重复的整数,要求查找出一个缺失的整数。

一、设计思路 为随机产生50个55以内的整数且不能重复&#xff0c;应先将已经产生的随机数保存下来&#xff0c;然后在获取到新的随机数时&#xff0c;与之前保存下来的值进行对比&#xff0c;如果已经出现过则抛弃&#xff0c;并再次获取&#xff0c;直到获取到不同的随机值为止…

Redis 从入门到精通【进阶篇】之过期和淘汰策略详解

文章目录 0. 前言Redis过期策略&#xff1a;1. 定期删除&#xff08;定时器方式&#xff09;&#xff1a;2. 惰性删除&#xff08;访问时检查方式&#xff09;&#xff1a; Redis淘汰策略&#xff1a;1. noeviction&#xff1a;2. allkeys-lru&#xff1a;3. volatile-lru&…

GOPATH、GOROOT(VSCode编写第一个go程序)

1. GOROOT和GOPATH GOROOT 和 GOPATH 都是 Go 语言中的环境变量&#xff0c;用于指定 Go 工具链和工作区的路径。 GOROOT 指定了 Go 工具链的安装路径&#xff0c;它包含了 Go 语言的标准库、编译器等工具。在使用 Go 编译器、运行时等工具时&#xff0c;它们会默认从 GOROOT…

Linux ➾ 端口占用检查

Linux ➾ 端口占用检查 &#x1f53b; 前言&#x1f53b; 一、什么是监听端口&#x1f53b; 二、使用lsof命令查看端口占用情况&#x1f53b; 三、使用netstat命令检查监听端口&#x1f53b; 四、使用ss 检查监听端口&#x1f53b; 总结—温故知新 &#x1f53b; 前言 在Linux系…

举例说明基于线性回归的单层神经网络网络(以梯度下降算法来求解权重的过程)...

我们将通过一个简单的例子来说明基于线性回归的单层神经网络&#xff0c;以及如何使用梯度下降算法来求解权重。 假设我们有以下数据集&#xff0c;表示学生的学习时间&#xff08;小时&#xff09;与他们的考试分数&#xff1a; 学习时间&#xff08;X&#xff09;&#xff1a…

C# 反转无头链。

给定一个单链表的头结点pHead(该头节点是有值的&#xff0c;比如在下图&#xff0c;它的val是1)&#xff0c;长度为n&#xff0c;反转该链表后&#xff0c;返回新链表的表头。 数据范围&#xff1a; 0≤n≤1000 要求&#xff1a;空间复杂度 O(1) &#xff0c;时间复杂度 O(n) 。…

【SpringBoot应用篇】SpringBoot集成atomikos实现多数据源配置和分布式事务管理

【SpringBoot应用篇】SpringBoot集成atomikos实现多数据源配置和分布式事务管理 分布式事务概念XA和JTA概述SpringBoot集成atomikos数据库结构pom通用工具类RBaseControllerBaseExceptionCodeExceptionCodeBaseExceptionBaseUncheckedExceptionBizException application.yml数据…