1. 為什么學習 string 類?
1.1 C 語言中的字符串
C 語言中,字符串是以'\0'結尾的一些字符的集合,為了操作方便,C 標準庫中提供了一些 str 系列的庫函數,
但是這些庫函數與字符串是分離開的,不太符合 OOP (面向對象程序設計)的思想,而且底層空間需要用戶自己管理,稍不留神可能還會越界訪問
2.標準庫中的 string 類
2.1 string 類的常用接口說明(注意下面只講解最常用的接口)
(constructor)函數名稱 | 功能說明 |
string() (重點) | 構造空的 string 類對象,即空字符串 |
string(const char* s) (重點) | 用 C-string 來構造 string 類對象 |
string(size_t n, char c) | string 類對象中包含 n 個字符 c |
string(const string&s) (重點) | 拷貝構造函數 |
void Teststring()
{ string s1; // 構造空的string類對象s1 string s2("hello bit"); // 用C格式字符串構造string類對象s2 string s3(s2); // 拷貝構造s3
}
2.2string 類對象的容量操作
函數名稱 | 功能說明 |
size(重點) | 返回字符串有效字符的長度 |
length | 返回字符串有效字符的長度(與 size 功能一致) |
capacity | 返回字符串當前分配的總空間大小(包括未使用的預留空間) |
empty(重點) | 檢測字符串是否為空串,若是則返回 true,否則返回 false |
clear(重點) | 清空字符串中的有效字符(不改變空間總大小,僅將 size 置為 0) |
reserve(重點) | 為字符串預留指定大小的空間,用于減少后續插入操作的內存分配次數 |
resize(重點) | 將有效字符的個數調整為 n 個: - 若 n 小于當前 size,則截斷字符串; - 若 n 大于當前 size,則用指定字符 c(默認 '\0')填充多出的部分 |
示例:
#include <iostream>
#include <string>
using namespace std;int main() {// 初始化一個字符串string str = "Hello";cout << "初始字符串: " << str << endl;// 1. size() 和 length():返回有效字符長度(功能一致)cout << "\n1. size() = " << str.size() << endl;cout << " length() = " << str.length() << endl;// 2. capacity():返回當前總空間大小(包括預留空間)cout << "\n2. 初始 capacity = " << str.capacity() << endl;// 3. reserve(n):預留空間(不改變有效字符數)str.reserve(20); // 預留至少20個字符的空間cout << " 調用 reserve(20) 后,capacity = " << str.capacity() << endl;cout << " 此時 size = " << str.size() << "(reserve不改變有效字符數)" << endl;// 4. resize(n):調整有效字符數(截斷或填充)cout << "\n3. 原字符串: " << str << endl;str.resize(8, '!'); // 擴展到8個字符,新增部分用'!'填充cout << " 調用 resize(8, '!') 后: " << str << endl;cout << " 此時 size = " << str.size() << ", capacity = " << str.capacity() << endl;str.resize(3); // 截斷到3個字符cout << " 調用 resize(3) 后: " << str << endl;cout << " 此時 size = " << str.size() << ", capacity = " << str.capacity() << endl;// 5. empty():檢測是否為空串cout << "\n4. 字符串是否為空? " << (str.empty() ? "是" : "否") << endl;// 6. clear():清空有效字符(size置0,capacity不變)str.clear();cout << " 調用 clear() 后,字符串: \"" << str << "\"" << endl;cout << " 此時 size = " << str.size() << ", capacity = " << str.capacity() << endl;cout << " 清空后是否為空? " << (str.empty() ? "是" : "否") << endl;return 0;
}
注意:
1. size()與 length()方法底層實現原理完全相同,引入 size()的原因是為了與其他容器的接口保持一致,一般情況下基本都是用 size()。
2. clear()只是將 string 中有效字符清空,不改變底層空間大小。
3.resize(size_t n) 與 resize(size_t n, char c)都是將字符串中有效字符個數改變到 n 個,不同的是當字符個數增多時:resize(n)用 0 來填充多出的元素空間,resize(size_t n, char c)用字符 c 來填充多出的元素空間。注意:resize 在改變元素個數時,如果是將元素個數增多,可能會改變底層容量的大小,如果是將元素個數減少,底層空間總大小不變。
4.reserve(size_t res_arg=0):為 string 預留空間,不改變有效元素個數,當 reserve 的參數小于 string 的底層空間總大小時,reserver 不會改變容量大小。
2.3 string 類對象的訪問及遍歷操作
函數 / 特性名稱 | 功能說明 |
operator[] | (重點)返回字符串中 pos 位置的字符。其中,const string 類對象調用時返回不可修改的字符(const char&),非 const 對象調用時返回可修改的字符(char&)。 |
begin() + end() | begin() 獲取指向字符串第一個字符的迭代器;end() 獲取指向字符串最后一個字符下一個位置的迭代器(作為遍歷結束標志)。兩者配合可遍歷整個字符串。 |
rbegin() + rend() | rbegin() 獲取指向字符串最后一個字符的反向迭代器(用于逆向遍歷的起始);rend() 獲取指向字符串第一個字符前一個位置的反向迭代器(作為逆向遍歷結束標志)。兩者配合可逆向遍歷整個字符串。 |
范圍 for 循環 | C++11 新增的簡潔遍歷方式,可自動遍歷字符串中的每個字符(語法:for (char c : str) { ... }),本質是迭代器的語法糖,遍歷過程中會自動處理迭代器的移動和邊界判斷。 |
這份代碼展示了 C++ string
的多種元素訪問和遍歷方式:
operator[]
訪問:最常用的訪問方式,通過索引直接訪問字符
支持讀寫操作,但不進行邊界檢查,訪問越界會導致未定義行為
at()
方法訪問:與
operator[]
類似,但會進行邊界檢查訪問越界時會拋出
out_of_range
異常,更安全
迭代器遍歷:
begin()
和end()
提供正向迭代器,用于從前往后遍歷rbegin()
和rend()
提供反向迭代器,用于從后往前遍歷
const 迭代器:
用于
const string
對象的遍歷保證不會修改字符串內容
范圍 for 循環:
C++11 引入的簡潔遍歷方式
通過引用 (
char&
) 可以修改元素,否則只能讀取
#include <iostream>
#include <string>
#include <algorithm>using namespace std;int main() {string str = "Hello, String!";cout << "原始字符串: " << str << endl;cout << "字符串長度: " << str.size() << endl << endl;// 1. 使用operator[]訪問單個元素cout << "1. 使用operator[]訪問:" << endl;if (!str.empty()) {cout << "第一個字符: " << str[0] << endl;cout << "最后一個字符: " << str[str.size() - 1] << endl;// 修改元素str[0] = 'h';cout << "修改后第一個字符: " << str[0] << endl;}cout << endl;// 2. 使用at()方法訪問單個元素(帶邊界檢查)cout << "2. 使用at()訪問:" << endl;try {cout << "索引為7的字符: " << str.at(7) << endl;// 嘗試訪問超出范圍的索引,會拋出out_of_range異常// cout << str.at(100) << endl;} catch (const out_of_range& e) {cout << "訪問異常: " << e.what() << endl;}cout << endl;// 3. 使用迭代器遍歷cout << "3. 使用迭代器遍歷:" << endl;cout << "正向遍歷: ";for (string::iterator it = str.begin(); it != str.end(); ++it) {cout << *it;}cout << endl;// 4. 使用反向迭代器遍歷cout << "4. 使用反向迭代器遍歷:" << endl;cout << "反向遍歷: ";for (string::reverse_iterator rit = str.rbegin(); rit != str.rend(); ++rit) {cout << *rit;}cout << endl << endl;// 5. 使用const迭代器遍歷(用于const string)cout << "5. 使用const迭代器遍歷:" << endl;const string const_str = "Const String";cout << "const字符串正向遍歷: ";for (string::const_iterator cit = const_str.begin(); cit != const_str.end(); ++cit) {cout << *cit;}cout << endl;cout << "const字符串反向遍歷: ";for (string::const_reverse_iterator crit = const_str.rbegin(); crit != const_str.rend(); ++crit) {cout << *crit;}cout << endl << endl;// 6. 使用范圍for循環遍歷(C++11及以上)cout << "6. 使用范圍for循環遍歷:" << endl;cout << "范圍for遍歷: ";for (auto c : str) {cout << c;}cout << endl;// 范圍for修改元素for (char& c : str) { // 注意使用引用才能修改if (c == ',') {c = ';';}}cout << "修改后的字符串: " << str << endl;return 0;
}