【C语言进阶】模拟实现memcpy memmove函数

一、memcpy函数

上一篇博客我们已经实现了 strcpy函数,有同学可能会问已经有了 strcpy 函数,为什么还要有memcp函数呢? 其实strcpy函数他只能操作字符串,对其他类型它是没有办法操作的,比如 int arr[5] = {1, 2, 3, 4, 5}像这个整型数组strcpy函数是不能进行操作的,只能运用memcpy函数,下面我们先看一下memcpy函数:

可以看到它的形参有三个 目标空间地址void* dest, 数据来源的地址const void*src,以及需要拷贝的字节数 size_t count 。因为我们不知道需要拷贝的数据是什么类型,那么为了它的通用性所以用来接受地址的指针都是void*。需要注意的是:

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

2.这个函数在遇到'\0'时不会停止

3. 如果src 和dest 有任何的从叠,复制的结果都是无效的。

先来看一个memcpy函数的应用:

【C语言进阶】模拟实现memcpy memmove函数_第1张图片

下面我们来实现这个函数:

#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
void* my_memcpy(void* dest, const void* src, size_t count)
{
	assert(dest && src);
	void* ret = dest;
	while (count--)
	{
		*(char*)dest = *(char*)src;//无类型指针不能进行解引用操作(不确定访问几个字节)
		                           //也不能进行 + -整数操作,所以要先进行强制类型转换
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}

int main()
{
	int arr1[20] = { 1, 2, 3, 4 };
	int arr2[] = { 7, 8 ,9, 10, 11, 12, 45, 56, 89 };
	my_memcpy(arr1, arr2, 36);
	
	int i = 0;
	for (i = 0; i < 9; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

我们刚刚讲了src和dest有重叠的部分,复制的结果是无效的,那么我们试一试 

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

这个代码的意思是将 1 2 3 4复制到从arr1[2]开始的四个数字,我们想要的结果应该是1 2 1 2 3 4;

但结果并不是这样,而是1 2 1 2 1 2。

 【C语言进阶】模拟实现memcpy memmove函数_第2张图片

为什么会这样呢?

其实你在将arr1[0]复制到arr[2]后,arr1[2]就变成了arr1[0]的值原来的值已经被覆盖掉了,你在将arr1[2]的值往后复制其实就是复制的arr1[0]的值,所以结果才会错误。为了解决这个问题就有了下面的函数memmove

 二、memmove函数

我们先来看一下这个函数:

可以看到形参和memcpy函数相同,但是功能确是不同,它主要来处理目标空间和源空间出现重叠的情况;还是刚才的代码,把memcpy改成memmove我们看一下结果 :

【C语言进阶】模拟实现memcpy memmove函数_第3张图片

这样结果就对了。

那么它是怎样实现的呢?其实它的实现分3种情况:

1. dest 在 src前(dest小于src) 

【C语言进阶】模拟实现memcpy memmove函数_第4张图片

 这种情况下,我们采用从前端开始复制,即从后往后开始,先将4复制到1的位置,以此类推,这样的话在4被覆盖之前我们已经复制过了,也就不会影响结果。

2. dest 在 src后,(dest大于scr)

【C语言进阶】模拟实现memcpy memmove函数_第5张图片

 在种情况下我们采用从src的后端开始复制,即从后往前复制,先将4复制到6的位置,接着3复制到5的位置,以此类推。同样的在4被覆盖之前已经复制过了,当然也就不会影响结果;

3.当两者没有交集的时候,以上两种方式后可以。

代码实现:

#include
#include

void* my_memmove(void* dest, const void* src, size_t count)
{
	assert(dest && src);
	//从前向后
	void* ret = dest;
	if (dest < src)
	{
		while (count--)
		{
			*(char*)dest = *(char*)src; //无类型指针不能进行解引用操作(不确定访问几个字节)
					                    //也不能进行 + -整数操作,所以要先进行强制类型转换
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	//从后向前
	else
	{
		while (count--)
		{
			*((char*)dest + count) = *((char*)src + count);
		}
	}
	return ret;
}

int main()
{
	int arr1[20] = { 1, 2, 3, 4 };
	my_memmove(arr1+2, arr1, 14);
	
	int i = 0;
	for (i = 0; i < 6; i++)
	{
		printf("%d ",arr1[i]);
	}
	return 0;
}

本篇博客到这就算结束了!感谢大家的观看,如果有错误请各位前辈指正!!!感激不尽

你可能感兴趣的:(c语言)