函数 - memcpy( )
一、前言
memcpy() 函数到底是干什么嘞呢😕一般从函数名字里就可以看出函数的功能,此函数即可,mem是memory的缩写,cpy是copy的缩写。二者合体就是内存复制的意思。咋个复制法呢🤔我们先来看官方解释🌞
二、官方解释
以下解释来源于:https://cplusplus.com/reference/cstring/memcpy/?kw=memcpy
此函数的声明如下:
void * memcpy ( void * destination, const void * source, size_t num );
size_t表示无符号整型。有了函数声明我想大家已经构想出函数的实现了(❁´◡`❁)。
<>这是官方英文解释:
<>这是翻译后的:
概括一下
将 num 字节值从源指向的位置直接复制到目标内存块。
源指针和目标指针所指向的对象的基础类型与此函数无关;结果是数据的二进制副本。
该函数不检查源中是否有任何终止空字符 - 它始终精确地复制数字字节。
为避免溢出,目标参数和源参数所指向的数组的大小应至少为 num 个字节,并且不应重叠(对于重叠的内存块,memmove 是一种更安全的方法)。
函数memcpy从source的位置开始向后复制num个字节的数据到destinatation
这个函数在遇到 ‘\0’ 的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是未定义的。
这是官方给的例子,举了结构体的拷贝:
/* memcpy example */
#include <stdio.h>
#include <string.h>
struct {
char name[40];
int age;
} person, person_copy;
int main ()
{
char myname[] = "Pierre de Fermat";
/* using memcpy to copy string: */
memcpy ( person.name, myname, strlen(myname)+1 );
person.age = 46;
/* using memcpy to copy structure: */
memcpy ( &person_copy, &person, sizeof(person) );
printf ("person_copy: %s, %d \n", person_copy.name, person_copy.age );
return 0;
}
运行结果如下:
三、参数解析
参数 | destination | source | num |
---|---|---|---|
解析 | 目标空间地址 | 待拷贝空间源地址 | 待拷贝内容字节数 |
四、功能实现
看完官方文档,我想我们可以自己尝试实现一下这个功能
void* My_memcpy(void* dest,const void* src, size_t num)
{
assert(dest && src); //断言一下,就像倒水一样,看看有没有存水空间
void* ret = dest; //把目标首地址记下来,最后return的就是它
while (num--)
{ //这个操作就是一个一个复制
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret; //返回目标首地址
}
大家可以思考一下这个实现存在什么问题🤔
五、用法
<1> 第一种用法
描述:将指定长度的字符串复制到目标字符串。(有长度限制)
参数:memcpy(target, str , sizeof(char) * n)
解释:将字符串str的前n个字符复制到target中。
其实这里 sizeof(char) * n 可以直接写成 n,因为一个字符占一个字节
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char target[100];
char str[]="I am handsome";
memcpy(target,str,7);
cout<< "复制之后的结果:%s" << target << endl;
return 0;
}
运行结果:
<2> 第二种用法
描述:将指定区间的字符复制到目标字符串。
参数:memcpy(target, str + n1 , sizeof(char) * n2)
解释:将str中从第3个字符开始的连续5个字符复制到target中。
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char target[100];
char str[]="I am handsome";
memcpy(target,str + 2, sizeof(char) * 5);
cout<< "复制之后的结果:%s" << target << endl;
return 0;
}
运行结果:
<3> 第三种用法
描述:将指定长度的字符覆盖到到目标字符串。
参数:memcpy(target, str , sizeof(char) * n)
解释:将字符串str的前n个字符覆盖到target中。
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char target[] = "I am handsome";
char str[]="*****";
memcpy(target,str, sizeof(char) * 5);
cout<< "复制之后的结果:%s" << target << endl;
return 0;
}
运行结果:
<4> 第四种用法
描述:将指定长度的字符覆盖到到目标字符串的指定位置。
参数:memcpy(target + 2, str , sizeof(char) * 2)
解释:将字符串str的前2个字符覆盖到target从第三个开始的位置出。
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char target[] = "I am handsome";
char str[]="*****";
memcpy(target + 2,str, sizeof(char) * 2);
cout<< "复制之后的结果:%s" << target << endl;
return 0;
}
运行结果:
看到这,大家应该会想到,还可以将待复制地址的指定区间覆盖到目标地址的指定区间。下面就不再展示了。
六、总结
但是用这个函数的时候我们要注意三个点
1. 一定要注意memcpy函数第三个参数传的是待传内容的字节数
举个例子,如果我们想把整形数组arr1中前五个元素传中arr2,在memcpy就要写20。为什么呢?因为arr1为整型数组,其中包含的元素也是整型,是4个字节。而我们要传递五个整型,所以就是4*5个字节
2. 目的空间大小一定要能容纳memcpy所拷贝的内容
如果拷贝在内容超过目的空间大小,那么就会溢出 编译器会报出警告
3. 尽量避免dest和src所指向的地址有内存重叠的部分(这就是上面自己实现时没有考虑到的情况)
例如:我们想把arr1中1、2、3分别拷贝到3、4、5的位置时,就出现了内存重叠的现象。
(其实,C语言自带的memcpy函数避免了这个问题(从低地址向高地址复制的时候,出现重叠,导致得到远离目标的结果))
到这里,memcpy( ) 函数就讲解完毕了,感谢您观看至此,若发现错误,敬请评论区自由批评指正,吾自当洗耳恭听并改正哈哈;如果大家觉得我写得还不错的话,还请点一波赞哈哈,您的肯定是对我创作的鼓励和支持,是我进一步创作的动力(❁´◡`❁)!
参考文献
- https://blog.csdn.net/weixin_53564801/article/details/123933689?spm=1001.2101.3001.6650.5&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-5-123933689-blog-122409857.235%5Ev38%5Epc_relevant_anti_t3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-5-123933689-blog-122409857.235%5Ev38%5Epc_relevant_anti_t3&utm_relevant_index=10
- https://blog.csdn.net/m0_65601072/article/details/125904069