系统相关
首页 > 系统相关> > 内存函数memcpy&memmove分析与实现

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

作者:互联网

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