欢迎关注本公众号,专注面试题拆解
分享一套视频课程:《C++实现百万并发服务器》 面试需要项目的可以找我获取,免费分享。 欢迎V:fb964919126
面试题:strcpy 与 memcpy区别?
这道题目是超高频面试题,今年的小米、大华、农行、b站、商汤。中科曙光等大企业都出了这道面试题。
在 C/C++ 编程中,内存拷贝是一个常见的操作。标准库提供了两个主要的函数:strcpy 和 memcpy。虽然它们都用于数据拷贝,但在设计目的、使用方式和性能特征上有着显著的差异
01
基本定义
// strcpy 函数原型
char *strcpy(char *dest, const char *src);
// memcpy 函数原型
void *memcpy(void *dest, const void *src, size_t n);
02
核心区别
2.1、 拷贝行为
strcpy 和 memcpy 在拷贝行为上有着根本的区别:
// strcpy 示例:遇到 '\0' 停止
char str1[] = "Hello";
char str2[10];
strcpy(str2, str1); // 只拷贝 "Hello\0"
// memcpy 示例:拷贝固定大小
int arr1[] = {1, 2, 3, 0, 4, 5}; // 0 不会停止拷贝
int arr2[6];
memcpy(arr2, arr1, sizeof(arr1)); // 拷贝整个数组
strcpy 会一直拷贝直到遇到源字符串的结束符('\0'),而 memcpy 则严格按照指定的字节数进行拷贝。
2.2、 应用范围
两个函数的应用场景有明显的区别:
// strcpy 只能用于字符串
char* str = "Hello";
strcpy(dest, str); // OK
// memcpy 可用于任何类型
int numbers[] = {1, 2, 3};
memcpy(dest, numbers, sizeof(numbers)); // OK
struct MyStruct data;
memcpy(dest, &data, sizeof(data)); // OK
strcpy 只适用于字符串,且源字符串必须以 \0 结尾。memcpy 可以用于任何类型的内存块,不仅仅是字符串。
03
安全性
strcpy有缓冲区溢出风险
// strcpy 的潜在危险
char small[5];
char* large = "Too long string";
strcpy(small, large); // 危险!缓冲区溢出
通常情况下,strcpy被strncpy代替
// 使用 strncpy
char dest[5];
strncpy(dest, src, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0';
是不是memcpy没有缓冲区溢出风险?不是的,memcpy同样有缓冲区溢出风险。
memcpy 本身并不检查目标缓冲区的大小,它只是按照指定的字节数进行内存拷贝。如果在调用 memcpy 时指定的拷贝字节数超过了目标缓冲区的实际大小,就会导致缓冲区溢出。这种情况可能会覆盖相邻的内存区域,导致未定义行为,包括数据损坏、程序崩溃或安全漏洞。
#include <cstring>
#include <iostream>
void unsafeMemcpy() {
char source[] = "This is a long string that exceeds the buffer size.";
char dest[10]; // 目标缓冲区大小为 10 字节
// 错误:拷贝的字节数超过了目标缓冲区的大小
memcpy(dest, source, sizeof(source)); // 可能导致缓冲区溢出
std::cout << "Destination: " << dest << std::endl; // 未定义行为
}
在这个例子中,memcpy 尝试将 source 中的所有内容拷贝到 dest 中,但 dest 的大小只有 10 字节,导致溢出。
使用 memcpy 时,务必确保指定的拷贝字节数不超过目标缓冲区的大小。
04
性能对比
strcpy:
strcpy 需要在复制过程中检查每个字符是否是终止符 \0,这增加了额外的开销。
对于短字符串,strcpy 的性能可能与 memcpy 相当。
对于长字符串,strcpy 的性能可能会稍差一些,因为它需要逐个字符检查终止符。
memcpy:
memcpy 不需要检查终止符,可以直接复制指定数量的字节,这使得它在处理大块内存时更高效。
memcpy 通常会使用优化的算法和指令集来加速内存复制。
05
strcpy和memcpy是不是原子的?
strcpy 和 memcpy 都不是原子操作。它们在执行过程中可能会被中断,导致在多线程环境下出现数据竞争。
// strcpy 的简化实现
char *strcpy(char *dest, const char *src) {
char *ret = dest;
while (*dest++ = *src++) // 逐字节拷贝
;
return ret;
}
// memcpy 的简化实现
void *memcpy(void *dest, const void *src, size_t n) {
char *d = dest;
const char *s = src;
while (n--) // 逐字节拷贝
*d++ = *s++;
return dest;
}
从实现可以看出:
两个函数都是循环操作
每次只拷贝一个或多个字节
整个过程可能被中断
06
总结
strcpy 只适用于字符串,且源字符串必须以 \0 结尾,但对于大量数据的复制性能较差。
memcpy 可用于任何类型的内存块,但需要确保源和目标内存块的类型和大小匹配,性能通常优于 strcpy,尤其是在处理大量数据时。
end
CppPlayer
关注,回复【电子书】珍藏CPP电子书资料赠送
精彩文章合集
专题推荐