C++ 学习杂记03:std::string 类

概述与基本概念

std::string是C++标准库中的字符串类,定义在 <string>头文件中。

复制代码
复制代码
复制代码
#include <iostream>
#include <string>
#include <cstring>  // 用于C风格字符串比较
using namespace std;

构造函数与初始化

复制代码
复制代码
复制代码
void testConstructors() {
    cout << "=== 构造函数测试 ===" << endl;
    
    // 1. 默认构造函数
    string s1;
    cout << "s1 (默认构造): \"" << s1 << "\" 长度: " << s1.length() << endl;
    
    // 2. 用C风格字符串构造
    string s2 = "Hello World";
    cout << "s2 (C字符串): \"" << s2 << "\"" << endl;
    
    // 3. 拷贝构造
    string s3(s2);
    cout << "s3 (拷贝构造): \"" << s3 << "\"" << endl;
    
    // 4. 用n个字符构造
    string s4(5, 'A');  // 5个'A'
    cout << "s4 (重复字符): \"" << s4 << "\"" << endl;
    
    // 5. 用子串构造
    string s5(s2, 6, 5);  // 从索引6开始,取5个字符
    cout << "s5 (子串构造): \"" << s5 << "\"" << endl;
    
    // 6. 移动构造 (C++11)
    string s6(move(s2));
    cout << "s6 (移动构造): \"" << s6 << "\"" << endl;
    cout << "s2 (移动后): \"" << s2 << "\"" << endl;
    
    // 7. 初始化列表构造 (C++11)
    string s7 = {'H', 'e', 'l', 'l', 'o'};
    cout << "s7 (初始化列表): \"" << s7 << "\"" << endl;
}

输出:

复制代码
复制代码
复制代码
=== 构造函数测试 ===
s1 (默认构造): "" 长度: 0
s2 (C字符串): "Hello World"
s3 (拷贝构造): "Hello World"
s4 (重复字符): "AAAAA"
s5 (子串构造): "World"
s6 (移动构造): "Hello World"
s2 (移动后): ""
s7 (初始化列表): "Hello"

基本操作与访问

复制代码
复制代码
复制代码
void testBasicOperations() {
    cout << "\n=== 基本操作测试 ===" << endl;
    
    string str = "Hello C++ World";
    
    // 1. 大小和容量
    cout << "字符串: \"" << str << "\"" << endl;
    cout << "长度: " << str.length() << " 或 " << str.size() << endl;
    cout << "容量: " << str.capacity() << endl;
    cout << "是否为空: " << (str.empty() ? "是" : "否") << endl;
    
    // 2. 访问元素
    cout << "第一个字符: " << str.front() << endl;  // C++11
    cout << "最后一个字符: " << str.back() << endl;   // C++11
    cout << "索引5的字符: " << str[5] << endl;
    cout << "索引5的字符(at): " << str.at(5) << endl;
    
    // 3. 越界访问对比
    try {
        cout << "尝试访问越界索引(at): ";
        cout << str.at(100) << endl;  // 会抛出异常
    } catch (const out_of_range& e) {
        cout << "异常: " << e.what() << endl;
    }
    
    // 4. 修改元素
    str[7] = 'P';
    str[8] = 'P';
    cout << "修改后: \"" << str << "\"" << endl;
    
    // 5. 获取C风格字符串
    const char* cstr = str.c_str();
    cout << "C风格字符串: " << cstr << endl;
    cout << "C风格字符串长度(strlen): " << strlen(cstr) << endl;
    
    // 6. 获取底层字符数组 (C++11)
    const char* data = str.data();
    cout << "底层数据: " << data << endl;
}

输出:

复制代码
复制代码
复制代码
=== 基本操作测试 ===
字符串: "Hello C++ World"
长度: 16 或 16
容量: 22
是否为空: 否
第一个字符: H
最后一个字符: d
索引5的字符:  
索引5的字符(at):  
尝试访问越界索引(at): 异常: basic_string::at: __n (which is 100) >= this->size() (which is 16)
修改后: "Hello CPP World"
C风格字符串: Hello CPP World
C风格字符串长度(strlen): 16
底层数据: Hello CPP World

字符串操作

