C++ string(初识)
目录
std::string不是 C++ 内置数据类型,而是标准库提供的模板类(准确说是 std::basic_string<char> 的别名),它封装了字符串的存储和各种操作,无需你手动管理内存(比如扩容、释放),是处理字符串的首选。
使用它的前置条件:
- 必须包含头文件
<string> - 它位于
std命名空间中,有两种使用方式:- 方式 1:添加
using namespace std;(推荐,简洁) - 方式 2:直接写
std::string(工程开发更规范,避免命名冲突)
- 方式 1:添加
初始化:
#include <iostream> #include <string> using namespace std; int main() { // 1. 直接赋值(最简洁) string s1 = "Hello C++"; // 2. 构造函数初始化(和方式1效果一致) string s2("Hello C++"); // 3. 初始化空字符串(后续可赋值) string s3; // 空字符串,长度为0 s3 = "Later fill content"; // 4. 用已有字符串的子串初始化(结合你之前的疑问) string s4(s1, 6); // 从s1的第6个字符(下标从0开始)开始,复制到末尾,结果为"C++" // 5. 用指定字符重复n次初始化 string s5(5, 'a'); // 5个字符'a',结果为"aaaaa" // 打印验证 cout << "s1: " << s1 << endl; cout << "s2: " << s2 << endl; cout << "s3: " << s3 << endl; cout << "s4: " << s4 << endl; cout << "s5: " << s5 << endl; return 0; }核心基础(std::string 常用基本操作):
获取字符串长度
两种方法,效果完全一致,推荐 size(),和其他标准库容器一致
string s = "Hello"; cout << "长度:" << s.size() << endl; // 输出:5 cout << "长度:" << s.length() << endl; // 输出:5访问单个字符
- 方式 1:
[]下标访问(不做越界检查,运行速度快,新手注意避免下标越界) - 方式 2:
at()方法(做越界检查,越界会抛异常,更安全)
string s = "Hello"; char c1 = s[0]; // 获取第一个字符,结果为'H' char c2 = s.at(4); // 获取最后一个字符,结果为'o' cout << c1 << " " << c2 << endl; // 输出:H o // 错误示例(越界) // s[5]; // 无报错,行为未定义(可能崩溃) // s.at(5); // 抛异常,提示越界字符串拼接
// 方式1:+ 运算符(支持 string 与 string、string 与常量字符串拼接) string s1 = "Hello"; string s2 = " C++"; string s3 = s1 + s2; // 结果为"Hello C++" // 方式2:append() 方法 string s4 = "Hello"; s4.append(" World"); // 结果为"Hello World" cout << s3 << endl; cout << s4 << endl;修改字符串
string s = "Hello"; // 1. 整体赋值 s = "Hi"; cout << s << endl; // 输出:Hi // 2. 修改单个字符 s[0] = 'h'; cout << s << endl; // 输出:hi // 3. 清空字符串 s.clear(); cout << "清空后长度:" << s.size() << endl; // 输出:0判断字符串是否为空
string; string s2 = "Hello"; cout << "s1是否为空:" << (s1.empty() ? "是" : "否") << endl; // 输出:是 cout << "s2是否为空:" << (s2.empty() ? "是" : "否") << endl; // 输出:否注意事项:
- 忘记包含
<string>头文件:使用std::string必须包含,否则编译器可能报错。 - 下标越界:访问字符时,下标不要超过
size()-1,优先用at()做安全访问。
#include <iostream> #include <string> using namespace std; int main() { string s = "Hello"; int index = 4; // 要访问的下标(最后一个字符的下标) // 先判断下标有效性 if (index >= 0 && index < s.size()) { char c = s.at(index); // 安全访问 cout << c << endl; // 输出:o } else { cout << "下标越界,无效!" << endl; } return 0; }- 修改
c_str()返回的指针:c_str()返回的是只读指针,不可修改其指向的内容,否则会触发未定义行为。
#include <iostream> #include <string> #include <cstring> // 包含strcpy函数 using namespace std; int main() { string s = "Hello"; // 做法1:直接修改原std::string对象(推荐,最安全) s[0] = 'h'; cout << s << endl; // 输出:hello // 做法2:复制到独立char[]数组后修改(兼容C风格接口) char arr[100]; // 定义足够大的数组 strcpy(arr, s.c_str()); // 把c_str()的内容复制到arr中 arr[0] = 'H'; cout << arr << endl; // 输出:Hello return 0; }- 空字符串访问:空字符串(
empty() == true)的size()为0,不可访问[0]或at(0)。
string 常用接口
string类的成员函数:
constructior 构造函数:

