C++ string 类从原理到实战

一、引言

在 C++ 编程中,string是处理字符串的核心类,相较于 C 风格字符数组,它自动管理内存、提供丰富操作接口,极大提升了开发效率与代码安全性。本文将从深浅拷贝原理string底层模拟实现、标准库string常用函数详解、迭代器与容器实战、字符串数字相加案例等维度,全面梳理string类的核心知识,形成从原理到实战的完整体系。

二、浅拷贝与深拷贝的基本概念

2.1 浅拷贝

浅拷贝仅复制对象成员变量的值,若成员包含指针,仅拷贝指针地址,使多个对象指向同一块内存

  • 问题:对象析构时,同一块内存会被重复释放,导致程序崩溃或悬空指针。
  • 本质:位拷贝,只拷贝指针,不拷贝指向的数据。

2.2 深拷贝

深拷贝会为指针成员重新分配独立内存,并复制原数据,使每个对象拥有专属内存空间,互不干扰。

  • 优势:避免内存重复释放、数据篡改等问题,是string类的默认拷贝机制。
  • 本质:重新开辟内存 + 数据拷贝。

三、C++ 中 string 类的默认行为

C++ 标准库std::string的拷贝构造函数、赋值运算符均实现深拷贝,修改一个对象不会影响另一个:

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

int main() {
    string original = "Hello, World!";
    string copy1(original);    // 拷贝构造(深拷贝)
    string copy2 = original;   // 赋值运算符(深拷贝)

    copy1[0] = 'h';
    // 修改copy1,original、copy2不受影响
    cout << original << endl;  // Hello, World!
    cout << copy1 << endl;     // hello, World!
    cout << copy2 << endl;     // Hello, World!
    return 0;
}

四、自定义字符串类 MyString 实现(深浅拷贝 + 核心功能)

4.1 基础框架(构造、析构、深浅拷贝)

cpp 复制代码
#include <iostream>
#include <cstring>
#include <assert.h>
using namespace std;

class MyString {
private:
    char* _str;
    size_t _size;
    size_t _capacity;

public:
    // 构造函数
    MyString(const char* str = "") {
        if (str == nullptr) str = "";
        _size = strlen(str);
        _capacity = _size;
        _str = new char[_capacity + 1];
        strcpy(_str, str);
    }

    // 拷贝构造(深拷贝)
    MyString(const MyString& other) {
        _size = other._size;
        _capacity = other._capacity;
        _str = new char[_capacity + 1];
        memcpy(_str, other._str, _size + 1);
    }

    // 赋值运算符(现代写法)
    MyString& operator=(MyString tmp) {
        swap(tmp);
        return *this;
    }

    // 移动赋值(C++11,转移资源)
    MyString& operator=(MyString&& other) noexcept {
        if (this != &other) {
            delete[] _str;
            _str = other._str;
            _size = other._size;
            _capacity = other._capacity;
            other._str = nullptr;
        }
        return *this;
    }

    // 析构函数
    ~MyString() {
        delete[] _str;
        _str = nullptr;
        _size = _capacity = 0;
    }

    // 交换成员
    void swap(MyString& s) {
        std::swap(_str, s._str);
        std::swap(_size, s._size);
        std::swap(_capacity, s._capacity);
    }
};

4.2 比较运算符重载(> < >= <= == !=)

基于strcmp实现字典序比较:

cpp 复制代码
bool operator>(const MyString& other) const {
    return strcmp(_str, other._str) > 0;
}
bool operator<(const MyString& other) const {
    return strcmp(_str, other._str) < 0;
}
bool operator>=(const MyString& other) const {
    return !(*this < other);
}
bool operator<=(const MyString& other) const {
    return !(*this > other);
}
bool operator==(const MyString& other) const {
    return strcmp(_str, other._str) == 0;
}
bool operator!=(const MyString& other) const {
    return !(*this == other);
}

4.3 resize 函数实现

调整字符串长度,支持缩小、扩大与填充字符:

cpp 复制代码
void resize(size_t new_size, char fill_char = '\0') {
    if (new_size < _size) {
        _size = new_size;
        _str[_size] = '\0';
    } else {
        reserve(new_size);
        for (size_t i = _size; i < new_size; ++i) {
            _str[i] = fill_char;
        }
        _size = new_size;
        _str[_size] = '\0';
    }
}

// 预留容量
void reserve(size_t n) {
    if (n > _capacity) {
        char* new_str = new char[n + 1];
        strcpy(new_str, _str);
        delete[] _str;
        _str = new_str;
        _capacity = n;
    }
}

4.4 + 运算符重载(字符串拼接)

支持MyString + MyStringMyString + const char*

cpp 复制代码
MyString operator+(const MyString& other) const {
    size_t new_size = _size + other._size;
    char* new_data = new char[new_size + 1];
    strcpy(new_data, _str);
    strcat(new_data, other._str);
    MyString res(new_data);
    delete[] new_data;
    return res;
}

