内存函数memcpy和memmove

本篇博客我们来学习两个个内存函数,这两个函数都是用来拷贝的,但是它们的使用范围有些许不同,所以有必要好好区分。


目录

1.memcpy:在缓存区中复制字符(可以复制任何整型、字符串等字符)

1.1函数示例

1.2模拟实现

​编辑

2.memmove:实现空间重叠拷贝

2.1代码示例

2.2模拟实现


1.memcpy:在缓存区中复制字符(可以复制任何整型、字符串等字符)

1.头文件:

#include<memory.h> 或者#include<string.h>

2.使用格式:void *memcpy( void *dest, const void *src, size_t count );

3.函数memcpy从src的位置开始向后复制count个字节的数据到dest的内存位置

4.函数在拷贝时遇到‘\0’并不会停下来

5.如果src和dest有任何的重叠,复制的结果都是未定义的

6.void* 参数类型不可定义,可以拷贝任意传过来的指针内容

7.size_t count :需要拷贝的字节数

1.1函数示例

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>

memcpy
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
    int arr2[10] = { 0 };
	memcpy(arr2, arr1, 20);//只拷贝前5个数组
	int sz = sizeof(arr2) / sizeof(arr2[0]);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
	

}

我们把count的值设置为了5,我们就只拷贝arr1中的前五个数据,其余部分保持初始化的0,

当我们不想从1开始拷贝数据时,比如想从3开始拷贝,只需要将源头字符串也就是arr1+2,就可以从3开始拷贝。

1.2模拟实现

void my_memcpy(void* dest, const void* src, size_t k)
{
	assert(dest && src);
	scanf("%d", &k);
	while (k)
	{
		*(int*)dest = *(int*)src;
		dest = (int*)dest+1;
		src = (int*)src + 1;
		k--;

	}
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	int k = 0;
	my_memcpy(arr2, arr1, k);
	int sz = sizeof(arr2) / sizeof(arr2[0]);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

2.memmove:实现空间重叠拷贝

1.头文件:#include<string.h>

2.使用格式:void *memcpy( void *dest, const void *src, size_t count );

3.memmove函数会确保重叠区域中的原始源字节在被覆盖之前被复制,即src和dest发生重叠时,会确保src已经被复制

2.1代码示例

我们就用重叠区域的拷贝来举例论证到底会不会在src和dest发生重叠时,src已经被复制

//memmove
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	int k = 0;
	int i = 0;
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	scanf("%d", &k);
	memmove(arr1, arr1+2, k);
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;

}

我们发现结果是3 4 5 6 7  6 7 8 9 10,这说明在src和dest发生重叠时,src已经被复制

2.2模拟实现

void my_memmove(void* dest, const void* src, size_t k)
{
	assert(dest && src);
	if (dest < src)
	{
//从前往后打印
		while (k--)
		{
			*(int*)dest = *(int*)src;
			dest = (int*)dest + 1;
			src = (int*)src + 1;
		}
	}
//从后往前打印
	else
	{
		while (k--)
		{
			*( (char*)dest + k) = *((char*)src + k);
		}
	}
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	int i = 0;
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	my_memmove(arr1, arr1+2, 5);
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;

}

接下来为大家详细解释一下为什么要这样实现(就以拷贝5个数据为例):

1.第一种情况(从前向后)

dest的起始位置为3之前的任意地址(即可以是从1开始往后5个空间,也可以是从2开始往后5个空间),要拷贝的src是34567,比如此时dest是12345,我们可以直接把3放到1的位置上,4放到2的位置上,5放到3的位置上,6放到4的位置上,7放到5的位置上,这时我们可以直接从前向后打印就可以实现函数拷贝;

2.第二种情况(从后往前)

dest的起始位置时3之后(不包括3,因为为3完全重叠,拷贝与否都是看不出来的)7之前(包括7)的任意位置,要拷贝的src是34567,比如此时目标空间dest是56789,这时,我们把7放到9的位置上,6放到8的位置上,往前推,直到把3放到5的位置上,如果我们依旧从前往后放数据,就会出现,3放到了5的位置,4放到6的位置,此时本该5的位置变成了3,继续拷贝只能再次把3放到了7的位置上,4放到了8的位置上,3放到9的位置上,src覆盖了原来要存放dest数据的空间,所以只能从后往前;

3.第三种情况(从前往后或者从后往前)

dest的起始位置在8之后(包括8)的任意位置,要拷贝的src是34567,此时,我们稍加思考就会发现从前往后拷贝或者从后往前拷贝都是可以的。

*( (char*)dest + k) = *((char*)src + k)这是从后往前拷贝函数的实现代码,dest+k我们找到的是目标空间的最后一个位置,src+k是需要拷贝的最后一个数据的位置,然后执行完一次后k--

就实现了从后向前的拷贝。


好了,这就是这两个函数了,通过对比讲解,大家肯定已经掌握了它们的本质,希望大家能戒骄戒躁,好好学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月亮夹馍干

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值