面试题:strcpy 与 memcpy区别

旅行   2024-11-07 08:02   广东  

欢迎关注本公众号,专注面试题拆解

分享一套视频课程:《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);
从函数原型可以看出它们的第一个区别:strcpy 专门用于字符串操作,而 memcpy 可以处理任意类型的数据。

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)); // OKstruct 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代替

// 使用 strncpychar 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电子书资料赠送

精彩文章合集

专题推荐

【专辑】计算机网络真题拆解
【专辑】大厂最新真题
【专辑】C/C++面试真题拆解

CppPlayer
一个专注面试题拆解的公众号
 最新文章