🎯 还在用 char str[100] 手动管理字符串?还在为 strlenstrcpystrcat 提心吊胆?醒醒!C++ 的 string 类早就帮你把这些脏活累活全包了。本文带你从定义到操作,彻底掌握这个字符串处理的"瑞士军刀"。


📖 文章导航

  • 11.1 string 类对象的定义:怎么创建一个 string?
  • 11.2 string 类成员函数:增删改查,样样精通
  • 11.3 string 类的操作符:用运算符直接操作字符串
  • 11.4 string 类串位置指针:用迭代器精准定位
  • 11.5 string 类串与 C 风格字符串的转化:新旧世界的桥梁

11.1 string 类对象的定义——七种姿势创建字符串

string 类定义在 <string> 头文件中,是 C++ 标准库提供的字符串类,比 C 风格的 char[] 安全、方便一万倍。

#include <iostream>
#include <string>
using namespace std;

int main() {
    // 姿势一:空字符串
    string s1;
    cout << "s1: \"" << s1 << "\" 长度: " << s1.length() << endl;  // "" 长度: 0

    // 姿势二:用字符串字面量初始化
    string s2 = "Hello, C++!";
    cout << "s2: " << s2 << endl;  // Hello, C++!

    // 姿势三:拷贝构造
    string s3(s2);
    cout << "s3: " << s3 << endl;  // Hello, C++!

    // 姿势四:用 n 个相同字符初始化
    string s4(5, '*');
    cout << "s4: " << s4 << endl;  // *****

    // 姿势五:用另一个 string 的子串
    string s5(s2, 7, 3);  // 从 s2 的第7个位置开始,取3个字符
    cout << "s5: " << s5 << endl;  // C++

    // 姿势六:C++11 列表初始化
    string s6 = {'H', 'i', '!'};
    cout << "s6: " << s6 << endl;  // Hi!

    // 姿势七:用 substr 截取(后面会详细讲)
    string s7 = s2.substr(0, 5);
    cout << "s7: " << s7 << endl;  // Hello

    return 0;
}

💡 一句话string 的定义方式比奶茶店的点单方式还多,选你顺手的用就行。


11.2 string 类成员函数——增删改查全搞定

2.1 获取信息:长度、判空、容量

#include <iostream>
#include <string>
using namespace std;

int main() {
    string s = "Hello, 你好世界!";

    // 长度(两种写法等价)
    cout << "length(): " << s.length() << endl;   // 13(字节数)
    cout << "size():   " << s.size() << endl;     // 13(同上)

    // 判空
    string empty = "";
    cout << "empty? " << empty.empty() << endl;   // 1(true)

    // 容量(已分配的存储空间)
    cout << "capacity(): " << s.capacity() << endl;  // 通常 >= size()

    return 0;
}

2.2 访问字符:at、front、back、[]

string s = "Hello";

// 下标访问(不检查越界,速度快但危险)
cout << s[0] << endl;    // H
cout << s[4] << endl;    // o

// at() 访问(检查越界,安全但稍慢)
cout << s.at(1) << endl; // e
// cout << s.at(10);     // 💥 抛出 out_of_range 异常

// 首尾字符
cout << s.front() << endl;  // H(第一个字符)
cout << s.back() << endl;   // o(最后一个字符)

// 修改字符
s[0] = 'h';
s.at(4) = 'O';
cout << s << endl;  // hellO

⚠️ 选择建议:确定不越界用 [],不确定用 at()——程序崩溃比数据损坏好得多。

2.3 拼接:push_back、append、+=

string s = "Hello";

// 追加单个字符
s.push_back('!');
cout << s << endl;  // Hello!

// 追加字符串
s.append(", World");
cout << s << endl;  // Hello!, World

// 用 += 追加(最常用!)
s += " 你好";
s += '!';
cout << s << endl;  // Hello!, World 你好!

// 追加 n 个字符
s.append(3, '~');
cout << s << endl;  // Hello!, World 你好!~~~

2.4 插入与删除:insert、erase

