C++ std::string 用法與完整範例

本篇 ShengYu 介紹 C++ std::string 用法與範例,C++ string 是一個存放 char 的序列容器,相較於 C-Style 字串可以自由地相加字串,std::string 會負責管理記憶體的工作,大幅減輕開發者的字串操作負擔。C++ std::string 字串操作是必須要學會的基本功,我把 C++ 常用到的 std::string 用法與範例彙整在這邊,並提供完整的 std::string C++ 範例程式碼。

以下 C++ string 內容將分為這幾部份,

  • C++ string 常用功能
  • C++ string 字串初始化
  • C++ string 字串比對 / 字串比較
  • C++ string 取得子字串
  • C++ string 字串搜尋 / 字串尋找
  • C++ string 字串相加
  • C++ string 取得長度大小
  • for 迴圈尋訪 string 容器
  • 清空 string 容器
  • 判斷 string 容器是否為空
  • C++ string size() 與 capacity() 的差異
  • C++ string reserve() 預先配置容器大小的用法
  • C++ string resize() 的用法

C++ 要使用 string 容器的話,需要引入的標頭檔<string>

C++ string 常用功能

以下是 C++ std::string 內常用的成員函式,
operator=:指定字串
operator+=:添加字串
operator+:字串相加
operator==:比較兩個字串的內容是否相同
operator[]:存取索引值[i]的字元,跟陣列一樣索引值從 0 開始
at(i):存取索引值[i]的字元,跟上面 operator[] 差異是 at(i) 會作邊界檢查,存取越界會拋出一個例外
find():字串搜尋
substr():取得子字串
empty():回傳是否為空,空則回傳true
size():回傳目前長度
length():回傳目前長度

C++ string 字串初始化

C++ std::string 以下有四種常見的字串初始化方式,建構 string 一開始沒有指定初始字串的話會是一個空字串,std::string 建構子可以帶入 C-Style 字串來初始化 std::string,或者 std::string 建構子可以帶入另一個 std::string 來初始化,另外也可以在宣告 std::string 變數同時用 = 來指定初始字串,如下範例所示,

std-string.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// g++ std-string.cpp -o a.out
#include <iostream>
#include <string>

int main() {
std::string str1; // 初始化為空字串
std::string str2("abc"); // 從 C-Style 字串來初始化 std::string
std::string str3(str2); // 從另一個 std::string 來初始化
std::string str4 = "def";

std::cout << "str1: " << str1 << '\n';
std::cout << "str2: " << str2 << '\n';
std::cout << "str3: " << str3 << '\n';
std::cout << "str4: " << str4 << '\n';
return 0;
}

結果輸出如下,

1
2
3
4
str1: 
str2: abc
str3: abc
str4: def

以下是 C-Style 字串來初始化 std::string 的幾種用法,

std-string2.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// g++ std-string2.cpp -o a.out
#include <iostream>
#include <string>

int main() {
const char *p = "abcde";
std::string str1(p, 3);
std::string str2(p, 5);
std::string str3(p);
std::cout << "str1: " << str1 << '\n';
std::cout << "str2: " << str2 << '\n';
std::cout << "str3: " << str3 << '\n';

char arr[] = "ABCDE";
std::string str4(arr);
std::cout << "str4: " << str4 << '\n';
return 0;
}

結果輸出如下,

1
2
3
4
str1: abc
str2: abcde
str3: abcde
str4: ABCDE

以下是 std::string 預先初始化連續同樣字元的用法,

std-string3.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// g++ std-string3.cpp -o a.out
#include <iostream>
#include <string>

int main() {
std::string str1(5, 0); // 初始化 5 個 0
std::string str2(5, '\0'); // 初始化 5 個 '\0' 字元
std::string str3(10, 'A'); // 初始化 10 個 A 字元
std::string str4(10, 65); // 初始化 10 個 65

std::cout << "str1: " << str1 << '\n';
std::cout << "str2: " << str2 << '\n';
std::cout << "str3: " << str3 << '\n';
std::cout << "str4: " << str4 << '\n';
return 0;
}

結果輸出如下,

1
2
3
4
str1: 
str2:
str3: AAAAAAAAAA
str4: AAAAAAAAAA

C++ string 字串比對 / 字串比較

以下介紹 C++ string 字串比較的方式,直接使用 operator== 的話是比較直覺且簡單的方式,除了用 operator== 的方式以外,還可以用 std::string::compare() 來做字串比較,

std-string4.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// g++ std-string4.cpp -o a.out
#include <iostream>
#include <string>

