C++ STL中容器string超詳細(xì)講解
前言:在學(xué)習(xí)string之前,我們得先了解STL容器,什么是STL容器呢?
STL(standard template libaray-標(biāo)準(zhǔn)模板庫):是C++標(biāo)準(zhǔn)庫的重要組成部分,不僅是一個可復(fù)用的 組件庫,而且是一個包羅數(shù)據(jù)結(jié)構(gòu)與算法的軟件框架。
下圖是STL的六大組件,后面會一一的了解容器,算法,仿函數(shù),迭代器等等

那么C++的STL庫的作用是什么?這就不得不說沒學(xué)C++之前都是使用的C語言刷題,寫一道題需要大量的代碼,而C++提供STL庫,我們可以使用里面的算法,它都幫我實(shí)現(xiàn)好了,比如兩個隊(duì)列模擬實(shí)現(xiàn)棧,C語言需要手動創(chuàng)建隊(duì)列的結(jié)構(gòu),而利用STL直接套用就行。
好了話不多說,我們直接開始學(xué)習(xí)第一個容器string?。。?/p>
1. 標(biāo)準(zhǔn)庫中的string
1.1 auto和范圍for
auto:
在早期C/C++中auto的含義是:使用auto修飾的變量,是具有自動存儲器的局部變量,后來這個不重要了。C++11中,標(biāo)準(zhǔn)委員會變廢為寶賦予了auto全新的含義即:auto不再是一個存儲類型指示符,而是作為一個新的類型指示符來指示編譯器,auto聲明的變量必須由編譯器在編譯時期推導(dǎo)而得。
什么意思呢?就跟類模板推導(dǎo)參數(shù)類型類似。
#include<iostream>
#include<string>
using namespace std;
int func1()
{
return 10;
}
auto func2()
{
return 100;
}
void func3(auto x) //error: 不允許使用auto做參數(shù)
{
}
int main()
{
auto a = 10; //這里的auto=int
auto* ra = &a; //auto=int
auto rra = &a; //auto=int*
auto b=3.14; //auto=char
auto& rb=b;
int ma = 10, mb = 30, mc = 90;
auto md = 100, me = 200;
auto ch = 'a', z = 10;//error,auto只對ch推導(dǎo)
return 0;
}1. auto聲明指針類型時:用auto和auto*沒有區(qū)別;但是在聲明引用類型時,必須加&(即auto&);
2. 當(dāng)在同一行聲明多個變量時,這些變量必須是相同的類型,否則編譯器將會報(bào)錯,因?yàn)榫幾g器實(shí)際只對第一個類型進(jìn)行推導(dǎo),然后用推導(dǎo)出來的類型定義其他變量;
3. auto不能作為函數(shù)的參數(shù),可以做返回值,但是建議謹(jǐn)慎使用;
4. auto不能直接用來聲明數(shù)組。
這里可能覺得使用auto沒什么用,但是到了后面的容器就會覺得太安逸了。
范圍for:
for循環(huán)后的括號由冒號“ :”分為兩部分:第一部分是范圍 內(nèi)用于迭代的變量,第二部分則表示被迭代的范圍,自動迭代(自動++),自動取數(shù)據(jù),自動判斷結(jié)束。(即arr數(shù)組中取得值賦值給ch,ch自動++,自動判斷結(jié)束)
相對于for循環(huán),三個自動勝過一切。常用于數(shù)組和對象的遍歷。那范圍for是如何實(shí)現(xiàn)的?這就得去理解它的底層迭代器,至于什么是迭代器,模擬實(shí)現(xiàn)得時候會初步講解,現(xiàn)在只需要理解如何使用!
void test01()
{
int arr[10] = { 1,2,3,4,5 };
for (auto& e : arr)
{
cout << e << " ";
}
cout << endl;
char s[] = { "hello,world" };
for (auto& ch : s)
{
cout << ch;
}
cout << endl;
string str("hello world");
for (auto ch : str)
{
cout << ch << " ";
}
cout << endl;
}
int main()
{
test01();
return 0;
}這里建議使用引用,這里是普通數(shù)組還好,如果是對象呢?那每次取值得時候就得調(diào)用拷貝構(gòu)造!
2. string常用接口說明
2.1 string類的常見構(gòu)造
https://legacy.cplusplus.com/reference/string/string/?kw=string(官網(wǎng)關(guān)于string的介紹)