string s = "HelloWorld";

// 在指定位置插入
s.insert(5, ", ");       // 在位置5插入
cout << s << endl;        // Hello, World

// 在指定位置删除
s.erase(5, 2);            // 从位置5开始删除2个字符
cout << s << endl;        // HelloWorld

// 删除从位置5到末尾
s.erase(5);
cout << s << endl;        // Hello

// 清空整个字符串
s.clear();
cout << "empty? " << s.empty() << endl;  // 1

2.5 截取子串:substr

string s = "Hello, C++ World!";

// substr(起始位置, 长度)
string sub1 = s.substr(7, 3);    // 从位置7开始取3个字符
cout << sub1 << endl;             // C++

// substr(起始位置) —— 从该位置取到末尾
string sub2 = s.substr(7);
cout << sub2 << endl;             // C++ World!

// 实用场景:提取文件扩展名
string filename = "report.pdf";
size_t dot = filename.rfind('.');  // 找最后一个 '.' 的位置
if (dot != string::npos) {
    string ext = filename.substr(dot + 1);
    cout << "扩展名: " << ext << endl;  // pdf
}

2.6 查找与替换:find、rfind、replace

string s = "Hello, Hello, Hello!";

// find:从前往后找,返回第一次出现的位置
size_t pos = s.find("Hello");
cout << "第一次出现位置: " << pos << endl;  // 0

// find 从指定位置开始找
pos = s.find("Hello", 1);
cout << "第二次出现位置: " << pos << endl;  // 7

// rfind:从后往前找
pos = s.rfind("Hello");
cout << "最后一次出现位置: " << pos << endl;  // 14

// 找不到返回 string::npos
if (s.find("World") == string::npos) {
    cout << "没找到 World" << endl;
}

// 统计出现次数
int count = 0;
size_t idx = 0;
while ((idx = s.find("Hello", idx)) != string::npos) {
    count++;
    idx += 5;  // 跳过已找到的
}
cout << "Hello 出现了 " << count << " 次" << endl;  // 3 次

// replace:替换
string s2 = "Hello, World!";
s2.replace(7, 5, "C++");   // 从位置7开始,替换5个字符为 "C++"
cout << s2 << endl;          // Hello, C++!

💡 查找家族速记

  • find —— 从前往后找(正向)
  • rfind —— 从后往前找(反向)
  • find_first_of —— 找第一个匹配字符集中的任意字符
  • find_last_of —— 找最后一个匹配字符集中的任意字符

2.7 比较:compare

string a = "apple";
string b = "banana";

// compare 返回值:< 0(a < b)、0(a == b)、> 0(a > b)
int result = a.compare(b);
if (result < 0) cout << a << " < " << b << endl;      // apple < banana
else if (result == 0) cout << a << " == " << b << endl;
else cout << a << " > " << b << endl;

// 也可以直接用比较运算符(更常用!)
if (a < b) cout << "apple 排在 banana 前面" << endl;
if (a == "apple") cout << "这是苹果!" << endl;

2.8 大小写转换(实用技巧)

#include <algorithm>

string s = "Hello, World!";

// 转大写
transform(s.begin(), s.end(), s.begin(), ::toupper);
cout << s << endl;  // HELLO, WORLD!

// 转小写
transform(s.begin(), s.end(), s.begin(), ::tolower);
cout << s << endl;  // hello, world!

11.3 string 类的操作符——用运算符优雅地操作字符串

string 类重载了大量运算符,让你可以用最直观的方式操作字符串。

3.1 赋值操作符:=、+=

string s1 = "Hello";
string s2;

s2 = s1;              // 拷贝赋值
cout << s2 << endl;   // Hello

s2 += " World";       // 拼接赋值
s2 += '!';
cout << s2 << endl;   // Hello World!

3.2 比较操作符:==、!=、<、>、<=、>=

string a = "abc";
string b = "abd";
string c = "abc";

