福建設(shè)計院網(wǎng)站百度百度一下就知道
目錄
一、標(biāo)準(zhǔn)庫中的string類
二、string類的常用接口
1、string類對象的常見構(gòu)造
2、string類對象的容量操作
2.1、size 與 length
2.2、capacity 與 reserve
2.3、resize
2.4、總結(jié)
3、string類對象的訪問及遍歷操作
3.1、operator[] 與 at
3.2、begin + end
3.3、rbegin + rend
3.4、 const類型迭代器
3.5、范圍for
4. string類對象的修改操作
4.1、push_back、append、operator+=
4.2、insert 與 erase
4.3、find?與 replace
4.4、substr 與 rfind
4.5、c_str
4.6、find_first_of 與 find_last_of
5、string類非成員函數(shù)
5.1、getline
一、標(biāo)準(zhǔn)庫中的string類
string類是由模板 basic_string 顯示實例化為 char 類型得到的類,并用關(guān)鍵字 typedef 命名為 string 。
?當(dāng)模板參數(shù)是 char 時,類名為 string ,與之相對的,還有其他各種各樣由模板 basic_string 顯示實例化的到的類名,比如:wstring、u16string、u32string等
?wstring 類管理的是 wchar_t 類型的字符,一個字符占據(jù) 2?個字節(jié)。
?u16string 類管理的是 char16_t 類型的字符,一個字符占據(jù) 2?個字節(jié)。
?u32string 類管理的是 char32_t 類型的字符,一個字符占據(jù)?4?個字節(jié)。
之所以要區(qū)分出這么多字符類,是為了滿足各種各樣不同的需求,比如編碼的需求。
?以 ascll 碼為例,ascll碼的出現(xiàn)是為了更好的表示英文,算上26個字母、10個數(shù)字以及各種各樣的符號、控制字符等等,只需要 128 個字符的映射表就能滿足幾乎所有的表示需求。
但是對于中文、甚至是更加復(fù)雜的文字而言,128個字符的映射表就已經(jīng)沒有辦法滿足需求了,就需要更多字符的映射表,自然也需要占據(jù)更多字節(jié)大小的空間。
為了更好的滿足這一需求,就出現(xiàn)了另一個編碼規(guī)則:Unicode,即統(tǒng)一碼。統(tǒng)一碼又分為 3 種,分別為 UTF-8、UTF-16、UTF-32。
UTF-8兼容ascll碼,對不同范圍的字符使用不同長度的編碼,也是我們最常用的編碼方式。
?對于0x00-0x7F之間的字符,UTF-8編碼與ascll編碼完全相同。UTF-8編碼的最大長度是4個字節(jié)。從上表可以看出,4字節(jié)模板有21個x,即可以容納21位二進制數(shù)字。統(tǒng)一碼的最大碼位0x10FFFF也只有21位。UTF-8 編碼以二進制數(shù)字的前綴來區(qū)分一個字符占據(jù)幾個字節(jié)。
其中類 string 所對應(yīng)的編碼方式就是 UFT-8 。
?
?我們來舉個例子具體說明一下:
?
?str1 中存儲的是英文字母,使用 ascll 碼即可表示(一個字符占據(jù)一個字節(jié)),例如 'h' 的值為十進制 104 ,換算到八位二進制為?01101000 ,前綴為零。
?str2 中存儲的是中文字符,一個字符占據(jù)兩個字節(jié),所以這兩個字節(jié)的二進制數(shù)前綴分別為 110 與 10。轉(zhuǎn)換成十進制表現(xiàn)為兩個負數(shù)。兩個中文字符就是四個字節(jié),加上最后的 '\0' 為五個字節(jié)大小。
通過更改中文字符的數(shù)值,我們可以觀察到中文字符編碼的規(guī)律是把同音字編在一起的:
?
二、string類的常用接口
1、string類對象的常見構(gòu)造
(constructor)函數(shù)名稱 | 功能說明 |
string() | 構(gòu)造空的string類對象,即空字符串 |
string(const char* s) | 用C-string來構(gòu)造string類對象 |
string(size_t n, char c) | string類對象中包含n個字符c |
string(const string& s) | 拷貝構(gòu)造函數(shù) |
string (const string& str, size_t pos, size_t len = npos) | 拷貝從字符串第 pos 個字符開始向后的 npos 個字符 |
例如:
?對于?string (const string& str, size_t pos, size_t len = npos) ,庫中提供了一些額外的解釋,如果 npos 的大小超出了字符串的有效長度范圍,就自動取到字符串中最后一個有效字符為止。如果沒有指定 npos 的值,就使用缺省參數(shù) -1 ,由于 size_t 是無符號整型,所以 -1 實際上是二進制的全一,即最大的整型數(shù)值 2^32 - 1 。
2、string類對象的容量操作
函數(shù)名稱 | 功能說明 |
size(重點) | 返回字符串有效字符長度 |
length | 返回字符串有效字符長度 |
capacity | 返回空間總大小 |
empty (重點) | 檢測字符串是否為空串,是返回true,否則返回false |
clear (重點) | 清空有效字符 |
reserve (重點) | 為字符串預(yù)留空間** |
resize (重點) | 將有效字符的個數(shù)改成n個,多出的空間用字符c填充 |
2.1、size 與 length
?size 與 length 都是返回字符串的有效字符長度,用法如下:
?功能完全相同,只是為了名字與 stl 中其他模板的名稱保持一致,就增加了一個 size ,除了名字不同外,沒有區(qū)別。
2.2、capacity 與 reserve
?capacity 返回空間總大小,用于觀察開辟空間的情況:
?當(dāng)不斷向string對象 s 中尾插字符時,會導(dǎo)致 s 不斷的擴容,可以發(fā)現(xiàn)除了第一次擴容外,其他擴容后的大小都是上一次的 1.5 倍。
?string 對象第一次擴容的規(guī)則大致如下:
?類string中有一個容量為 16 個字符的數(shù)組 buf ,如果對象中存儲的字符數(shù)量小于等于 16 個,就會把字符存入數(shù)組 buf 中,不使用指針 _ptr 。如果對象中存儲的字符數(shù)量大于 16 個,就會使用指針 _ptr 來開辟空間,第一次直接開辟 32 個字符的空間,并把字符存放在新開辟的空間中, buf 不再使用。之后每次開辟的空間大小是開辟之前大小的 1.5 倍。
這種規(guī)則只適用于VS編譯器,不同的編譯器有不同的擴容規(guī)則。
為了防止編譯器不斷的給 string 對象擴容空間,造成資源的浪費,我們可以使用 reserve 直接給對象預(yù)留一定大小的空間:
?其中因為一些內(nèi)存對齊等原因,實際內(nèi)存空間與我們設(shè)定的有一些出入,但一定不會比我們設(shè)置的小。
2.3、resize
?resize 將有效字符的個數(shù)改成 n 個,多出的空間用字符c填充。?resize 可以擴容空間,并進行初始值填充:
可以看到 resize 與 reserve 不同。使用 resize 進行擴容的時候,也進行了字符填充,使對象的有效字符長度也發(fā)生了變化。
?在vs編譯器中,默認(rèn)填充的字符是 '\0' 。
我們也可以指定填充的字符,寫成如下形式:
?如果指定的 n 值比 size 小,則會刪除數(shù)據(jù),保留前 n 個:
?size 變?yōu)?span style="color:#fe2c24;"> 5 , capacity 的值不變。?
2.4、總結(jié)
- size()與length()方法底層實現(xiàn)原理完全相同,引入size()的原因是為了與其他容器的接口保持一致,一般情況下基本都是用size()。
- clear()只是將string中有效字符清空,不改變底層空間大小。
- resize(size_t n) 與 resize(size_t n, char c)都是將字符串中有效字符個數(shù)改變到n個,不同的是當(dāng)字符個數(shù)增多時:resize(n)用0來填充多出的元素空間,resize(size_t n, char c)用字符c來填充多出的元素空間。注意:resize在改變元素個數(shù)時,如果是將元素個數(shù)增多,可能會改變底層容量的大小,如果是將元素個數(shù)減少,底層空間總大小不變。
- reserve(size_t res_arg=0):為string預(yù)留空間,不改變有效元素個數(shù),當(dāng)reserve的參數(shù)小于string的底層空間總大小時,reserver不會改變?nèi)萘看笮 ?/li>
3、string類對象的訪問及遍歷操作
函數(shù)名稱 | 功能說明 |
operator[] | 返回pos位置的字符,const string類對象調(diào)用 |
begin+ end | begin獲取一個字符的迭代器 + end獲取最后一個字符下一個位置的迭 代器 |
rbegin + rend | begin獲取一個字符的迭代器 + end獲取最后一個字符下一個位置的迭 代器 |
范圍for | C++11支持更簡潔的范圍for的新遍歷方式 |
3.1、operator[] 與 at
?operator[] 返回pos位置的字符,是一個運算符重載,關(guān)于運算符重載的內(nèi)容,在《類和對象(二)》里有過詳細的說明。
?at 的作用與 [] 類似,都是獲取指定下標(biāo)的數(shù)據(jù),只不過在越界的處理方面有些不同。如果 [] 中的下標(biāo)越界,程序會直接發(fā)生斷言錯誤,終止程序,而如果 at 指向的下標(biāo)越界,則會進行拋異常。
3.2、begin + end
我們想要打印一個數(shù)組,除了使用運算符重載 [] 外,還可以使用 begin 與 end 獲取迭代器。具體用法如下:
?關(guān)于迭代器,大家暫時可以先理解為指針, begin 是第一個位置的指針, end 是最后一個位置的下一個位置的指針。
3.3、rbegin + rend
?rbegin 與 rend 獲取的是反向迭代器,目前階段同樣可以先把他們看作指針,其中 rbegin 指向最后一個數(shù)據(jù)的位置, rend 指向第一個位置的前一個位置:
?用法如下:
3.4、 const類型迭代器
當(dāng)使用 const 類型來接收string類對象時,如果直接使用關(guān)鍵字 interator 來定義迭代器變量,編譯器會報錯。
?所以為了保證權(quán)限不被放大,需要使用關(guān)鍵字?const_iterator 來定義迭代器變量:
3.5、范圍for
打印一個數(shù)組,還有另一種方法,就是使用 范圍for ,具體用法如下:
?實際上,范圍for的底層就是使用迭代器來實現(xiàn)的。
4. string類對象的修改操作
函數(shù)名稱 | 功能說明 |
push_back | 在字符串后尾插字符c |
append | 在字符串后追加一個字符串 |
operator+= (重點) | 在字符串后追加字符串str |
c_str(重點) | 返回C格式字符串 |
find(重點) | 從字符串pos位置開始往后找字符c,返回該字符在字符串中的位置 |
replace | 替換字符串pos位置,len長度的字符 |
rfind | 從字符串pos位置開始往前找字符c,返回該字符在字符串中的位置 |
substr | 在str中從pos位置開始,截取n個字符,然后將其返回 |
insert | 在str中插入字符 |
erase | 在str中刪除字符 |
find_first_of | 找到其中任意一個字符,并返回其位置 |
find_last_of |
4.1、push_back、append、operator+=
?push_back 在字符串尾部插入字符,具體用法如下:
?append 在字符串尾部插入字符串,具體用法如下:
?相比較于以上兩種接口,最簡單且最常用的其實是 operator+= ,具體用法如下:
4.2、insert 與 erase
?insert :在字符串的 pos 位置插入字符串或者 n 個字符。
比如在字符串 "world" 的第 0 個位置插入字符串 "hello" :
在字符串 "helloworld" 第 5 個位置插入 1 個字符 ' ' :?
??erase?:在字符串的 pos 位置刪除 n 個字符。
例如,在字符串 "hello world" 的第?6?個位置刪除 1 個字符:
?如果指定的 n 超出了字符串的有效范圍,或者不指定 n 的值,就刪除到字符串最后的位置。
?
?注意:?insert 與 erase 不推薦經(jīng)常使用,因為他們可能都要挪動數(shù)據(jù),效率低下。
4.3、find?與 replace
?find :從字符串的 pos 位置向后尋找指定字符,返回該字符在字符串中的位置,如果沒有指定 pos 的值,就使用缺省參數(shù) 0 。如果字符串中沒有找到指定字符,就返回 npos ,即無符號整型 -1 。
例如,找到字符串 "hello world" 中 ' ' 的位置:
?找到字符串 "hello world i love you" 中第二個 ' ' 的位置:
?replace :替換字符串 pos 位置, len 長度的字符。
例如,把字符串 "hello world i love you" 中所有的 ' ' 都替換為 "%20" :
?這樣每次使用 replace 來替換字符,都會擴容空間,為了提高效率,我們可以使用 reserve 來提前開辟空間:
4.4、substr 與 rfind
?substr :在str中從 pos 位置開始,截取 n 個字符,然后將其返回。
例如:打印字符串 "string.cpp" 的后綴:
如果我們不指定 n 的值,就使用缺省參數(shù) npos ,即無符號整型 -1 。?不指定 pos 的值,就是用缺省參數(shù) 0 :
不過也有時,文件的名字中存在多個字符 '.' ,?為了尋找文件真正的后綴,我們需要找到最后一個?'.' 的位置??梢允褂?span style="color:#fe2c24;"> rfind :從字符串pos位置開始往前找指定字符,返回該字符所在的位置:
4.5、c_str
?c_str 返回C格式字符串。
打印字符串有如下兩種方式:
?其中第一種,s 是自定義類型, "<<" 是自定義類型重載的流插入。第二種 s.c_str() 返回的是C格式字符串的指針,類型為 char* , "<<" 是庫里面的流插入。如果把?s.c_str()?返回的指針強轉(zhuǎn)成其他類型,就會打印出指針,而不是字符串:
?如果把字符串進行以下處理后,這兩種打印方式得到的結(jié)果是不同的:
?可知,如果我們使用流插入來打印string對象,會以 size 的大小來打印,不會關(guān)注 '\0' 。而使用流插入來打印 char* 類型的指針,就會打印到 '\0' 后結(jié)束。
4.6、find_first_of 與 find_last_of
?find_first_of??:在字符串中,從前往后找到其中任意一個字符,并返回其位置。
例如,把一段字符串中所有的 'a'、'b'、'c'、'd' 都替換為 '*' 。
?find_last_of :在字符串中,從后往前找到其中任意一個字符,并返回其位置。
5、string類非成員函數(shù)
函數(shù) | 功能說明 |
operator+ | 盡量少用,因為傳值返回,導(dǎo)致深拷貝效率低 |
operator>> | 輸入運算符重載 |
operator<< | 輸出運算符重載 |
getline (重點) | 獲取一行字符串 |
relational operators | 大小比較 |
5.1、getline
?當(dāng)我們使用 cin 來提取字符串時,字符串中不能含有空格,因為 cin 在遇到空格、'\n' 等字符時,會默認(rèn)提取結(jié)束。
為了解決這個問題,我們可以使用 getline :
int main()
{string str;//cin >> str;getline(cin, str);return 0;
}
關(guān)于string類的使用相關(guān)內(nèi)容就講到這里,希望同學(xué)們多多支持,如果有不對的地方歡迎大佬指正,謝謝!