MyString operator+(const char* str) const {
    size_t len = strlen(str);
    size_t new_size = _size + len;
    char* new_data = new char[new_size + 1];
    strcpy(new_data, _str);
    strcat(new_data, str);
    MyString res(new_data);
    delete[] new_data;
    return res;
}

4.5 迭代器实现(简单模拟)

string迭代器本质是字符指针:

cpp 复制代码
typedef char* iterator;
typedef const char* const_iterator;

iterator begin() { return _str; }
iterator end() { return _str + _size; }
const_iterator begin() const { return _str; }
const_iterator end() const { return _str + _size; }

五、标准库 string 常用函数详解

5.1 初始化方式

cpp 复制代码
string s0;                  // 空字符串
string s1("hello");         // 字面量初始化
string s2 = s1;             // 拷贝初始化
string s3(5, 'a');          // 重复字符:"aaaaa"

5.2 容量与长度

  • size()/length():返回字符串长度(功能完全一致)
  • capacity():返回已分配内存容量
  • reserve(n):预分配容量,减少扩容
  • shrink_to_fit():释放多余内存,使容量等于长度
  • clear():清空字符串内容,不释放内存

5.3 字符串操作

  1. 拼接+=append()
  2. 查找find()rfind()find_first_of()(未找到返回string::npos
  3. 子串substr(pos, len)(省略len取到末尾)
  4. 替换replace(pos, len, str)
  5. 插入 / 删除insert()erase()(效率低,少用)
  6. 字符访问[](不检查越界)、at()(越界抛异常)

5.4 数值与字符串转换

  • 数值→字符串:to_string()(C++11,标准通用)
  • 字符串→整数:atoi()(C 风格)、stoi()(C++11,抛异常)
  • 通用转换:stringstream(跨平台、支持任意类型)

5.5 输入输出

  • cin:以空格 / 换行分隔,无法读取带空格字符串
  • getline(cin, str):读取整行,包含空格(需处理前导换行符)
cpp 复制代码
cin.ignore();  // 清空缓冲区换行
getline(cin, str);

六、迭代器与容器配合

6.1 string 遍历方式

  1. 下标遍历
cpp 复制代码
for (size_t i = 0; i < s.size(); ++i) cout << s[i];
  1. 迭代器遍历
cpp 复制代码
string::iterator it = s.begin();
while (it != s.end()) cout << *it++;
  1. 反向迭代器
cpp 复制代码
string::reverse_iterator rit = s.rbegin();
while (rit != s.rend()) cout << *rit++;
  1. 范围 for 循环(简洁推荐)
cpp 复制代码
for (auto& ch : s) cout << ch;

6.2 STL 算法配合

需包含<algorithm>

cpp 复制代码
reverse(s.begin(), s.end());  // 反转
sort(s.begin(), s.end());     // 排序

七、实战案例:字符串数字相加

处理超大数字(超出整型范围),模拟手工加法:

cpp 复制代码
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

string addStrings(string num1, string num2) {
    int i = num1.size() - 1, j = num2.size() - 1;
    string res;
    int carry = 0;

    while (i >= 0 || j >= 0 || carry) {
        int val1 = i >= 0 ? num1[i--] - '0' : 0;
        int val2 = j >= 0 ? num2[j--] - '0' : 0;
        int sum = val1 + val2 + carry;
        carry = sum / 10;
        res.push_back(sum % 10 + '0');
    }

    reverse(res.begin(), res.end());
    return res;
}

// 测试
int main() {
    cout << addStrings("123456789", "987654321") << endl; // 1111111110
    return 0;
}

八、总结

  1. 深浅拷贝 :浅拷贝共享内存易崩溃,深拷贝独立内存更安全,string默认深拷贝。
  2. 自定义string:需实现构造、析构、拷贝构造、赋值运算符,重载常用运算符与迭代器。
  3. 标准string :接口丰富,优先使用+=reserve优化性能,注意findsubstr边界。
  4. 迭代器:是 STL 容器通用访问方式,配合算法可高效操作字符串。
  5. 实战 :字符串数字相加核心为逆序逐位相加 + 处理进位 + 反转结果,适用于超大数运算。

本文覆盖string原理、实现、使用、实战全流程,是 C++ 字符串编程的核心参考资料。

相关推荐
库奇噜啦呼2 小时前
【iOS】Effective Objective-C第一章
开发语言·ios·objective-c
不会写DN2 小时前
Go 语言并发编程的 “工具箱”
开发语言·后端·golang
叶宇燚2 小时前
Java整理--数据结构篇
java·开发语言·数据结构
Mr_WangAndy2 小时前
C++数据结构与算法_大数据处理
c++·大数据查重·大数据求topk
晚枫歌F2 小时前
btree B树实现key-value存储
开发语言·数据结构
foundbug9992 小时前
多智能体三维编队飞行控制MATLAB实现
开发语言·matlab
炸膛坦客2 小时前
单片机/C语言八股:(七)C 程序运行时内存布局的动态变化
c语言·开发语言
ZCollapsar.2 小时前
C++从入门到入土 (5):.C/C++内存管理
c语言·c++·学习
超级哇塞3 小时前
vscode快速验证和团队协作
c++