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的数字。

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

使用案例:

相关推荐
范纹杉想快点毕业6 分钟前
深入解析C++静态成员变量与函数
java·开发语言·jvm
Brookty19 分钟前
【MySQL】数据库约束
数据库·后端·学习·mysql
小石(努力版)20 分钟前
嵌入式STM32学习——串口USART 2.0(printf重定义及串口发送)
stm32·嵌入式硬件·学习
JosieBook1 小时前
【web应用】配置Java JDK与maven3的环境变量
java·开发语言
普通的冒险者1 小时前
用java实现内网通讯,可多开客户端链接同一个服务器
java·开发语言
Muroidea1 小时前
解决RedisTemplate的json反序列泛型丢失问题
java·开发语言·json
大飞记Python2 小时前
自动化测试脚本点击运行后,打开Chrome很久??
开发语言·python
程序员麻辣烫2 小时前
go语法大赏
开发语言·数据库·golang
虾球xz2 小时前
游戏引擎学习第302天:使用精灵边界进行排序
c++·学习·算法·游戏引擎
虾球xz2 小时前
游戏引擎学习第297天:将实体分离到Z层中
c++·人工智能·学习·游戏引擎