cout << (a == c) << endl;  // 1(true)—— 内容相同
cout << (a != b) << endl;  // 1(true)—— 内容不同
cout << (a < b) << endl;   // 1(true)—— 字典序:abc < abd
cout << (a > b) << endl;   // 0(false)

// 比较规则:逐字符按 ASCII 码比较,类似字典排序
// 'a' < 'b',所以 "abc" < "abd"

3.3 连接操作符:+

string first = "Hello";
string second = " World";
string full = first + second + "!";
cout << full << endl;  // Hello World!

// 可以和 C 风格字符串混用
string s = "C++" + string(" is ") + "awesome!";
cout << s << endl;  // C++ is awesome!

// ⚠️ 两个字符串字面量不能直接用 + 连接!
// string bad = "Hello" + "World";  // ❌ 编译错误
// 因为 "Hello" 和 "World" 都是 const char*,不是 string 对象

3.4 流操作符:<<、>>

string name;
cout << "请输入你的名字: ";
cin >> name;              // >> 遇到空格就停止
cout << "你好, " << name << "!" << endl;

// 用 getline 读取整行(包括空格)
cin.ignore();  // 清除缓冲区中的换行符
string sentence;
cout << "请输入一句话: ";
getline(cin, sentence);
cout << "你说的是: " << sentence << endl;

3.5 下标操作符:[]

string s = "Hello";

// 读取
cout << s[0] << endl;   // H

// 修改
s[0] = 'h';
cout << s << endl;      // hello

// 遍历
for (size_t i = 0; i < s.length(); i++) {
    cout << s[i] << " ";
}
// h e l l o

11.4 string 类串位置指针——迭代器精准定位

迭代器是 STL 的"万能遥控器",可以用它在 string 中精确定位和操作。

4.1 迭代器基础

#include <iostream>
#include <string>
using namespace std;

int main() {
    string s = "Hello, C++!";

    // 正向迭代器:从头到尾
    cout << "正向遍历: ";
    for (string::iterator it = s.begin(); it != s.end(); ++it) {
        cout << *it;
    }
    cout << endl;  // Hello, C++!

    // 反向迭代器:从尾到头
    cout << "反向遍历: ";
    for (string::reverse_iterator it = s.rbegin(); it != s.rend(); ++it) {
        cout << *it;
    }
    cout << endl;  // !++C ,olleH

    // C++11 简化写法:auto + 范围 for
    for (auto c : s) cout << c;   // Hello, C++!
    cout << endl;

    return 0;
}

4.2 迭代器与算法配合

string s = "Hello, World!";

// 用迭代器指定范围进行操作
// 反转
auto it1 = s.begin() + 7;   // 指向 'W'
auto it2 = s.begin() + 12;  // 指向 '!'
reverse(it1, it2);           // 只反转 "World" 部分
cout << s << endl;            // Hello, dlroW!

// 用迭代器查找并插入
string s2 = "I C++!";
auto pos = s2.find("C++");
if (pos != string::npos) {
    s2.insert(s2.begin() + pos, 'L');  // 在 C++ 前面插入 L
    cout << s2 << endl;                  // I LC++!
}

// 删除指定位置的字符
string s3 = "Helloo";
s3.erase(s3.begin() + 4);   // 删除下标4的字符
cout << s3 << endl;          // Hello

4.3 const_iterator:只读迭代器

void printString(const string& s) {
    // 只能用 const_iterator,不能修改内容
    for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
        cout << *it;
        // *it = 'X';  // ❌ 编译错误!const_iterator 不能修改
    }
    cout << endl;
}

int main() {
    string s = "Hello";
    printString(s);  // Hello
}

💡 迭代器速记

  • begin() / end() → 正向(头→尾)
  • rbegin() / rend() → 反向(尾→头)
  • cbegin() / cend() → const 正向(只读)
  • crbegin() / crend() → const 反向(只读)

11.5 string 类串与 C 风格字符串的转化——新旧世界的桥梁

在实际开发中,你经常需要在 stringchar* 之间转换——比如调用 C 语言的库函数、和老代码对接等。

5.1 string → C 风格字符串

