memcpy、memmove的使用和模拟实现

一、memcpy的使用

memcpy是C语言的一个库函数,它与strcpy有相似之处,都是对一组数据进行剪切,但是memcpy可以对各种类型的数据进行剪切,而strcpy是字符串函数,它只能对字符串进行剪切

使用memcpy之前我们可以先看一下它的参数和返回类型,

 接下来我们对整形数组进行剪切,代码如下:

#include<stdio.h>
#include<string.h>
//memcpy的头文件
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };
	memcpy(arr2, arr1, 20);
//20为要剪切的字节数
		for (int i = 0; i < 20; i++)
			printf("%d ", arr2[i]);
   return 0;
}

运行结果如下:

可以看到,我们剪切了20个字节,也就是5个整形。

二、memcpy的模拟实现

前面我们已经了解了mencpy的参数以及返回值,我们可以根据它来设计my_memcpy的参数以及放回值,下面看具体的代码实现:

#include<stdio.h>
#include<string.h>
//返回目标空间的起始地址
void* my_memcpy(void* p2, void* p1, size_t num)
{
	void* ret = p2;
	//由于我们要返回的值是目标空间的起始地址,因此我们需要先记录起始地址p2,
	//因为p2在后面的运算中会发生改变,就不再是其实地址了
	for (int i = 0; i < num; i++)
	{
		*(char*)p2 = *(char*)p1;
		((char*)p1)++;
		//强制类型转化是临时的,因此不能写成(char*)p1++,必须再来一个括号括起来
		((char*)p2)++;
	}
	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);
	for (int i = 0; i < 20; i++)
		printf("%d ", arr2[i]);
   return 0;
}

其中,((char*)p2)++,((char*)p1)++也可以写成p2=(char*)p2+1;  p1=(char*)p1+1;

三、memmove的使用

对于memcpy,有一个问题,那就是当需要剪切的内存空间发生重叠时,其结果可能是未定义的(当然也有可能是对的),如以下一段代码:

#include<stdio.h>
#include<string.h>
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	memcpy(arr1 + 2, arr1, 20);
	//在这里我们想要将1,2,3,4,5剪切到3,4,5,6,7中
	//那么这里就发生了内存的重叠
		for (int i = 0; i < 10; i++)
			printf("%d ", arr1[i]);
   return 0;
}

在这段代码中,我们预期的结果是1 2 1 2 3 4 5 8 9 10,那么如果是要运行这段代码的话,结果可能是对的,也可能是错的,因此如果是要对有内存重叠的数据进行剪切的话,使用memmove函数

下面我们来看memove的使用:

可以发现,它的返回值与参数与memmove一模一样,其使用如下:

#include<stdio.h>
#include<string.h>
int main()
{
	int arr1[] = { 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的模拟实现

在编写代码之前我们先分析以下,如下图:

我们的目的是将1,2,3,4,5剪切到3,4,5,6,7中,那么首先p1指向的值会赋值给p2指向的空间 ,然后p1,p2自增指向2和4,然后再进行赋值,那么我们发现,当我们想要将原来的5改成3是,3已经消失了,已近被改为了1,为了避免这种情况,我们可以从后往前开始交换,但是如果是将3,4,5,6,7,拷贝到1,2,3,4,5怎么办呢,这个时候我们可以从前往后交换,当然如果两组数据之间没有内存重叠的话,两种方法都适用,下面是代码的实现:

#include<stdio.h>
void* my_memmove(void* p2, void* p1, size_t num)
{
	void* ret = p2;
	//通过比较两个地址的大小来确定剪切方向
	if (p2 < p1)
		//前->后
		//这种情况的思路和memcpy一样
	{
		for (int i = 0; i < num; i++)
		{
			*(char*)p2 = *(char*)p1;
			((char*)p2)++;
			((char*)p1)++;
		}
	}
	else
		//后->前
		//我们可以再p1\p2强制类型转化为char*后加上19,刚好使
		//p1,p2都指向最后一个数据
	{
		while (num--)
		{
			*((char*)p2 + num) = *((char*)p1 + num);
		}
	}
	return ret;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr1+2, arr1, 20);
	for (int i = 0; i < 10; i++)
		printf("%d ", arr1[i]);
   return 0;
}

运行结果如下,可以看到结果与预想的相一致,

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值