- string()(重点) 无参构造空的string类对象,即空字符串
- string(const char* s) (重点) 带参的常量字符串初始化
- string(const string&s) (重点) 拷贝构造函数
- string (const char* s, size_t n) 对一个字符串的前n个初始化
- string (size_t n, char c) 用 n 个 c 初始化
- string (const string& str, size_t pos, size_t len = npos) 从pos位置处取len长度的字符进行拷贝构造
void test_string1() { string s1; string s2("hello c++"); string s3(s2); string s4(s2, 1, 5);//拷贝部分内容 const char* s5 = "heihei"; string s6(s5); string s7(s5, 5); string s8(100, '#'); cout << s1 << endl; cout << s2 << endl; cout << s3 << endl; cout << s4 << endl; cout << s6 << endl; cout << s7 << endl; cout << s8 << endl; } int main() { test_string1(); return 0; }
destructor 析构函数
这里我们无需操作,编译器会默认调用构造函数
operator= 赋值

迭代器:


void test_string3() { string s1("123456"); const string s2("hello world"); // [begin(), end()) // 2、迭代器 (所有容器主流遍历+修改方式) // s1的的每个字符都-- string::iterator it1 = s1.begin(); while (it1 != s1.end()) { (*it1)--; ++it1; } cout << s1 << endl; string::const_iterator it2 = s2.begin(); while (it2 != s2.end()) { // (*it2)--; 不能修改 ++it2; } cout << s2 << endl; string::reverse_iterator it3 = s1.rbegin(); while (it3 != s1.rend()) { cout << *it3 << " "; ++it3; } cout << endl; string::const_reverse_iterator it4 = s2.rbegin(); while (it4 != s2.rend()) { // 不能修改 // *it4 = 'x'; cout << *it4 << " "; ++it4; } cout << endl; } int main() { test_string3(); return 0; }容量:


#include<iostream> #include<string> #include<list> #include<vector> #include<algorithm> using namespace std; void test_string4() { string s1("12323456567"); cout << s1.size()<< endl; cout << s1.capacity() << endl; string s2; // 确定知道需要多少空间,提前开好,避免扩容,提高效率 //s2.reserve(100); size_t old = s2.capacity(); cout << "capacity:" << old << endl; for (size_t i = 0; i < 100; i++) { s2.push_back('x'); if (s2.capacity() != old) { cout << "capacity:" << s2.capacity() << endl; old = s2.capacity(); } } cout << s1 << endl; s1.clear(); cout << s1 << endl; // 不会缩容,缩容要重新开空间,代价很大 cout << "size:" << s2.size() << endl; cout << "capacity:" << s2.capacity() << endl; //s2.clear(); for (size_t i = 0; i < 50; i++) { s2.pop_back(); } s2.shrink_to_fit(); cout << "size:" << s2.size() << endl; cout << "capacity:" << s2.capacity() << endl; } int main() { /*test_string1();*/ //test_string2(); //test_string3(); test_string4(); return 0; }额外解释reserve::




考虑到内存对齐,但一定不会比100少;避免连续扩容,效率高
看编译器:VS编译器下,reserve不缩容

resize


#include<iostream> #include<string> #include<list> #include<vector> #include<algorithm> using namespace std; void test_string6() { string s2("123456"); cout << s2 << endl; cout << "size:" << s2.size() << endl; cout << "capacity:" << s2.capacity() << endl; // 插入数据,让size到n个 // n > capacity > size; s2.resize(20, 'x'); cout << s2 << endl; cout << "size:" << s2.size() << endl; cout << "capacity:" << s2.capacity() << endl; // capacity > n > size; //s2.resize(25, 'x'); s2.resize(25); // 插入的是\0 s2.push_back('y'); cout << s2 << endl; cout << "size:" << s2.size() << endl; cout << "capacity:" << s2.capacity() << endl; // 删除数据 // n < size; s2.resize(5); cout << s2 << endl; cout << "size:" << s2.size() << endl; cout << "capacity:" << s2.capacity() << endl; } int main() { test_string6(); return 0; }