#include <iostream>
#include <string>
#include <cstring>
using namespace std;

int main() {
    string s = "Hello, World!";

    // 方法一:c_str()(推荐!返回 const char*)
    const char* cstr1 = s.c_str();
    cout << cstr1 << endl;          // Hello, World!
    cout << strlen(cstr1) << endl;  // 13

    // 方法二:data()(C++11 之前和 c_str() 相同)
    const char* cstr2 = s.data();
    cout << cstr2 << endl;          // Hello, World!

    // 方法三:拷贝到 char 数组
    char buf[100];
    s.copy(buf, s.length());
    buf[s.length()] = '\0';  // ⚠️ copy 不会自动加 '\0',需要手动加!
    cout << buf << endl;     // Hello, World!

    return 0;
}

⚠️ 重要警告c_str() 返回的指针指向 string 内部的缓冲区,如果 string 被修改或销毁,该指针就失效了!

const char* p;
{
    string s = "Hello";
    p = s.c_str();
}   // s 在这里被销毁了
// cout << p;  // 💥 未定义行为!p 已经是野指针了

// 正确做法:立即拷贝
string s = "Hello";
string safe_copy(s.c_str());  // 拷贝一份

5.2 C 风格字符串 → string

// 非常简单!直接赋值或构造即可
const char* cstr = "Hello from C!";
string s1 = cstr;           // 赋值
string s2(cstr);            // 构造
string s3(cstr, 5);         // 只取前5个字符:"Hello"

cout << s1 << endl;  // Hello from C!
cout << s2 << endl;  // Hello from C!
cout << s3 << endl;  // Hello

5.3 数字与 string 的互转(实用技巧)

#include <string>
#include <sstream>
using namespace std;

int main() {
    // ===== 数字 → string =====

    // 方法一:to_string(C++11,最简单!)
    int n = 42;
    double d = 3.14;
    string s1 = to_string(n);
    string s2 = to_string(d);
    cout << s1 << endl;  // "42"
    cout << s2 << endl;  // "3.140000"

    // 方法二:ostringstream(更灵活)
    ostringstream oss;
    oss << "值是: " << n << ", 精度: " << fixed << setprecision(2) << d;
    string s3 = oss.str();
    cout << s3 << endl;  // "值是: 42, 精度: 3.14"

    // ===== string → 数字 =====

    // 方法一:stoi / stod(C++11,最简单!)
    string numStr = "123";
    int x = stoi(numStr);
    cout << x + 1 << endl;  // 124

    string floatStr = "3.14";
    double y = stod(floatStr);
    cout << y * 2 << endl;  // 6.28

    // 方法二:istringstream
    string data = "100 3.14 Hello";
    istringstream iss(data);
    int a; double b; string c;
    iss >> a >> b >> c;
    cout << a << " " << b << " " << c << endl;  // 100 3.14 Hello

    return 0;
}

实战综合案例:文本处理器

把前面学的所有 string 知识串起来,写一个实用的文本处理器:

#include <iostream>
#include <string>
#include <algorithm>
#include <sstream>
#include <vector>
using namespace std;

// 功能1:统计单词数量
int countWords(const string& text) {
    istringstream iss(text);
    string word;
    int count = 0;
    while (iss >> word) count++;
    return count;
}

// 功能2:替换所有指定子串
string replaceAll(string text, const string& from, const string& to) {
    size_t pos = 0;
    while ((pos = text.find(from, pos)) != string::npos) {
        text.replace(pos, from.length(), to);
        pos += to.length();
    }
    return text;
}

// 功能3:提取所有邮箱地址
vector<string> extractEmails(const string& text) {
    vector<string> emails;
    size_t pos = 0;
    while (pos < text.length()) {
        size_t atPos = text.find('@', pos);
        if (atPos == string::npos) break;

        // 往前找邮箱开头
        size_t start = atPos;
        while (start > 0 && (isalnum(text[start-1]) || text[start-1] == '.' || text[start-1] == '_'))
            start--;

        // 往后找邮箱结尾
        size_t end = atPos;
        while (end < text.length() && (isalnum(text[end]) || text[end] == '.' || text[end] == '_'))
            end++;

        if (start < atPos && end > atPos) {
            emails.push_back(text.substr(start, end - start));
        }
        pos = end;
    }
    return emails;
}

