前言:在之前的文章中,介绍了一些简单实用的字符串函数,但是这些函数只能对字符串使用,适用性太狭小。所以在本章,将介绍几个内存操作函数,适用于所有类型的数据。
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函数的原理,便于更好的掌握使用。
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类似,但是支持拷贝重叠部分
cplusplus对其介绍如下:(仅供参考,看不懂英文也没关系)
由图可知,memmove函数具有3个参数,第一个为目的地,第二个为源(要复制的内容),第三个为想要复制的字节数n。
通俗点说:将源(第2个参数)的n(第3个参数)个字节的数值复制到目的地(第1个参数),总体来说与memcpy无差别,但memmove允许目的地和来源重叠。
1.第3个参数的单位是字节,使用时要考虑数据类型。
2. 目的地必须是可变的,比如常量字符串不可变,不能作为目的地
3.目的地必须足够大,能够存放的下拷贝的内容
通过代码模拟实现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:对哪里有问题的朋友,可以在评论区留言,若哪里写的有问题,也欢迎朋友们在评论区指出,博主看到后会第一时间确定修改。最后,制作不易,希望朋友们给点点赞和关注。