memcpy()&memmove()

120 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情

👋『大家好,我是謓泽,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流>』
✔「life motto」⇢ 种一棵树最好是十年前⇿其次是现在👌
📝<juejin>个人主页謓泽 的个人主页 - 文章 - 掘金 (juejin.cn)
📚<系列专栏>⇥51单片机 - 謓泽的专栏 - 掘金 (juejin.cn)

 🎆memcpy() - 内存拷贝不重叠🎇

memcpy()指定头文件是:#include<string.h>

memcpy() 函数的声明方式如下 👇 

void *memcpy(void *str1, const void *str2, size_t n)

参数讲解:↓

  1. str1 → 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
  2. str2 → 指向要复制的数据源,类型强制转换为 void* 指针。
  3. n  →  要被复制的字节数。size_t实际上就是和无符号差不多的。

这里注意下它的参数的数据类型是无类型指针也就是说它是不会说必须是要整形指针类型或者是字符串类型这种,它所有的数据类型都是可以适用的因为它是 void * 类型的。

返回值:该函数返回一个指向目标存储区 str1 的指针。

🎆memcpy()代码示例🎇

这个代码是把arr1的元素赋值给arr2的元素,但是只是赋值前五个元素。这里我们就可以用memcpy()内存函数来进行实现。

示例代码如下 ↓

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main(void)
{
	int arr1[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int arr2[10] = { 0 };
	memcpy(arr2, arr1, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(arr2 + i));
	}
}

运行结果 ↓

1 2 3 4 5 0 0 0 0 0

🎆创建自定义函数实现memcpy()🎇

📑注意⇢在无类型指针数据类型的时候我们是不能直接进行解引用操作以及++--的,因为它是无具体类型的指针,因为我们++--或者是解引用访问的时候我们不知道到底要访问多少个字节。在这里转换成char*指针类型是最合适的,它是一个字节一个字节拷贝过去的。

示例代码如下 👇

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
void *my_memcpy(void *str1, const void *str2, size_t n)
{
	assert(str1 && str2 != NULL);
	void *ret = str1;
	while (n--)
	{
		*(char*)str1 = *(char*)str2;
		str1 = (char*)str1 + 1;
		str2 = (char*)str2 + 1;
	}
	return ret;
}
int main(void)
{
	int i;
	int arr1[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int arr2[10] = { 0 };
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	int *ret = my_memcpy(arr2, arr1, 20);
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(ret + i));
	}
	return 0;
}

运行结果 ↓

1 2 3 4 5 0 0 0 0 0

那在这里假设我们想要重arr1当中第三个元素开始进行拷贝怎么办,很简单只需要改变下memcpy();当中第二个参数就可以,如上代码位为演示:↓

int *ret = my_memcpy(arr2, arr1+2, 20);

只需要这个样子运行结果就会重第三个元素开始,这里+2是下标是从0开始的注意下这点。 

那么这里的运行结果就是:3 4 5 6 7 0 0 0 0 0

🔥注意⇢memcpy函数应该拷贝不重叠的内存。


🎉memmove() - 内存拷贝可重叠🎊

memmove() 指定头文件是:#include<string.h>

实际上memmove()函数和memcpy()函数的用法是一样的,但是既然是不同的函数还是具有不同之处的:↓

  • memmove()函数是可以处理内存重叠的情况的。
  • memcpy()函数应该可以拷贝的是不重叠内存的情况的。
  • 在这里重叠的意思实际上就是数组名相同的。

memmove() 函数的声明方式如下 👇  

void *memmove(void *str1, const void *str2, size_t n)

 在这里我们可以发现是和memcpy()是一样的。

参数讲解:↓

  • str1 → 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
  • str2 → 指向要复制的数据源,类型强制转换为 void* 指针。
  • n → 要被复制的字节数。

返回值→该函数返回一个指向目标存储区 str1 的指针。

🎉memmove()代码示例🎊  

用同一个数组名进行内存拷贝。

示例代码如下 ↓

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

运行结果 ↓

1 2 1 2 3 4 5 8 9 10

🔥注意:在这里如果你用memcpy()函数的话是不可以的。其实这个就是memcpy()函数和memmove()函数的区别所在了。

🎉创建自定义函数实现memmove()🎊 

示例代码如下 👇

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
void *my_memmove(void *str1, const void *str2, size_t n)
{	
	void *ret = str1;	
	assert(str1 && str2 != NULL);
	if (str1 < str2)
	{
		//前向后,小于。
		while (n--)
		{
			*(char*)str1 = *(char*)str2;
			str1 = (char*)str1 + 1;
			str2 = (char*)str2 + 1;
		}
	}
	else
	{
		//后向前,大于。
		while (n--)
		{
			*((char*)str1 + n) = *((char*)str2 + n);
		}
	}
	return ret;
}
int main(void)
{
	int i = 0;
	int arr1[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	//               1  2  1  2  3  4  5  8  9  10
	my_memmove(arr1+2, arr1, 20);
	return 0;
}

先来看看 str1 > str2 的调试结果↓

再来看看 str2 < str1 的调试结果↓ 把上述代码的这段修改下即可。

my_memmove(arr1, arr1+2, 20);

不知道你学会了没有👀反复观看✨