字符串处理是编程中最频繁的操作之一。C 的 char[] + strcpy/strlen 既啰嗦又容易越界;C++ 的 std::string 自动管理内存、支持运算符重载,一行顶 C 三行。本文带你掌握最常用的字符串操作。
1. 构造与基本操作
#include <string>
using namespace std;
string s1 = "hello"; // 字面量构造
string s2(5, 'a'); // "aaaaa"
string s3 = s1 + " world"; // 拼接:"hello world"
s3.push_back('!'); // 尾部加字符
s3 += "!!"; // 追加字符串
int n = s3.length(); // 长度(与 size() 相同)
bool empty = s3.empty();
char c = s3[0]; // 下标访问,越界不检查
char c2 = s3.at(1); // 越界抛 out_of_range
2. 拼接与比较
拼接直接用 +,比较直接用 ==/<(按字典序),告别 C 的 strcmp:
string a = "abc", b = "abd";
if (a < b) { /* abc 排在 abd 前面 */ }
// 字符串与数字混拼
int score = 95;
string msg = "分数: " + to_string(score);
3. 查找与子串
string s = "hello world, hello cpp";
size_t pos = s.find("world"); // 返回下标 6
if (pos != string::npos) { // npos 表示"没找到"
string sub = s.substr(6, 5); // 从 6 开始取 5 个字符:"world"
}
// 反向查找、查找任一字符
size_t last = s.rfind("hello"); // 13
size_t comma = s.find_first_of(",;!"); // 11
// 用 find 循环统计子串出现次数
int cnt = 0;
pos = s.find("hello");
while (pos != string::npos) {
++cnt;
pos = s.find("hello", pos + 1);
}
4. 数字与字符串互转
#include <string>
using namespace std;
// 数字 → 字符串
string a = to_string(3.14); // "3.140000"
string b = to_string(42); // "42"
// 字符串 → 数字(C++11 起,失败抛异常)
int i = stoi("42"); // 42
long l = stol("123456789");
double d = stod("3.14");
float f = stof("2.5f");
// 带进制解析
int hexv = stoi("ff", nullptr, 16); // 255
老项目里常见的 atoi/atof 失败时不报错、返回 0,容易掩盖 bug;新代码优先用 stoi 系列。
5. 与 C 字符串互转
// C++ → C:只读,别修改返回值指向的内容
const char* cstr = s.c_str();
// C++ → C:可写副本
vector<char> buf(s.begin(), s.end());
buf.push_back('\0'); // C 字符串需要结尾 '\0'
char* writable = buf.data();
// C → C++:直接构造
const char* old = "from c";
string now(old);
6. 处理中文时的注意事项
| 操作 | 说明 |
|---|---|
| length() | UTF-8 下返回字节数,不是字符数 |
| s[0] | 取到的是字节,中文会取到半个字 |
| substr | 按字节切,可能切开汉字 |
| find("你") | 按字节序列查找,一般仍能正确找到 |
简单场景按字节处理没问题;要按"字符"处理中文,建议用 std::wstring 或第三方库(如 ICU)。
💡 练习:实现一个split(s, delim)函数把字符串按分隔符拆成 vector<string>,再实现trim去掉首尾空格。这两个工具函数在刷题和工程里天天用。