C语言---内存函数

memcpy函数的使用及模拟实现

memcpy的功能和strcpy类似,都是用来拷贝数据的。与strcpy不同的是,memcpy的适用性更广并且是以字节为单位来拷贝的。

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

memcpy函数的作用就是拷贝从source这个地址开始向后num个字节的数据destinction里边去。返回的是的destinction的首地址。

使用案例

模拟实现

分析:

在上边知道了memcpy的使用方式以及形参和返回值之后,我们可以试着模拟实现一下。

由于传过来的参数都是void*类型的指针,而我又不知道我将要处理什么类型的数据,恰恰我们知道所要处理的字节数,所以我们想将其强转为char*类型来以字节为单位处理数据。其本质也是拷贝数据,拷贝的次数就是num次,一个一个字节的拷贝,用循环来实现。

代码实现:

cpp 复制代码
#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* des, const void* sor, size_t num)
{
	assert(des && sor);
	void* p = des;
	while (num--)
	{
		*(char*)des = *(char*)sor;
		//先强转再++
		((char*)des)++;
		((char*)sor)++;
	}
	return p;
}

int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[20] = { 0 };
	my_memcpy(arr2, arr1, 20);
	return 0;
}

memmove函数的使用及模拟实现

其实memmove和memcpy函数的功能是一样的,两者其实是用于不同的场景,memmove用于拷贝的数据是可以重叠的。

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

memmove函数的形参跟返回值的意义和memcpy一模一样

何谓可以重叠?

假设还是那个arr1数组,里边还是存放着1,2,3,4,5。但我现在不将它拷贝到arr2数组里边去了,我想将arr1数组的内容拷贝到arr1+1的位置,还是拷贝20个字节。这个时候用memcpy函数就显得有点力不从心了,memmove函数就是可以解决这个问题。

使用案例

模拟实现

分析:

由于情况较多,我用画图的形式来呈现。

从图片里边的两种情况来看,我们在模拟实现memmove的时候,就是要考虑到这些点,

简单总结一下,当sor在des所在矩形的里边的时候,我们是需要从前往后拷贝数据的,此时的代码逻辑跟刚才的memcpy是一样的。而当sor在des所在矩形左边的时候,就要从后往前拷贝,此时就需要我们先找到要拷贝的最后一个元素的地址,从上图来看,就是我们要找到5末尾的地址和7末尾的地址来从后往前拷贝。

那具体怎么找呢?

分析完了以上的信息,还有一种情形3 (这种情况从后往前和从前往后都不影响)

但为了代码的方便,我们选择从后往前的方式。

代码实现:

cpp 复制代码
#include<stdio.h>
#include<assert.h>
void* my_memmove(void* des,const void* sor,size_t num)
{
	assert(des && sor);
	void* ret = des;
	//当sor在des的左边的时候,就从后往前实现
	if (sor < des)
	{
		//先找到要拷贝的最后一个数据的末尾的地址,然后实现从后往前交换
		//假设我要拷贝五个int类型的数据,那一开始num是20,num--之后就会变成19
		//而des和sor指针经过类型转换之后再加上num就能得到我们想要的地址
		//大家可以对照前边图片里边的 char arr2[20] 数组
		while (num--)
		{
			*((char*)des + num) = *((char*)sor + num);
		}
	}
	//接下来就是从前往后拷贝,实现逻辑跟memcpy一样
	else
	{
		while (num--)
		{
			*(char*)des = *(char*)sor;
			//先强转再++
			((char*)des)++;
			((char*)sor)++;
		}
	}
	return ret;
}

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr1 + 1, arr1, 20);
	return 0;
}

memset的使用

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

memset是用于以字节为单位来修改数据的,一般用于字符数组和整型数组设置其值全部为0的时候。修改字符数组这很好理解,因为字符数组里边的值都是只占一个字节,以字节修改是最合适的。但为什么整型数组除了0,其他的值修改不了呢?我会在代码里边用注释来解释)

解释一下形参和返回值:

value是你想要修改的值,num是你想要修改的字节个数,ptr是你想要修改的起始地址,返回的也是也是该起始地址。

使用案例1:

使用案例2:

使用案例3:

对于使用案例3,出现这样结果的原因就是因为memset是按照字节来修改数据的。

对于一个int类型的数据,它是有4个字节

对于1来说,它的补码就是

00000000 00000000 00000000 00000001

那要按照字节来修改为1的话,就变成了

00000001 00000001 00000001 00000001

而这个就是一个非常大的数字

memcmp的使用

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

memcmp是用来比较从ptr1和ptr2指向的内存的数据进行比较。从ptr1和ptr2开始,向后比较num个字节。它的返回值跟strcmp类似。

如果ptr1>ptr2,就返回大于0的数字,如果小于,就返回小于0的数字,如果等于,就返回等于0的数字。

一旦遇到不相等的字节,它就不会往下边去比较了,直接返回。

使用案例:

相关推荐
wuminyu10 小时前
JVM规范学习总结:解释器与JIT编译器如何处理JVM字节码
java·linux·c语言·jvm·c++
小徐不徐说10 小时前
序列化与反序列化:把 C++ 对象可靠地保存下来
开发语言·数据库·c++·php
ragnwang10 小时前
Notes: Python pybind11 import C++ module
开发语言·c++·python
Wang's Blog10 小时前
Java 项目实战: 交友项目 - 搜索附近的功能概述和分析
java·开发语言·交友
骑着蜗牛撵大象32711 小时前
大模型 Agent 的沙箱护栏:gVisor 隔离、出口白名单与审计闭环
java·开发语言·jvm·安全·agent沙箱·gvisor·microvm
Dxy123931021612 小时前
JS DES 加密详解
开发语言·javascript·arcgis
充值内卷12 小时前
我给桌面加了个鱼缸:C++ 写后端,WebView2 里养一座 Three.js 小岛
开发语言·javascript·c++
云和数据.ChenGuang12 小时前
深入解析 Python 的 dir():从用法到 CPython 源码实现
开发语言·人工智能·python·langchain
叼烟扛炮12 小时前
[Git 实战] 学习笔记:从生成 SSH 密钥到解决 TortoiseGit 推送报错全指南
linux·运维·笔记·git·学习
nice_lcj52013 小时前
深入理解 Java 反射:从 Class 对象到方法调用(含性能实测 + 迷你 IOC 实战 + 面试考点)
java·开发语言·后端·面试