本專欄內(nèi)容為:C++學(xué)習(xí)專欄,分為初階和進(jìn)階兩部分。 通過(guò)本專欄的深入學(xué)習(xí),你可以了解并掌握C++。
??博主csdn個(gè)人主頁(yè):小小unicorn
?專欄分類:C++
??代碼倉(cāng)庫(kù):小小unicorn的代碼倉(cāng)庫(kù)??
??????關(guān)注我?guī)銓W(xué)習(xí)編程知識(shí)
string各函數(shù)接口總覽
namespace NIC
{
//模擬實(shí)現(xiàn)string類
class string
{
public:
typedef char* iterator;
typedef const char* const_iterator;
//默認(rèn)成員函數(shù)
string(const char* str = ""); //構(gòu)造函數(shù)
string(const string& s); //拷貝構(gòu)造函數(shù)
string& operator=(const string& s); //賦值運(yùn)算符重載函數(shù)
~string(); //析構(gòu)函數(shù)
//迭代器相關(guān)函數(shù)
iterator begin();
iterator end();
const_iterator begin()const;
const_iterator end()const;
//容量和大小相關(guān)函數(shù)
size_t size();
size_t capacity();
void reserve(size_t n);
void resize(size_t n, char ch = '\0');
bool empty()const;
//修改字符串相關(guān)函數(shù)
void push_back(char ch);
void append(const char* str);
string& operator+=(char ch);
string& operator+=(const char* str);
string& insert(size_t pos, char ch);
string& insert(size_t pos, const char* str);
string& erase(size_t pos, size_t len);
void clear();
void swap(string& s);
const char* c_str()const;
//訪問(wèn)字符串相關(guān)函數(shù)
char& operator[](size_t i);
const char& operator[](size_t i)const;
size_t find(char ch, size_t pos = 0)const;
size_t find(const char* str, size_t pos = 0)const;
size_t rfind(char ch, size_t pos = npos)const;
size_t rfind(const char* str, size_t pos = 0)const;
//關(guān)系運(yùn)算符重載函數(shù)
bool operator>(const string& s)const;
bool operator>=(const string& s)const;
bool operator<(const string& s)const;
bool operator<=(const string& s)const;
bool operator==(const string& s)const;
bool operator!=(const string& s)const;
private:
char* _str; //存儲(chǔ)字符串
size_t _size; //記錄字符串當(dāng)前的有效長(zhǎng)度
size_t _capacity; //記錄字符串當(dāng)前的容量
static const size_t npos; //靜態(tài)成員變量(整型最大值)
};
const size_t string::npos = -1;
//<<和>>運(yùn)算符重載函數(shù)
istream& operator>>(istream& in, string& s);
ostream& operator<<(ostream& out, const string& s);
istream& getline(istream& in, string& s);
}
注:為了防止與標(biāo)準(zhǔn)庫(kù)當(dāng)中的string類產(chǎn)生命名沖突,模擬實(shí)現(xiàn)時(shí)需放在自己的命名空間當(dāng)中。
默認(rèn)成員函數(shù):
構(gòu)造函數(shù)
構(gòu)造函數(shù)設(shè)置為缺省參數(shù),若不傳入?yún)?shù),則默認(rèn)構(gòu)造為空字符串。字符串的初始大小和容量均設(shè)置為傳入C字符串的長(zhǎng)度(不包括’\0’)
//構(gòu)造函數(shù)
string(const char* str = "")
:_size(strlen(str))//初始時(shí),字符串大小設(shè)置為字符串長(zhǎng)度
, _capacity(_size)///初始時(shí),字符串容量設(shè)置為字符串長(zhǎng)度
{
_str = new char[_capacity + 1];//為存儲(chǔ)字符開(kāi)辟空間(多開(kāi)一個(gè)用于存放'\0')
strcpy(_str, str);//將字符串拷貝到已經(jīng)開(kāi)好的空間
}
拷貝構(gòu)造函數(shù)
在模擬實(shí)現(xiàn)拷貝之前,先了解一下深淺拷貝問(wèn)題:
淺拷貝:拷貝出來(lái)的目標(biāo)對(duì)象的指針和源對(duì)象的指針指向的內(nèi)存空間是同一塊空間。其中一個(gè)對(duì)象的改動(dòng)會(huì)對(duì)另一個(gè)對(duì)象造成影響。
深拷貝:深拷貝是指源對(duì)象與拷貝對(duì)象互相獨(dú)立。其中任何一個(gè)對(duì)象的改動(dòng)不會(huì)對(duì)另外一個(gè)對(duì)象造成影響。
很明顯,我們并不希望拷貝出來(lái)的兩個(gè)對(duì)象之間存在相互影響,因此,我們這里需要用到深拷貝。下面提供深拷貝的兩種寫法:
1.傳統(tǒng)寫法:
傳統(tǒng)寫法的思想:先開(kāi)辟一塊足以容納源對(duì)象字符串的空間,然后將源對(duì)象的字符串拷貝過(guò)去,接著把源對(duì)象的其他成員變量也賦值過(guò)去即可。因?yàn)榭截悓?duì)象的_str與源對(duì)象的_str指向的并不是同一塊空間,所以拷貝出來(lái)的對(duì)象與源對(duì)象是互相獨(dú)立的。
// 傳統(tǒng)寫法
// s2(s1)
string(const string& s)
{
_str = new char[s._capacity+1];
strcpy(_str, s._str);//將s._str拷貝一份到_str
_size = s._size;//_size賦值
_capacity = s._capacity;//_capacity賦值
}
2.現(xiàn)代寫法
現(xiàn)代寫法與傳統(tǒng)寫法的思想不同:先根據(jù)源字符串的C字符串調(diào)用構(gòu)造函數(shù)構(gòu)造一個(gè)tmp對(duì)象,然后再將tmp對(duì)象與拷貝對(duì)象的數(shù)據(jù)交換即可。拷貝對(duì)象的_str與源對(duì)象的_str指向的也不是同一塊空間,是互相獨(dú)立的。
//現(xiàn)代寫法
// s2(s1)
string(const string& s)
:_str(nullptr)
, _size(0)
, _capacity(0)
{
string tmp(s._str);//調(diào)用構(gòu)造函數(shù)
swap(tmp);//交換這兩個(gè)對(duì)象
}
注:swap成員函數(shù)的模擬實(shí)現(xiàn)在文章的后面。
析構(gòu)函數(shù)
string類的析構(gòu)函數(shù)需要我們進(jìn)行編寫,因?yàn)槊總€(gè)string對(duì)象中的成員_str都指向堆區(qū)的一塊空間,當(dāng)對(duì)象銷毀時(shí)堆區(qū)對(duì)應(yīng)的空間并不會(huì)自動(dòng)銷毀,為了避免內(nèi)存泄漏,我們需要使用delete手動(dòng)釋放堆區(qū)的空間。
//析構(gòu)函數(shù)
~string()
{
delete[] _str; //釋放_(tái)str指向的空間
_str = nullptr; //及時(shí)置空,防止非法訪問(wèn)
_size = 0; //大小置0
_capacity = 0; //容量置0
}
賦值運(yùn)算符重載函數(shù)
與拷貝構(gòu)造函數(shù)類似,賦值運(yùn)算符重載函數(shù)的模擬實(shí)現(xiàn)也涉及深淺拷貝問(wèn)題,我們同樣需要采用深拷貝。下面也提供深拷貝的兩種寫法:
1.傳統(tǒng)寫法
賦值運(yùn)算符重載函數(shù)的傳統(tǒng)寫法與拷貝構(gòu)造函數(shù)的傳統(tǒng)寫法幾乎相同,只是左值的_str在開(kāi)辟新空間之前需要先將原來(lái)的空間釋放掉,并且在進(jìn)行操作之前還需判斷是否是自己給自己賦值,若是自己給自己賦值,則無(wú)需進(jìn)行任何操作。
//傳統(tǒng)寫法
string& operator=(const string& s)
{
if (this != &s) //防止自己給自己賦值
{
delete[] _str; //將原來(lái)_str指向的空間釋放
_str = new char[s._capacity + 1]; //重新申請(qǐng)一塊空間
strcpy(_str, s._str); //將s._str拷貝一份到_str
_size = s._size; //_size賦值
_capacity = s._capacity; //_capacity賦值
}
return *this; //返回左值(支持連續(xù)賦值)
}
1.現(xiàn)代寫法
賦值運(yùn)算符重載函數(shù)的現(xiàn)代寫法與拷貝構(gòu)造函數(shù)的現(xiàn)代寫法也是非常類似,但拷貝構(gòu)造函數(shù)的現(xiàn)代寫法是通過(guò)代碼語(yǔ)句調(diào)用構(gòu)造函數(shù)構(gòu)造出一個(gè)對(duì)象,然后將該對(duì)象與拷貝對(duì)象交換;而賦值運(yùn)算符重載函數(shù)的現(xiàn)代寫法是通過(guò)采用“值傳遞”接收右值的方法,讓編譯器自動(dòng)調(diào)用拷貝構(gòu)造函數(shù),然后我們?cè)賹⒖截惓鰜?lái)的對(duì)象與左值進(jìn)行交換即可。
//現(xiàn)代寫法1
string& operator=(string s) //編譯器接收右值的時(shí)候自動(dòng)調(diào)用拷貝構(gòu)造函數(shù)
{
swap(s); //交換這兩個(gè)對(duì)象
return *this; //返回左值(支持連續(xù)賦值)
}
但這種寫法無(wú)法避免自己給自己賦值,就算是自己給自己賦值這些操作也會(huì)進(jìn)行,雖然操作之后對(duì)象中_str指向的字符串的內(nèi)容不變,但是字符串存儲(chǔ)的地址發(fā)生了改變,為了避免這種操作我們可以采用下面這種寫法:
//現(xiàn)代寫法2
string& operator=(const string& s)
{
if (this != &s) //防止自己給自己賦值
{
string tmp(s); //用s拷貝構(gòu)造出對(duì)象tmp
swap(tmp); //交換這兩個(gè)對(duì)象
}
return *this; //返回左值(支持連續(xù)賦值)
}
但實(shí)際中很少出現(xiàn)自己給自己賦值的情況,所以采用“現(xiàn)代寫法1”就行了。
迭代器相關(guān)函數(shù)
string類中的迭代器可以認(rèn)為是就是字符指針(原生指針),只是給字符指針起了一個(gè)別名叫iterator而已。但并不是說(shuō)所有迭代器都是指針。
typedef char* iterator;
typedef const char* const_iterator;
begin與end
string類中的begin和end函數(shù)的實(shí)現(xiàn)簡(jiǎn)單,begin函數(shù)的作用就是返回字符串中第一個(gè)字符的地址:
iterator begin()
{
return _str; //返回字符串中第一個(gè)字符的地址
}
const_iterator begin()const
{
return _str; //返回字符串中第一個(gè)字符的const地址
}
end函數(shù)的作用就是返回字符串中最后一個(gè)字符的后一個(gè)字符的地址(即’\0’的地址):
iterator end()
{
return _str + _size; //返回字符串中最后一個(gè)字符的后一個(gè)字符的地址
}
const_iterator end()const
{
return _str + _size; //返回字符串中最后一個(gè)字符的后一個(gè)字符的const地址
}
在明白了string類中迭代器的底層實(shí)現(xiàn),再來(lái)看看我們用迭代器遍歷string的代碼,其實(shí)就是用指針在遍歷字符串而已。
string s("hello world!!!");
string::iterator it = s.begin();
while (it != s.end())
{
cout << *it << " ";
it++;
}
cout << endl;
在string介紹中我們還說(shuō)到,可以用范圍for來(lái)遍歷string,可能很多初學(xué)者都會(huì)覺(jué)得范圍for是個(gè)很神奇的東西,只需要一點(diǎn)點(diǎn)代碼就能實(shí)現(xiàn)string的遍歷。
實(shí)際上范圍for并不神奇,因?yàn)樵诖a編譯的時(shí)候,編譯器會(huì)自動(dòng)將范圍for替換為迭代器的形式,也就是說(shuō)范圍for是由迭代器支持的,現(xiàn)在我們已經(jīng)實(shí)現(xiàn)了string類的迭代器,自然也能用范圍for對(duì)string進(jìn)行遍歷:
string s("hello world!!!");
//編譯器將其替換為迭代器形式
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
容量相關(guān):
size和capacity
因?yàn)閟tring類的成員變量是私有的,我們并不能直接對(duì)其進(jìn)行訪問(wèn),所以string類設(shè)置了size和capacity這兩個(gè)成員函數(shù),用于獲取string對(duì)象的大小和容量。
size函數(shù)用于獲取字符串當(dāng)前的有效長(zhǎng)度(不包括’\0’)。
//大小
size_t size()const
{
return _size; //返回字符串當(dāng)前的有效長(zhǎng)度
}
capacity函數(shù)用于獲取字符串當(dāng)前的容量。
//容量
size_t capacity()const
{
return _capacity; //返回字符串當(dāng)前的容量
}
reserve與resize
reserve和resize這兩個(gè)函數(shù)的執(zhí)行規(guī)則一定要區(qū)分清楚。
reserve規(guī)則:
?1、當(dāng)n大于對(duì)象當(dāng)前的capacity時(shí),將capacity擴(kuò)大到n或大于n。
?2、當(dāng)n小于對(duì)象當(dāng)前的capacity時(shí),什么也不做。
//改變?nèi)萘?,大小不?/span>
void reserve(size_t n)
{
if (n > _capacity) //當(dāng)n大于對(duì)象當(dāng)前容量時(shí)才需執(zhí)行操作
{
char* tmp = new char[n + 1]; //多開(kāi)一個(gè)空間用于存放'\0'
strncpy(tmp, _str, _size + 1); //將對(duì)象原本的C字符串拷貝過(guò)來(lái)(包括'\0')
delete[] _str; //釋放對(duì)象原本的空間
_str = tmp; //將新開(kāi)辟的空間交給_str
_capacity = n; //容量跟著改變
}
}
注意:代碼中使用strncpy進(jìn)行拷貝對(duì)象C字符串而不是strcpy,是為了防止對(duì)象的C字符串中含有有效字符’\0’而無(wú)法拷貝(strcpy拷貝到第一個(gè)’\0’就結(jié)束拷貝了)。
resize規(guī)則:
?1、當(dāng)n大于當(dāng)前的size時(shí),將size擴(kuò)大到n,擴(kuò)大的字符為ch,若ch未給出,則默認(rèn)為’\0’。
?2、當(dāng)n小于當(dāng)前的size時(shí),將size縮小到n。
//改變大小
void resize(size_t n, char ch = '\0')
{
if (n <= _size) //n小于當(dāng)前size
{
_size = n; //將size調(diào)整為n
_str[_size] = '\0'; //在size個(gè)字符后放上'\0'
}
else //n大于當(dāng)前的size
{
if (n > _capacity) //判斷是否需要擴(kuò)容
{
reserve(n); //擴(kuò)容
}
for (size_t i = _size; i < n; i++) //將size擴(kuò)大到n,擴(kuò)大的字符為ch
{
_str[i] = ch;
}
_size = n; //size更新
_str[_size] = '\0'; //字符串后面放上'\0'
}
}
empty
empty是string的判空函數(shù),我們可以調(diào)用strcmp函數(shù)來(lái)實(shí)現(xiàn),strcmp函數(shù)是用于比較兩個(gè)字符串大小的函數(shù),當(dāng)兩個(gè)字符串相等時(shí)返回0。
//判空
bool empty()
{
return strcmp(_str, "") == 0;
}
注意:兩個(gè)字符串相比較千萬(wàn)不能用 == 。
訪問(wèn)字符串相關(guān)函數(shù)
operator[ ]
[ ]運(yùn)算符的重載是為了讓string對(duì)象能像C字符串一樣,通過(guò)[ ] +下標(biāo)的方式獲取字符串對(duì)應(yīng)位置的字符。
在C字符串中我們通過(guò)[ ] +下標(biāo)的方式可以獲取字符串對(duì)應(yīng)位置的字符,并可以對(duì)其進(jìn)行修改,實(shí)現(xiàn)[ ] 運(yùn)算符的重載時(shí)只需返回對(duì)象C字符串對(duì)應(yīng)位置字符的引用即可,這樣便能實(shí)現(xiàn)對(duì)該位置的字符進(jìn)行讀取和修改操作了,但需要注意在此之前檢測(cè)所給下標(biāo)的合法性。
//[]運(yùn)算符重載(可讀可寫)
char& operator[](size_t i)
{
assert(i < _size); //檢測(cè)下標(biāo)的合法性
return _str[i]; //返回對(duì)應(yīng)字符
}
在某些場(chǎng)景下,我們可能只能用[ ] +下標(biāo)的方式讀取字符而不能對(duì)其進(jìn)行修改。
例如,對(duì)一個(gè)const的string類對(duì)象進(jìn)行[ ] +下標(biāo)的操作,我們只能讀取所得到的字符,而不能對(duì)其進(jìn)行修改。所以我們需要再重載一個(gè)[ ] 運(yùn)算符,用于只讀操作。
//[]運(yùn)算符重載(只讀)
const char& operator[](size_t i)const
{
assert(i < _size); //檢測(cè)下標(biāo)的合法性
return _str[i]; //返回對(duì)應(yīng)字符
}
find和rfind
find函數(shù)和rfind函數(shù)都是用于在字符串中查找一個(gè)字符或是字符串,find函數(shù)和rfind函數(shù)分別用于正向查找和反向查找,即從字符串開(kāi)頭開(kāi)始向后查找和從字符串末尾開(kāi)始向前查找。
find函數(shù):
1、正向查找第一個(gè)匹配的字符。
首先判斷所給pos的合法性,然后通過(guò)遍歷的方式從pos位置開(kāi)始向后尋找目標(biāo)字符,若找到,則返回其下標(biāo);若沒(méi)有找到,則返回npos。(npos是string類的一個(gè)靜態(tài)成員變量,其值為整型最大值)
//正向查找第一個(gè)匹配的字符
size_t find(char ch, size_t pos = 0)
{
assert(pos < _size); //檢測(cè)下標(biāo)的合法性
for (size_t i = pos; i < _size; i++) //從pos位置開(kāi)始向后尋找目標(biāo)字符
{
if (_str[i] == ch)
{
return i; //找到目標(biāo)字符,返回其下標(biāo)
}
}
return npos; //沒(méi)有找到目標(biāo)字符,返回npos
}
2、正向查找第一個(gè)匹配的字符串。
首先也是先判斷所給pos的合法性,然后我們可以通過(guò)調(diào)用strstr函數(shù)進(jìn)行查找。strstr函數(shù)若是找到了目標(biāo)字符串會(huì)返回字符串的起始位置,若是沒(méi)有找到會(huì)返回一個(gè)空指針。若是找到了目標(biāo)字符串,我們可以通過(guò)計(jì)算目標(biāo)字符串的起始位置和對(duì)象C字符串的起始位置的差值,進(jìn)而得到目標(biāo)字符串起始位置的下標(biāo)。
//正向查找第一個(gè)匹配的字符串
size_t find(const char* str, size_t pos = 0)
{
assert(pos < _size); //檢測(cè)下標(biāo)的合法性
const char* ret = strstr(_str + pos, str); //調(diào)用strstr進(jìn)行查找
if (ret) //ret不為空指針,說(shuō)明找到了
{
return ret - _str; //返回字符串第一個(gè)字符的下標(biāo)
}
else //沒(méi)有找到
{
return npos; //返回npos
}
}
rfind函數(shù):
實(shí)現(xiàn)rfind函數(shù)時(shí),我們可以考慮復(fù)用已經(jīng)寫好了的兩個(gè)find函數(shù),但rfind函數(shù)是從后先前找,所以我們需要將對(duì)象的C字符串逆置一下,若是查找字符串,還需將待查找的字符串逆置一下,然后調(diào)用find函數(shù)進(jìn)行查找,但注意傳入find函數(shù)的pos以及從find函數(shù)接收到的pos都需要鏡像對(duì)稱一下。
1、反向查找第一個(gè)匹配的字符。
首先我們需要用對(duì)象拷貝構(gòu)造一個(gè)臨時(shí)對(duì)象tmp,因?yàn)槲覀儾⒉幌M{(diào)用rfind函數(shù)后對(duì)象的C字符串就被逆置了。我們將tmp對(duì)象的C字符串逆置,然后將所給pos鏡像對(duì)稱一下再調(diào)用find函數(shù),再將從find函數(shù)接收到的返回值鏡像對(duì)稱一下作為rfind函數(shù)的返回值返回即可。
//反向查找第一個(gè)匹配的字符
size_t rfind(char ch, size_t pos = npos)
{
string tmp(*this); //拷貝構(gòu)造對(duì)象tmp
reverse(tmp.begin(), tmp.end()); //調(diào)用reverse逆置對(duì)象tmp的C字符串
if (pos >= _size) //所給pos大于字符串有效長(zhǎng)度
{
pos = _size - 1; //重新設(shè)置pos為字符串最后一個(gè)字符的下標(biāo)
}
pos = _size - 1 - pos; //將pos改為鏡像對(duì)稱后的位置
size_t ret = tmp.find(ch, pos); //復(fù)用find函數(shù)
if (ret != npos)
return _size - 1 - ret; //找到了,返回ret鏡像對(duì)稱后的位置
else
return npos; //沒(méi)找到,返回npos
}
注:rfind函數(shù)規(guī)定,當(dāng)所給的pos大于等于字符串的有效長(zhǎng)度時(shí),看作所給pos為字符串最后一個(gè)字符的下標(biāo)。
2、反向查找第一個(gè)匹配的字符串。
首先我們還是需要用對(duì)象拷貝構(gòu)造一個(gè)臨時(shí)對(duì)象tmp,然后將tmp對(duì)象的C字符串逆置,同時(shí)我們還需要拷貝一份待查找的字符串,也將其逆置。然后將所給pos鏡像對(duì)稱一下再調(diào)用find函數(shù)。注意:此時(shí)我們將從find函數(shù)接收到的值鏡面對(duì)稱后,得到的是待查找字符串的最后一個(gè)字符在對(duì)象C字符串中的位置,而我們需要返回的是待查找字符串在對(duì)象C字符串中的第一個(gè)字符的位置,所以還需做進(jìn)一步調(diào)整后才能作為rfind函數(shù)的返回值返回。
//反向查找第一個(gè)匹配的字符串
size_t rfind(const char* str, size_t pos = npos)
{
string tmp(*this); //拷貝構(gòu)造對(duì)象tmp
reverse(tmp.begin(), tmp.end()); //調(diào)用reverse逆置對(duì)象tmp的C字符串
size_t len = strlen(str); //待查找的字符串的長(zhǎng)度
char* arr = new char[len + 1]; //開(kāi)辟arr字符串(用于拷貝str字符串)
strcpy(arr, str); //拷貝str給arr
size_t left = 0, right = len - 1; //設(shè)置左右指針
//逆置字符串a(chǎn)rr
while (left < right)
{
::swap(arr[left], arr[right]);
left++;
right--;
}
if (pos >= _size) //所給pos大于字符串有效長(zhǎng)度
{
pos = _size - 1; //重新設(shè)置pos為字符串最后一個(gè)字符的下標(biāo)
}
pos = _size - 1 - pos; //將pos改為鏡像對(duì)稱后的位置
size_t ret = tmp.find(arr, pos); //復(fù)用find函數(shù)
delete[] arr; //銷毀arr指向的空間,避免內(nèi)存泄漏
if (ret != npos)
return _size - ret - len; //找到了,返回ret鏡像對(duì)稱后再調(diào)整的位置
else
return npos; //沒(méi)找到,返回npos
}
修改字符串相關(guān)函數(shù)
push_back
push_back函數(shù)的作用就是在當(dāng)前字符串的后面尾插上一個(gè)字符,尾插之前首先需要判斷是否需要增容,若需要,則調(diào)用reserve函數(shù)進(jìn)行增容,然后再尾插字符,注意尾插完字符后需要在該字符的后方設(shè)置上’\0’,否則打印字符串的時(shí)候會(huì)出現(xiàn)非法訪問(wèn),因?yàn)槲膊宓淖址蠓讲灰欢ň褪恰痋0’
//尾插字符
void push_back(char ch)
{
if (_size == _capacity) //判斷是否需要增容
{
reserve(_capacity == 0 ? 4 : _capacity * 2); //將容量擴(kuò)大為原來(lái)的兩倍
}
_str[_size] = ch; //將字符尾插到字符串
_str[_size + 1] = '\0'; //字符串后面放上'\0'
_size++; //字符串的大小加一
}
實(shí)現(xiàn)push_back還可以直接復(fù)用下面即將實(shí)現(xiàn)的insert函數(shù)。
//尾插字符
void push_back(char ch)
{
insert(_size, ch); //在字符串末尾插入字符ch
}
append
append函數(shù)的作用是在當(dāng)前字符串的后面尾插一個(gè)字符串,尾插前需要判斷當(dāng)前字符串的空間能否容納下尾插后的字符串,若不能,則需要先進(jìn)行增容,然后再將待尾插的字符串尾插到對(duì)象的后方,因?yàn)榇膊宓淖址蠓阶陨韼в小痋0’,所以我們無(wú)需再在后方設(shè)置’\0’。
//尾插字符串
void append(const char* str)
{
size_t len = _size + strlen(str); //尾插str后字符串的大?。ú话?\0')
if (len > _capacity) //判斷是否需要增容
{
reserve(len); //增容
}
strcpy(_str + _size, str); //將str尾插到字符串后面
_size = len; //字符串大小改變
}
實(shí)現(xiàn)append函數(shù)也可以直接復(fù)用下面即將實(shí)現(xiàn)的insert函數(shù)。
//尾插字符串
void append(const char* str)
{
insert(_size, str); //在字符串末尾插入字符串str
}
operator+=
+=運(yùn)算符的重載是為了實(shí)現(xiàn)字符串與字符、字符串與字符串之間能夠直接使用+=運(yùn)算符進(jìn)行尾插。
+=運(yùn)算符實(shí)現(xiàn)字符串與字符之間的尾插直接調(diào)用push_back函數(shù)即可。
//+=運(yùn)算符重載
string& operator+=(char ch)
{
push_back(ch); //尾插字符串
return *this; //返回左值(支持連續(xù)+=)
}
+=運(yùn)算符實(shí)現(xiàn)字符串與字符串之間的尾插直接調(diào)用append函數(shù)即可。
//+=運(yùn)算符重載
string& operator+=(const char* str)
{
append(str); //尾插字符串
return *this; //返回左值(支持連續(xù)+=)
}
insert
insert函數(shù)的作用是在字符串的任意位置插入字符或是字符串。
insert函數(shù)用于插入字符時(shí),首先需要判斷pos的合法性,若不合法則無(wú)法進(jìn)行操作,緊接著還需判斷當(dāng)前對(duì)象能否容納插入字符后的字符串,若不能則還需調(diào)用reserve函數(shù)進(jìn)行擴(kuò)容。插入字符的過(guò)程也是比較簡(jiǎn)單的,先將pos位置及其后面的字符統(tǒng)一向后挪動(dòng)一位,給待插入的字符留出位置,然后將字符插入字符串即可。
//在pos位置插入字符
string& insert(size_t pos, char ch)
{
assert(pos <= _size); //檢測(cè)下標(biāo)的合法性
if (_size == _capacity) //判斷是否需要增容
{
reserve(_capacity == 0 ? 4 : _capacity * 2); //將容量擴(kuò)大為原來(lái)的兩倍
}
char* end = _str + _size;
//將pos位置及其之后的字符向后挪動(dòng)一位
while (end >= _str + pos)
{
*(end + 1) = *(end);
end--;
}
_str[pos] = ch; //pos位置放上指定字符
_size++; //size更新
return *this;
}
insert函數(shù)用于插入字符串時(shí),首先也是判斷pos的合法性,若不合法則無(wú)法進(jìn)行操作,再判斷當(dāng)前對(duì)象能否容納插入該字符串后的字符串,若不能則還需調(diào)用reserve函數(shù)進(jìn)行擴(kuò)容。插入字符串時(shí),先將pos位置及其后面的字符統(tǒng)一向后挪動(dòng)len位(len為待插入字符串的長(zhǎng)度),給待插入的字符串留出位置,然后將其插入字符串即可。
//在pos位置插入字符串
string& insert(size_t pos, const char* str)
{
assert(pos <= _size); //檢測(cè)下標(biāo)的合法性
size_t len = strlen(str); //計(jì)算需要插入的字符串的長(zhǎng)度(不含'\0')
if (len + _size > _capacity) //判斷是否需要增容
{
reserve(len + _size); //增容
}
char* end = _str + _size;
//將pos位置及其之后的字符向后挪動(dòng)len位
while (end >= _str + pos)
{
*(end + len) = *(end);
end--;
}
strncpy(_str + pos, str, len); //pos位置開(kāi)始放上指定字符串
_size += len; //size更新
return *this;
}
注意:插入字符串的時(shí)候使用strncpy,不能使用strcpy,否則會(huì)將待插入的字符串后面的’\0’也插入到字符串中。
erase
erase函數(shù)的作用是刪除字符串任意位置開(kāi)始的n個(gè)字符。刪除字符前也需要判斷pos的合法性,進(jìn)行刪除操作的時(shí)候分兩種情況:
1、pos位置及其之后的有效字符都需要被刪除。
這時(shí)我們只需在pos位置放上’\0’,然后將對(duì)象的size更新即可。
2、pos位置及其之后的有效字符只需刪除一部分。
這時(shí)我們可以用后方需要保留的有效字符覆蓋前方需要?jiǎng)h除的有效字符,此時(shí)不用在字符串后方加’\0’,因?yàn)樵诖酥白址┪簿陀小痋0’了。
//刪除pos位置開(kāi)始的len個(gè)字符
string& erase(size_t pos, size_t len = npos)
{
assert(pos < _size); //檢測(cè)下標(biāo)的合法性
size_t n = _size - pos; //pos位置及其后面的有效字符總數(shù)
if (len >= n) //說(shuō)明pos位置及其后面的字符都被刪除
{
_size = pos; //size更新
_str[_size] = '\0'; //字符串后面放上'\0'
}
else //說(shuō)明pos位置及其后方的有效字符需要保留一部分
{
strcpy(_str + pos, _str + pos + len); //用需要保留的有效字符覆蓋需要?jiǎng)h除的有效字符
_size -= len; //size更新
}
return *this;
}
clear函數(shù)用于將對(duì)象中存儲(chǔ)的字符串置空,實(shí)現(xiàn)時(shí)直接將對(duì)象的_size置空,然后在字符串后面放上’\0’即可。
//清空字符串
void clear()
{
_size = 0; //size置空
_str[_size] = '\0'; //字符串后面放上'\0'
}
swap
swap函數(shù)用于交換兩個(gè)對(duì)象的數(shù)據(jù),直接調(diào)用庫(kù)里的swap模板函數(shù)將對(duì)象的各個(gè)成員變量進(jìn)行交換即可。
但我們?nèi)羰窍朐谶@里調(diào)用庫(kù)里的swap模板函數(shù),需要在swap函數(shù)之前加上“::”(作用域限定符),告訴編譯器優(yōu)先在全局范圍尋找swap函數(shù),否則編譯器編譯時(shí)會(huì)認(rèn)為你調(diào)用的是正在實(shí)現(xiàn)的swap函數(shù)(就近原則)。
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
c_str
c_str函數(shù)用于獲取對(duì)象C類型的字符串,實(shí)現(xiàn)時(shí)直接返回對(duì)象的成員變量_str即可。
//返回C類型的字符串
const char* c_str()const
{
return _str;
}
關(guān)系運(yùn)算符重載函數(shù)
關(guān)系運(yùn)算符有 >、>=、<、<=、==、!= 這六個(gè),但是對(duì)于C++中任意一個(gè)類的關(guān)系運(yùn)算符重載,我們均只需重載其中的兩個(gè),剩下的四個(gè)關(guān)系運(yùn)算符可以通過(guò)復(fù)用已經(jīng)重載好了的兩個(gè)關(guān)系運(yùn)算符來(lái)實(shí)現(xiàn)。
例如,對(duì)于string類,我們可以選擇只重載 > 和 == 這兩個(gè)關(guān)系運(yùn)算符
//>運(yùn)算符重載
bool operator>(const string& s)const
{
return strcmp(_str, s._str) > 0;
}
//==運(yùn)算符重載
bool operator==(const string& s)const
{
return strcmp(_str, s._str) == 0;
}
剩下的四個(gè)關(guān)系運(yùn)算符的重載,就可以通過(guò)復(fù)用這兩個(gè)已經(jīng)重載好了的關(guān)系運(yùn)算符來(lái)實(shí)現(xiàn)了。
//>=運(yùn)算符重載
bool operator>=(const string& s)const
{
return (*this > s) || (*this == s);
}
//<運(yùn)算符重載
bool operator<(const string& s)const
{
return !(*this >= s);
}
//<=運(yùn)算符重載
bool operator<=(const string& s)const
{
return !(*this > s);
}
//!=運(yùn)算符重載
bool operator!=(const string& s)const
{
return !(*this == s);
}
>>和<<運(yùn)算符的重載以及getline函數(shù)
>>運(yùn)算符的重載
重載>>運(yùn)算符是為了讓string對(duì)象能夠像內(nèi)置類型一樣使用>>運(yùn)算符直接輸入。輸入前我們需要先將對(duì)象的C字符串置空,然后從標(biāo)準(zhǔn)輸入流讀取字符,直到讀取到’ ‘或是’\n’便停止讀取。
//>>運(yùn)算符的重載
istream& operator>>(istream& in, string& s)
{
s.clear(); //清空字符串
char ch = in.get(); //讀取一個(gè)字符
while (ch != ' '&&ch != '\n') //當(dāng)讀取到的字符不是空格或'\n'的時(shí)候繼續(xù)讀取
{
s += ch; //將讀取到的字符尾插到字符串后面
ch = in.get(); //繼續(xù)讀取字符
}
return in; //支持連續(xù)輸入
}
<<運(yùn)算符的重載
重載<<運(yùn)算符是為了讓string對(duì)象能夠像內(nèi)置類型一樣使用<<運(yùn)算符直接輸出打印。實(shí)現(xiàn)時(shí)我們可以直接使用范圍for對(duì)對(duì)象進(jìn)行遍歷即可。
//<<運(yùn)算符的重載
ostream& operator<<(ostream& out, const string& s)
{
//使用范圍for遍歷字符串并輸出
for (auto e : s)
{
cout << e;
}
return out; //支持連續(xù)輸出
}
getline
getline函數(shù)用于讀取一行含有空格的字符串。實(shí)現(xiàn)時(shí)于>>運(yùn)算符的重載基本相同,只是當(dāng)讀取到’\n’的時(shí)候才停止讀取字符。
//讀取一行含有空格的字符串
istream& getline(istream& in, string& s)
{
s.clear(); //清空字符串
char ch = in.get(); //讀取一個(gè)字符
while (ch != '\n') //當(dāng)讀取到的字符不是'\n'的時(shí)候繼續(xù)讀取
{
s += ch; //將讀取到的字符尾插到字符串后面
ch = in.get(); //繼續(xù)讀取字符
}
return in;
}
測(cè)試相關(guān)接口函數(shù):
測(cè)試1.對(duì)元素的訪問(wèn):迭代器.c_str.與運(yùn)算符重載[]
示例:
將字符串s1按照[]訪問(wèn),按照迭代器訪問(wèn),按照范圍for訪問(wèn)。
void test_string1()
{
string s1("hello world");
cout << s1.c_str() << endl;
string s2;
cout << s2.c_str() << endl;
//訪問(wèn)字符串
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1[i] ;
}
cout << endl;
//迭代器
string::iterator it = s1.begin();
while (it != s1.end())
{
//寫
(*it)++;
//讀
cout << *it << " ";
++it;
}
cout << endl;
//范圍for
for (auto& ch : s1)
{
ch++;
cout << ch << " ";
}
cout << endl;
cout << s1.c_str() << endl;
}
測(cè)試結(jié)果:
測(cè)試2.修改字符串
示例:
給s1字符串插入其他字符串,用push_back與+=
void test_string2()
{
string s1("hello world");
cout << s1.c_str() << endl;
s1.push_back(' ');
s1.append("hello bit hello bit");
cout << s1.c_str() << endl;
s1 += '#';
s1 += "*********************";
cout << s1.c_str() << endl;
string s2;
s2 += '#';
s2 += "*********************";
cout << s2.c_str() << endl;
}
測(cè)試結(jié)果:
測(cè)試3.insert
示例:
測(cè)試insert
void test_string3()
{
string s1("hello world");
cout << s1.c_str() << endl;
s1.insert(5, '%');
cout << s1.c_str() << endl;
s1.insert(s1.size(), '%');
cout << s1.c_str() << endl;
s1.insert(0, '%');
cout << s1.c_str() << endl;
}
測(cè)試結(jié)果:
測(cè)試4.關(guān)系運(yùn)算符與流插入流提取
示例:
比較s1與s2,輸入字符串并打印
void test_string4()
{
string s1("hello world");
string s2("hello world");
cout << (s1 >= s2) << endl;
s1[0] = 'z';
cout << (s1 >= s2) << endl;
cout << s1 << endl;
cin >> s1;
cout << s1 << endl;
}
測(cè)試結(jié)果:
測(cè)試5.erase
示例:
測(cè)試rease
void test_string5()
{
string s1("hello world");
s1.insert(5, "abc");
cout << s1 << endl;
s1.insert(0, "xxx");
cout << s1 << endl;
s1.erase(0, 3);
cout << s1 << endl;
s1.erase(5, 100);
cout << s1 << endl;
s1.erase(2);
cout << s1 << endl;
}
測(cè)試結(jié)果:
測(cè)試6.resize
示例:
測(cè)試resize
void test_string6()
{
string s1("hello world");
cout << s1 << endl;
s1.resize(5);
cout << s1 << endl;
s1.resize(25, 'x');
cout << s1 << endl;
}
測(cè)試結(jié)果:
測(cè)試7.find
示例:
將網(wǎng)址按照協(xié)議,域名,資源名三部分找出來(lái)。
void test_string7()
{
string s1("test.cpp.tar.zip");
//size_t i = s1.find('.');
//size_t i = s1.rfind('.');
//string s2 = s1.substr(i);
//cout << s2 << endl;
string s3("https://legacy.cplusplus.com/reference/string/string/rfind/");
//string s3("ftp://www.baidu.com/?tn=65081411_1_oem_dg");
// 協(xié)議
// 域名
// 資源名
string sub1, sub2, sub3;
size_t i1 = s3.find(':');
if (i1 != string::npos)
sub1 = s3.substr(0, i1);
else
cout << "沒(méi)有找到i1" << endl;
size_t i2 = s3.find('/', i1 + 3);
if (i2 != string::npos)
sub2 = s3.substr(i1 + 3, i2 - (i1 + 3));
else
cout << "沒(méi)有找到i2" << endl;
sub3 = s3.substr(i2 + 1);
//域名
cout << "協(xié)議" << endl;
cout << sub1 << endl;
cout << "域名" << endl;
cout << sub2 << endl;
cout << "資源名" << endl;
cout << sub3 << endl;
}
測(cè)試結(jié)果:
測(cè)試8:拷貝構(gòu)造
示例:
將s3拷貝給s2
void test_string8()
{
string s1("hello world");
string s2 = s1;
cout << s1 << endl;
cout << s2 << endl;
string s3("xxxxxxxxxxxxxxxxxxx");
s2 = s3;
cout << s2 << endl;
cout << s3 << endl;
}
結(jié)果:
測(cè)試9.容量與大小
示例:
計(jì)算字符串“hello world”的長(zhǎng)度與容量
void test_string9()
{
string s1("hello world");
cout << s1 << endl;
cout << s1.size() << endl;
cout << s1.capacity() << endl;
}
結(jié)果:
string模擬實(shí)現(xiàn)源碼
模擬實(shí)現(xiàn)中,我們沒(méi)有進(jìn)行對(duì)其定義與聲明分離,將測(cè)試函數(shù)寫成成員函數(shù)包裝在命名空間里。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-753301.html
string.h
#include<assert.h>
namespace NIC
{
class string
{
public:
//迭代器相關(guān)
typedef char* iterator;
typedef const char* const_iterator;
iterator begin()
{
return _str;//返回字符串中第一個(gè)字符的地址
}
iterator end()
{
return _str + _size; //返回字符串中最后一個(gè)字符的后一個(gè)字符的地址
}
const_iterator begin() const
{
return _str;//返回字符串中第一個(gè)字符的const地址
}
const_iterator end() const
{
return _str + _size; //返回字符串中最后一個(gè)字符的后一個(gè)字符的地址
}
/*string()
:_str(new char[1]{'\0'})
,_size(0)
,_capacity(0)
{}*/
//構(gòu)造函數(shù)
string(const char* str = "")
:_size(strlen(str))//初始時(shí),字符串大小設(shè)置為字符串長(zhǎng)度
, _capacity(_size)///初始時(shí),字符串容量設(shè)置為字符串長(zhǎng)度
{
_str = new char[_capacity + 1];//為存儲(chǔ)字符開(kāi)辟空間(多開(kāi)一個(gè)用于存放'\0')
strcpy(_str, str);//將字符串拷貝到已經(jīng)開(kāi)好的空間
}
傳統(tǒng)寫法
s2(s1)
//string(const string& s)
//{
// _str = new char[s._capacity+1];
// strcpy(_str, s._str);//將s._str拷貝一份到_str
// _size = s._size;//_size賦值
// _capacity = s._capacity;//_capacity賦值
//}
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
//現(xiàn)代寫法
// s2(s1)
string(const string& s)
:_str(nullptr)
, _size(0)
, _capacity(0)
{
string tmp(s._str);//調(diào)用構(gòu)造函數(shù)
swap(tmp);//交換這兩個(gè)對(duì)象
}
//賦值運(yùn)算符重載函數(shù)
s2 = s3
// 寫法一:
//string& operator=(const string& s)
//{
// if (this != &s)//防止自己給自己賦值
// {
// char* tmp = new char[s._capacity + 1];
// strcpy(tmp, s._str);
// delete[] _str;
// _str = tmp;
// _size = s._size;
// _capacity = s._capacity;
// }
// return *this;
//}
//寫法二:
// s2 = s3
//string& operator=(const string& s)
//{
// if (this != &s)
// {
// string tmp(s);
// //this->swap(tmp);
// swap(tmp);
// }
// return *this;
//}
//寫法一:
// s2 = s3
string& operator=(string tmp)
{
swap(tmp);
return *this;
}
//析構(gòu)函數(shù)
~string()
{
delete[] _str;//釋放_(tái)str指向的空間
_str = nullptr;//及時(shí)置空,防止非法訪問(wèn)
_size = _capacity = 0;
}
//容量相關(guān)
//大小
size_t size() const
{
return _size;
}
//容量
size_t capacity() const
{
return _capacity;
}
//reserve
void reserve(size_t n)
{
if (n > _capacity)
{
char* tmp = new char[n + 1];
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = n;
}
}
//resize
void resize(size_t n, char ch = '\0')
{
if (n <= _size)//n小于當(dāng)前size
{
_str[n] = '\0';//在size個(gè)字符后放上'\0'
_size = n;//將size調(diào)整為n
}
else//n大于當(dāng)前的size
{
reserve(n);
while (_size < n)
{
_str[_size] = ch;
++_size;
}
_str[_size] = '\0';
}
}
char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
const char& operator[](size_t pos) const
{
assert(pos < _size);
return _str[pos];
}
const char* c_str() const
{
return _str;
}
size_t find(char ch, size_t pos = 0)
{
for (size_t i = pos; i < _size; i++)
{
if (_str[i] == ch)
{
return i;
}
}
return npos;
}
size_t find(const char* sub, size_t pos = 0)
{
const char* p = strstr(_str + pos, sub);
if (p)
{
return p - _str;
}
else
{
return npos;
}
}
string substr(size_t pos, size_t len = npos)
{
string s;
size_t end = pos + len;
if (len == npos || pos + len >= _size) // 有多少取多少
{
len = _size - pos;
end = _size;
}
s.reserve(len);
for (size_t i = pos; i < end; i++)
{
s += _str[i];
}
return s;
}
void push_back(char ch)
{
if (_size == _capacity)
{
reserve(_capacity == 0 ? 4 : _capacity * 2);
}
_str[_size] = ch;
++_size;
_str[_size] = '\0';
}
void append(const char* str)
{
size_t len = strlen(str);
if (_size + len > _capacity)
{
reserve(_size + len);
}
strcpy(_str + _size, str);
_size += len;
}
string& operator+=(char ch)
{
push_back(ch);
return *this;
}
string& operator+=(const char* str)
{
append(str);
return *this;
}
// insert(0, 'x')
void insert(size_t pos, char ch)
{
assert(pos <= _size);
if (_size == _capacity)
{
reserve(_capacity == 0 ? 4 : _capacity * 2);
}
// 17:17
size_t end = _size + 1;
while (end > pos)
{
_str[end] = _str[end - 1];
--end;
}
_str[pos] = ch;
_size++;
}
void insert(size_t pos, const char* str)
{
assert(pos <= _size);
size_t len = strlen(str);
if (_size + len > _capacity)
{
reserve(_size + len);
}
// 挪動(dòng)數(shù)據(jù)
int end = _size;
while (end >= (int)pos)
{
_str[end + len] = _str[end];
--end;
}
strncpy(_str + pos, str, len);
_size += len;
}
void erase(size_t pos, size_t len = npos)
{
assert(pos < _size);
if (len == npos || pos + len >= _size)
{
_str[pos] = '\0';
_size = pos;
}
else
{
size_t begin = pos + len;
while (begin <= _size)
{
_str[begin - len] = _str[begin];
++begin;
}
_size -= len;
}
}
bool operator<(const string& s) const
{
return strcmp(_str, s._str) < 0;
}
bool operator==(const string& s) const
{
return strcmp(_str, s._str) == 0;
}
bool operator<=(const string& s) const
{
return *this < s || *this == s;
}
bool operator>(const string& s) const
{
return !(*this <= s);
}
bool operator>=(const string& s) const
{
return !(*this < s);
}
bool operator!=(const string& s) const
{
return !(*this == s);
}
void clear()
{
_str[0] = '\0';
_size = 0;
}
private:
char* _str;
size_t _size;
size_t _capacity;
//const static size_t npos = -1; // 特例
//const static double npos = 1.1; // 不支持
public:
const static size_t npos;
};
const size_t string::npos = -1;
ostream& operator<<(ostream& out, const string& s)
{
/*for (size_t i = 0; i < s.size(); i++)
{
out << s[i];
}*/
for (auto ch : s)
out << ch;
return out;
}
istream& operator>>(istream& in, string& s)
{
s.clear();
//s.reserve(128);
char buff[129];
size_t i = 0;
char ch;
ch = in.get();
while (ch != ' ' && ch != '\n')
{
buff[i++] = ch;
if (i == 128)
{
buff[i] = '\0';
s += buff;
i = 0;
}
//s += ch;
ch = in.get();
}
if (i != 0)
{
buff[i] = '\0';
s += buff;
}
return in;
}
void test_string1()
{
string s1("hello world");
cout << s1.c_str() << endl;
string s2;
cout << s2.c_str() << endl;
//訪問(wèn)字符串
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1[i] ;
}
cout << endl;
//迭代器
string::iterator it = s1.begin();
while (it != s1.end())
{
//寫
(*it)++;
//讀
cout << *it << " ";
++it;
}
cout << endl;
//范圍for
for (auto& ch : s1)
{
ch++;
cout << ch << " ";
}
cout << endl;
cout << s1.c_str() << endl;
}
void test_string2()
{
string s1("hello world");
cout << s1.c_str() << endl;
s1.push_back(' ');
s1.append("hello bit hello bit");
cout << s1.c_str() << endl;
s1 += '#';
s1 += "*********************";
cout << s1.c_str() << endl;
string s2;
s2 += '#';
s2 += "*********************";
cout << s2.c_str() << endl;
}
void test_string3()
{
string s1("hello world");
cout << s1.c_str() << endl;
s1.insert(5, '%');
cout << s1.c_str() << endl;
s1.insert(s1.size(), '%');
cout << s1.c_str() << endl;
s1.insert(0, '%');
cout << s1.c_str() << endl;
}
void test_string4()
{
string s1("hello world");
string s2("hello world");
cout << (s1 >= s2) << endl;
s1[0] = 'z';
cout << (s1 >= s2) << endl;
cout << s1 << endl;
cin >> s1;
cout << s1 << endl;
/*char ch1, ch2;
cin >> ch1 >> ch2;*/
}
void test_string5()
{
string s1("hello world");
s1.insert(5, "abc");
cout << s1 << endl;
s1.insert(0, "xxx");
cout << s1 << endl;
s1.erase(0, 3);
cout << s1 << endl;
s1.erase(5, 100);
cout << s1 << endl;
s1.erase(2);
cout << s1 << endl;
}
void test_string6()
{
string s1("hello world");
cout << s1 << endl;
s1.resize(5);
cout << s1 << endl;
s1.resize(25, 'x');
cout << s1 << endl;
}
void test_string7()
{
string s1("test.cpp.tar.zip");
//size_t i = s1.find('.');
//size_t i = s1.rfind('.');
//string s2 = s1.substr(i);
//cout << s2 << endl;
string s3("https://legacy.cplusplus.com/reference/string/string/rfind/");
//string s3("ftp://www.baidu.com/?tn=65081411_1_oem_dg");
// 協(xié)議
// 域名
// 資源名
string sub1, sub2, sub3;
size_t i1 = s3.find(':');
if (i1 != string::npos)
sub1 = s3.substr(0, i1);
else
cout << "沒(méi)有找到i1" << endl;
size_t i2 = s3.find('/', i1 + 3);
if (i2 != string::npos)
sub2 = s3.substr(i1 + 3, i2 - (i1 + 3));
else
cout << "沒(méi)有找到i2" << endl;
sub3 = s3.substr(i2 + 1);
//域名
cout << "協(xié)議" << endl;
cout << sub1 << endl;
cout << "域名" << endl;
cout << sub2 << endl;
cout << "資源名" << endl;
cout << sub3 << endl;
}
void test_string8()
{
string s1("hello world");
string s2 = s1;
cout << s1 << endl;
cout << s2 << endl;
string s3("xxxxxxxxxxxxxxxxxxx");
s2 = s3;
cout << s2 << endl;
cout << s3 << endl;
}
void test_string9()
{
string s1("hello world");
cout << s1 << endl;
cout << s1.size() << endl;
cout << s1.capacity() << endl;
}
}
test.c
test.c用于測(cè)試接口函數(shù):文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-753301.html
#include<string>
using namespace std;
#include"string.h"
int main()
{
NIC::test_string9();
return 0;
}
到了這里,關(guān)于【C++初階】STL詳解(二)string類的模擬實(shí)現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!