string
- 深入探索 C++ STL 中的 std::string
- 一、`std::string` 的基本概念
- 1. 內存管理
- 2. 安全性
- 二、`std::string` 的構造與初始化
- 1. 默認構造
- 2. 從 C 風格字符串構造
- 3. 從字符串的一部分構造
- 4. 使用重復字符構造
- 三、`std::string` 的常用操作
- 1. 字符串拼接
- 2. 字符串比較
- 3. 字符串查找
- 4. 字符串替換
- 5. 字符串分割
- 6. 字符串大小和容量
- 7. 字符訪問
- 四.string類對象的訪問及遍歷操作
- 一、`std::string`的容量相關概念
- 1. `size`(或`length`)
- 2. `capacity`
- 3. `max_size`
- 二、`reserve`:預留內存
- 使用場景
- 示例代碼
- 注意事項
- 三、`shrink_to_fit`:收縮內存
- 使用場景
- 示例代碼
- 注意事項
- 四、`resize`:調整字符串大小
- 示例代碼
- 注意事項
- 五、容量操作的性能優化
- 1. 預留足夠的內存
- 2. 及時收縮內存
- 3. 避免不必要的拷貝
- 五.string類對象的修改操作
- 一、`std::string`的修改操作概述
- 二、直接修改字符
- 示例代碼
- 注意事項
- 三、插入操作
- 1. 插入單個字符
- 2. 插入字符串
- 3. 插入字符數組
- 注意事項
- 四、刪除操作
- 示例代碼
- 參數說明
- 注意事項
- 五、替換操作
- 示例代碼
- 參數說明
- 注意事項
- 六、追加操作
- 1. 追加單個字符
- 2. 追加字符串
- 3. 追加字符數組
- 注意事項
- 七、清空字符串
- 示例代碼
- 注意事項
- 八、使用`std::stringstream`進行復雜修改
- 示例代碼
- 六.string類非成員函數
- 一、什么是`std::string`的非成員函數?
- 二、常見的`std::string`非成員函數
- 1. **`std::swap`**
- 示例代碼
- 2. **`std::to_string`**
- 示例代碼
- 3. **`std::stoi`、`std::stod`、`std::stof`等**
- 示例代碼
- 4. **`std::getline`**
- 示例代碼
- 5. **`std::operator<<` 和 `std::operator>>`**
- 示例代碼
- 6. **`std::operator+` 和 `std::operator+=`**
- 示例代碼
- 7. **`std::operator==`、`std::operator!=`、`std::operator<`等**
- 示例代碼
- 七、總結

