一、为什么学 string
C 语言中字符串是 char[],依赖 strcpy/strlen 函数。有几个缺点:
- 字符串与操作分离,不符合面向对象思想
- 用户自管内存,容易越界或泄漏
- 容量固定,无法自动扩展
string 解决了这些问题——自动管理内存、动态扩容、异常处理、迭代器支持。
二、构造与赋值
示例 1:string 构造与赋值
#include <iostream>
#include <string>
using namespace std;
int main() {
string s1;
string s2("Hello");
string s3(s2);
string s4(5, 'A');
string s5(s2, 1, 3);
cout << "s1=[" << s1 << "]\\ns2=[" << s2 << "]\\n";
cout << "s3=[" << s3 << "]\\ns4=[" << s4 << "]\\n";
cout << "s5=[" << s5 << "]\\n";
s1 = s2; s1 = "World"; s1 = 'X';
return 0;
}
三、容量管理
- size()/length():有效字符个数
- capacity():当前分配的总大小
- empty():判空
- reserve(n):预留空间,不改 size
- resize(n,c):改变 size,多余用 c 填充
- clear():清空
示例 2:容量管理
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
cout << "size=" << s.size() << ",cap=" << s.capacity() << "\\n";
s = "Hello World!";
cout << "size=" << s.size() << ",cap=" << s.capacity() << "\\n";
s.reserve(100);
cout << "after reserve: size=" << s.size() << ",cap=" << s.capacity() << "\\n";
s.resize(5);
cout << "after resize(5): [" << s << "] size=" << s.size() << "\\n";
s.resize(200, 'X');
cout << "after resize(200): size=" << s.size() << ",cap=" << s.capacity() << "\\n";
return 0;
}
四、元素访问与遍历
示例 3:遍历三种方式
#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "C++ String";
for (size_t i = 0; i < s.size(); ++i) cout << s[i];
cout << "\\n";
for (auto it = s.begin(); it != s.end(); ++it) cout << *it;
cout << "\\n";
for (char c : s) cout << c;
cout << "\\n";
return 0;
}
五、修改操作
示例 4:常见修改接口
#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "Hello";
s.push_back('!'); s.append(" World"); s += "!!";
cout << s << "\\n";
s.insert(0, ">> "); cout << s << "\\n";
s.erase(0, 3); cout << s << "\\n";
s.replace(6, 5, "C++"); cout << s << "\\n";
string t = "Temp"; s.swap(t);
cout << "s=" << s << " t=" << t << "\\n";
return 0;
}
六、查找与子串
示例 5:find 和 substr
#include <iostream>
#include <string>
using namespace std;
int main() {
string url = "https://en.cppreference.com/w/cpp/string";
size_t pos = url.find("://");
if (pos != string::npos)
cout << "Protocol: " << url.substr(0, pos) << "\\n";
pos = url.rfind('/');
if (pos != string::npos)
cout << "Last: " << url.substr(pos+1) << "\\n";
pos = url.find('c', 10);
cout << "pos=" << pos << "\\n";
if (url.find("https") == 0) cout << "starts with https\\n";
return 0;
}
七、c_str 与 getline
c_str() 返回 const char*,与 C API 交互。getline 读取含空格的一整行。
示例 6:getline 和 c_str
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
int main() {
string line;
cout << "Enter a line: "; getline(cin, line);
cout << "You entered: " << line << "\\n";
const char* cstr = line.c_str();
cout << "length=" << strlen(cstr) << "\\n";
string part;
getline(cin, part, '|');
cout << "Part: " << part << "\\n";
return 0;
}
八、比较运算符
示例 7:字符串比较
#include <iostream>
#include <string>
using namespace std;
int main() {
string a = "apple", b = "banana", c = "app";
if (a < b) cout << a << " < " << b << "\\n";
if (a == "apple") cout << "Equal\\n";
if (a > c && c < b) cout << c << " is between\\n";
int r = a.compare(0, 3, c);
cout << "compare: " << r << "\\n";
return 0;
}
九、深拷贝与浅拷贝
涉及动态内存的类必须自定义拷贝构造和赋值。这与之前学习类与对象时的深拷贝原理一致。浅拷贝会导致多个对象共享内存,释放时重复释放崩溃。
示例 8:自定义 String 模拟深拷贝
#include <iostream>
#include <cstring>
using namespace std;
class String {
public:
String(const char* str="")
: _str(new char[strlen(str)+1]) { strcpy(_str,str); }
String(const String& o)
: _str(new char[strlen(o._str)+1]) { strcpy(_str,o._str); }
String& operator=(const String& o) {
if (this != &o) {
delete[] _str;
_str = new char[strlen(o._str)+1];
strcpy(_str,o._str);
}
return *this;
}
~String() { delete[] _str; }
const char* c_str() const { return _str; }
private:
char* _str;
};
int main() {
String s1("Hello");
String s2(s1);
String s3; s3 = s1;
cout << s1.c_str() << "\\n" << s2.c_str() << "\\n" << s3.c_str() << "\\n";
return 0;
}
总结
- 构造、容量管理、元素访问、遍历、修改、查找、子串、比较、c_str/getline
- 深拷贝是理解底层的关键,也是面试高频考点
- 后续 vector/list 等容器的遍历方式与 string 类似




