C memcpy() 语法
memcpy() 是 C 语言 <string.h> 或 <memory.h> 标准库的一个函数,它用于将 “源内存区域” 中的指定字节数复制到 “目标内存区域” 中。
语法:
memcpy(dest, src, n)说明:
memcpy() 函数接收以下 3 个参数。
dest(void*):指向目标内存区域的指针。src(const void*):指向源内存区域的指针。n(size_t):要复制的字节数。
memcpy(dest, src, n) 会从 src 指向的内存位置开始,复制 n 个字节到 dest 指向的内存位置。复制是以 “字节” 为单位进行的,我们不需要关心源和目标内存区域中存储的数据类型。
与字符串函数(如 strcpy() 等)不同,memcpy() 不会检查或关心终止符 '\0',它只会精确地复制指定的 n 个字节。
提示:
- memcpy 是 “memory copy” 的缩写。
- memcpy() 函数用于 “复制” 内存中的字节,而 memset() 函数用于 “设置” 内存中的字节。
C memcpy() 摘要
| 使用频率 | 高 |
|---|---|
| 修改字符串 | 是 |
| 官方文档 | 查看 |
C memcpy() 示例
接下来,我们通过几个简单的例子来讲解一下 C memcpy() 函数是如何使用的。
示例 1:memcpy() 复制字符串
#include <stdio.h>
#include <string.h>
int main(void)
{
char dest[20];
char src[] = "JavaScript";
// 将 src 复制到 dest 中
memcpy(dest, src, strlen(src) + 1);
puts(dest);
return 0;
}运行结果如下。
JavaScript分析:
strlen(src) + 1 表示使用 strlen() 函数获取 src 的长度然后加上 1。之所以加上 1,其实是加上 '\0' 的长度。
示例 2:memcpy() 复制数组
#include <stdio.h>
#include <string.h> // 或 #include <memory.h>
int main(void)
{
int arr[] = {10, 20, 30, 40, 50};
int resultArr[5];
size_t elementsLength = sizeof(arr) / sizeof(arr[0]); // 计算元素数量
size_t bytesLength = sizeof(arr); // 计算总字节数
// 使用 memcpy() 复制整个数组
memcpy(resultArr, arr, bytesLength);
printf("源数组: ");
for (size_t i = 0; i < elementsLength; i++) {
printf("%d ", arr[i]);
}
printf("\n");
printf("目标数组: ");
for (size_t i = 0; i < elementsLength; i++) {
printf("%d ", resultArr[i]);
}
printf("\n");
return 0;
}运行结果如下。
源数组 : 10 20 30 40 50
目标数组 : 10 20 30 40 50分析:
在这个例子中,我们尝试使用 memcpy() 来复制一个数组。首先,我们使用 sizeof(arr) 计算了源数组的总字节数,然后将这些字节从 arr 复制到 resultArr。使用 memcpy() 不需要关心数据类型,它只会按照指定的字节数进行复制。
示例 3:memcpy() 复制结构体
#include <stdio.h>
#include <string.h>
// 定义结构体
struct Point
{
int x;
int y;
};
int main(void)
{
struct Point p1 = {10, 20};
struct Point p2;
// 使用 memcpy() 复制结构体
memcpy(&p2, &p1, sizeof(struct Point));
printf("源结构体: (%d, %d)\n", p1.x, p1.y);
printf("目标结构体: (%d, %d)\n", p2.x, p2.y);
return 0;
}运行结果如下。
源结构体 : (10, 20)
目标结构体 : (10, 20)分析:
memcpy() 也可以用来复制结构体,它会复制结构体占用的所有字节。需要注意的是,如果结构体中包含指针,则 memcpy() 复制的是指针本身的值(地址),而不是指针指向的数据。
memcpy() 与 strcpy() 的区别
memcpy() 和 strcpy() 都可以用于复制数据,但它们之间存在一个关键区别:
strcpy():用于复制 “字符串” 。它会从源字符串的开头一直复制到遇到终止符 '\0' 为止,并将终止符 '\0' 也复制到目标位置。strcpy() 不会关心复制了多少字节,它只依赖于终止符来确定复制结束。不过 strcpy() 存在缓冲区溢出风险,因为它不检查目标缓冲区大小。memcpy():用于复制 “任意字节块” 。它会精确地复制指定的 n 个字节,而不关心是否遇到终止符 '\0'。memcpy() 适合用于复制非字符串数据(如数组、结构体)或字符串的一部分,而无需考虑终止符 '\0'。
用简单的一句话来说就是:strcpy() 是面向字符串的,而 memcpy() 是面向内存块的。
memcpy() 与 memmove() 的区别
memcpy() 和 memmove() 都可以用于复制字节块,但它们在处理 “重叠内存区域” 时的行为是不同的。
memcpy():它的行为在 “源内存区域” 和 “目标内存区域” 重叠时是未定义的。在内存重叠的情况下使用 memcpy(),可能会导致数据被错误地复制,因为目标区域在复制过程中可能覆盖尚未读取的源区域数据。memmove():它被设计用来正确处理 “源内存区域” 和 “目标内存区域” 重叠的情况。memmove() 会确保在将数据复制到目标区域之前,先将源区域的数据完全读取或暂存起来,从而避免数据损坏。其中,memmove() 在处理重叠区域时可能比 memcpy() 效率稍低。
如果能够确定 “源内存区域” 和 “目标内存区域” 不重叠,我们可以考虑使用 memcpy(),因为它的效率更高。如果 “源内存区域” 和 “目标内存区域” 可能存在重叠,或者不确定是否重叠,则我们应该始终使用更安全的 memmove() 函数。
