字符串
std::string 是 C++ 标准库中用于处理字符串的类,位于
char* (C 风格字符串):本身没有成员函数,不能使用 .size() 或 .length()。要获取其长度,必须使用 C 语言的库函数 strlen(),这个函数定义在
(或 C 的 <string.h>) 头文件中。
C++ 字符串末尾没有 \0 字符。事实上,除了 C 语言外,其他语言都是将字符串本身及其长度存在内存中,因此不用 \0 标记结尾
其迭代器是随机访问迭代器, 支持跳跃式访问
常用接口:
size()/length():获取字符串长度empty():判断字符串是否为空clear():清空字符串reserve(n):预分配内存append()/+=:字符串连接compare():字符串比较substr(pos, len):获取子字符串find()/rfind():查找子字符串insert(pos, str):插入子字符串erase(pos, len):删除子字符串push_back(char)/pop_back():在字符串末尾添加或删除字符
定义和初始化
1 |
|
vector<char>和string
在实际使用中, vector
1 | string str = "Hello, World!"; |
因此, 如果需要动态修改字符串内容,
也可以用vector
- 当 std::string str 这行代码执行完毕后,变量 str
已经拥有了一个确定的、合法的、可用的值。它不是未定义的、也不是指向 null
的 ( RAII 的体现 )。std::string
的默认构造函数会将字符串初始化为一个空字符串 (Empty
String), 具有以下明确的属性:
- 值为 ““:它不包含任何字符。
- 长度为 0:调用 str.length() 或 str.size() 会返回 0。
- 是“空的”:调用 str.empty() 会返回 true。
- 是有效的:可以立即对它进行各种操作,而不会导致程序错误。
- 因为 std::string 是一个 类 (Class),而不是像 int 或 char[] 这样的基础数据类型。在 C++ 中,当一个类的对象被创建时,会自动调用其相应的构造函数 (Constructor) 来进行初始化。
访问和赋值
1 | char c1 = s[0]; // 通过[]访问(不检查越界), 但注意此时s[i]返回的是char类型的单个字符 |
在赋值时和 C 字符串的差别:
1 | char char1[20]; |
C 风格字符串 (char[]) 本质是“数组”, 当声明 char char1[20]; 时,实际是在内存的栈上请求了一块连续的、包含 20 个 char 类型元素的空间。char1 这个名字就代表了这块内存的起始地址。
尝试执行 char1 = char2; 时,实际上是在命令编译器:“请把 char1 这个地址常量,修改为 char2 这个地址常量所代表的地址”。这在逻辑上是行不通的,也是 C/C++ 语法所禁止的。编译器会报错,通常提示“表达式必须是可修改的左值”或“数组类型不可赋值”。
字符串长度
1 | int len = s.size(); // 或 s.length() |
字符串连接
1 | string s = "Hello"; |
字符串比较
1 | string a = "apple", b = "banana"; |
关于单引号和双引号:
| 符号 | 用途 | 类型 | 内存内容 | 示例 |
|---|---|---|---|---|
| ’ ’ | 单个字符 | char | ASCII 值 | ‘A’ |
| ” ” | 字符串 | const char* | 字符序列 + \0 | “Hello” |
因此对于string类型的s, 下列代码不正确s[i] == “V”而应该是s[i] == ‘V’
子串操作
substr() 函数 - 获取子字符串:s.substr(pos, len), 注意参数不是迭代器 - 参数: - pos:起始索引。 - len:长度(可选,默认到字符串末尾)( 不是终点位置!!! 已知终点算长度要 pos-start)
1 | string s = "Hello World"; |
子串查找
1 | size_t pos = s.find("World"); // 查找子串,返回起始索引,找不到返回 string::npos |
插入和删除
1 | s.insert(5, " INSERTED "); // 在索引5插入字符串 |
字符串输入和输出
1 | std::string s; |
- 如果 cin 之后用到 getline,由于 cin 遇到空白字符时就停止往后读,输入流里可能还有未被读取的换行符,而 getline 将会读取一行字符串,直到遇到换行符。所以在使用 getline 前,应当先用 cin.get() 读取换行符(这个函数的功能是读取单个字符),然后再用 getline。
string和栈
string本身提供了push_back()和pop_back()方法, 可以把string当作栈来用
1 |
|
底层实现
std::string 通常在底层使用动态数组来存储字符数据。它会自动管理内存的分配和释放,以适应字符串长度的变化。常见的实现细节包括: - 动态内存分配:当字符串长度超过当前容量时,std::string 会分配更大的内存块,并将现有数据复制过去。 - 小字符串优化 (SSO):许多 std::string 实现会使用小字符串优化技术,将较短的字符串直接存储在对象内部的固定大小缓冲区中,以减少动态内存分配的开销。