int main() {
std::string str1 = "hello";
std::string str2 = "world";
if (str1 == str2) {
std::cout << "equal\n";
} else {
std::cout << "not equal\n";
}

if (str1 == "hello") {
std::cout << "equal\n";
} else {
std::cout << "not equal\n";
}

if (str1.compare(str2) == 0) {
std::cout << "equal\n";
} else {
std::cout << "not equal\n";
}

if (str1.compare("hello") == 0) {
std::cout << "equal\n";
} else {
std::cout << "not equal\n";
}
return 0;
}

結果輸出如下,

1
2
3
4
not equal
equal
not equal
equal

C++ string 取得子字串

C++ 使用 std::string::substr() 來取得子字串,substr 第一個參數為起始位置,從0開始,第二個參數為長度,不帶入第二個參數的話會一直到結尾,另外實務上也常會用 std::string::find() 搜尋目標字串的起始位置後再搭配 std::string::substr() 來取得子字串,如下範例,

std-string5.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// g++ std-string5.cpp -o a.out
#include <iostream>
#include <string>

int main() {
std::string str = "hello world !!";
std::cout << str.substr(6, 5) << '\n';
std::cout << str.substr(6) << '\n';

std::size_t pos = str.find("world");
std::cout << pos << '\n';
std::cout << str.substr(pos) << '\n';
return 0;
}

結果輸出如下,

1
2
3
4
world
world !!
6
world !!

C++ string 字串搜尋 / 字串尋找

C++ 使用 std::string::find() 來字串搜尋,std::string::find() 如果有搜尋到目標字串的話會回傳起始位置,沒搜尋到的話會回傳 std::string::npos,另外 std::string::find() 回傳的起始位置可以搭配 std::string::substr() 來取得子字串,如下範例,

std-string6.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// g++ std-string6.cpp -o a.out
#include <iostream>
#include <string>

int main() {
std::string str = "hello world !!";
std::size_t pos1 = str.find("hello");
std::size_t pos2 = str.find("lo");
std::size_t pos3 = str.find("world");
std::cout << pos1 << '\n';
std::cout << pos2 << '\n';
std::cout << pos3 << '\n';
std::cout << str.substr(pos3) << '\n';

std::size_t pos4 = str.find("abc");
if (found != std::string::npos) {
std::cout << "found at " << found << "\n";
} else {
std::cout << "abc not found\n";
}
return 0;
}

結果輸出如下,

1
2
3
4
5
0
3
6
world !!
abc not found

想要瞭解 std::string::find() 的詳細用法可以參考這篇

C++ string 字串相加

字串相加在 C 裡是用 strcat,這邊示範一下 C++ std::string 的字串相加用法,std::string 用 operator+ 不但可以跟 std::string 相加以外,也可以跟 C-Style 字串相加,如下範例,

std-string7.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// g++ std-string7.cpp -o a.out
#include <iostream>
#include <string>

int main() {
char str[] = "wrold";
std::string str2 = "hello ";
str2 = str2 + str; // 跟 C-Style 字串相加
std::cout << str2 << '\n';

std::string str3 = " !!";
str3 = str2 + str3; // 跟 std::string 字串相加
str3 = str3 + " this is " + "c++ string " + "example";
std::cout << str3 << '\n';
return 0;
}

結果輸出如下,

1
2
hello wrold
hello wrold !! this is c++ string example

除了用 operator+= 來添加字串以外,還可以用 std::string::append() 來做字串添加,如下範例,

std-string8.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// g++ std-string8.cpp -o a.out
#include <iostream>
#include <string>

int main() {
std::string str = "hello ";
std::string str2 = "wrold";
str += str2;
std::cout << str << '\n';

str += " !";
std::cout << str << '\n';

str.append(" this is c++ string example");
std::cout << str << '\n';
return 0;
}

結果輸出如下,

1
2
3
hello wrold
hello wrold !
hello wrold ! this is c++ string example

C++ string 取得長度大小

這邊介紹 C++ string 取得長度大小,可以使用 std::string::length() 來取得長度,也可以使用 std::string::size() 來取得大小,兩者內部實作其實都是一樣的,都可以達成同樣的目的,如下範例,

std-string9.cpp
1
2
3
4
5
6
7
8
9
10
// g++ std-string9.cpp -o a.out
#include <iostream>
#include <string>

int main() {
std::string str = "hello";
std::cout << "size: " << str.size() << '\n';
std::cout << "length: " << str.length() << '\n';
return 0;
}

結果輸出如下,

1
2
size: 5
length: 5

for 迴圈尋訪 string 容器

以下介紹 for 迴圈尋訪 string 容器的使用範例,使用 operator[] 來存取索引值[i]的字元,就跟 C-Style 字元陣列的操作一樣,

std-string10.cpp
1
2
3
4
5
6
7
8
9
10
11
// g++ std-string10.cpp -o a.out
#include <iostream>
#include <string>

