C++中strcpy()拷贝的3种写法示例详解

 更新时间:2026年05月13日 10:46:01   作者:sanqima  
本文详细探讨了C++中字符串拷贝函数strcpy的实现与优化,提供了测试案例和使用场景建议,强调在性能与安全性之间的权衡,不同版本适用于不同场景:基础版适合高性能需求,安全版则优先保障稳定性,感兴趣的朋友跟随小编一起看看吧

   C++中,有个常见的字符串拷贝函数:char* strcpy(char* dst, const char* src), 作用是将1个字符串src,拷贝到另外一个字符串dst。需要考虑的边界条件如下:

  • 空指针:dst或src为NULL时会触发非法内存访问。
  • 内存重叠:dst和src的地址范围存在重叠,从前向后拷贝会覆盖尚未读取的src内容。
  • 空字符串:src仅包含’\0’,需保证拷贝后dst仍然是合法空串。
  • 缓冲区溢出:dst空间不足导致拷贝越界,是严重的安全漏洞。
  • 结束符丢失:必须保证拷贝后的dst以’\0’结尾,否则后续strlen/printf等字符串操作会越界。

1 基本版本

#include <cassert>
// 对齐标准strcpy签名,src加const保证常量正确性
char* my_strcpy(char* dst, const char* src) {
    // 调试期断言快速定位空指针问题,发布模式可关闭断言不影响性能
    assert(dst != nullptr && src != nullptr);
    // 保存目标地址首指针,后续会移动dst指针
    char* ret = dst;
    // 拷贝逻辑:赋值表达式返回赋值后的值,遇到'\0'时循环终止,自动包含结束符
    while ((*dst++ = *src++) != '\0');
    return ret;
}

1.1 优点

   实现了核心功能,适合调用方能保证参数合法性的高性能场景。

1.2 缺点

  • 若发布模式关闭断言,则传入空指针,会触发未定义行为。
  • 没有处理内存重叠场景,若dst落在src的地址范围内且dst > src,会导致拷贝内容错误。
  • 没有检查dst缓冲区大小,极易出现溢出。

2 进阶版(支持内存重叠)

   参考memmove的语义,处理重叠场景,特别存在地址重叠的情况(如字符串内部移动)

#include <cstddef> // size_t定义
char* my_strcpy(char* dst, const char* src) {
    // 发布期也保留空指针检查,避免程序崩溃
    if (dst == nullptr || src == nullptr) {
        return nullptr;
    }
    char* ret = dst;
    // 第一步:计算src总长度(包括末尾'\0')
    size_t len = 0;
    while (src[len] != '\0') len++;
    len += 1; // 包含结束符的总拷贝字节数
    // 第二步:判断内存重叠,选择拷贝方向
    if (dst < src || dst >= src + len) {
        // 无重叠 / dst在src前面,从前向后拷贝性能更高
        for (size_t i = 0; i < len; i++) {
            dst[i] = src[i];
        }
    } else {
        // 重叠且dst在src后面,从后向前拷贝避免覆盖未读取的src内容
        // 注意:size_t是无符号类型,禁止写i>=0(永远为真),改为从len倒序到1
        for (size_t i = len; i > 0; i--) {
            dst[i-1] = src[i-1];
        }
    }
    return ret;
}

2.1 特点

  • 即使参数为空也返回nullptr,避免程序崩溃。
  • 正确处理所有内存重叠场景,例如dst = src + 2这类后向重叠场景,也能得到正确结果。
  • 仍然依赖调用方保证src以’\0’结尾、dst缓冲区足够大。

3 高级版(缓存区防护)

   在实际开发中,禁止使用无长度限制的strcpy,推荐实现带缓冲区长度的安全版本,彻底避免溢出:

#include <cstddef>
char* my_strcpy_s(char* dst, size_t dst_size, const char* src) {
    if (dst == nullptr || src == nullptr || dst_size == 0) {
        return nullptr;
    }
    size_t i = 0;
    // 最多拷贝dst_size-1个字符,预留1个位置给'\0'
    while (src[i] != '\0' && i < dst_size - 1) {
        dst[i] = src[i];
        i++;
    }
    // 强制加结束符,保证dst永远是合法C字符串(解决strncpy不自动加'\0'的缺陷)
    dst[i] = '\0';
    return dst;
}

