ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

内存函数memcpy&memmove分析与实现

2022-02-20 11:30:00  阅读:201  来源: 互联网

标签:src memmove dest void char 内存 memcpy


1.几个常见常用内存函数的介绍与使用

在字符串库函数中,strcpy这类函数可以轻松对字符串进行修改,但如果换成int、double这类类型数据时,str家族显得无能为力,由此,mem家族(内存函数)诞生,并可以轻松地解决这类问题


首先我们来看memcpy和memmove 官方给的函数原型与介绍

 推荐查阅网站:

en.cppreferrence.com

cplusplus.com


memcpy和memmove的作用是将src指针处的前count个字节内容拷贝到dest处

特注:此处size_t count是指字节数

他们有三个参数 目标指针dest 源地址src 字节数count

此处开发者将两个关键指针和memcpy/memmove的返回类型都设置为void*

原因就是为了适配,因为开发者无法得知使用者在调用函数时适配的类型,于是设置为百变怪-void* 

举个例子 尝试使用这两个函数(以memcpy为例,memmove的使用同理)

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

想把arr1中前20个字节的元素拷贝到arr2中并打印 这便是内存函数memcpy的作用

效果如→:

2.memcpy模拟实现

成品如下:

//模拟实现memcpy
void* my_memmcpy(void* dest, const void* src, size_t n)
{
	void* ret = dest;
    assert(dest&&src);
	while (n--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}

因为我们在执行memcpy功能时,不会对源指针进行修改,所以这里加const修饰;

char* 一个字节为单位,强制类型转换和我们要拷贝的字节数单位一致;

但是强制类型转化都是临时的,我们在对dest,src操作时切忌dest++,src++,我们还要进行强制类型转化,拷贝一个字节dest、src往后走一个字节;

此处用assert保证dest与src指针为非空指针;


3.memcpy与memmove的区别

我们先来看这个代码

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10};
	my_memcpy(arr + 2, arr, 5 * sizeof(arr[0]));
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

此时我们使用的是自己设计的my_memcpy函数 我们预期的运行结果是

1 2 1 2 3 4 5 8 9 10

但我们会惊讶地发现运行结果和我们设想的不同

这是为什么呢?


这里出现了内存覆盖的情况 我们原本要拷贝的3 4 5被拷贝过来的1 2 1覆盖 导致后面要拷贝3 4 5时 拷贝了1 2 1;

特注特注特注:如果你和博主一样使用vs编译器的话,memcpy在此处可以解决内存重叠的问题,我们可以用memcpy得到下图的预期效果(在某些编译器下memcpy可能不支持重叠拷贝);

但是,C语言库只要求memcpy处理内存不重叠情况 memmove来处理内存重叠的情况;

此时就要使用memmove函数 memmove在进行拷贝的时候,是允许内存重叠的;

这便是我们想要的拷贝效果

 其实在处理这类问题时,无脑用memmove就完事了;

 

4.memmove模拟实现

成品如下:

//模拟实现memmove
void my_memmove(void* dest, const void* src, size_t n)
{
	void* ret = dest;
	assert(dest && src);
	if (dest < src)
	{
		while (n--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src =(char*)src + 1;
		}
	}
	else
	{
		while (n--)
		{
			*((char*)dest + n) = *((char*)src + n);
		}
	}
	return ret;
}

细节与memcpy实现时同理;

在实现3中的重叠问题时,我们可以倒着拷贝

此时dest>src

但dest<src时,倒着拷贝明显也会出现内存重叠


所以此处我们正着拷贝,一个分类解决问题; 

5.总结

memcpy是C语言在发展史中诞生的产物,没办法抹消掉,但他并不是毫无意义;

我们在碰到要使用内存函数拷贝时,使用memmove就可以了;

如有错误,多多斧正;一起成长 一起加油!

标签:src,memmove,dest,void,char,内存,memcpy
来源: https://blog.csdn.net/SudaPXDBD/article/details/123027451

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有