C语言自行实现内存函数的过程与思考:memcpy和memmove

先上代码

memcpy

void* my_memcpy(void* dest,const void* src,size_t num)

{

	void* ret = dest;

	assert(dest && src);

	while (num--)

	{

		*(char*)dest = *(char*)src;

		dest = (char*)dest + 1;

		src = (char*)src + 1;

	}

	return ret;

}

int main()

{

	int arr1[] = { 1,2,3,4,5,6 };

	int arr2[10] = {0};

	my_memcpy(arr2,arr1,12);

	int i = 0;

	for (i = 0; i < 3; i++)

	{

		printf("%d ", arr2[i]);

	}

	return 0;

}

memmove

void* my_memmove(void* dest,const void* begin, size_t size)

{

	void* tmp = dest;

	assert(dest && begin);

	if (dest < begin)

	{

		while (size--)

		{

			*(char*)dest = *(char*)begin;

			dest = (char*)dest + 1;

			begin = (char*)begin + 1;

		}

	}

	else

	{

		while (size--)

		{

			*((char*)dest + size) = *((char*)begin + size);

		}

	}

	return tmp;

}

int main()

{

	int arr1[] = { 1,2,3,4,5,6 };

	my_memmove(arr1+2,arr1,12);

	int i = 0;

	for (i = 0; i < 6; i++)

	{

		printf("%d ", arr1[i]);

	}

	return 0;

}

memcpy:

首先memcpy有三个参数:拷贝目标地址,拷贝数据的源头地址和需要拷贝的字节个数。它们的类型分别对应void* (因为其可以接受任意类型的地址), const void* (同上,const是因为源头的数据不需要被改变),以及size_t (单位为字节,因为是内存)。函数的整体返回类型是void*,是因为在实现内存拷贝后,我们需要将拷贝目标的起始地址返回过来,所以同样是可以接受任意类型的地址。

memcpy的实现:首先在进行逐字节拷贝的过程中,目标地址dest会发生变化,于是这里我们创建了一个临时的 void* 变量 ret 来记录一下目标的起始地址,以便于整个函数完成后的地址返回。接下来就是进行逐个字节拷贝中要进行的问题:void* 类型的指针不能直接被检引用或加减,于是我们需要进行强制类型转换,其中 char* 类型被检引用只能获取一个字节十分合适,于是才有了 *(char*)dest = *(char*)begin; 。在进行了一个字节的拷贝后,地址需要转到下一个需要被拷贝的字节,于是要用++操作,强制类型转换是临时的,所以这里需要重新强制类型转换成 char*,加一后再赋值给下一个 void* 类型的地址。此循环操作取决于需要拷贝的字节数量,也就是传过来的num,于是可以用while循环解决。最终函数返回之前存的拷贝目标起始地址。

memmove: 

此函数的实现与memcpy十分相似,甚至可以说是memcpy的升级版。三个参数的功能与memcpy一致: 拷贝目标地址,拷贝数据的源头地址和需要拷贝的字节个数。并且memmove还解决了在同一字符串中移动数据可能会被覆盖的困难。设想一下:我们要将12345中的123移动(本质也是拷贝)到345的位置变成12123。在使用memcpy的过程中:1拷贝到3,2拷贝到4,当我们想把3移到5时,我们会发现3的位置已经被拷贝到这里的1霸占了,结果会改变(不同编译器结果不同,但代码是有问题的)。于是乎memmove应运而生。

memmove的实现:首先,按照惯例创建临时void*变量tmp记录一下目标的起始地址。接下来便是不一样的操作,我们首先需要比较一下目标地址和拷贝起始地址的大小,这一步的原因如下:
在上面例子里3会被拷贝过来的1霸占,所以这时拷贝的顺序需要颠倒过来,3拷贝到5,2拷贝到4,1拷贝到3,一切正常。其前提就是 拷贝起始地址begin < 目标地址dest 。这里我先使用了if函数:目标地址比拷贝起始地址小时,这种情况下就不需要我们以颠倒顺序来进行字节拷贝,所以它的实现就和memcpy一模一样,这里直接照搬。那么else中实现的便是颠倒顺序的字节拷贝,这里不需要像memcpy那么复杂,我们首先要在强制类型转换成char*时直接加上我们需要转换的字节个数size后检引用,随后这个循环将会随着size--来进行逐字节拷贝,直至结束。

本人这里还使用了memmove测试两个不同字符串之间的字符拷贝,由于不同字符串占的地址空间不同,所以无论是进行顺序还是逆序拷贝,都不存在数据的覆盖。这边个人想法是memcpy可以直接被memmove所取代,也就是完爆,请问您怎么看?

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值