3.1 特点

  • 完全避免缓冲区溢出,即使src远长于dst的空间,也只会截断到缓冲区可容纳的最大长度。
  • 始终保证dst以’\0’结尾,不会出现非法字符串。

4 测试案例

测试场景用例代码预期结果
普通字符串拷贝char dst[20]; my_strcpy(dst, “hello world”);dst内容为"hello world"
空字符串拷贝char dst[10]; my_strcpy(dst, “”);dst[0] == ‘\0’
自拷贝char buf[] = “test”; my_strcpy(buf, buf);buf内容不变,仍为"test"
后向内存重叠char buf[20] = “abcdefgh”; my_strcpy(buf+2, buf);buf内容为"ababcdefgh"(基础版会得到"abababab…"错误结果)
空参数传入my_strcpy(nullptr, “test”);返回nullptr,程序不崩溃
缓冲区不足(安全版)char dst[5]; my_strcpy_s(dst, 5, “hello world”);dst内容为"hell",自动截断并加结束符

5 使用场景

  • const 正确性:src参数必须加const修饰,既可以传入const字符串,也能避免函数内部误修改源字符串。
  • 指针溢出:嵌入式 / 内核开发中,若src地址接近地址空间上限,src + len可能出现指针溢出,可转为uintptr_t整数类型后再做范围比较。
  • 性能取舍:如果业务不存在重叠场景,基础版的性能更高;如果优先保证安全性,直接使用带长度的安全版本。

到此这篇关于C++中strcpy()拷贝的3种写法示例详解的文章就介绍到这了,更多相关C++ strcpy()拷贝内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 教你5分钟轻松搞定内存字节对齐

    教你5分钟轻松搞定内存字节对齐

    随便google一下,人家就可以跟你解释的,一大堆的道理,我们没怎么多时间,讨论为何要对齐.直入主题,怎么判断内存对齐规则,sizeof的结果怎么来的,请牢记以下3条原则
    2013-09-09
  • c++10进制转换为任意2-16进制数字的实例

    c++10进制转换为任意2-16进制数字的实例

    下面小编就为大家带来一篇c++10进制转换为任意2-16进制数字的实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • C++实现职工信息管理系统

    C++实现职工信息管理系统

    这篇文章主要为大家详细介绍了c++实现职工信息管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • C语言中进程间通讯的方式详解

    C语言中进程间通讯的方式详解

    这篇文章主要为大家详细介绍了C语言中几种进程间通讯的方式,文中的示例代码讲解详细, 对我们学习或工作有一定的借鉴价值,需要的可以参考一下
    2022-08-08
  • C语言数组详细介绍

    C语言数组详细介绍

    大家好,本篇文章主要讲的是C语言数组详细介绍,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2022-01-01
  • 从C到C++理解右值引用和移动语义的过程解析

    从C到C++理解右值引用和移动语义的过程解析

    在C++中,理解右值引用(Rvalue references)和移动语义(Move semantics)是现代C++编程的核心部分,它们极大地提高了程序的性能和资源管理效率,下面将介绍从C到C++理解右值引用和移动语义的方法,感兴趣的朋友跟随小编一起看看吧
    2025-11-11
  • C++实现LeetCode(7.翻转整数)

    C++实现LeetCode(7.翻转整数)

    这篇文章主要介绍了C++实现LeetCode(7.翻转整数),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C++详细讲解图的拓扑排序

    C++详细讲解图的拓扑排序

    拓扑排序(Topological Sorting)若一个由图中所有点构成的序列 A 满足:对于图中的每条边 (x,y),x 在 A 中都出现在 y 之前,则称 A 是该图的一个拓扑序列
    2022-05-05
  • C语言中查找字符在字符串中出现的位置的方法

    C语言中查找字符在字符串中出现的位置的方法

    这篇文章主要介绍了C语言中查找字符在字符串中出现的位置的方法,分别是strchr()函数和strrchr()函数的使用,需要的朋友可以参考下
    2015-08-08
  • C++20新增属性[[no_unique_address]]详解(最新整理)

    C++20新增属性[[no_unique_address]]详解(最新整理)

    [[no_unique_address]]让空类型的类数据成员有机会不再占用额外的内存空间,从而减轻了因为地址规定带来的性能影响,同时还让空基类优化代码得到了简化的机会,本文给大家详细介绍C++20新增属性[[no_unique_address]],感兴趣的朋友一起看看吧
    2025-09-09

最新评论