内存函数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