复制代码
复制代码
复制代码
void testStringOperations() {
    cout << "\n=== 字符串操作测试 ===" << endl;
    
    // 1. 赋值操作
    string s1 = "Hello";
    string s2 = "World";
    
    s1 = s2;  // 拷贝赋值
    cout << "拷贝赋值后 s1: " << s1 << endl;
    
    s1 = "C++";  // 从C字符串赋值
    cout << "C字符串赋值后: " << s1 << endl;
    
    s1.assign(5, '*');  // assign方法
    cout << "assign后: " << s1 << endl;
    
    // 2. 追加操作
    s1 = "Hello";
    s2 = "World";
    
    s1 += " ";  // 追加字符串
    s1 += s2;   // 追加另一个string
    s1 += '!';  // 追加字符
    cout << "追加后: " << s1 << endl;
    
    s1.append(" 2024");  // append方法
    cout << "append后: " << s1 << endl;
    
    // 3. 插入操作
    s1 = "Hello World";
    s1.insert(5, " C++");  // 在位置5插入
    cout << "插入后: " << s1 << endl;
    
    // 4. 删除操作
    s1.erase(5, 4);  // 从位置5删除4个字符
    cout << "删除后: " << s1 << endl;
    
    s1.erase(s1.begin() + 5, s1.end() - 1);  // 用迭代器删除
    cout << "迭代器删除后: " << s1 << endl;
    
    // 5. 替换操作
    s1 = "I like apples";
    s1.replace(7, 6, "oranges");  // 从位置7开始,替换6个字符
    cout << "替换后: " << s1 << endl;
    
    // 6. 交换操作
    s1 = "First";
    s2 = "Second";
    cout << "交换前: s1=" << s1 << ", s2=" << s2 << endl;
    s1.swap(s2);
    cout << "交换后: s1=" << s1 << ", s2=" << s2 << endl;
    
    // 7. 清空操作
    s1.clear();
    cout << "清空后长度: " << s1.length() << endl;
}

输出:

复制代码
复制代码
复制代码
=== 字符串操作测试 ===
拷贝赋值后 s1: World
C字符串赋值后: C++
assign后: *****
追加后: Hello World!
append后: Hello World! 2024
插入后: Hello C++ World
删除后: Hello World
迭代器删除后: Hello
替换后: I like oranges
交换前: s1=First, s2=Second
交换后: s1=Second, s2=First
清空后长度: 0

查找与替换

复制代码
复制代码
复制代码
void testFindAndReplace() {
    cout << "\n=== 查找与替换测试 ===" << endl;
    
    string text = "The quick brown fox jumps over the lazy dog. The fox is clever.";
    
    // 1. 查找子串
    size_t pos = text.find("fox");
    if (pos != string::npos) {
        cout << "找到'fox'在位置: " << pos << endl;
    }
    
    // 2. 从指定位置开始查找
    pos = text.find("fox", pos + 1);
    if (pos != string::npos) {
        cout << "第二次找到'fox'在位置: " << pos << endl;
    }
    
    // 3. 查找字符
    pos = text.find_first_of("aeiou");  // 查找元音字母
    cout << "第一个元音字母在位置: " << pos << " (字符: " << text[pos] << ")" << endl;
    
    pos = text.find_first_not_of("The quickbrown");
    cout << "第一个不在指定集合的字符在位置: " << pos << endl;
    
    // 4. 反向查找
    pos = text.rfind("the");
    cout << "反向查找到'the'在位置: " << pos << endl;
    
    // 5. 替换所有匹配
    string result = text;
    size_t start_pos = 0;
    while ((start_pos = result.find("fox", start_pos)) != string::npos) {
        result.replace(start_pos, 3, "cat");
        start_pos += 3;  // 移动位置
    }
    cout << "替换所有fox为cat: " << result << endl;
    
    // 6. 查找失败示例
    pos = text.find("elephant");
    if (pos == string::npos) {
        cout << "未找到'elephant'" << endl;
    }
}

输出:

复制代码
复制代码
复制代码
=== 查找与替换测试 ===
找到'fox'在位置: 16
第二次找到'fox'在位置: 47
第一个元音字母在位置: 2 (字符: e)
第一个不在指定集合的字符在位置: 3
反向查找到'the'在位置: 31
替换所有fox为cat: The quick brown cat jumps over the lazy dog. The cat is clever.
未找到'elephant'