這里來說一些構(gòu)造非常常用的接口:
| 函數(shù)名 | 功能說明 |
| string() | 默認(rèn)構(gòu)造,構(gòu)造空字符串 |
| string(const char* s) | 用字符串構(gòu)造string類型字符串(string不含\0) |
| string(size_t n, char c) | 構(gòu)造由n個字符c構(gòu)成的字符串 |
| string(const string&s) | 拷貝構(gòu)造,用string對象構(gòu)造另一個string對象 |
| ~string() | 析構(gòu)函數(shù):淺拷貝(自動生成的足夠)/深拷貝(需要手動實(shí)現(xiàn)) |
void test02()
{
string s1;
cout << s1 << endl;
string s2("A ship in harbor is safe, but that's not what ships are built for");
cout << s2 << endl;
string s3("hello world");
cout << s3 << endl;
string s4(10, 'x');
cout << s4 << endl;
string s5(s2);
cout << s5 << endl;
}2.2 string類的插入
(1)尾插:末尾插入數(shù)據(jù)
| void push_back(char); |
void test03()
{
string s1("hello world");
s1.push_back(' ');
s1.push_back('x');
s1.push_back('i');
s1.push_back('a');
s1.push_back('o');
s1.push_back('l');
s1.push_back('i');
cout << s1 << endl;
s1.pop_back();
cout << s1 << endl;
}(2)使用insert在指定位置插入數(shù)據(jù)
| string& insert (size_t pos, size_t n, char c); //在pos位置插入n個字符c |
| string& insert (size_t pos, const char* s); //在pos位置插入字符串 |
| string& insert (size_t pos, const string& str); //在pos位置插入string |
void test05()
{
string s1("hello,xiaoli");
//頭插
s1.insert(0, 3, 'x');
s1.insert(0, "excuse");
//中間插入
string s2("hi");
s2.insert(1,3,'z');
s2.insert(2, "hello");
//尾插
string s3("today");
s3.insert(4, s2);
}2.3 string類的刪除
(1)尾刪:尾部刪除數(shù)據(jù)
| void pop_back(); |
void test06()
{
string s1("hello,xiaoli");
s1.pop_back();
s1.pop_back();
s1.pop_back();
cout << s1 << endl;
}(2)erase:任意位置的刪除
| string& erase (size_t pos = 0, size_t len = npos); |
| iterator erase (iterator first, iterator last); //迭代器版本的刪除指定范圍數(shù)據(jù) |
void test07()
{
string s1("hello,xiaoli");
s1.erase(0, 2);
s1.erase(5, 3);
string s2("hello,tomorror");
string::iterator it = s2.begin();//迭代器
s2.erase(it + 3, it + 5);
}2.4 string類的拼接
(1)append:在字符末尾拼接字符/字符串
| string& append (const string& str); |
| string& append (const char* s); |
| string& append (size_t n, char c); |
void test08()
{
string s1("hello,xiaoli");
s1.append(3, 'x');
string s2("hello,tomorror");
s2.append(" today");
s2.append(s1);
}2.5 string類的替換
(1)assign:為字符串分配一個新值,替換其當(dāng)前內(nèi)容。
| string& assign (size_t n, char c); |
| string& assign (const char* s); |
| string& assign (const string& str); |
void test09()
{
string s1("hello,xiaoli");
s1.assign("excuse me");
cout << s1 << endl;
string s2("hello,tomorror");
s2.assign(s1);
cout << s2 << endl;
}(2)replace:將字符串中以字符pos開頭并跨len字符的部分(或字符串中介于[i1,i2) 之間的部分替換為新內(nèi)容
| string& replace (size_t pos, size_t len, const string& str); |
| string& replace (size_t pos, size_t len, const char* s); |
| string& replace (size_t pos, size_t len, size_t n, char c); |
這里每一個都有對應(yīng)的迭代器版本!
//replace
void test10()
{
string s1("hello,xiaoli");
s1.replace(2, 3, 5,'x');//從下標(biāo)為2的位置開始長度為3個字符替換成5個x
cout << s1 << endl; ////hexxxxx,xiaoli
string s2("hello,tomorror");
s2.replace(3, 5, "excuse"); //helexcusemorror
cout << s2 << endl;
}可能有點(diǎn)懵,就是我只是保證從pos開始跨len個字符的部分內(nèi)容修改,其余內(nèi)容不變。這len個字符替換成給的內(nèi)容。就比如s1,我只保證llo內(nèi)容改變,llo替換成xxxxx,其余不動。
2.6 string類的查找
(1)find:查找字符串中的內(nèi)容(如果指定pos,就從pos位置開始查找,僅匹配其中一個字符是不夠的,而是整個序列必須匹配;如果匹配返回匹配的第一個位置的下標(biāo),否則返回npos)
| size_t find (char c, size_t pos = 0) const; |
| size_t find (const char* s, size_t pos = 0) const; |
| size_t find (const string& str, size_t pos = 0) const; |
//find
void test11()
{
string s1("hello,xiaoli");
cout<<s1.find("llo")<<endl; //從下標(biāo)為0開始找,返回2
cout << s1.find("he",6)<< endl; //從下標(biāo)為6開始找,返回18446744073709551615
string s2("hello,tomorror");
cout << s2.find(s1, 3) << endl; //返回18446744073709551615
}(2)rfind:從后往前開始匹配
| size_t rfind (char c, size_t pos = 0) const; |
| size_t rfind (const char* s, size_t pos = 0) const; |
| size_t rfind (const string& str, size_t pos = 0) const; |
//rfind
void test12()
{
string s1("hello,xiaoli");
cout << s1.rfind("llo") << endl; //從下標(biāo)為0開始往前找
cout << s1.rfind("he", 6) << endl; //從下標(biāo)為6開始往前找
string s2("hello,tomorror");
cout << s2.rfind(s1, 3) << endl;
string s3("hello,today,hello tomorror");
cout<<s3.rfind("hello")<<endl; //12,匹配第二個hello
cout<<s3.find("hello")<<endl; //0,匹配第一個hello
}注意:rfind是從尾往前(即從右往左)開始找,但是子字符串時從左往右開始匹配。
2.7 string類的容量
(1)size:字符串的有效字符的長度
| size_t size() const; |
void test13()
{
string s1("hello,xiaoli");
cout << s1.size() << endl; //12
string s2("hello,tomorror");
cout << s2.size() << endl; //14
}(2)capacity:字符串的總空間大小
| size_t capacity() const; |
void test14()
{
string s1("A ship in harbor is safe, but that's not what ships are built for");
cout << s1.capacity() << endl; //79
string s2("hello,tomorror");
cout << s2.capacity() << endl; //15
}(3)length:字符串的有效字符的長度
| size_t length() const; |
void test13()
{
string s1("hello,xiaoli");
cout << s1.length() << endl; //12
string s2("hello,tomorror");
cout << s2.length() << endl; //14
}(4)reserve:開辟指定大小的空間,當(dāng)n<size()時,reserver不會改變?nèi)萘看笮 ?/p>
| void reserve (size_t n = 0); |
void test15()
{
string s1("A ship in harbor is safe, but that's not what ships are built for");
s1.reserve(120);
cout << s1.capacity() << endl;
string s2("hello,tomorror");
cout << s2.capacity() << endl;
s2.reserve(10);
cout << s2.capacity() << endl;
}注意:這里reserve(120),編譯器會多開幾個空間,因?yàn)榫幾g器的擴(kuò)容是按1.5倍增長。
(5)empty:檢查字符串是否是空串
| bool empty() const; |
(6)clear:清空有效字符
(7)resize:將有效字符的個數(shù)變成n個,多出的空間用字符c填充。
| void resize (size_t n); |
| void resize (size_t n, char c); |

