C语言重点——剖析内存函数memcpy和memmove

今天来讲讲,复制内存块函数memcpy和移动内存块函数memmove与字符窜函数的区别。

由于字符窜函数strcpy等只能处理字符窜,面对其他类型时它束手无策。而内存函数很好的弥补了字符窜函数的不足,不管任何类型都可以进行处理。

首先看看内存函数的参数和运行场景:

 我们进行一个实例看看它的结果会怎么样:

#include<stdio.h>
#include<string.h>
int main()
{
	int arr1[5] = { 0 };
	int arr2[5] = { 1,2,3,4,5 };
	memcpy(arr1, arr2, 12);
	for (int i = 0; i < 5; i++)
	{
		printf("%d", arr1[i]);
	}
	return 0;
}

可以看到给定12字节个数。他就会把源数组arr2起始地址开始里面的12字节拷贝到目标数组arr1里面,比字符窜函数strcpy更强大更牛逼。它只需要拷贝字节数,并不要求是什么类型

那我们不妨自己来模拟实现一下memcpy函数,首先分析memcpy的参数:参数1是传目标起始地址,参数2是传源目标起始地址(参数2进行了const修饰,不允许修改内容),参数三是传需要拷贝的字节数, 返回类型是void*类型,声明部分就分析完了

接着我们分析内部实现:因为传参没有规定类型,所以我们对它进行拷贝的时候最好是一个一个字节的进行拷贝。如:(char *)destination=(char *)source,然后destination往后走一个字节,source往后走一个字节,直到把num个字节都拷贝完。但是我们这儿又不能写成(char *)destination++=(char *)source++,因为强制类型转换在这只是临时的,等后边的++结合的时候又变成void *类型了。所以这儿我们选择用destination=(char *)destination+1和source=(char *)source+1来使他们往后走一个字节。因为还要返回目标的起始地址,所以我们一开始用个指针接收一下。现在分析完了,开始操作实现代码。

#include<stdio.h>
#include<string.h>
#include<assert.h>
void* my_memcpy(void* dest,const void* score,size_t num)
{
	assert(dest && score);//因为下面要用指针内部内容,所以判断一下不能是空指针
	void * ret = dest;
	while (num--)
	{
		*(char *)dest=*(char *)score;
		 dest=(char *)dest+1;
		 score=(char *)score+1;
	}
	return ret;
}
int main()
{
	int arr1[5] = { 0 };
	int arr2[5] = { 1,2,3,4,5 };
	my_memcpy(arr1, arr2, 12);
	for (int i = 0; i < 5; i++)
	{
		printf("%d", arr1[i]);
	}
	return 0;
}

运行结果我们可以看到我们自己实现的这个函数和库里面的memcpy一样了。

但是有没有想过这种情况,直接情况+图片展现给大家方便了解

假设有数组 arr[10]={1,2,3,4,5,6,7,8,9,10};

情况:如果我们想把从下标为0位置往后的五个元素复制到从下标为2往后的五个元素会怎么样

我们可以看到并不是我们想要的结果,我们想输出12123458910而它输出的是12121218910.让我们画个图看一下内部到底是因为什么

这时候发现倒着存放就可以避免了。

面对这种时候其实库函数还提供了一个函数叫做memmove内存块移动函数。可以直接实现。

用例展示:

#include<stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	 memmove(arr+2, arr, 20);
	for (int i = 0; i < 10; i++)
	{
		printf("%d", arr[i]);
	}
	return 0;
}

接着我们自己来看看memmove函数,然后模拟实现一下。

 

现在我们开始实现它,发现只要把第二种的情况补充上就好了。

#include<stdio.h>
#include<assert.h>
#include<string.h>

void* my_mmove(void* dest, void* score, size_t num)
{
	void* ret = dest;
	assert(dest && score);
	if (dest < score)
	{
		while (num--)
		{
			*(char*)dest = *(char*)score;
			dest = (char*)dest + 1;
			score = (char*)score + 1;
		}
	}
	else
	{
		while (num--)
		{
			*((char*)dest + num) = *((char*)score + num);
		}
	}
	return ret;
}
int main()
{
	 
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	my_mmove(arr+2, arr, 20);
	for (int i = 0; i < 10; i++)
	{
		printf("%d", arr[i]);
	}
	return 0;
}

 

 到这咱们就模拟实现完memmove函数了!

感谢各位朋友的支持!下次再见

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值