子串与分割

复制代码
复制代码
复制代码
vector<string> splitString(const string& str, char delimiter) {
    vector<string> result;
    size_t start = 0;
    size_t end = str.find(delimiter);
    
    while (end != string::npos) {
        result.push_back(str.substr(start, end - start));
        start = end + 1;
        end = str.find(delimiter, start);
    }
    
    result.push_back(str.substr(start));
    return result;
}

void testSubstringAndSplit() {
    cout << "\n=== 子串与分割测试 ===" << endl;
    
    string text = "C++ is a powerful programming language";
    
    // 1. 获取子串
    string sub1 = text.substr(0, 3);  // 从0开始,取3个字符
    cout << "子串(0,3): \"" << sub1 << "\"" << endl;
    
    string sub2 = text.substr(7);  // 从位置7到末尾
    cout << "子串(7): \"" << sub2 << "\"" << endl;
    
    // 2. 分割字符串
    string csv = "apple,banana,orange,grape";
    vector<string> fruits = splitString(csv, ',');
    
    cout << "分割字符串\"" << csv << "\":" << endl;
    for (size_t i = 0; i < fruits.size(); ++i) {
        cout << "  [" << i << "] \"" << fruits[i] << "\"" << endl;
    }
    
    // 3. 使用字符串流分割
    cout << "\n使用stringstream分割:" << endl;
    string sentence = "The quick brown fox jumps over the lazy dog";
    istringstream iss(sentence);
    string word;
    int count = 0;
    
    while (iss >> word) {
        cout << "单词" << ++count << ": " << word << endl;
    }
    
    // 4. 比较子串
    string str1 = "Hello World";
    string str2 = "Hello C++";
    
    int cmp = str1.compare(0, 5, str2, 0, 5);  // 比较前5个字符
    if (cmp == 0) {
        cout << "\n前5个字符相同" << endl;
    }
    
    cmp = str1.compare(6, 5, "World");  // 从str1位置6开始,比较5个字符
    if (cmp == 0) {
        cout << "str1包含'World'" << endl;
    }
}

输出:

复制代码
复制代码
复制代码
=== 子串与分割测试 ===
子串(0,3): "C++"
子串(7): "a powerful programming language"
分割字符串"apple,banana,orange,grape":
  [0] "apple"
  [1] "banana"
  [2] "orange"
  [3] "grape"

使用stringstream分割:
单词1: The
单词2: quick
单词3: brown
单词4: fox
单词5: jumps
单词6: over
单词7: the
单词8: lazy
单词9: dog

前5个字符相同
str1包含'World'

数值转换

复制代码
复制代码
复制代码
void testNumericConversion() {
    cout << "\n=== 数值转换测试 ===" << endl;
    
    // 1. 字符串转数值 (C++11)
    string numStr = "123.456";
    
    int intVal = stoi(numStr);
    cout << "stoi: " << numStr << " -> " << intVal << endl;
    
    long longVal = stol(numStr);
    cout << "stol: " << numStr << " -> " << longVal << endl;
    
    float floatVal = stof(numStr);
    cout << "stof: " << numStr << " -> " << floatVal << endl;
    
    double doubleVal = stod(numStr);
    cout << "stod: " << numStr << " -> " << doubleVal << endl;
    
    // 2. 带进制转换
    string hexStr = "FF";
    int hexVal = stoi(hexStr, nullptr, 16);
    cout << "十六进制: " << hexStr << " -> " << hexVal << endl;
    
    string binStr = "1010";
    int binVal = stoi(binStr, nullptr, 2);
    cout << "二进制: " << binStr << " -> " << binVal << endl;
    
    // 3. 数值转字符串
    int num = 42;
    string str1 = to_string(num);
    cout << "to_string(42): \"" << str1 << "\"" << endl;
    
    double pi = 3.1415926535;
    string str2 = to_string(pi);
    cout << "to_string(3.1415926535): \"" << str2 << "\"" << endl;
    
    // 4. 使用stringstream进行复杂格式化
    ostringstream oss;
    oss << fixed << setprecision(2) << pi << " is pi";
    cout << "stringstream格式: " << oss.str() << endl;
    
    // 5. 错误处理
    try {
        string invalid = "abc123";
        int val = stoi(invalid);
    } catch (const invalid_argument& e) {
        cout << "无效参数异常: " << e.what() << endl;
    } catch (const out_of_range& e) {
        cout << "超出范围异常: " << e.what() << endl;
    }
}