void test16()
{
string s1("xiaoli");
cout << s1.size() << endl;//6
cout << s1.capacity() << endl;//15
//s1.resize(20);
//cout << s1.size() << endl; //20
//s1.resize(12);
//cout << s1.size() << endl; //12
s1.resize(3);
cout << s1.size() << endl; //3
cout << s1.capacity() << endl; //15
}2.8 string類的遍歷和訪問
(1)operator[ ]:訪問指定下標(biāo)的元素(string類里面已經(jīng)實(shí)現(xiàn)operator[ ]的重載)
| char& operator[] (size_t pos); |
| const char& operator[] (size_t pos) const; |
void test17()
{
string s1("xiaoli");
cout << s1[2] << endl;
}at同operator[ ],就不再敘述了。
(2)front和back:取首元素和最后一個元素,一樣的操作。
(3)begin:返回第一個字符迭代器(通俗一點(diǎn):返回第一個字符的指針)
end:返回最后一個字符迭代器(通俗一點(diǎn):返回最后一個字符的指針)
(4)rbegin:返回最后一個字符迭代器(通俗一點(diǎn):返回第一個字符的指針)
rend:返回第一個字符迭代器(通俗一點(diǎn):返回最后一個字符的指針)
注意:(3)和(4)與迭代器有著非常緊密的關(guān)系,會常常使用
這里一般用于數(shù)組或者對象的遍歷。如下:有三種遍歷方式
void test18()
{
string s1("hello xiaoli");
//遍歷方式
// 下標(biāo) + []
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}
cout << endl;
// 迭代器
string::iterator it = s1.begin(); //在模擬實(shí)現(xiàn)的時候具體講解
while (it != s1.end())
{
(*it)++;
cout << *it << " ";
it++;
}
cout << endl;
// 范圍for
for (auto ch : s1)
{
ch--;
cout << ch << " ";
}
cout << endl;
}2.9 string類的交換
(1)swap:交換兩個string的內(nèi)容
| void swap (string& str); |
void test19()
{
string s1("hello xiaoli");
string s2("A ship in harbor is safe, but that's not what ships are built for");
swap(s1, s2);
cout << s1 << endl;
cout << s2 << endl;
}2.10 string類的運(yùn)算符
(1)operator=:賦值運(yùn)算符,在string中實(shí)現(xiàn)了函數(shù)重載(相當(dāng)于修改字符串內(nèi)容),其實(shí)功能和assign是類似的。
| string& operator= (char c); |
| string& operator= (const char* s); |
| string& operator= (const string& str); |
void test20()
{
string s1("I Love you!");
s1 = "hello,world";
cout << s1 << endl;
s1 = 'x';
cout << s1 << endl;
}(2)operator+=:在string中實(shí)現(xiàn)了函數(shù)重載(相當(dāng)于在末端追加字符串內(nèi)容),相當(dāng)于push_back的升級版,多了尾插字符串和string功能。
| string& operator+= (char c); |
| string& operator+= (const char* s); |
| string& operator+= (const string& str); |
void test21()
{
string s1("I Love you!");
s1 += "hello,world";
cout << s1 << endl;
s1 += ' x';
cout << s1 << endl;
}(3)上面兩個都是成員函數(shù),這里余下的大小關(guān)系的比較是不屬于成員函數(shù)的,因?yàn)槌蓡T函數(shù)的第一個參數(shù)是隱藏的this指針,而比較可能是字符和字符比較,也可以是字符串和字符串比較。
并且字符和字符串比較都是先比較第一個字符,比較的是字符的ascll碼值。
void test21()
{
string s1("I Love you!");
string s2("I love Code");
cout << (s1 < s2) << endl;//注意優(yōu)先級關(guān)系
cout << (s1 == s2) << endl;//注意優(yōu)先級關(guān)系
}(4)operator>> 和 operator<< :輸入流和輸出流,也是非成員函數(shù),理由和上面一樣,第一個不一定是this指針。
2.11 string類中g(shù)etline函數(shù)
在 C++ 中,使用 >> 運(yùn)算符進(jìn)行輸入提取時,默認(rèn)情況下確實(shí)會以空白字符(包括空格、制表符、換行符等)作為分隔符,并在遇到空白字符時停止當(dāng)前的提取操作.
而使用getline,則分為兩種情況,一種是遇到'\0'停止;另一種是遇到自己定義的終止符停止提取。
| istream& getline (istream& is, string& str);(遇到'\0'停止) |
| istream& getline (istream& is, string& str, char delim);(遇到delim停止) |
void test22()
{
string str;
cin >> str; // 輸入 "Hello World"
cout << str; // 輸出 "Hello"(只提取到第一個空格前的內(nèi)容)
}第一種:讀取一整行,遇到'\0'停止
void test23()
{
string s;
getline(cin, s); // 輸入 "Hello World"
cout << s; // 輸出 "Hello World"(讀取整行內(nèi)容)
}第二種:讀取一整行,遇到delim停止
void test24()
{
string s1;
getline(cin, s1, '#'); // 輸入 "Hello World"
cout << s1; // 輸出 "Hello World"(讀取整行內(nèi)容)
}2.11 string類中的substr函數(shù)
| string substr (size_t pos = 0, size_t len = npos) const; |
substr:生成子字符串,返回一個新構(gòu)造的對象,其值初始化為該對象的子字符串的副本。也就是選取該字符串的一部分構(gòu)造一個新對象。
void test25()
{
string s1("A ship in harbor is safe, but that's not what ships are built for");
cout << s1.substr(3, 15) << endl;
string s2 = s1.substr(5, 10);
cout << s2 << endl;
}那么到這里,string一些常見的接口就了解的差不多了,下一期來模擬實(shí)現(xiàn)string。
到此這篇關(guān)于C++ STL中容器string超詳細(xì)講解的文章就介紹到這了,更多相關(guān)stl容器string內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++ 多態(tài)性虛函數(shù)和動態(tài)綁定學(xué)習(xí)筆記
這篇文章主要為大家介紹了C++ 多態(tài)性虛函數(shù)和動態(tài)綁定學(xué)習(xí)筆記,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
vs2022項(xiàng)目文件夾內(nèi).vs文件夾容量虛高問題的解決
經(jīng)常會發(fā)現(xiàn)VS的項(xiàng)目文件夾占用空間很大,本文主要介紹了vs2022項(xiàng)目文件夾內(nèi).vs文件夾容量虛高問題的解決,具有一定的參考價值,感興趣的可以了解一下2023-09-09
C語言數(shù)據(jù)的存儲超詳細(xì)講解中篇練習(xí)
使用編程語言進(jìn)行編程時,需要用到各種變量來存儲各種信息。變量保留的是它所存儲的值的內(nèi)存位置。這意味著,當(dāng)您創(chuàng)建一個變量時,就會在內(nèi)存中保留一些空間。您可能需要存儲各種數(shù)據(jù)類型的信息,操作系統(tǒng)會根據(jù)變量的數(shù)據(jù)類型,來分配內(nèi)存和決定在保留內(nèi)存中存儲什么2022-04-04
C++中typedef 及其與struct的結(jié)合使用
這篇文章主要介紹了C++中typedef 及其與struct的結(jié)合使用,需要的朋友可以參考下2014-02-02
OpenCV實(shí)現(xiàn)簡易標(biāo)定板
這篇文章主要為大家詳細(xì)介紹了OpenCV實(shí)現(xiàn)簡易標(biāo)定板,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-04-04

