前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >内存函数memcpy和memmove详解及模拟实现

内存函数memcpy和memmove详解及模拟实现

作者头像
咬咬
发布2024-06-12 14:06:08
960
发布2024-06-12 14:06:08
举报
文章被收录于专栏:学习笔记学习笔记

   前言:

                     大家好,我学习完memmove函数后做了如下一些总结,和大家一起探讨交流,如有错误和遗漏欢迎大家在评论区指出。

介绍memmove函数:

          君子性非异也,善假于物也。想要了解一个函数,首先可以利用工具,了解它的基本用法

这里我用www.cplusplus.com这个网站进行查找。

通过这个网站我们可以基本了解到这个函数的作用:

从*source一个字节一个字节的拷贝num个字节到*destination

区分memcpy和memmove:

       在学习memmove之前,我们可以先了解一下memcpy,同样通过上面的网站查找:

不难发现,这两个函数的差别好像不大

其实 标准值规定:

memcpy来实现不重叠的内存拷贝;

memmove来实现重叠的内存拷贝。

那么什么是重叠的内存拷贝呢?

代码语言:javascript
复制
int main()//内存里以字节为单位拷贝
{
	int arr1[] = { 1,2,3,4,5,6,7,8 };
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	memmove(arr1, arr1+2, 20);
	print(arr1, sz);
	return 0;
}

像我这样*source是arr1+2,*destination是arr1,拷贝20个字节,可以发现数组中3,4,5所占的字节重叠了,这就是重叠的内存。

模拟实现memcpy:

    由浅入深,我们先来模拟不重叠的内存拷贝也就是模拟memcpy:

先准备两个数组,写一个打印数组的函数:

代码语言:javascript
复制
#include<stdio.h>
void print(int arr[], int sz)//打印数组的函数
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}
int main()//内存里以字节为单位拷贝
{
	int arr1[] = { 1,2,3,4,5,6,7,8 };
	int arr2[] = { 9,8,7,6,5 };
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	my_memcpy(arr1, arr2, 16);
	print(arr1, sz);
	return 0;
}

接下来就是拷贝过程的实现:

其实只要利用循环,将*destination = *source,再都加上1,循环num次,但要注意他们都是void*类型,想要一个字节一个字节的拷贝和进行加减操作的话,必须先把他们强制转换为char*类型

代码语言:javascript
复制
void* my_memcpy(void* dest, const void* src, size_t num)
{
	void* arr3 = dest;
	while (num--)
	{
		*((char*)dest) = *((char*)src);
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return arr3;
}

最后整个代码如下:

代码语言:javascript
复制
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void print(int arr[], int sz)//打印数组的函数
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}
void* my_memcpy(void* dest, const void* src, size_t num)
{
	void* arr3 = dest;
	while (num--)
	{
		*((char*)dest) = *((char*)src);
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return arr3;
}
int main()//内存里以字节为单位拷贝
{
	int arr1[] = { 1,2,3,4,5,6,7,8 };
	int arr2[] = { 9,8,7,6,5 };
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	my_memcpy(arr1, arr2, 16);
	print(arr1, sz);
	return 0;
}

运行输出如下:

模拟实现memmove:

其实重叠部分的拷贝难点就在于:当进行到重叠部分的拷贝时,可能原始数据已被修改,导致拷贝出错,最简单的解决办法就是将原始数据再放入一块空间记住下来,但是这样就又多占了一块内存,有没有其他更高效的方法呢?

很简单可以分两种情况:

1.*destination在*source前面:

这个时候我们像memcpy一样拷贝可以拷贝完成。

2.*destination在*source后面:

这时候再从前往后拷贝,就会把修改过的数据再次拷贝一份。

解决方法就是不妨试试从后往前拷贝,这样就可以完成,所以最后函数内部代码如下:

代码语言:javascript
复制
void* my_memmove(void* dest, const void* src, size_t num)
{
	void* arr3 = dest;
	assert(dest && src);
	if (dest < src)//从前往后拷贝
	{
		while (num--)
		{
			*((char*)dest) = *((char*)src);
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else if (dest > src)//从后往前拷贝
	{
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}

	return arr3;
}

最后整个代码如下:

代码语言:javascript
复制
#include <stdio.h>
#include<assert.h>
void print(int arr[], int sz)//打印数组的函数
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}
void* my_memmove(void* dest, const void* src, size_t num)
{
	void* arr3 = dest;
	assert(dest && src);
	if (dest < src)//从前往后拷贝
	{
		while (num--)
		{
			*((char*)dest) = *((char*)src);
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else if (dest > src)//从后往前拷贝
	{
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}

	return arr3;
}
int main()//内存里以字节为单位拷贝
{
	int arr1[] = { 1,2,3,4,5,6,7,8 };
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	my_memmove(arr1, arr1+2, 20);
	print(arr1, sz);
	return 0;
}

运行输出如下:

最后拷贝成功。

大家有什么建议或者补充欢迎大家留在评论区,谢谢大家。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-10-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  •    前言:
  • 介绍memmove函数:
  • 区分memcpy和memmove:
  • 模拟实现memcpy:
  • 模拟实现memmove:
    • 1.*destination在*source前面:
      • 2.*destination在*source后面:
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档