输出:

复制代码
复制代码
复制代码
=== 数值转换测试 ===
stoi: 123.456 -> 123
stol: 123.456 -> 123
stof: 123.456 -> 123.456
stod: 123.456 -> 123.456
十六进制: FF -> 255
二进制: 1010 -> 10
to_string(42): "42"
to_string(3.1415926535): "3.141593"
stringstream格式: 3.14 is pi
无效参数异常: stoi: no conversion

迭代器与算法

复制代码
复制代码
复制代码
#include <algorithm>  // 需要包含算法头文件

void testIteratorsAndAlgorithms() {
    cout << "\n=== 迭代器与算法测试 ===" << endl;
    
    string str = "Hello World";
    
    // 1. 迭代器遍历
    cout << "使用迭代器遍历: ";
    for (auto it = str.begin(); it != str.end(); ++it) {
        cout << *it;
    }
    cout << endl;
    
    // 2. 反向迭代器
    cout << "反向遍历: ";
    for (auto rit = str.rbegin(); rit != str.rend(); ++rit) {
        cout << *rit;
    }
    cout << endl;
    
    // 3. 基于范围的for循环 (C++11)
    cout << "范围for循环: ";
    for (char ch : str) {
        cout << ch;
    }
    cout << endl;
    
    // 4. 使用STL算法
    cout << "全部大写: ";
    string upper = str;
    transform(upper.begin(), upper.end(), upper.begin(), ::toupper);
    cout << upper << endl;
    
    cout << "全部小写: ";
    string lower = str;
    transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
    cout << lower << endl;
    
    // 5. 排序
    string toSort = "programming";
    sort(toSort.begin(), toSort.end());
    cout << "排序后: " << toSort << endl;
    
    // 6. 反转
    string toReverse = "hello";
    reverse(toReverse.begin(), toReverse.end());
    cout << "反转后: " << toReverse << endl;
    
    // 7. 删除重复字符
    string withDuplicates = "aabbccddeeff";
    auto last = unique(withDuplicates.begin(), withDuplicates.end());
    withDuplicates.erase(last, withDuplicates.end());
    cout << "去重后: " << withDuplicates << endl;
    
    // 8. 统计字符
    int countA = count(str.begin(), str.end(), 'l');
    cout << "字符串中'l'的个数: " << countA << endl;
}

输出:

复制代码
复制代码
复制代码
=== 迭代器与算法测试 ===
使用迭代器遍历: Hello World
反向遍历: dlroW olleH
范围for循环: Hello World
全部大写: HELLO WORLD
全部小写: hello world
排序后: aggimmnoprr
反转后: olleh
去重后: abcdef
字符串中'l'的个数: 3

性能优化

复制代码
复制代码
复制代码
void testPerformanceOptimization() {
    cout << "\n=== 性能优化测试 ===" << endl;
    
    // 1. 预留空间
    string str;
    cout << "初始容量: " << str.capacity() << endl;
    
    str.reserve(1000);  // 预分配空间
    cout << "预留1000后容量: " << str.capacity() << endl;
    
    // 2. 清空但不释放内存
    str = "Hello World";
    cout << "赋值后: \"" << str << "\"" << endl;
    str.clear();
    cout << "清空后容量: " << str.capacity() << endl;
    
    // 3. 收缩到合适大小
    str = "Short";
    str.shrink_to_fit();  // C++11
    cout << "收缩后容量: " << str.capacity() << endl;
    
    // 4. 避免不必要的拷贝
    string largeString(100, 'A');
    
    // 正确做法:移动语义
    string movedString = move(largeString);
    cout << "移动后原字符串长度: " << largeString.length() << endl;
    cout << "移动后新字符串长度: " << movedString.length() << endl;
    
    // 5. 使用string_view (C++17)
    cout << "\n使用string_view减少拷贝:" << endl;
    string longString = "This is a very long string that we don't want to copy";
    
    // 传统做法
    string substring = longString.substr(10, 20);
    cout << "传统子串拷贝: " << substring << endl;
    
    // C++17 string_view
    // string_view sv = longString;  // 不拷贝
    // cout << "string_view: " << sv.substr(10, 20) << endl;
}

