前言:在之前的文章中,介绍了一些简单实用的字符串函数,但是这些函数只能对字符串使用,适用性太狭小。所以在本章,将介绍几个内存操作函数,适用于所有类型的数据。

memcpy(拷贝内存块)

cplusplus对其介绍如下:(仅供参考,看不懂英文也没关系)

由图可知,memcpy函数具有3个参数,第一个为目的地,第二个为源(要拷贝的内容),第三个为想要拷贝的字节数n。
通俗点说:将源(第2个参数)的n(第3个参数)个字节的数值拷贝到目的地(第1个参数)

举以下例子,方便理解(字符串):

#include#include//引用字符串函数头文件int main(){char arr1[] = "hello friend"; //源char arr2[10] = "world";//目的地printf("拷贝前:%s\n", arr2);//打印拷贝前的arr2数组,便于比较memcpy(arr2, arr1, 5);//将arr1数组的5个字节的数值拷贝到arr2数组printf("拷贝后:%s\n", arr2);//打印拷贝后的arr2数组return 0;}

输出:

观察上图控制台输出结果,可知arr1数组中的hello拷贝到了arr2数组中,并且将其前五个字节上的值覆盖。由此可见,memcpy可以实现strcpy的功能。

举以下例子,方便理解(整型):

在文章开头,我们说过memcpy的适用性非常广泛,下面再给出拷贝整型的例子,其余类型的拷贝都与此相似。

#include#include//引用字符串函数头文件int main(){int arr1[] = { 1,2,3,4,5,6,7,8,9,0 }; //源int arr2[10]; //目的地memcpy(arr2, arr1, 40); //将arr1数组的40个字节的数值拷贝到arr2数组for (int i = 0; i < 10; i++) { printf("%d ", arr2[i]); //打印拷贝后的arr2数组 }}

输出:

使用时注意事项:

1.第3个参数的单位是字节,使用时要考虑数据类型。
2. 目的地必须是可变的,比如常量字符串不可变,不能作为目的地
3.目的地必须足够大,能够存放的下拷贝的内容

模拟实现memcpy

通过代码模拟实现memcpy的功能,让大家明白memcpy函数的原理,便于更好的掌握使用。

void* my_memcpy(void* dest, const void* rce, size_t num){void* p = dest;//记录其目的地起始地址,便于返回while (num--)//进行num个循环{*(char*)dest = *(char*)rce;//逐字节赋值dest = (char*)dest+1;//目的地地址向后跳一字节rce = (char*)rce + 1;//源地址向后跳一字节}return p;//返回目的地起始地址}

memcpy虽然好用,但是它也有缺陷,在内存重叠的时候,可能会出现意想不到的情况,具体请看以下代码:

#include#include//引用字符串函数头文件int main(){int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };memcpy(arr1+2, arr1, 20);for (int i = 0; i < 10; i++){printf("%d ", arr1[i]);}return 0;}

理想打印出来的应该是1,2,1,2,3,4,5,8,9,10

但是输出结果为:

出现这种输出的原因:

因此,当内存重叠时,不适合使用memcpy函数(某些IDE中就算重叠也不会出现上述情况,但出于严谨,最好还是不要这么使用),下面,我们请出memmove函数,它的功能与memcpy类似,但是支持拷贝重叠部分

memmove(移动内存块)

cplusplus对其介绍如下:(仅供参考,看不懂英文也没关系)

由图可知,memmove函数具有3个参数,第一个为目的地,第二个为源(要复制的内容),第三个为想要复制的字节数n。
通俗点说:将源(第2个参数)的n(第3个参数)个字节的数值复制到目的地(第1个参数),总体来说与memcpy无差别,但memmove允许目的地和来源重叠。

使用时注意事项:

1.第3个参数的单位是字节,使用时要考虑数据类型。
2. 目的地必须是可变的,比如常量字符串不可变,不能作为目的地
3.目的地必须足够大,能够存放的下拷贝的内容

模拟实现memmove

通过代码模拟实现memmove的功能,让大家明白memmove函数的原理,便于更好的掌握使用。

void* my_memmove(void* dest, const void* src, size_t num){if (dest < src)//当目的地地址小于来源地址时,从前向后赋值{while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}}else //当目的地地址大于来源地址时,从后向前赋值{while (num--){*((char*)dest + num) = *((char*)src + num);}}}

将memmove模拟实现的代码与memcpy模拟实现的代码比较,可以看出两者前半部分差不多,但memmove比memcpy多了后半部分当目的地地址大于来源地址时,从后向前赋值的情况,因此它允许目的地和来源重叠。

总结:

memcpy用于目的地和来源不重叠的情况。
memmove无论目的地和来源重不重叠,都可以使用。
可以说memcpy包含在memmove内。

文末BB:对哪里有问题的朋友,可以在评论区留言,若哪里写的有问题,也欢迎朋友们在评论区指出,博主看到后会第一时间确定修改。最后,制作不易,希望朋友们给点点赞和关注。