内存操作函数【memcpy、memmove、memset、memcmp函数的使用和模拟复现】

内存操作函数

1.memcpy函数

void* memcpy(void* destination, const void* source, size_t num);
  1. 函数memcpy 从source的位置 开始向后复制 num个字节 的数据到destination指向的内存位置
  2. 这个函数在遇到\0的时候也不会停下来
  3. 如果source和destination有任何的重叠 ,复制的结果都是未定义的、

我们来看一个memcpy使用的例子

// memcpy 函数的使用 -- 针对内存卡进行拷贝  任何类型都可以进行拷贝
int main()
{
	// 之前我们学习过字符串的拷贝 strcpy
	// strcpy能实现的功能 memcpy也是能实现的
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };
	memcpy(arr2, arr1, 20);//  这里的20指的是20字节
	for (int i = 0; i < 20; i++)
	{
		printf("%d", arr2[i]);//  将arr2打印出来 观察是否粘贴了5个元素
	}
	return 0;
}
memcpy函数的模拟实现:
// memcpy 函数的模拟实现
# include<assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)// 该函数在结束之后会返回目标空间的起始地址
// 注意了这个size_t num 形参的单位是字节 
{
	void* ret = dest;
	assert(src && dest);
	for (int i = 0; i < num; i++)// while循环也是可以的
	{
		// 由于我们不知道传进来的地址解引用后是什么类型的数据 因此我们就一个一个字节的传
		*(char*)dest = *(char*)src; // 我们将传进来的地址强行强制转换 
		// 为什么是转化成char* 呢 因为万一传进来的类型是奇数大小时 我们仍然可以传输
		src = (char*)src + 1;// char*类型的指针刚好是一个字节 符合我们一个一个字节的传输
		// ((char*)src)++; // 如果要搞成++ 要这样写
		dest = (char*)dest + 1;
		// ((char*)dest)++;
	}
	return ret;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };
	my_memcpy(arr2, arr1, 20);// 20个字节
	for (int i = 0; i < 20; i++)  // 12345000000000000000
	{
		printf("%d", arr2[i]);//  将arr2打印出来 观察是否粘贴了5个元素
	}
	// memcpy也是可以实现自己给自己复制的
	//int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	//my_memcpy(arr1 + 2, arr1, 20);// 20个字节
	//for (int i = 0; i < 10; i++)
	//{
	//	printf("%d ", arr1[i]);//  1 2 1 2 1 2 1 8 9 10  这个结果明显和我们想要的结果是不一样的
	//	// memcpy库函数实是能完成我们想要的结果的  但是实际上这个函数是不负责这个内存重叠的拷贝的
	//	// 负责内存重叠的拷贝是memmove函数负责的
	//}
	//return 0;
}

2.memmove函数

memmove和memcpy的差别就是源内存块和 目标内存块是可以重叠的

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

我们来看memmove的使用

// memmove 函数的使用
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	memmove(arr + 2, arr, 5 * sizeof(int));// 这里的5 * sizeof(int)就是20
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);// 1 2 1 2 3 4 5 8 9 10
	}

	return 0;
}
memmove 函数的复现:

想要复现memmove函数 我们就要实现内存空间即便重叠了 也能完成复制功能

那么我们就要思考几种情况

第一种情况:

我们的dest 被指向要被复制的地方 在src 的左边 内存空间有重叠 那么这个时候我们考虑从前向后的复制

也就是3–>1 4–>2 5–3 6–4 7–>5

image-20240401150506895

第二种情况:

dest在src的右边但内存空间还是有重叠

image-20240401150845400

这种情况就要从后向前 7复制到9的位置 6复制到8的位置 …

第三种情况 :

dest在src的左边还是右边 但是内存空间没有重叠 那么这个时候从后向前还是从前向后都没也区别

image-20240401151011114

因此我们的代码就要考虑上述几种情况

因此我们现在开始复现memmove函数:

// memmove 函数的复现
# include<assert.h>
void* my_memmove(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	void* ret = dest;
	if (dest < src) // 从前向后
	{
		while (num--)// 用for循环也是可以的 参考上面memcpy复现的代码
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else// 从后向前
	{
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}

}
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr, arr + 2, 4 * sizeof(int));// 这里的4 * sizeof(int)就是16
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);// 1 2 1 2 3 4 5 8 9 10
	}
	// 也可以用返回值去打印

	return 0;
}

3.memset函数的使用

void* memset(void* ptr, int value, size_t num)
ptr 指向的是要被储存的空间
value 把ptr所指向的空间内的数据改成value值
num 是你要让多少字节的数据 被设置成value值
memset函数使用的例子:
// memset函数的使用
int main()
{
	// 修改字符类型的数据
	char arr1[] = "hello world";
	memset(arr1 + 1, 'y', 5);// 5指的是5个字节
	printf("%s\n", arr1);// hyyyyyworld
	// 修改整形类型的数据
	int arr2[5] = { 0 };
	memset(arr2, 1, 20);// 20指的是20个字节  
	// 注意了memset函数在修改数据的时候是以字节为单位的 做不到以元素为单位 因此 这里让arr2里的五个元素都变成1是做不到的
	for (int i = 0; i < 5; i++)
	{
		printf("%d ",arr2);
	}
	return 0;
}

image-20240401172025230

这里的内存是arr2数组的内存空间

4.memcmp函数的使用

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

memcmp完成的是内存块的比较

比较ptr1 和 ptr2 指针指向的位置开始 向后的num个字节

如果ptr1 > ptr2 返回大于0的值

ptr1 = ptr2 返回0

ptr1 < ptr2 返回小于0的值

我们来看memcmp函数的使用:
// memcmp 函数的使用
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7 };
	int arr2[] = { 1,2,3,4,7,8,8 };
	int ret = memcmp(arr1, arr2, 17);// 这里的17是17个字节
	// 如果在17个字节之前比较完毕 的话 那就不会比较到17个字节
	printf("%d\n", ret);
	return 0;
}
// memcmp 函数的使用
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7 };
	int arr2[] = { 1,2,3,4,7,8,8 };
	int ret = memcmp(arr1, arr2, 17);// 这里的17是17个字节
	// 如果在17个字节之前比较完毕 的话 那就不会比较到17个字节
	printf("%d\n", ret);
	return 0;
}
  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值