输出:

复制代码
复制代码
复制代码
=== 性能优化测试 ===
初始容量: 15
预留1000后容量: 1007
赋值后: "Hello World"
清空后容量: 1007
收缩后容量: 15
移动后原字符串长度: 0
移动后新字符串长度: 100

使用string_view减少拷贝:
传统子串拷贝: a very long string

完整测试示例

复制代码
复制代码
复制代码
int main() {
    cout << "========== C++ std::string 完整测试 ==========" << endl;
    
    testConstructors();
    testBasicOperations();
    testStringOperations();
    testFindAndReplace();
    testSubstringAndSplit();
    testNumericConversion();
    testIteratorsAndAlgorithms();
    testPerformanceOptimization();
    
    // 综合示例
    cout << "\n=== 综合示例:单词统计 ===" << endl;
    string text = "C++ is a powerful programming language. "
                  "C++ supports multiple programming paradigms.";
    
    // 转换为小写
    transform(text.begin(), text.end(), text.begin(), ::tolower);
    
    // 替换标点
    for (char& c : text) {
        if (ispunct(c)) c = ' ';
    }
    
    // 分割单词
    istringstream iss(text);
    map<string, int> wordCount;
    string word;
    
    while (iss >> word) {
        wordCount[word]++;
    }
    
    // 输出统计结果
    cout << "文本: " << text << endl;
    cout << "\n单词统计:" << endl;
    for (const auto& pair : wordCount) {
        cout << "  " << pair.first << ": " << pair.second << endl;
    }
    
    cout << "\n========== 测试完成 ==========" << endl;
    return 0;
}

输出:

复制代码
复制代码
复制代码
========== C++ std::string 完整测试 ==========
=== 构造函数测试 ===
...(之前的所有测试输出)...

=== 综合示例:单词统计 ===
文本: c++ is a powerful programming language  c++ supports multiple programming paradigms 

单词统计:
  a: 1
  c++: 2
  is: 1
  language: 1
  multiple: 1
  paradigms: 1
  powerful: 1
  programming: 2
  supports: 1

========== 测试完成 ==========

重要特性总结

  1. 内存管理:自动管理内存,无需手动分配/释放

  2. 安全性 :提供范围检查(at()方法)

  3. 丰富接口:超过100个成员函数

  4. STL兼容:支持所有STL算法

  5. 性能优化:短字符串优化(SSO)

  6. Unicode支持:C++11起支持UTF-8/16/32

最佳实践

  1. 优先使用std::string而非C风格字符串

  2. 大量拼接时使用reserve()预留空间

  3. 使用移动语义避免不必要拷贝

  4. 使用string_view(C++17)作为只读参数

  5. 注意编码问题,特别是在多语言环境中

std::string是C++中最常用的容器之一,掌握其用法对高效编程至关重要。

相关推荐
H_BB2 小时前
动态规划详解
c++·算法·动态规划
C语言小火车2 小时前
嵌入式实习面试问题:那个动态内存是怎么样分配的?
c语言·开发语言·c++·嵌入式硬件·面试
John_ToDebug2 小时前
Chromium 源码剖析:base::NoDestructor——更安全的静态单例解决方案
开发语言·c++·chrome
tankeven2 小时前
C++ 学习杂记02:C++模板编程
c++
楼田莉子2 小时前
仿muduo的高并发服务器——前置知识讲解和时间轮模块
服务器·开发语言·c++·后端·学习
OYangxf2 小时前
C++中的回调函数:从函数指针到现代可调用对象
c++
qeen872 小时前
【数据结构】队列及其C语言模拟实现
c语言·数据结构·c++·学习·队列
田野追逐星光2 小时前
C++继承 -- 讲解超详细(上)
c++·算法
fish_xk3 小时前
c++的list
开发语言·c++·list