目录
C++ string类完全指南:从入门到实战
写给初学者的前言
当你刚开始学习C++时,可能会对字符串处理感到困惑——为什么要有string类?它和C语言的字符数组有什么区别?为什么总说string更好用?这篇文章将用最通俗易懂的方式,带你彻底理解C++中的string类。
一、为什么需要string类?
1. C语言字符串的烦恼
想象你要记录一个班级的学生姓名:
char name1[20] = "张三";
char name2[20] = "李四";
// 想要拼接两个名字
strcat(name1, name2); // 危险!可能超出20个字符
C语言的字符串就像固定大小的盒子:
- 必须预先知道最大长度
- 拼接、复制容易出错
- 需要记住各种str开头的函数
2. string类就像智能字符串
string name1 = "张三";
string name2 = "李四";
string fullName = name1 + name2; // 自动处理内存
string类就像会自动扩容的智能容器:
- 不用预先设定大小
- 基本操作直接用运算符(+, =等)
- 内存自动管理
二、string类的基本使用
1. 创建字符串的5种方式
string s1; // 空字符串
string s2 = "hello"; // 直接赋值
string s3("world"); // 构造函数
string s4(5, 'A'); // "AAAAA"
string s5(s2); // 拷贝构造
2. 最常用的10个操作
// 1. 获取长度
int len = s.size(); // 或者s.length()
// 2. 判断是否为空
if (s.empty()) cout << "字符串为空";
// 3. 访问字符
char c1 = s[0]; // 不检查越界
char c2 = s.at(0); // 会检查越界
// 4. 字符串比较
if (s1 == s2) {...}
if (s1 < s2) {...} // 按字典序比较
// 5. 字符串连接
s1 += s2; // 追加
s1.append("!!"); // 同样功能
// 6. 查找子串
int pos = s.find("lo"); // 返回位置或string::npos
// 7. 截取子串
string sub = s.substr(2, 3); // 从位置2开始,取3个字符
// 8. 插入删除
s.insert(3, "插入的内容");
s.erase(3, 5); // 从位置3删除5个字符
// 9. 替换
s.replace(2, 4, "新内容"); // 从位置2开始替换4个字符
// 10. 转换C风格字符串
const char* p = s.c_str();
3. 新特性:auto和范围for
// 自动类型推导
auto s = "自动推导为string"s; // 注意结尾的s
// 遍历字符串的每个字符
for (auto ch : s) {
cout << ch << " ";
}
三、string类的底层秘密
1. string类的存储方式
string类实际上是在堆上动态分配内存存储字符,但有两种优化策略:
VS编译器:
- 短字符串(<16字符)直接存在对象内部
- 长字符串才在堆上分配
- 总大小固定为28字节
GCC编译器:
- 全部在堆上分配
- 使用引用计数实现写时复制(COW)
- 多个string可共享同一内存
2. 为什么需要深拷贝?
// 浅拷贝的问题
string s1 = "hello";
string s2 = s1; // 如果只是简单复制指针...
// s1和s2指向同一内存,析构时会重复释放!
string类必须实现深拷贝:
- 每个string对象有自己的内存副本
- 拷贝时会完全复制内容
- 避免多个对象共享同一内存
四、实战练习(oj在线均有原题)
1. 反转字符串
void reverseString(string& s) {
int left = 0, right = s.size() - 1;
while (left < right) {
swap(s[left], s[right]);
left++;
right--;
}
}
2. 验证回文串
bool isPalindrome(string s) {
int left = 0, right = s.size() - 1;
while (left < right) {
if (s[left] != s[right]) return false;
left++;
right--;
}
return true;
}
3. 字符串分割
vector<string> split(const string& s, char delim) {
vector<string> tokens;
string token;
for (char ch : s) {
if (ch == delim) {
if (!token.empty()) {
tokens.push_back(token);
token.clear();
}
} else {
token += ch;
}
}
if (!token.empty()) tokens.push_back(token);
return tokens;
}
五、常见问题解答
1. string和char[]如何选择?
- 需要固定大小或与C函数交互 → char[]
- 其他情况 → string
2. string会内存泄漏吗?
不会!string的析构函数会自动释放内存
3. 为什么有时要用c_str()?
当需要传递给C函数时:
FILE* f = fopen(s.c_str(), "r");
4. 如何提高string性能?
- 预先用reserve()分配足够空间
- 少用+运算符,多用+=
- 传递const string&避免拷贝
六、学习路线建议
- 初级阶段:掌握基本API,能完成常见操作
- 中级阶段:理解内存管理,避免常见陷阱
- 高级阶段:研究底层实现,尝试自己实现string类
记住:string是C++中最常用的工具之一,多练习才能真正掌握!
229

被折叠的 条评论
为什么被折叠?