// 功能4:首字母大写
string capitalize(const string& text) {
    string result = text;
    bool newWord = true;
    for (size_t i = 0; i < result.length(); i++) {
        if (result[i] == ' ') {
            newWord = true;
        } else if (newWord && isalpha(result[i])) {
            result[i] = toupper(result[i]);
            newWord = false;
        }
    }
    return result;
}

int main() {
    string text = "hello world! this is a test. contact us at test@example.com or admin@school.edu.cn for more info.";

    cout << "=== 原文 ===" << endl;
    cout << text << endl;

    // 统计单词数
    cout << "\n单词数量: " << countWords(text) << endl;

    // 替换
    string replaced = replaceAll(text, "test", "demo");
    cout << "\n=== 替换后 ===" << endl;
    cout << replaced << endl;

    // 提取邮箱
    cout << "\n=== 邮箱地址 ===" << endl;
    for (auto& email : extractEmails(text)) {
        cout << "  " << email << endl;
    }

    // 首字母大写
    cout << "\n=== 首字母大写 ===" << endl;
    cout << capitalize(text) << endl;

    // 大小写转换
    string upper = text;
    transform(upper.begin(), upper.end(), upper.begin(), ::toupper);
    cout << "\n=== 全大写 ===" << endl;
    cout << upper << endl;

    return 0;
}

输出:

=== 原文 ===
hello world! this is a test. contact us at test@example.com or admin@school.edu.cn for more info.

单词数量: 17

=== 替换后 ===
hello world! this is a demo. contact us at demo@example.com or admin@school.edu.cn for more info.

=== 邮箱地址 ===
  test@example.com
  admin@school.edu.cn

=== 首字母大写 ===
Hello World! This Is A Test. Contact Us At Test@Example.Com Or Admin@School.Edu.Cn For More Info.

=== 全大写 ===
HELLO WORLD! THIS IS A TEST. CONTACT US AT TEST@EXAMPLE.COM OR ADMIN@SCHOOL.EDU.CN FOR MORE INFO.

总结:string 类知识全景图

string 类字符串处理
│
├── 📝 定义(11.1)
│   ├── 默认构造:string s;
│   ├── 字面量构造:string s = "hello";
│   ├── 拷贝构造:string s2(s1);
│   ├── 重复字符:string s(5, '*');
│   └── 子串构造:string s(src, pos, len);
│
├── 🔧 成员函数(11.2)
│   ├── 信息:size() / length() / empty() / capacity()
│   ├── 访问:[] / at() / front() / back()
│   ├── 拼接:push_back() / append() / +=
│   ├── 插删:insert() / erase() / clear()
│   ├── 截取:substr()
│   ├── 查找:find() / rfind() / find_first_of()
│   ├── 替换:replace()
│   └── 比较:compare()
│
├── ⚡ 操作符(11.3)
│   ├── 赋值:= / +=
│   ├── 比较:== / != / < / > / <= / >=
│   ├── 连接:+
│   ├── 流:<< / >>
│   └── 下标:[]
│
├── 🔍 位置指针 / 迭代器(11.4)
│   ├── 正向:begin() / end()
│   ├── 反向:rbegin() / rend()
│   └── 只读:cbegin() / cend()
│
└── 🌉 与 C 风格字符串互转(11.5)
    ├── string → char*:c_str() / data()
    ├── char* → string:直接赋值/构造
    └── 数字 ↔ string:to_string() / stoi() / stod()

🎯 一句话总结string 类把 C 语言中那些"手动挡"的字符串操作全部升级成了"自动挡"——你只管踩油门(调函数),剩下的它帮你搞定。


如果觉得有帮助,欢迎点赞收藏 👍 有问题可以在评论区讨论!

更多推荐