C语言高频面试题——strcpy与memcpy区别
1. 功能与用途
strcpy
- 功能:专门用于复制字符串(以
\0
结尾的字符数组)。 - 用途:
- 将一个字符串完整地复制到另一个字符串缓冲区中。
- 自动处理字符串的结束符
\0
。
- 声明:
char* strcpy(char* dest, const char* src);
dest
:目标缓冲区。src
:源字符串(必须以\0
结尾)。- 返回值:返回目标缓冲区
dest
的指针。
memcpy
- 功能:通用的内存复制函数,可以复制任意类型的数据。
- 用途:
- 复制一段固定大小的内存区域(不一定是字符串)。
- 不会自动停止于
\0
,而是严格按照指定的字节数进行复制。
- 声明:
void* memcpy(void* dest, const void* src, size_t n);
dest
:目标缓冲区。src
:源缓冲区。n
:要复制的字节数。- 返回值:返回目标缓冲区
dest
的指针。
2. 内存操作方式
strcpy
- 行为:
- 从源字符串的起始地址开始逐字节复制,直到遇到
\0
(终止符)为止。 - 自动将
\0
复制到目标缓冲区。
- 从源字符串的起始地址开始逐字节复制,直到遇到
- 关键点:
- 假设源字符串是合法的(即必须以
\0
结尾)。 - 如果源字符串未以
\0
结尾,会导致未定义行为(如越界访问)。
- 假设源字符串是合法的(即必须以
- 示例:
char src[] = "hello"; char dest[10]; strcpy(dest, src); // 复制 "hello\0" 到 dest
memcpy
- 行为:
- 按照指定的字节数
n
,从源内存逐字节复制到目标内存。 - 不关心数据的内容或是否包含
\0
。 - 如果复制的是字符串,需要手动确保复制足够的字节数(包括
\0
)。
- 按照指定的字节数
- 示例:
char src[] = "hello"; char dest[10]; memcpy(dest, src, 6); // 复制 "hello\0" 到 dest(需显式指定6字节)
3. 安全性与边界检查
strcpy
- 问题:
- 不检查目标缓冲区是否有足够空间容纳源字符串。
- 如果目标缓冲区太小,可能导致缓冲区溢出。
- 改进版本:
- 使用更安全的
strncpy
,可以限制复制的最大字节数。char dest[5]; strncpy(dest, "hello", sizeof(dest) - 1); // 最多复制4个字符,留出空间给 '\0' dest[sizeof(dest) - 1] = '\0'; // 确保末尾有 '\0'
- 使用更安全的
memcpy
- 问题:
- 同样不检查目标缓冲区是否有足够空间。
- 需要程序员手动确保
n
的值合理。
- 改进版本:
- 使用
memmove
,可以处理源和目标内存重叠的情况。char buffer[10] = "abcdefghi"; memmove(buffer + 2, buffer, 5); // 复制前5个字节到偏移2的位置
- 使用
4. 性能对比
strcpy
:- 由于需要逐字节扫描源字符串直到
\0
,性能可能稍低。 - 适用于字符串操作。
- 由于需要逐字节扫描源字符串直到
memcpy
:- 直接按字节数复制,性能通常更高。
- 适用于非字符串数据(如结构体、数组等)。
5. 示例代码对比
#include <stdio.h>
#include <string.h>int main() {// 使用 strcpychar src1[] = "hello";char dest1[10];strcpy(dest1, src1);printf("strcpy: %s\n", dest1); // 输出 "hello"// 使用 memcpychar src2[] = "world";char dest2[10];memcpy(dest2, src2, 6); // 复制6字节(包括 '\0')printf("memcpy: %s\n", dest2); // 输出 "world"return 0;
}
6. 核心区别总结
特性 | strcpy | memcpy |
---|---|---|
功能 | 专门用于字符串复制 | 通用的内存复制 |
结束符处理 | 自动复制 \0 | 不自动停止于 \0 |
参数 | 不需要指定长度 | 需要指定复制的字节数 |
安全性 | 存在缓冲区溢出风险 | 同样存在溢出风险 |
适用场景 | 字符串操作 | 任意数据类型(如数组、结构体等) |
7. 实际应用场景
strcpy
- 适用于简单的字符串复制操作。
- 示例:文件名、用户输入等字符串处理。
memcpy
- 适用于复杂数据结构的复制。
- 示例:
- 复制结构体:
struct Point { int x, y; }; struct Point p1 = {1, 2}, p2; memcpy(&p2, &p1, sizeof(struct Point)); // 复制整个结构体
- 复制数组:
int arr1[5] = {1, 2, 3, 4, 5}; int arr2[5]; memcpy(arr2, arr1, sizeof(arr1)); // 复制整个数组
- 复制结构体:
8. 注意事项
strcpy
:- 确保目标缓冲区足够大。
- 源字符串必须以
\0
结尾。
memcpy
:- 明确知道需要复制的字节数。
- 如果源和目标内存可能重叠,使用
memmove
替代。
总结
strcpy
:专为字符串设计,自动处理\0
,但容易引发缓冲区溢出。memcpy
:通用性强,适合任意类型数据,但需要手动控制字节数。