int main() {
std::string str = "hello";
for (int i = 0; i < str.length(); i++) {
std::cout << str[i] << '\n';
}
return 0;
}

結果輸出如下,

1
2
3
4
5
h
e
l
l
o

如果是要使用 range-based for loop 寫法的話,因為 range-based for loop 是 C++11 中增加的新特性,所以編譯時要加上 C++11 的編譯選項,使用範例如下,

std-string11.cpp
1
2
3
4
5
6
7
8
9
10
11
// g++ std-string11.cpp -o a.out -std=c++11
#include <iostream>
#include <string>

int main() {
std::string str = "world";
for (auto &c : str) {
std::cout << c << '\n';
}
return 0;
}

結果輸出如下,

1
2
3
4
5
h
e
l
l
o

清空 string 容器

這邊介紹 C++ 清空 string 容器的用法,要清空 string 的話可以使用 std::string::clear() 或者賦值空字串,如下範例,

std-string12.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// g++ std-string12.cpp -o a.out
#include <iostream>
#include <string>

int main() {
std::string str = "hello";
std::cout << "str: " << str << '\n';
str.clear();
std::cout << "str: " << str << '\n';

std::string str2 = "world";
std::cout << "str2: " << str2 << '\n';
str2 = "";
std::cout << "str2: " << str2 << '\n';
return 0;
}

結果輸出如下,

1
2
3
4
str: hello
str:
str2: world
str2:

判斷 string 容器是否為空

這邊介紹 C++ 如何判斷 string 容器是否為空,要判斷是否為空的話可以使用 std::string::empty() 來作判斷,如果為空字串的話則回傳 ture,反之回傳 false,如下範例,

std-string13.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// g++ std-string13.cpp -o a.out
#include <iostream>
#include <string>

int main() {
std::string str1;
std::string str2 = "";
std::string str3 = "wrold";

if (str1.empty()) {
std::cout << "empty\n";
} else {
std::cout << "not empty\n";
}
if (str2.empty()) {
std::cout << "empty\n";
} else {
std::cout << "not empty\n";
}
if (str3.empty()) {
std::cout << "empty\n";
} else {
std::cout << "not empty\n";
}
return 0;
}

結果輸出如下,

1
2
3
empty
empty
not empty

C++ string size() 與 capacity() 的差異

string 使用 size() 是取得目前 string 裡的元素個數,而 string 使用 capacity() 是取得目前 string 裡的預先配置的空間大小,當容量(capacity)空間不夠使用時 string 就會重新申請空間,容量(capacity)會增加為原來的容量約 2 倍,各個編譯器可能不同,來看看下面範例,

std-string14.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// g++ std-string14.cpp -o a.out
#include <iostream>
#include <string>

using namespace std;

int main() {
std::string s;
cout << "size=" << s.size() << ", capacity=" << s.capacity() << "\n";
s += "abcdefghij";
cout << "size=" << s.size() << ", capacity=" << s.capacity() << "\n";
s += "abcdefghij";
cout << "size=" << s.size() << ", capacity=" << s.capacity() << "\n";
s += "abcdefghij";
cout << "size=" << s.size() << ", capacity=" << s.capacity() << "\n";
s += "abcdefghij";
cout << "size=" << s.size() << ", capacity=" << s.capacity() << "\n";
s += "abcdefghij";
cout << "size=" << s.size() << ", capacity=" << s.capacity() << "\n";
s += "abcdefghij";
s += "abcdefghij";
s += "abcdefghij";
s += "abcdefghij";
s += "abcdefghij";
cout << "size=" << s.size() << ", capacity=" << s.capacity() << "\n";

return 0;
}

輸出結果如下,從以下的輸出可以發現在我使用的 clang 編譯器中 capacity 是以這樣的方式增長下去,

1
2
3
4
5
6
7
size=0, capacity=22
size=10, capacity=22
size=20, capacity=22
size=30, capacity=47
size=40, capacity=47
size=50, capacity=95
size=100, capacity=191

C++ string reserve() 預先配置容器大小的用法

string 使用 reserve() 是預留空間的意思,如果我們一開始就知道容器的裡要放置多少個元素的話,可以透過 reserve() 來預先配置容器大小,這樣可以減少一直配置記憶體的機會。

如下例所示,先宣告一個 string,假設我想要預先配置好 10 個大小的話可以這樣寫 string.reserve(10),這樣會預留大於或等於 10 個元素的空間,使用 capacity() 會得到 22,但裡面還沒有任何元素所以使用 size() 會得到 0,之後用 operator+= 將元素新增進去,然後我們來觀察看看 size 與 capacity 的變化,

之後將 string 新增 5 個字元進去,再次使用 capacity() 還是 22,而使用 size() 會得到 20,

