memcpy函数的作用以及四种用法,后面那三种很巧妙(看完不亏)

memcpy()函数用于内存块的复制,它不检查源和目标内存是否重叠,如果内存区域重叠,使用memmove()更安全。函数接受目标地址、源地址和字节数作为参数,按字节复制数据。需要注意避免内存溢出和正确计算字节数。文章提供了memcpy的简单实现示例以及多种使用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

函数 - 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表示无符号整型。有了函数声明我想大家已经构想出函数的实现了(❁´◡`❁)。

<>这是官方英文解释:

此处为英文原文档

<>这是翻译后的:

此处为google浏览器翻译结果
概括一下

将 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;
}

运行结果如下:
在这里插入图片描述

三、参数解析

参数destinationsourcenum
解析目标空间地址待拷贝空间源地址待拷贝内容字节数

四、功能实现

看完官方文档,我想我们可以自己尝试实现一下这个功能

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( ) 函数就讲解完毕了,感谢您观看至此,若发现错误,敬请评论区自由批评指正,吾自当洗耳恭听并改正哈哈;如果大家觉得我写得还不错的话,还请点一波赞哈哈,您的肯定是对我创作的鼓励和支持,是我进一步创作的动力(❁´◡`❁)!

参考文献

  1. 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
  2. https://blog.csdn.net/m0_65601072/article/details/125904069
<think>嗯,用户想了解memcpy用法。我需要先回忆一下这个函数的基本信息。memcpy是C语言中的一个库函数,属于<string.h>头文件,对吧?它的作用应该是内存复制,把源地址的内容拷贝到目标地址。 首先,我得确定函数的原型。应该是void* memcpy(void* dest, const void* src, size_t n)。参数分别是目标指针、源指针和要复制的字节数。返回的是目标指针dest。这点需要确认是否正确,避免记错了参数顺序或者返回类型。 接下来,用户可能需要知道如何正确使用它。比如,参数dest和src都需要是有效的指针,而且内存区域应该重叠,否则应该用memmove。这里要强调重叠的问题,因为memcpy处理这种情况,可能导致数据错误。 然后,关于第三个参数,是复制的字节数。需要提醒用户注意数据类型的大小,比如复制一个int数组时,应该用sizeof(int)*元素个数。否则容易算错字节数,导致复制足或越界。 另外,使用memcpy时目标缓冲区必须有足够的空间,否则会造成缓冲区溢出,这是常见的安全问题。这里需要举例说明,比如复制字符串或者结构体的时候,要确保dest有足够的空间。 还要提到返回值,虽然通常使用dest指针,但有时候可以直接用返回值进行链式操作,过这种情况可能太常见,但可以举例说明。 可能用户会混淆memcpy和strcpy的区别。这时候需要指出,strcpy遇到空字符停止,而memcpy严格按字节数复制,管内容。所以对于非字符串数据或者需要精确控制的情况,应该用memcpy。 另外,实际例子会帮助用户理解。比如复制数组、结构体或者内存块的例子。要注意示例的正确性,比如正确计算字节数,避免越界。 可能用户在使用时遇到问题,比如内存重叠导致的数据错误,这时候需要提醒使用memmove代替。或者参数传递错误,比如忘记取地址或者使用错误的指针类型,需要强调类型转换的问题,因为memcpy的参数是void*,所以任何指针都可以直接传入。 还要注意,memcpy是逐字节复制的,所以对于包含指针的结构体,复制后两个结构体的指针会指向同一块内存,这可能引发问题,属于浅拷贝的问题,需要用户自己处理深拷贝。 最后,需要检查有没有常见的错误用法,比如目标空间足,或者size计算错误。确保提供的示例代码正确,并标注必要的注释,帮助用户理解每一步的作用。</think>memcpy 是 C/C++ 中用于内存拷贝的标准库函数,以下是其核心用法和注意事项的逐步说明: --- ### **1. 函数原型** ```c #include <string.h> void* memcpy(void* dest, const void* src, size_t n); ``` - **作用**:从源内存地址 `src` 拷贝 `n` 个字节到目标内存地址 `dest` - **返回值**:返回目标地址 `dest`(可直接使用或忽略) --- ### **2. 核心参数** | 参数 | 类型 | 说明 | |--------|--------------|----------------------------------------------------------------------| | `dest` | `void*` | 目标内存地址(需确保有足够空间) | | `src` | `const void*`| 源内存地址(内容会被修改) | | `n` | `size_t` | 要拷贝的字节数(通常用 `sizeof` 计算) | --- ### **3. 使用步骤** #### (1) 基本用法示例 ```c #include <stdio.h> #include <string.h> int main() { char src[] = "Hello, memcpy!"; char dest[20]; // 拷贝整个字符串(包括结尾的空字符) memcpy(dest, src, sizeof(src)); printf("拷贝结果: %s\n", dest); // 输出: Hello, memcpy! return 0; } ``` #### (2) 拷贝结构体 ```c struct Point { int x; int y; }; struct Point p1 = {10, 20}; struct Point p2; // 按字节拷贝结构体 memcpy(&p2, &p1, sizeof(struct Point)); ``` #### (3) 拷贝数组 ```c int arr1[] = {1, 2, 3, 4, 5}; int arr2[5]; // 计算总字节数 = 元素个数 * 单个元素大小 memcpy(arr2, arr1, 5 * sizeof(int)); ``` --- ### **4. 关键注意事项** 1. **内存重叠问题** ❌ 如果 `dest` 和 `src` 内存区域重叠,必须改用 `memmove`(`memcpy` 保证重叠时的正确性) ✅ 正确做法: ```c char str[] = "memmove example"; memmove(str + 3, str, 5); // 安全处理重叠 ``` 2. **缓冲区溢出风险** ```c char src[10] = "123456789"; char dest[5]; // 错误!目标缓冲区大小memcpy(dest, src, 10); // 导致未定义行为 ``` 3. **类型安全** 当处理非字符类型时,必须准确计算字节数: ```c int* src = ...; int* dest = ...; // 正确计算字节数 memcpy(dest, src, num_elements * sizeof(int)); ``` --- ### **5. 与 `strcpy` 的对比** | 特性 | `memcpy` | `strcpy` | |--------------|-----------------------------------|---------------------------| | 终止条件 | 严格按字节数拷贝 | 遇到 `\0` 停止 | | 安全性 | 需手动确保目标空间足够 | 同左 | | 适用场景 | 二进制数据、结构体、数组等 | 仅字符串 | | 性能 | 更高(无终止符检查) | 略低 | --- ### **6. 典型错误案例** ```c // 错误1:忘记计算字节数 float data_src[10]; float data_dest[10]; memcpy(data_dest, data_src, 10); // 应写 10 * sizeof(float) // 错误2:指针未初始化 char* dest; char src[] = "test"; memcpy(dest, src, 5); // dest 未分配内存! ``` --- 掌握 `memcpy` 的关键是:明确内存布局、准确计算字节数、避免内存重叠。在实际项目中,建议配合 `assert` 或条件检查确保缓冲区有效性。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_a_yang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值