C语言模拟实现memcpy和memmove

文章详细介绍了memcpy和memmove函数的基本概念、功能、使用方法以及如何模拟实现这两个函数。memcpy用于不重叠的内存区域复制,而memmove能处理重叠的内存复制,是memcpy的增强版。文中给出了具体的代码示例来展示它们的工作原理。
摘要由CSDN通过智能技术生成

目录

一.模拟实现memcpy

1.基本介绍

1.1函数原型

1.2功能

1.3头文件

1.4返回值

2.说明

3.memcpy的使用

4.模拟memcpy

二.模拟实现memmove

1.基本介绍

1.1函数原型

1.2功能

1.3头文件

1.4返回值

2.说明

3.使用memmove

4.模拟memmove

4.1分析:

4.2代码解析


一.模拟实现memcpy

1.基本介绍

1.1函数原型

 

 

1.2功能

由src指针指向地址为起始地址的连续num个字节复制到以dest指针指向地址为起始地址的空间内.

1.3头文件

memcpy函数是包含在string.h库里的。

1.4返回值

memcpy函数的返回值是void*类型,指向dest的首地址。

2.说明

1.srouce指针和destination指针所指向的地址不能重叠,函数返回的是指向destination首地址的指针。如果想复制重叠地址的字符串,应该选择用memmove函数。

2.和strcpy函数不同的是,memcpy函数遇到src中的\0并不会停止复制,而是一定要复制完n个字节的字符.

3.strcpy提供了字符串的复制,即strcpy只能用于字符串的复制,并且strcpu会复制字符串末尾的\0.

4.memcpy提供了一般内存的复制,相对于strcpy,memcpy对复制的内容并没有限制。

5.因为memcpy是一个字节一个字节的进行复制的,所以在对整型数组或者其他元素字节不为1的数组进行复制时,传参时要传sizeof(元素类型)*要复制的长度。例如对整形数组就要传sizeof(int)*size。

3.memcpy的使用

 将arr1字符串复制到arr2字符串中:

int main()
{
	char arr1[] = "hello world";
	char arr2[20];
	memcpy(arr2, arr1, strlen(arr1));
	arr2[strlen(arr1)] = '\0'; //将arr2末尾字符置为结束符\0
	printf("%s\n", arr2);
	return 0;
}

//输出结果
hello world

 将arr1的第6个字符开始往后的5个字符复制到arr2中:

int main()
{
	char arr1[] = "hello world";
	char arr2[20];
	memcpy(arr2, arr1+6, 5);
	arr2[5] = '\0';
	printf("%s\n", arr2);
	return 0;
}

//输出结果
world

覆盖arr1中的部分数据:

int main()
{
	char arr1[] = "hello world";
	memcpy(arr1, "xxxxx", 5);
	printf("%s\n", arr1);
	return 0;
}

//输出结果
xxxxx world

4.模拟memcpy

void* my_memcpy(void* dest, const void* src, size_t num)
{
	assert(dest && src); //确保dest和src不为空指针
	char* ret = (char*)dest;// 记录dest的首地址
	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}
int main()
{
	char arr1[20] = "hello world";
	char arr2[] = "------";
	my_memcpy(arr1, arr2, strlen(arr2);
	printf("%s", arr1);
	return 0;
}

//输出结果
----- world

二.模拟实现memmove

1.基本介绍

1.1函数原型

 

void* my_memmove(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	char* ret = (char*)dest;
	if (dest < src)
	{
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	return ret;
}

1.2功能

将num个字节数的字符从src指向的位置复制到dest指向的内存块中。复制就像使用了中间缓冲区一样,允许destsrc重叠。

1.3头文件

memmove函数包含在string.h库中

1.4返回值

memmove函数返回的是void*类型的指针,指向dest的首地址。

2.说明

2.1 和memcpy函数相同,memmove对复制内容没有限制。

2.2 和memcpy函数相同,memmove遇见src中的\0并不会停止复制,而是复制完num个字节数的数据后才停止。

2.3 为了避免溢出,要确保被复制的数组空间足够。

2.4 相对于memcpy函数,memmove能够对重叠空间的内容进行复制。因而可以理解为memmove函数是memcpy函数的加强版。

3.使用memmove

大部分和memcpy函数相同,这里我们只介绍对重叠空间内容的复制。

int main()
{
	char str[] = "memmove can be very useful......";
	memmove(str + 20, str + 15, 11);
	puts(str);
	return 0;
}

//输出结果
memmove can be very very useful.

4.模拟memmove

4.1分析:

不重叠的时候 跟memcpy函数是类似的。我们只讨论重叠的时候。

第一种情况:当dest指针所指向的地址在src指针所指向的地址的左边时。

 这时候只需要将src所指向的元素从前向后依次复制到dest指向的空间里。每复制一次dest和src都向后挪动一格,直到复制了num个元素停止。

第二种情况:当dest指针所指向的地址在src指针所指向的地址的右边时。

我能想到的只有两种解法:

一是再创建一个数组;二是换一种复制的顺序。

第一种方法因为不知道创建数组需要的空间大小,太小放不下,太大内存浪费 。所以第一种不可取。(VS2019不支持动态数组)。

第二种可以从后向前复制,这样就可以在src所指向的元素被覆盖前就把元素复制过去。

4.2代码解析

void* my_memmove(void* dest, const void* src, size_t num)
{
	assert(dest && src);      //防止dest和src为空指针
	char* ret = (char*)dest;    //记录dest数组的首地址
	if (dest < src)         //第一种情况
	{
		while (num--)
		{
			*(char*)dest = *(char*)src;  //因为dest 和src均为无类型指针,所以不能直接解引用
			dest = (char*)dest + 1;   //同样空指针不能进行算术计算,先将dest转换成char*类型
                                      //的指针,然后因为对无类型指针强制类型转换只是暂时的,所
			src = (char*)src + 1;     //以左边依然是无类型指针,可以接收任意类型的指针。
		}
	}
	else            //第二种情况
	{
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	return ret;
}
int main()
{
	char arr1[20] = "abcdef";
	my_memmove(arr1 + 3, arr1, 3);
	printf("%s", arr1);
	return 0;
}


//输出结果
abcabc

以上就是我们对memcpy函数和memmove函数的使用和模拟实现啦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值