1
2
3
4
5
6
string s;
cout << "size=" << s.size() << ", capacity=" << s.capacity() << "\n";
s.reserve(10);
cout << "size=" << s.size() << ", capacity=" << s.capacity() << "\n";
s += "AAAAA";
cout << "size=" << s.size() << ", capacity=" << s.capacity() << "\n";

輸出如下,

1
2
3
size=0, capacity=22
size=0, capacity=22
size=5, capacity=22

那 string reserve 預留 22 個元素的空間後,之後使用超過 22 個元素 capacity 會發生什麼變化呢?

1
2
3
4
5
6
7
8
9
10
11
string s;
s.reserve(22);
s += "AAAAAAAAAA";
cout << "size=" << s.size() << ", capacity=" << s.capacity() << "\n";
s += "AAAAAAAAAA";
s += "AAAAAAAAAA";
s += "AAAAAAAAAA";
s += "AAAAAAA";
cout << "size=" << s.size() << ", capacity=" << s.capacity() << "\n";
s += "A";
cout << "size=" << s.size() << ", capacity=" << s.capacity() << "\n";

輸出如下,可以發現當 string 的元素超過預留的 22 個元素時,會將容量增長為原本 capacity 的約兩倍,

1
2
3
size=10, capacity=22
size=47, capacity=47
size=48, capacity=95

在 string 建構子帶入數量 n 會初始化 n 個元素且預設初始值為 'A' 字元(或者其他字元或其他數字,例如:0),所以使用 size() 會回傳 n,跟上述的 reserve() 用途是不一樣的,詳見下列範例,

1
2
3
4
5
6
7
8
9
10
11
string s(2, 'A');
cout << "size=" << s.size() << ", capacity=" << s.capacity() << "\n";
s += 'B'; // AAB
s += 'C'; // AABC
s += 'D'; // AABCD
cout << "size=" << s.size() << ", capacity=" << s.capacity() << "\n";
cout << s << "\n";
for (int i = 0; i < s.size(); i++) {
cout << (int)s[i] << " ";
}
cout << "\n";

輸出如下,一開始在 string 建構子帶入的數量 2 跟 'A' 字元會初始化 2 個 'A' 字元,

1
2
3
4
size=2, capacity=22
size=5, capacity=22
AABCD
65 65 66 67 68

C++ string resize() 的用法

C++ string 使用 resize 跟 reserve 不太一樣,resize 變大時會把多的元素補 0,例如:

1
2
3
4
5
6
7
8
string s;
s.resize(5);
cout << "size=" << s.size() << ", capacity=" << s.capacity() << "\n";
cout << s << "\n";
for (int i = 0; i < s.size(); i++) {
cout << (int)s[i] << " ";
}
cout << "\n";

輸出如下,印出來的元素都是 0,

1
2
3
size=5, capacity=22

0 0 0 0 0

resize 如果要順便指定元素初始值的話,可以將初始值帶入 resize() 的第二個引數,像這樣寫,

1
2
3
4
5
6
7
8
string s;
s.resize(5, 'A');
cout << "size=" << s.size() << ", capacity=" << s.capacity() << "\n";
cout << s << "\n";
for (int i = 0; i < s.size(); i++) {
cout << (int)s[i] << " ";
}
cout << "\n";

輸出如下,這些新增的元素初始值都設成 'A' 字元也就是 65,

1
2
3
size=5, capacity=22
AAAAA
65 65 65 65 65

如果 resize 的大小超過 capacity 容量大小會怎麼樣呢?

1
2
3
4
5
6
7
8
9
string s = "AAAAAAAAAABBBBBBBBBBCC";
cout << "size=" << s.size() << ", capacity=" << s.capacity() << "\n";
s.resize(30);
cout << "size=" << s.size() << ", capacity=" << s.capacity() << "\n";
cout << s << "\n";
for (int i = 0; i < s.size(); i++) {
cout << (int)s[i] << " ";
}
cout << "\n";

輸出如下,原本的 AAAAAAAAAABBBBBBBBBBCC 元素有保留以外,剩下新增的元素補 0,

1
2
3
4
size=22, capacity=22
size=30, capacity=47
AAAAAAAAAABBBBBBBBBBCC
65 65 65 65 65 65 65 65 65 65 66 66 66 66 66 66 66 66 66 66 67 67 0 0 0 0 0 0 0 0

以上就是 C++ std::string 用法與範例的介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其他參考
string - C++ Reference
https://www.cplusplus.com/reference/string/string/
std::basic_string - cppreference.com
https://en.cppreference.com/w/cpp/string/basic_string

其它相關文章推薦
如果你想學習 C++ 相關技術,可以參考看看下面的文章,
C/C++ 新手入門教學懶人包
std::string::find 搜尋字串
std::vector 用法與範例
std::sort 用法與範例