在c語言中,我們想要記錄字符串需要創(chuàng)建一個字符串的數(shù)組,而c++則提供了另一種方式;
成都創(chuàng)新互聯(lián)是一家專業(yè)從事做網(wǎng)站、網(wǎng)站設(shè)計的網(wǎng)絡(luò)公司。作為專業(yè)的建站公司,成都創(chuàng)新互聯(lián)依托的技術(shù)實力、以及多年的網(wǎng)站運營經(jīng)驗,為您提供專業(yè)的成都網(wǎng)站建設(shè)、全網(wǎng)整合營銷推廣及網(wǎng)站設(shè)計開發(fā)服務(wù)!也就是這篇博客所說的string類;
目錄
string類
string類的成員函數(shù)
string的構(gòu)造函數(shù)
string的容量操作函數(shù)
size() / length() / capacity() 函數(shù)
reserve(size_t n) / resize(size_t n, char c) 函數(shù)
string類對象的訪問及遍歷操作
operator[] (size_t pos)
begin()/end()/rbegin()/rend()
迭代器——iterator
string類對象修改操作
string的其他函數(shù)
string類#include
作為字符串數(shù)組的升級版,string類自然也有它的獨特之處——可變長數(shù)組;
c語言中的字符串數(shù)組只能在創(chuàng)建的時候定好初始的長度,數(shù)據(jù)長度不能超過數(shù)組長度;
而string類則沒有這樣的顧慮,雖然string變量都有自己的初始長度,但是它內(nèi)部的成員函數(shù)會在輸入數(shù)據(jù)超過初始長度的時候,會自動開辟空間,因此可以不用考慮數(shù)組長度;
此外,c++考慮到需要兼容c語言,也給string類重載了一個類似于c語言創(chuàng)建字符串數(shù)組的構(gòu)造方式
但是這里有一點需要注意的是,雖然string類這里的創(chuàng)建方式和c語言的字符串數(shù)組一樣;
但是它還是有很多不同的;
首先就是它并不是以 ‘\0’ 作為結(jié)束的標志;
我們可以看下它內(nèi)部:
可以看到 s1 并不是以 '\0’ 作為結(jié)束標志的;
好,說了那么多 string類和 c語言數(shù)組的不同,那么來講講string類特有的功能吧;
string類的成員函數(shù)
string類中實現(xiàn)了許多成員函數(shù),并且每種函數(shù)根據(jù)不同的情況有不同的重載;
這里我們就認識一下用的比較多的函數(shù)吧;
string的構(gòu)造函數(shù)
?函數(shù)名稱 | 功能? ? ?? |
string() | 創(chuàng)造一個空的string對象 |
string(const char* s) | 用一個字符串創(chuàng)建string對象 |
string(size_t n,char c) | 用 n 個 c 字符創(chuàng)建string對象 |
string(const string& s) | 用string對象拷貝構(gòu)造一個string對象 |
void test3()
{
string s1;
string s2("abcd");
string s3(5, 'c');
string s4(s3);
cout<< "s1 = "<< s1<< endl;
cout<< "s2 = "<< s2<< endl;
cout<< "s3 = "<< s3<< endl;
cout<< "s4 = "<< s4<< endl;
}
我們能夠看到,使用不同方式都成功創(chuàng)建了對應(yīng)的字符串;
string的容量操作函數(shù)
?函數(shù)名 | 功能 |
size() | 返回字符串有效字符長度 |
length() | 返回字符串有效字符長度 |
capacity() | 返回空間總大小 |
empty() | 檢測是否為空 |
clear() | 清空有效字符 |
reserve(size_t n = 0) | 為字符串開辟空間 |
resize(size_t n)/(size_t n ,char c) | 更改有效字符為n,多出的用字符c填充 |
c++中對于string的容量操作的函數(shù)可不少,我們先來一個一個學(xué)習(xí)吧;
size() / length() / capacity() 函數(shù)
void test4()
{
string s1 = "hello world!";
cout<< s1.size()<< endl;
cout<< s1.length()<< endl;
cout<< s1.capacity()<< endl;
}
首先是string的檢查容量大小的函數(shù);
我們發(fā)現(xiàn) size() 函數(shù)和 length() 函數(shù)的返回值其實是一樣的;
這是因為c++中,其他容器中的檢查容量大小的函數(shù)都是 size() ,因此又引入了 size() 函數(shù);?
此外,我們發(fā)現(xiàn) capacity() 函數(shù)的返回值和其他兩個函數(shù)不一樣,這是由string類的實現(xiàn)形成的;
string類的實現(xiàn)可以看做是一個char類型的指針(實際上比這更復(fù)雜一點,但是為了好理解可以視為是char類型的指針),并且內(nèi)部除了 char* 指針,還有一個 size 和 capacity 變量;
而它們?nèi)叩年P(guān)系類似下圖:?
實際上string對象開辟的大小為 capacity 這么大,而內(nèi)部存儲的字符串大小為size大??;
這就是為什么兩個函數(shù)返回值不同的原因;
而 clear() 函數(shù)和empty()函數(shù)只在乎size()的大?。?/p>
而 size 和 capacity 的大小也是有成員變量可以修改的;
reserve(size_t n) / resize(size_t n, char c) 函數(shù)
這兩個函數(shù)都是針對 capacity 變量和 size 變量而出現(xiàn)的函數(shù);
我們先看看 resize 函數(shù);
void test5()
{
string s1 = "hello world!";
cout<<"s1.size:"<< s1.size()<<' '<<"s1.capacity:"<
我們發(fā)現(xiàn),resize() 更改了有效字符的長度,而 capacity 并未改變;
并且就算我們將 size 改回原來的長度,也無法恢復(fù)原來的數(shù)據(jù);
而 reserve() 函數(shù)則不用多說,自然是修改 capacity 的大小了,但是它改變得比較奇怪;
void test7()
{
string s1 = "hello world!";
cout<< "s1.capacity : "<< s1.capacity()<< ' '<< s1<< endl;
s1.reserve(20);
cout<< "s1.capacity : "<< s1.capacity()<< ' '<< s1<< endl;
s1.reserve(10);
cout<< "s1.capacity : "<< s1.capacity()<< ' '<< s1<< endl;
}
我們發(fā)現(xiàn),命名我們用 reserve 函數(shù)將 capacity 更改到20,但是實際上它的大小為31;
而更改到10則沒變化;
這是為什么呢?
我們先去官網(wǎng)上看看reserve函數(shù)的描述:
大致意思是:
如果 n 比string 的capacity 大,那么編譯器就會擴大容器的大小到 n 或者更大,而其他情況下,就根據(jù)容器的實現(xiàn)進行優(yōu)化;
也就是說,reserve 函數(shù)并非根據(jù)你輸入的數(shù)據(jù)來擴大容量,而是根據(jù)編譯器內(nèi)部的實現(xiàn)來進行擴大;
因此這就是為什么我們擴大到20的時候,會擴大到31;
而至于為什么我們想要縮小到10的時候,則沒變呢?
雖然官網(wǎng)描述中說自由優(yōu)化,實際上大部分編譯器的實現(xiàn)當 n 小于 capacity 的時候,并不會對capacity 進行修改;
此外,官網(wǎng)的描述中,規(guī)定這個函數(shù)不會影響字符串的內(nèi)容,因此當 n 小于 capacity 的時候就不作修改了;
string類對象的訪問及遍歷操作
函數(shù)名稱 | 功能 |
operator[] (size_t pos) | 返回 pos 位置的字符 |
begin()+end() | 迭代器訪問 |
rbegin()+end() | 反向迭代器訪問 |
范圍for | c++支持的新型for循環(huán)訪問 |
通過之前的實踐,我們都知道 string 類對象都可以直接通過 cout 直接輸出;
但是c++還提供了其他方法遍歷 string 類對象;
?operator[] (size_t pos)
首先就是運算符重載的 operator[] 訪問了;
void test8()
{
string s1 = "hello world!";
for (int i = 0; i< s1.size(); i++)
{
cout<< s1[i];
}
cout<< endl;
}
這種訪問方式就和 c 語言中訪問字符數(shù)組一樣了;
而這樣的訪問方式實際上是在類內(nèi)部實現(xiàn)的;
begin()/end()/rbegin()/rend()
c++中有各種各樣的容器,由于底層結(jié)構(gòu)不同,所以各種容器的訪問方式也不同;
但是c++為了保證容器的統(tǒng)一性,而創(chuàng)造出了迭代器——iterator,來保證容器訪問方式的一致性;
迭代器——iterator
每個容器里面都有 iterator ,它是一個類似于指針的東西,用戶通過迭代器能夠訪問容器的內(nèi)容;
而每一個容器的 begin() 和 end() 函數(shù)都是為迭代器服務(wù)的;
接下來我們看看迭代器的使用方式吧!
void test9()
{
string s1 = "hello world!";
string::iterator is1 = s1.begin();
while (is1 != s1.end())
{
cout<< *is1;
is1++;
}
cout<< endl;
}
迭代器并非通過下標訪問那樣,只用比較 i 和 size 之間的大??;
迭代器只能通過和容器內(nèi)部的 end() 返回值來比較,看是否到達變量的尾部;
并且,迭代器也有 const 類型的迭代器,用于被 const 修飾容器變量;
void test9()
{
const string s1 = "hello world!";
string::const_iterator is1 = s1.begin();
while (is1 != s1.end())
{
cout<< *is1;
is1++;
}
cout<< endl;
}
rbegin() 和 rend()
前面說過,這兩個函數(shù)屬于反向迭代器,而它的用法和普通迭代器一模一樣;
void test9()
{
string s1 = "hello world!";
string::reverse_iterator is1 = s1.rbegin();
while (is1 != s1.rend())
{
cout<< *is1;
is1++;
}
cout<
通過反向迭代器,我們能夠反向遍歷容器內(nèi)容的內(nèi)容,其使用方式和普通迭代器是一樣的;
范圍for
范圍for應(yīng)該算是比較通用的,就不用過多講解了;
void test9()
{
string s1 = "hello world!";
string::reverse_iterator is1 = s1.rbegin();
for (auto e : s1)
{
cout<< e;
}
cout<
string類對象修改操作
函數(shù)名 | 功能 |
push_back(char c) | 在字符串后面添加c |
append()? ? //有多種重載 | 在字符串后面追加字符串 |
operator+= | 在字符串后面追加字符串str |
c_str() | 返回c格式字符串 |
find()+npos | 在pos位置往后找字符c,并返回所在位置 |
rfind() | 在pos位置往前找字符c,并返回所在位置 |
erase() | 刪除對應(yīng)位置的元素,并且返回該元素的下一個位置 |
substr | 在 str 中從pos位置截取 n 個字符,并返回 |
push_back(char c)
這個函數(shù)一次只能在字符串尾端放一個字符;
可以直接放,也能夠放char類型的變量;
void test10()
{
string s1 = "hello world!";
char a = 'a';
cout<< s1<< endl;
s1.push_back('!');
s1.push_back('!');
s1.push_back('!');
s1.push_back('!');
s1.push_back(a);
cout<< s1<< endl;
}
這里可以看到成功的在尾端放入了字符;
append(const char * s)
append(const char* s ,size_t n)
append(const string & s)
append(const string& s,size_t subpos,size_t sublen);
append(size_t n ,char c)
template
append(InputIterator first,InputIterator last)
append這個函數(shù)有比較多的重載,接下來我們看看這些重載都是怎么用的吧:
void test10()
{
string s1 = "hello world!";
cout<< s1<< endl;
//append(const char * s)
s1.append("!!!");//添加!?。〉絪1尾部
cout<< s1<< endl;
//append(const char* s ,size_t n)
s1.append("++++++",5);//有6個 + ,但只加了5個上去
s1.append("@", 5);//n為5,但是由于字符串只有一個@,因此只加一個@
cout<< s1<< endl;
string s2 = "how are you?";
//append(const string & s)
s1.append(s2);//將s2添加上去
cout<< s1<< endl;
//append(const string& s,size_t subpos,size_t sublen);
s1.append(s2, 4,3);//在 s2 中從 subpos位置開始添加sublen長度的字符串到s1中
cout<< s1<< endl;
//append(size_t n ,char c)
s1.append(5, '*');//添加n個c到s1中
cout<< s1<< endl;
//template//append(InputIterator first,InputIterator last)
string s3 = "goodbye!";
s1.append(s3.begin(), s3.begin() + 3);//將s3中從begin()位置開始到begin()+3位置的字符添加到s1中
cout<< s1<< endl;
}
用法如上
operator+=?
相比于 append ,+= 的重載就比較少;
它的用法就是單純的將 += 右邊的字符串添加到左邊字符串的尾端;
也是比較常用的一種接口;?
void test11()
{
string s1 = "hello world!";
s1 += "!!";
cout<< s1<< endl;
string s2 = "how are you?";
s1 += s2;
cout<< s1<< endl;
s1 += '#';
cout<< s1<< endl;
}
const char* c_str() const
c_str()是一個普通的函數(shù),就是返回string對象中的c字符串;
void test11()
{
string s1 = "hello world!";
cout<< s1.c_str()<< endl;
}
find(const string& s,size_t pos = 0)
find(const char* s,size_t pos = 0)
find(const char* s,size_t pos,size_t n)
find(char c,size_t pos = 0)
該函數(shù)就是在對象找尋找對應(yīng)字符的位置,并且返回,若是沒找到就會返回-1;
void test11()
{
string s1 = "hello world!";
string s2 = " wo";
//find(const string& s,size_t pos = 0)
int pos = s1.find(s2);//默認從0位置開始找
cout<< pos<< endl;
pos = s1.find(s2, 3);//從3位置開始找
cout<< pos<< endl;
//find(const char* s,size_t pos = 0)
pos = s1.find("llo", 0);//從0位置開始找
cout<< pos<< endl;
//find(const char* s,size_t pos,size_t n)
pos = s1.find("ld!",0,5);//從0位置開始找,只找5個位置
cout<< pos<< endl;
//find(char c,size_t pos = 0)
pos = s1.find('d', 0);//從0位置開始找
cout<< pos<< endl;
}
rfind(const string& s,size_t pos = npos)
rfind(const char* s,size_t pos = npos)
rfind(const char* s,size_t pos,size_t n)
rfind(char c,size_t pos = npos)
rfind?和 find 的使用方式一樣,只不過是向前尋找,就不做多解釋了;
而上面的 npos 實際上就是表示 string 字符串的尾部,因為 rfind 是向前尋找,因此缺省值給的尾部值;
erase(iterator p)
該函數(shù)會刪除p位置的元素,然后將后面的元素一個一個往前移,然后返回p元素的下一個元素的位置;
void test1()
{
string s1 = "abcd";
string::iterator is1 = s1.begin();
is1 = s1.erase(is1);
cout<< *is1<< endl;
}
當使用erase函數(shù)的時候,若是在erase函數(shù)前面容器擴容了,就會導(dǎo)致迭代器失效
因此需要更新迭代器位置;
substr(size_t pos = 0,size_t? len = npos)
void test12()
{
string s1 = "hello world!";
cout<
這個函數(shù)就是在字符串中從 pos 位置截取 len 長度的字符并返回;
不過原字符串不會消失;
string的其他函數(shù)
函數(shù)名 | 功能 |
operator+ | 將兩個string或者字符串加起來并返回 |
operator>> | 整體輸入string類 |
operator<< | 整體輸出string類 |
getline() | 以行接收string類 |
relational_operators | 比較大小 |
operator+?
void test13()
{
string s1 = "hello world!";
cout<< s1<< endl;
s1 = s1 + "!!!";
cout<< s1<< endl;
}
這是一個運算符重載,返回一個 + 左邊的字符串在前,右邊的字符串在后組合而成的字符串;
當然,它也可以多個字符串相加;
void test13()
{
string s1 = "hello world!";
cout<< s1<< endl;
s1 = s1 + "!!!";
cout<< s1<< endl;
s1 = "!!!" + s1 + "!!!";
cout<< s1<< endl;
}
operator>>/ operator<<
這兩個其實在前面就已經(jīng)用過多次了:
void test13()
{
string s1;
cin >>s1;
cout<< s1;
}
其中的 operator>>和普通的輸入一樣,遇見空格或者換行就會中斷,如上圖;
getline(istream& in,string& s,char delim)
getline(istream& in,string& s)
為了能夠按行輸入string,c++有 getline 函數(shù);
一種形式是遇到和 delim 相同的字符就停止
void test13()
{
string s1;
//getline(istream& in,string& s,char delim)
getline(cin, s1,'o');//按行接收字符串,遇到delim就結(jié)束,這里遇到o就不接收
cout<< s1<< endl;
}
一種解釋單純的按行接收
void test13()
{
string s1;
//getline(istream& in,string& s)
getline(cin, s1);//按行接收字符串
cout<< s1<< endl;
}
以上就是string類常用的幾種函數(shù)。
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