深入探索 C++ STL 中的 std::string
在 C++ 編程中,字符串處理是一個常見的任務,而 C++ 標準模板庫(STL)中的 std::string
類為我們提供了強大的功能來簡化這一過程。
一、std::string
的基本概念
std::string
是 C++ STL 中的一個類,用于表示和操作字符串。它屬于 <string>
頭文件,是基于模板的 std::basic_string
類的一個特化版本,專門用于處理字符類型為 char
的字符串。與傳統的 C 風格字符串(以空字符結束的字符數組)相比,std::string
提供了更高的安全性和更豐富的功能。
1. 內存管理
std::string
內部會動態管理內存,這意味著你不需要手動分配和釋放內存。當你對字符串進行修改時,std::string
會自動調整內存大小以適應新的內容。例如:
std::string str = "Hello";
str += ", World!"; // 內部自動調整內存大小
2. 安全性
std::string
不會像 C 風格字符串那樣容易出現越界訪問或內存泄漏的問題。它提供了邊界檢查和異常處理機制,確保字符串操作的安全性。
二、std::string
的構造與初始化
std::string
提供了多種構造方式,可以根據不同的需求選擇合適的構造函數。
1. 默認構造
std::string str; // 創建一個空字符串
2. 從 C 風格字符串構造
const char* c_str = "Hello";
std::string str(c_str); // 使用 C 風格字符串初始化
3. 從字符串的一部分構造
std::string str1 = "Hello World";
std::string str2(str1, 6, 5); // 從 str1 的第 6 個字符開始,取 5 個字符
// str2 的內容為 "World"
4. 使用重復字符構造
std::string str(5, 'a'); // 創建一個包含 5 個 'a' 的字符串
// str 的內容為 "aaaaa"
三、std::string
的常用操作
1. 字符串拼接
std::string
提供了多種方式來拼接字符串,包括使用 +
運算符和 +=
運算符。
std::string str1 = "Hello";
std::string str2 = "World";
std::string str3 = str1 + ", " + str2 + "!"; // 使用 + 拼接
str1 += " "; // 使用 += 拼接
str1 += str2;
// str1 的內容為 "Hello World"
2. 字符串比較
std::string
支持使用比較運算符(如 ==
、!=
、<
、>
等)來比較字符串內容。
std::string str1 = "apple";
std::string str2 = "banana";
if (str1 < str2) {std::cout << "apple is less than banana" << std::endl;
}
3. 字符串查找
std::string
提供了 find
方法,用于查找子字符串的位置。
std::string str = "Hello World";
size_t pos = str.find("World");
if (pos != std::string::npos) {std::cout << "Found 'World' at position " << pos << std::endl;
}
4. 字符串替換
std::string
的 replace
方法可以用來替換字符串中的部分內容。
std::string str = "Hello World";
str.replace(6, 5, "Universe");
// str 的內容變為 "Hello Universe"
5. 字符串分割
雖然 std::string
沒有直接提供分割字符串的方法,但可以通過循環和 find
方法實現。
std::string str = "apple,banana,orange";
std::string delimiter = ",";
size_t pos = 0;
std::string token;
while ((pos = str.find(delimiter)) != std::string::npos) {token = str.substr(0, pos);std::cout << token << std::endl;str.erase(0, pos + delimiter.length());
}
std::cout << str << std::endl; // 輸出最后一個子字符串
6. 字符串大小和容量
std::string
提供了 size
和 capacity
方法來獲取字符串的長度和當前分配的內存容量。
std::string str = "Hello";
std::cout << "Size: " << str.size() << std::endl; // 輸出 5
std::cout << "Capacity: " << str.capacity() << std::endl; // 輸出實際分配的容量
7. 字符訪問
可以通過下標運算符 []
或 at
方法訪問字符串中的字符。
std::string str = "Hello";
char c = str[0]; // 使用下標訪問
char d = str.at(1); // 使用 at 方法訪問
四.string類對象的訪問及遍歷操作
一、std::string
的容量相關概念
在深入了解容量操作之前,我們需要明確幾個與std::string
容量相關的重要概念:
1. size
(或length
)
size
函數返回字符串中實際存儲的字符數量,不包括末尾的空字符'\0'
。length
函數與size
功能完全相同,只是名字不同。
std::string str = "Hello, World!";
std::cout << "Size: " << str.size() << std::endl; // 輸出:Size: 13
2. capacity
capacity
函數返回字符串當前分配的內存容量,單位是字符數。capacity
通常大于或等于size
,因為std::string
會預留一些額外的內存,以便在字符串擴展時減少內存分配的次數。
std::string str = "Hello, World!";
std::cout << "Capacity: " << str.capacity() << std::endl; // 輸出:Capacity: 15(具體值可能因實現而異)
3. max_size
max_size
函數返回std::string
能夠存儲的最大字符數。這個值通常取決于系統的內存限制和std::string
的實現。
std::string str;
std::cout << "Max size: " << str.max_size() << std::endl; // 輸出:Max size: 18446744073709551615(64位系統)
二、reserve
:預留內存
reserve
函數用于顯式地為std::string
預留一定量的內存。這可以減少在字符串頻繁擴展時的內存分配次數,從而提高性能。
使用場景
當你知道字符串將要存儲大量字符時,可以使用reserve
預先分配足夠的內存。例如,當你從文件中讀取大量文本并拼接到字符串中時,reserve
可以顯著提高效率。
示例代碼
std::string str;
str.reserve(1000); // 預留1000個字符的內存
for (int i = 0; i < 1000; ++i) {str += 'a';
}
std::cout << "Size: " << str.size() << std::endl; // 輸出:Size: 1000
std::cout << "Capacity: " << str.capacity() << std::endl; // 輸出:Capacity: 1000
注意事項
reserve
不會改變字符串的內容,只是改變其容量。- 如果
reserve
的參數小于當前capacity
,std::string
的容量不會減少。 reserve
是一個非強制性操作,具體行為可能因標準庫的實現而異。
三、shrink_to_fit
:收縮內存
shrink_to_fit
函數用于收縮std::string
的容量,使其盡可能接近實際的size
。這可以減少不必要的內存占用,但需要注意的是,shrink_to_fit
是一個非強制性操作,具體行為可能因標準庫的實現而異。
使用場景
當你完成了一個字符串的頻繁修改操作后,可以使用shrink_to_fit
來釋放多余的內存。例如,在字符串拼接完成后,調用shrink_to_fit
可以優化內存使用。
示例代碼
std::string str = "Hello";
str += "World";
str.shrink_to_fit();
std::cout << "Size: " << str.size() << std::endl; // 輸出:Size: 10
std::cout << "Capacity: " << str.capacity() << std::endl; // 輸出:Capacity: 10(具體值可能因實現而異)
注意事項
shrink_to_fit
不會改變字符串的內容,只是嘗試減少其容量。shrink_to_fit
是一個非強制性操作,可能不會立即生效。
四、resize
:調整字符串大小
resize
函數用于調整字符串的大小。如果新的大小大于當前size
,則會用指定的字符填充新分配的部分;如果新的大小小于當前size
,則會截斷字符串。
示例代碼
std::string str = "Hello, World!";
str.resize(5); // 截斷字符串
std::cout << "Resized string: " << str << std::endl; // 輸出:Hellostr.resize(10, 'x'); // 擴展字符串并用'x'填充
std::cout << "Resized string: " << str << std::endl; // 輸出:Helloxxxxx
注意事項
resize
會改變字符串的內容,而reserve
和shrink_to_fit
不會。resize
的第二個參數是可選的,默認填充字符為空字符'\0'
。
五、容量操作的性能優化
合理使用std::string
的容量操作可以顯著提高程序的性能。以下是一些優化建議:
1. 預留足夠的內存
如果你知道字符串將要存儲大量字符,使用reserve
預先分配足夠的內存可以減少內存分配的次數。
2. 及時收縮內存
在完成字符串的頻繁修改操作后,使用shrink_to_fit
可以釋放多余的內存,優化內存使用。
3. 避免不必要的拷貝
std::string
的拷貝構造和賦值操作可能會導致不必要的內存分配和拷貝。如果可能,盡量使用引用或std::move
來避免拷貝。
五.string類對象的修改操作
一、std::string
的修改操作概述
std::string
提供了多種方法來修改字符串的內容,包括插入、刪除、替換、直接修改字符等。這些操作使得字符串的編輯變得非常靈活,同時也避免了C語言中直接操作字符數組時可能出現的內存錯誤。
二、直接修改字符
std::string
支持通過下標操作符[]
或at
函數直接修改字符串中的字符。這兩種方式的主要區別在于,[]
操作符不進行邊界檢查,而at
函數會進行邊界檢查并拋出異常。
示例代碼
std::string str = "Hello, World!";
str[0] = 'h'; // 將第一個字符修改為小寫的'h'
str.at(7) = 'w'; // 將第8個字符(索引為7)修改為小寫的'w'
std::cout << str << std::endl; // 輸出:hello, world!
注意事項
- 使用
[]
操作符時,如果索引超出字符串范圍,行為是未定義的。 - 使用
at
函數時,如果索引超出范圍,會拋出std::out_of_range
異常。
三、插入操作
std::string
提供了多種插入操作,允許你在字符串的任意位置插入字符、字符串或字符數組。
1. 插入單個字符
std::string str = "Hello, World!";
str.insert(5, "X"); // 在索引5的位置插入字符'X'
std::cout << str << std::endl; // 輸出:HelloX, World!
2. 插入字符串
std::string str = "Hello, World!";
str.insert(7, "C++"); // 在索引7的位置插入字符串"C++"
std::cout << str << std::endl; // 輸出:Hello, C++World!
3. 插入字符數組
std::string str = "Hello, World!";
char arr[] = "Python";
str.insert(7, arr); // 在索引7的位置插入字符數組"Python"
std::cout << str << std::endl; // 輸出:Hello, PythonWorld!
注意事項
- 插入操作會改變字符串的
size
和capacity
。 - 如果插入位置超出字符串范圍,行為是未定義的。
四、刪除操作
std::string
提供了erase
函數,用于刪除字符串中的一部分內容。
示例代碼
std::string str = "Hello, World!";
str.erase(7, 5); // 從索引7開始刪除5個字符
std::cout << str << std::endl; // 輸出:Hello, !
參數說明
- 第一個參數是刪除的起始位置(索引)。
- 第二個參數是刪除的字符數。
注意事項
- 如果刪除的起始位置超出字符串范圍,行為是未定義的。
- 刪除操作會改變字符串的
size
,但不會改變capacity
。
五、替換操作
std::string
提供了replace
函數,用于替換字符串中的一部分內容。
示例代碼
std::string str = "Hello, World!";
str.replace(7, 5, "C++"); // 從索引7開始,替換5個字符為"C++"
std::cout << str << std::endl; // 輸出:Hello, C++!
參數說明
- 第一個參數是替換的起始位置(索引)。
- 第二個參數是替換的字符數。
- 第三個參數是新的內容。
注意事項
- 替換操作會改變字符串的
size
,但不會改變capacity
。 - 如果替換的起始位置超出字符串范圍,行為是未定義的。
六、追加操作
std::string
提供了多種追加操作,允許你在字符串的末尾添加字符、字符串或字符數組。
1. 追加單個字符
std::string str = "Hello";
str.push_back(' '); // 追加一個空格
str += 'W'; // 追加字符'W'
std::cout << str << std::endl; // 輸出:Hello W
2. 追加字符串
std::string str = "Hello ";
str += "World"; // 追加字符串"World"
std::cout << str << std::endl; // 輸出:Hello World
3. 追加字符數組
std::string str = "Hello ";
char arr[] = "C++";
str.append(arr); // 追加字符數組"C++"
std::cout << str << std::endl; // 輸出:Hello C++
注意事項
- 追加操作會改變字符串的
size
,但不會改變capacity
。 - 如果
capacity
不足,std::string
會自動分配更大的內存。
七、清空字符串
std::string
提供了clear
函數,用于清空字符串的內容,但不會釋放內存。
示例代碼
std::string str = "Hello, World!";
str.clear();
std::cout << "Size: " << str.size() << std::endl; // 輸出:Size: 0
std::cout << "Capacity: " << str.capacity() << std::endl; // 輸出:Capacity: 15(具體值可能因實現而異)
注意事項
clear
函數只會清空字符串的內容,不會釋放內存。- 如果需要釋放內存,可以結合
shrink_to_fit
使用。
八、使用std::stringstream
進行復雜修改
對于復雜的字符串修改操作,可以使用std::stringstream
。std::stringstream
是一個非常靈活的工具,可以方便地進行字符串的拼接、格式化和提取。
示例代碼
#include <sstream>std::string str = "Hello, World!";
std::stringstream ss(str);
std::string word;
ss >> word; // 提取第一個單詞
ss << "C++"; // 替換為"C++"
ss >> word; // 提取第二個單詞
ss << "Programming"; // 替換為"Programming"
str = ss.str(); // 將修改后的內容賦值回str
std::cout << str << std::endl; // 輸出:Hello, C++Programming
六.string類非成員函數
一、什么是std::string
的非成員函數?
std::string
的非成員函數是指那些不屬于std::string
類的成員函數,但專門用于操作std::string
對象的函數。這些函數通常定義在<string>
頭文件中,或者通過標準庫的其他部分提供。非成員函數的優勢在于它們可以提供更通用的操作方式,同時避免了對std::string
類本身的過度擴展。
二、常見的std::string
非成員函數
1. std::swap
std::swap
用于交換兩個std::string
對象的內容。它是一個非成員函數,可以高效地交換兩個字符串的內容,而不需要逐個字符復制。
示例代碼
#include <iostream>
#include <string>
#include <algorithm> // 包含std::swapint main() {std::string str1 = "Hello";std::string str2 = "World";std::swap(str1, str2);std::cout << "str1: " << str1 << std::endl; // 輸出:str1: Worldstd::cout << "str2: " << str2 << std::endl; // 輸出:str2: Hello
}
2. std::to_string
std::to_string
是一個非常有用的非成員函數,用于將數值類型(如int
、float
、double
等)轉換為std::string
。它提供了一種簡單且類型安全的方式來實現數值與字符串之間的轉換。
示例代碼
#include <iostream>
#include <string>int main() {int num = 42;double pi = 3.14159;std::string numStr = std::to_string(num);std::string piStr = std::to_string(pi);std::cout << "Number as string: " << numStr << std::endl; // 輸出:Number as string: 42std::cout << "Pi as string: " << piStr << std::endl; // 輸出:Pi as string: 3.141590
}
3. std::stoi
、std::stod
、std::stof
等
這些函數用于將std::string
對象轉換為數值類型。std::stoi
將字符串轉換為int
,std::stod
將字符串轉換為double
,std::stof
將字符串轉換為float
等。這些函數提供了一種簡單且安全的方式來解析字符串中的數值。
示例代碼
#include <iostream>
#include <string>int main() {std::string numStr = "42";std::string piStr = "3.14159";int num = std::stoi(numStr);double pi = std::stod(piStr);std::cout << "Number from string: " << num << std::endl; // 輸出:Number from string: 42std::cout << "Pi from string: " << pi << std::endl; // 輸出:Pi from string: 3.14159
}
4. std::getline
std::getline
是一個非成員函數,用于從輸入流(如std::cin
或std::ifstream
)中讀取一行內容并存儲到std::string
對象中。它支持按分隔符讀取,例如按逗號、空格等分隔。
示例代碼
#include <iostream>
#include <string>
#include <sstream>int main() {std::string line = "Hello, World!";std::istringstream ss(line);std::string word;while (std::getline(ss, word, ',')) {std::cout << word << std::endl; // 輸出:Hello 和 World!}
}
5. std::operator<<
和 std::operator>>
這些操作符重載允許你直接使用std::cin
和std::cout
來輸入和輸出std::string
對象。它們是C++標準庫提供的非成員函數,使得字符串的輸入輸出變得非常方便。
示例代碼
#include <iostream>
#include <string>int main() {std::string str;std::cout << "Enter a string: ";std::cin >> str;std::cout << "You entered: " << str << std::endl;
}
6. std::operator+
和 std::operator+=
雖然這些操作符是std::string
的成員函數,但它們也可以作為非成員函數使用。std::operator+
用于拼接兩個字符串,而std::operator+=
用于將一個字符串追加到另一個字符串的末尾。這些操作符使得字符串拼接變得非常直觀。
示例代碼
#include <iostream>
#include <string>int main() {std::string str1 = "Hello";std::string str2 = "World";std::string result = str1 + " " + str2; // 使用std::operator+str1 += " "; // 使用std::operator+=str1 += str2;std::cout << "Result: " << result << std::endl; // 輸出:Result: Hello Worldstd::cout << "Modified str1: " << str1 << std::endl; // 輸出:Modified str1: Hello World
}
7. std::operator==
、std::operator!=
、std::operator<
等
這些操作符重載允許你直接比較兩個std::string
對象。它們按照字典序進行比較,使得字符串的比較變得非常方便。
示例代碼
#include <iostream>
#include <string>int main() {std::string str1 = "Hello";std::string str2 = "World";if (str1 == str2) {std::cout << "Strings are equal." << std::endl;} else {std::cout << "Strings are not equal." << std::endl; // 輸出:Strings are not equal.}if (str1 < str2) {std::cout << "str1 is less than str2." << std::endl; // 輸出:str1 is less than str2.}
}
七、總結
std::string
是 C++ STL 中一個非常強大且靈活的工具,它提供了豐富的功能來處理字符串,同時避免了許多傳統字符串操作的常見問題。通過掌握 std::string
的構造、操作、性能優化以及高級用法,你可以更高效地編寫字符串處理相關的代碼。在實際開發中,合理使用 std::string
能夠大大提高代碼的可讀性和安全性。