寧波網(wǎng)站建設(shè)c nb網(wǎng)站優(yōu)化網(wǎng)
文章目錄
- 1、什么是STL
- 2、STL簡(jiǎn)介
- 3、什么是string類
- 4、string類的常用接口說明
- 1、常見構(gòu)造函數(shù)
- 2、容量操作
- 3、迭代器
- 4、其他的標(biāo)準(zhǔn)庫的string類
關(guān)于string類的內(nèi)容,可以在cplusplus.com查看到。
1、什么是STL
STL是C++標(biāo)準(zhǔn)庫的重要組成部分,不僅是一個(gè)可復(fù)用的組件庫,而且是一個(gè)包羅數(shù)據(jù)結(jié)構(gòu)與算法的軟件框架。
2、STL簡(jiǎn)介
STL最初是在惠普實(shí)驗(yàn)室誕生的,并向外開源。
原始版本
Alexander Stepanov、Meng Lee 在惠普實(shí)驗(yàn)室完成的原始版本,本著開源精神,他們聲明允許任何人任意
運(yùn)用、拷貝、修改、傳播、商業(yè)使用這些代碼,無需付費(fèi)。唯一的條件就是也需要向原始版本一樣做開源使
用。 HP 版本–所有STL實(shí)現(xiàn)版本的始祖。
P. J. 版本
由P. J. Plauger開發(fā),繼承自HP版本,被Windows Visual C++采用,不能公開或修改,缺陷:可讀性比較低,
符號(hào)命名比較怪異。
RW版本
由Rouge Wage公司開發(fā),繼承自HP版本,被C+ + Builder 采用,不能公開或修改,可讀性一般。
SGI版本
由Silicon Graphics Computer Systems,Inc公司開發(fā),繼承自HP版 本。被GCC(Linux)采用,可移植性好,
可公開、修改甚至販賣,從命名風(fēng)格和編程 風(fēng)格上看,閱讀性非常高。一般學(xué)習(xí)STL要閱讀部分源代碼,
主要參考的就是這個(gè)版本。
STL分為仿函數(shù),算法,容器,迭代器,空間配置器,配接器
3、什么是string類
C語言中,字符串是以’\0’結(jié)尾的一些字符的集合,為了操作方便,C標(biāo)準(zhǔn)庫中提供了一些str系列的庫函數(shù),
但是這些庫函數(shù)與字符串是分離開的,不太符合OOP的思想,而且底層空間需要用戶自己管理,稍不留神可能還會(huì)越界訪問。
string類則是C++定義的一個(gè)類。根據(jù)官方文檔記錄:
- 字符串是表示字符序列的類
- 標(biāo)準(zhǔn)的字符串類提供了對(duì)此類對(duì)象的支持,其接口類似于標(biāo)準(zhǔn)字符容器的接口,但添加了專門用于操作
單字節(jié)字符字符串的設(shè)計(jì)特性。 - string類是使用char(即作為它的字符類型,使用它的默認(rèn)char_traits和分配器類型(關(guān)于模板的更多信
息,請(qǐng)參閱basic_string)。 - string類是basic_string模板類的一個(gè)實(shí)例,它使用char來實(shí)例化basic_string模板類,并用char_traits
和allocator作為basic_string的默認(rèn)參數(shù)(根于更多的模板信息請(qǐng)參考basic_string)。 - 注意,這個(gè)類獨(dú)立于所使用的編碼來處理字節(jié):如果用來處理多字節(jié)或變長(zhǎng)字符(如UTF-8)的序列,這個(gè)
類的所有成員(如長(zhǎng)度或大小)以及它的迭代器,將仍然按照字節(jié)(而不是實(shí)際編碼的字符)來操作。
總結(jié):
- string是表示字符串的字符串類
- 該類的接口與常規(guī)容器的接口基本相同,再添加了一些專門用來操作string的常規(guī)操作。
比特就業(yè)課 - string在底層實(shí)際是:basic_string模板類的別名,typedef basic_string<char, char_traits, allocator>
string; - 不能操作多字節(jié)或者變長(zhǎng)字符的序列。
在使用string類時(shí),必須包含#include頭文件以及using namespace std;
簡(jiǎn)單看一個(gè)代碼
#include <iostream>
#include <string>
using namespace std;int main()
{string s1;string s2("hello world");for (size_t i = 0; i < s2.size(); ++i){s2[i]++;}cout << s2 << endl;return 0;
}
string需要頭文件string,s2[i]++會(huì)讓對(duì)應(yīng)的字符往后一位,比如h變?yōu)閕,e變?yōu)閒。
4、string類的常用接口說明
1、常見構(gòu)造函數(shù)
string(const char* s) 和上面的代碼一樣,可以string s2(“hello world”); 也可以string s2 = “hello world”。
string(const string& str, size_t pos, size_t len = npos)。這個(gè)構(gòu)造函數(shù)的意思就是取字符串的一部分,從pos位置開始往后len個(gè)字符。
string s3 = "hello world";string s4(s3, 6, 3);
結(jié)果是wor。第6個(gè)位置是空格,打印空格之后3個(gè)位置。如果后面的長(zhǎng)度過大,那么就會(huì)取到字符串結(jié)束,而不是按照實(shí)際的len去越界。如果不給len,那么就會(huì)按照它的缺省值來打印,len的缺省值是npos,定義中給的值是無符號(hào)整數(shù)-1,所以就是整數(shù)的最大值,那么就會(huì)打印到字符串結(jié)束。
string(const char* s, size_t n),用字符串前n個(gè)進(jìn)行構(gòu)造。
string s5("hello world", 6);cout << s5 << endl;
打印hello和空格。
string(size_t n, char c),用n個(gè)字符c來構(gòu)造。
string s6(10, '*');cout << s6 << endl;
cplusplus.com可以查到相關(guān)文檔。
2、容量操作
int main()
{string s1("hello world");cout << s1.size() << endl;cout << s1.length() << endl;return 0;
}
size和length兩個(gè)功能一樣,返回有效字符串長(zhǎng)度。max_size()則是察看能達(dá)到的最大值,42億9千萬多,沒有多大意義。
capacity(),結(jié)果是15,不包含’\0’,返回空間總大小。
int main()
{string s1("hello");s1.push_back('?');s1.append("asda");cout << s1 << endl;return 0;
}
push_back只能加字符,而append可以加字符串。append還有別的用法,在cplusplus.com查看。統(tǒng)合這兩個(gè)功能,+=就可以全實(shí)現(xiàn)。
s1 += '!';s1 += "asdghjfk";cout << s1 << endl;
capacity函數(shù),會(huì)在原有空間不足時(shí)進(jìn)行自動(dòng)擴(kuò)容,這個(gè)根據(jù)不同的編譯器有不同的結(jié)果,vs是1.5倍擴(kuò)容,Linux不一樣。
int main()
{string s;cout << sizeof(s) << endl;size_t sz = s.capacity();cout << "make s grow:\n";cout << "capacity changed: " << sz << '\n';for (int i = 0; i < 100; ++i){s.push_back('c');if (sz != s.capacity()){sz = s.capacity();cout << "capacity changed: " << sz << endl;}}
}
也有方法阻止自動(dòng)擴(kuò)容,reserve函數(shù),預(yù)留空間。
string s;s.reserve(100);
不一定會(huì)多開100空間,但是一定開得比100多。
resize可以開空間并初始化。
int main()
{string s1("hello world");s1.reserve(100);cout << s1.capacity() << endl;cout << s1.size() << endl;string s2("hello world");s2.resize(100);cout << s2.capacity() << endl;cout << s2.size() << endl;return 0;
}
resize括號(hào)里第二個(gè)參數(shù)可以加上字符,用來初始化空白的空間為指定的字符。resize也可以刪除數(shù)據(jù),括號(hào)的數(shù)字n比size小,就會(huì)保留前n個(gè),但不會(huì)縮小capacity,縮容對(duì)于系統(tǒng)來說難度比較大,系統(tǒng)原生一般不支持。
3、迭代器
int main()
{string s1("hello world");string::iterator it = s1.begin();while (it != s1.end()){cout << *it << " ";++it;}cout << endl;return 0;
}
分析一下這段代碼。我們可以暫且理解為s1指向hello world字符串,s1.begin就是首元素地址,給了it,end則是’\0’的位置,it指向了第一個(gè)元素,然后邊打印邊++。
我們也可以用范圍for,不過底層原理都一樣,都是迭代器。
for (auto ch : s1){cout << ch << " ";}cout << endl;
iterator是string類里的typedef的一個(gè)函數(shù)。用迭代器需要用它。迭代器可以反向使用。
string::reverse_iterator rit = s1.rbegin();while (rit != s1.rend()){cout << *rit << " ";++rit;}
反向迭代器需要用到reverse_iterator。rbegin指向hello world的d而不是’\0’,rend則指向h前面的位置,這里正是因?yàn)槭欠聪?#xff0c;所以++就等于–。
如果是加上了const
void func(const string& s)
{string::const_iterator it = s.begin();while (it != s.end()){cout << *it << " ";++it;}cout << endl;
}
如果是const的變量,那么就得用const_iterator,剛才的反向迭代器也一樣,需要用專用的,并且rbegin這些也得對(duì)應(yīng)著用。const修飾,就只能遍歷和讀,而不能寫;反向迭代器加上const,類的函數(shù)就應(yīng)當(dāng)是string::const_reverse_iterator。
4、其他的標(biāo)準(zhǔn)庫的string類
string s1("hello world");s1[100];s1.at(100);
越界了會(huì)直接報(bào)錯(cuò),如果是at,則會(huì)拋異常,雖然也報(bào)錯(cuò),但可以捕獲異常。
insert整體是插入的意思,有很多函數(shù),可以插入string類對(duì)象,可以插入字符串,可以選擇位置來控制插入。
string s1("hello world");//s1[100];//s1.at(100);s1.insert(0, "hhhh");cout << s1 << endl;s1.insert(4, 1, ' ');cout << s1 << endl;return 0;
或者s1.insert(4, " ")這樣。括號(hào)里也可以加上迭代器。
s1.insert(s1.begin() + 4, ' ');cout << s1 << endl;
string s2("hello world");s2.erase(5, 1);//s2.erase(s2.begin() + 5);cout << s2 << endl;
erase可以用來刪除
如果括號(hào)里給的數(shù)字過大時(shí),那就會(huì)有多少刪多少。
insert和erase可能存在挪動(dòng)數(shù)據(jù),效率低下,所以不推薦常用。
之前有在字符串空格處把空格換成別的字符的題,現(xiàn)在用C++寫
string s1("hello, the world");size_t pos = s1.find(' ');if (pos != string::npos){s1.replace(pos, 1, "%20");}cout << s1 << endl;return 0;
這里會(huì)把第一個(gè)空格改成%20,加個(gè)循環(huán)就可以把所有空格都換上。
while(pos != string::npos){s1.replace(pos, 1, "%20");pos = s1.find(' ');}
不過這個(gè)程序還有改進(jìn)之處。pos = s1.find(’ ', pos + 3),可以從%20的0處往后開始找下一個(gè)空格,增加一點(diǎn)效率。replace存在擴(kuò)容,會(huì)把1個(gè)字符擴(kuò)成3個(gè)字符。所以我們可以提前開好,避免replace開空間。
string s1("hello the world");size_t num = 0;for (auto ch : s1){if (ch == ' ')++num;}s1.reserve(s1.size() + 2 * num);size_t pos = s1.find(' ');while(pos != string::npos){s1.replace(pos, 1, "%20");pos = s1.find(' ', pos + 3);}cout << s1 << endl;
結(jié)束。