详解string容器(应用+模拟实现,string练习题)
為什么要有string容器
string:其實就是一個字符串,c++對字符串進行了封裝的,封裝到一個類里面,這樣用戶就不用擔(dān)心開辟空間的問題,只需要往string類里放字符串就可以了,string其實還可以自增長
很多人就會有一個疑問,以前在c語言中,已經(jīng)有字符串了,其實c語言中表示字符串就是char*,也就是字符數(shù)組+'\0'
string應(yīng)用
string類的應(yīng)用
string類常用接口
構(gòu)造
string s1;string s2("hello");string s3(10, '$');string s4(s3);容量
void TestString() {string s("hello");cout << s.size() << endl; //size和length都是求字符串的有效個數(shù)cout << s.length() << endl;cout << s.capacity() << endl;if (s.empty())cout << "NULL" << endl;elsecout << "NOT NULL string" << endl;//只清空string類中有效字符個數(shù),不會改變底層空間的大小s.clear(); //不會清空容量cout << s.size() << endl;cout << s.capacity() << endl;if (s.empty())cout << "NULL" << endl;elsecout << "NOT NULL string" << endl; }resize()
void resize(size_t n, char ch):功能—將string類中的有效字符改變到n個,多的字符采用ch進行填充
注意
reserve()
void reserve(size_t newcapacity)注意:
只改變?nèi)萘看笮?#xff0c;不會改變有效元素個數(shù)
string類維護了一個空間16字節(jié)
元素訪問
void TestString5() {string s("hello");cout << s[0] << endl;s[0] = 'H';//[] 如果越界----assert觸發(fā)cout << s.at(2) << endl;s.at(2) = 'L';//s.at()如果越界---拋出out_of_range的異常//不同點//cout << s[10] << endl; //越界訪問cout << s.at(10) << endl; } cout << s[10] << endl; //越界訪問 cout << s.at(10) << endl;//越界訪問元素修改
void TestString6() {string s1;s1.push_back('I');s1 += " Love ";string s2("you");s1 += s2;s1.append(1, ',');s1.append("祖國");s1.append(3, '!');cout << s1 << endl; }string類擴容機制
字符串特殊操作
void TestString7() {string s("123456");int ret = atoi(s.c_str());}//find rfind void TestString8() {string s("hello world");size_t pos = s.find( ' ');if (pos != string::npos){cout << ' ' << "is in s"<<endl;}pos = s.find("world");if (pos != string::npos){cout << "world" << "is in s" << endl;}//獲取文件后綴string ss("2019-10-26.cpp.cpp");pos = ss.rfind('.') + 1; //后綴的位置從.的后面開始cout << pos << endl;string filepos = ss.substr(pos);cout << filepos << endl;}迭代器(string中很少用到)
三種遍歷方法
void TestString9() {string s("hello");for (auto e : s){cout << e;}cout << endl;for (int i = 0; i < s.size(); ++i)cout << s[i];cout << endl;//char *string::iterator it = s.begin();while (it!=s.end()){cout << *it ;++it;}cout << endl; }反轉(zhuǎn)字符串
一個函數(shù)調(diào)用就可以
//反轉(zhuǎn)字符串 void reversestring(string &s) {//char* begin = (char *)s.c_str();//char* end = begin + s.size() - 1;//while (begin < end)//{// swap(*begin, *end);// begin++;// end--;//}reverse(s.begin(), s.end()); }字符串中第一個唯一字符
字符做為數(shù)組下標(biāo)
class Solution { public:int firstUniqChar(string s) {//1.統(tǒng)計每個字符出現(xiàn)的次數(shù)int count[256]={0};for(auto e:s){count[e]++;}//2.找第一個只出現(xiàn)一次的字符for(size_t i = 0; i < s.size(); ++i){if(count[s[i]] == 1)return i;}return -1;} };字符串最后一個單詞的長度
cin用來接受字符串,如果字符串中出現(xiàn)空格,換行,是無法拿到整個字符串的
#include<iostream> #include<string> using namespace std;int main() {string s;getline(cin,s);//找到最后一個單詞的位置cout<< s.substr(s.rfind(' ')+1).size();return 0; }字符串相加
大數(shù)相加,無法用普通的類型進行保存
可以把這些數(shù)據(jù)看成是字符串
string模擬實現(xiàn)
string模擬實現(xiàn)
如何實現(xiàn)
string是動態(tài)管理字符串,不論多少個數(shù),都可以管理,編譯器中會有一個靜態(tài)數(shù)組,剛開始大小為16字節(jié),有效元素個數(shù)為15個,所以當(dāng)有效字符小于15個時,直接用靜態(tài)數(shù)組存放,效率高一些
我們實現(xiàn)的string只給出動態(tài)數(shù)組,維護一個char*指針,創(chuàng)建對象開辟空間即可
構(gòu)造
有參構(gòu)造
用戶在創(chuàng)建對象時,一般有參的話,都會給出c風(fēng)格的字符串,所以我們的參數(shù),就是一個char*的指針,最好設(shè)個默認值為空。然后在有參構(gòu)造里做兩件事情,一個是申請空間,另外一個就是拷貝數(shù)據(jù)
但是要注意用戶一般很傻,有可能會傳一個空的指針進來,會引起代碼崩潰。所以我們一定要對傳來的數(shù)據(jù)進行判空處理,如果為空,則初始化為空串即可。
拷貝構(gòu)造
系統(tǒng)會給出默認的拷貝構(gòu)造,但是存在淺拷貝問題
什么是淺拷貝?
淺拷貝可能通過默認的拷貝構(gòu)造發(fā)生,也有可能通過編譯器默認的賦值運算符的重載發(fā)生。
所以我們在拷貝構(gòu)造和賦值時,讓每個對象都要擁有一份獨立的資源
賦值運算符重載
析構(gòu)
看一下當(dāng)前對象指針有沒有資源,如果有,釋放掉,隨后指針指向空,防止野指針。
~string(){if (_str)delete[]_str;_str = nullptr;}以上的是模擬實現(xiàn)的一個string的版本
另外一個版本實現(xiàn)string
資源的轉(zhuǎn)移
namespace bite {class string{public:string(char *str = ""){//如果指針為空,則初始化位空字符串if (nullptr == str)str = "";//申請空間_str = new char[strlen(str) + 1];strcpy(_str, str);}string(const string& s):_str(nullptr){string strTemp(s._str);swap(_str, strTemp._str);}string& operator=(const string& s){//自己給自己賦值,不用做任何操作if (this != &s){string strTemp(s._str);swap(_str, strTemp._str);}return *this;}~string(){if (_str)delete[]_str;_str = nullptr;}//編譯器生成的默認賦值運算符重載存在淺拷貝,而且會有資源泄露,沒有釋放資源private:char * _str;};}此版本有一個缺陷,就是創(chuàng)立的臨時對象的地址不為空,則會引起代碼崩潰,在vs2013編譯器下這個樣實現(xiàn)的string沒有問題,因為vs2013默認值為空,其他編譯器給的默認值可能是隨機值。我們可以直接在拷貝構(gòu)造函數(shù)加一個參數(shù)列表,給臨時對象賦值為空
還有一種引用計數(shù)的方式,采用引用計數(shù)來解決淺拷貝的問題
寫時拷貝
總結(jié)
以上是生活随笔為你收集整理的详解string容器(应用+模拟实现,string练习题)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 输卵管团绕能展开吗
- 下一篇: 浅拷贝+引用计数--写时拷贝---模拟实