日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

详解string容器(应用+模拟实现,string练习题)

發(fā)布時(shí)間:2023/11/30 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 详解string容器(应用+模拟实现,string练习题) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

為什么要有string容器

string:其實(shí)就是一個(gè)字符串,c++對(duì)字符串進(jìn)行了封裝的,封裝到一個(gè)類里面,這樣用戶就不用擔(dān)心開辟空間的問題,只需要往string類里放字符串就可以了,string其實(shí)還可以自增長
很多人就會(huì)有一個(gè)疑問,以前在c語言中,已經(jīng)有字符串了,其實(shí)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都是求字符串的有效個(gè)數(shù)cout << s.length() << endl;cout << s.capacity() << endl;if (s.empty())cout << "NULL" << endl;elsecout << "NOT NULL string" << endl;//只清空string類中有效字符個(gè)數(shù),不會(huì)改變底層空間的大小s.clear(); //不會(huì)清空容量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個(gè),多的字符采用ch進(jìn)行填充
注意

  • 將string類中有效元素縮小,只改變有效元素的個(gè)數(shù),不會(huì)改變底層空間的大小
  • 如果是將string類中有效元素增多,可能需要擴(kuò)容
  • void TestString3() {string s("hello");cout << s << endl;cout << s.size() << endl;cout << s.capacity() << endl;//resize 10個(gè)有效字符,原來有5個(gè),多出來的5個(gè)用!號(hào)進(jìn)行填充s.resize(10,'!');cout << s << endl;cout << s.size() << endl;cout << s.capacity() << endl;}
    reserve()
    void reserve(size_t newcapacity)
  • newcapacity > oldcapacity(string 類舊空間增多---->容量改變(最終容量大小) >= newcapacity)
  • newcapacity < oldcapacity(string 類舊空間縮小---->該函數(shù)直接返回,除非newcapacity < 15,縮小到15
    注意:
    只改變?nèi)萘看笮?#xff0c;不會(huì)改變有效元素個(gè)數(shù)
  • void TestString4() {string s("hello");cout << s.size() << endl;cout << s.capacity() << endl;s.reserve(20);cout << s.size() << endl;cout << s.capacity() << endl;s.reserve(40);cout << s.size() << endl;cout << s.capacity() << endl;s.reserve(24);cout << s.size() << endl;cout << s.capacity() << endl;s.reserve(5);cout << s.size() << endl;cout << s.capacity() << endl; }


    string類維護(hù)了一個(gè)空間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的異常//不同點(diǎn)//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類擴(kuò)容機(jī)制
  • vs—PJ----1.5倍擴(kuò)容
  • Linux-----SGI----2倍擴(kuò)容
  • 如果提前直到大概要往string類存放多少個(gè)元素,可以通過reserve將空間給好
  • void TestPushBack() { string s; //維護(hù)一個(gè)數(shù)組,最多放15個(gè)有效字符size_t sz = s.capacity(); cout << "making s grow:\n"; for (int i = 0; i < 100; ++i) { s.push_back( 'c'); if (sz != s.capacity()) //sz記錄上一次容量大小{ sz = s.capacity(); cout << "capacity changed: " << sz << '\n'; } } }

    字符串特殊操作

    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)字符串

    一個(gè)函數(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()); }

    字符串中第一個(gè)唯一字符

    字符做為數(shù)組下標(biāo)

    class Solution { public:int firstUniqChar(string s) {//1.統(tǒng)計(jì)每個(gè)字符出現(xiàn)的次數(shù)int count[256]={0};for(auto e:s){count[e]++;}//2.找第一個(gè)只出現(xiàn)一次的字符for(size_t i = 0; i < s.size(); ++i){if(count[s[i]] == 1)return i;}return -1;} };

    字符串最后一個(gè)單詞的長度

    cin用來接受字符串,如果字符串中出現(xiàn)空格,換行,是無法拿到整個(gè)字符串的

    #include<iostream> #include<string> using namespace std;int main() {string s;getline(cin,s);//找到最后一個(gè)單詞的位置cout<< s.substr(s.rfind(' ')+1).size();return 0; }

    字符串相加


    大數(shù)相加,無法用普通的類型進(jìn)行保存
    可以把這些數(shù)據(jù)看成是字符串

    class Solution { public:string addStrings(string num1, string num2) {int LSize = num1.size(); int RSize = num2.size(); // 以長字符串作為外部循環(huán) if(LSize < RSize) { num1.swap(num2); swap(LSize, RSize); } string strRet; strRet.reserve(LSize+1); char cRet = 0; char cstep = 0;for(size_t i = 0; i < LSize; ++i) { cRet = num1[LSize - i - 1] - '0' + cstep; cstep = 0; if(i < RSize) { cRet += num2[RSize - i - 1] - '0'; } if(cRet >= 10) { cRet -= 10; cstep = 1; } strRet += cRet + '0'; } if(cstep) strRet += '1'; reverse(strRet.begin(), strRet.end()); return strRet; } };

    string模擬實(shí)現(xiàn)

    string模擬實(shí)現(xiàn)

    如何實(shí)現(xiàn)

    string是動(dòng)態(tài)管理字符串,不論多少個(gè)數(shù),都可以管理,編譯器中會(huì)有一個(gè)靜態(tài)數(shù)組,剛開始大小為16字節(jié),有效元素個(gè)數(shù)為15個(gè),所以當(dāng)有效字符小于15個(gè)時(shí),直接用靜態(tài)數(shù)組存放,效率高一些


    我們實(shí)現(xiàn)的string只給出動(dòng)態(tài)數(shù)組,維護(hù)一個(gè)char*指針,創(chuàng)建對(duì)象開辟空間即可

    構(gòu)造

    有參構(gòu)造
    用戶在創(chuàng)建對(duì)象時(shí),一般有參的話,都會(huì)給出c風(fēng)格的字符串,所以我們的參數(shù),就是一個(gè)char*的指針,最好設(shè)個(gè)默認(rèn)值為空。然后在有參構(gòu)造里做兩件事情,一個(gè)是申請(qǐng)空間,另外一個(gè)就是拷貝數(shù)據(jù)
    但是要注意用戶一般很傻,有可能會(huì)傳一個(gè)空的指針進(jìn)來,會(huì)引起代碼崩潰。所以我們一定要對(duì)傳來的數(shù)據(jù)進(jìn)行判空處理,如果為空,則初始化為空串即可。

    string(char *str = ""){//如果指針為空,則初始化位空字符串if (nullptr == str)str = "";//申請(qǐng)空間_str = new char[strlen(str) + 1];//strcpy(_str, str);}

    拷貝構(gòu)造
    系統(tǒng)會(huì)給出默認(rèn)的拷貝構(gòu)造,但是存在淺拷貝問題
    什么是淺拷貝?
    淺拷貝可能通過默認(rèn)的拷貝構(gòu)造發(fā)生,也有可能通過編譯器默認(rèn)的賦值運(yùn)算符的重載發(fā)生。
    所以我們?cè)诳截悩?gòu)造和賦值時(shí),讓每個(gè)對(duì)象都要擁有一份獨(dú)立的資源

    string(const string& s):_str(new char[strlen(s._str)+1]) //開辟空間{strcpy(_str, s._str);}

    賦值運(yùn)算符重載

  • 開辟新空間
  • 拷貝元素
  • 釋放舊空間
  • 指向新空間
  • string& operator=(const string& s){//自己給自己賦值,不用做任何操作if (this != &s){//不是自己給自己賦值//1.申請(qǐng)新空間char *temp = new char[strlen(s._str) + 1];//2.拷貝數(shù)據(jù)strcpy(temp, s._str);//3.釋放原來空間delete[]_str;//4.原空間指針指向新空間_str = temp;}return *this;}

    析構(gòu)

    看一下當(dāng)前對(duì)象指針有沒有資源,如果有,釋放掉,隨后指針指向空,防止野指針。

    ~string(){if (_str)delete[]_str;_str = nullptr;}

    以上的是模擬實(shí)現(xiàn)的一個(gè)string的版本

    另外一個(gè)版本實(shí)現(xiàn)string

    資源的轉(zhuǎn)移

    namespace bite {class string{public:string(char *str = ""){//如果指針為空,則初始化位空字符串if (nullptr == str)str = "";//申請(qǐng)空間_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;}//編譯器生成的默認(rèn)賦值運(yùn)算符重載存在淺拷貝,而且會(huì)有資源泄露,沒有釋放資源private:char * _str;};}

    此版本有一個(gè)缺陷,就是創(chuàng)立的臨時(shí)對(duì)象的地址不為空,則會(huì)引起代碼崩潰,在vs2013編譯器下這個(gè)樣實(shí)現(xiàn)的string沒有問題,因?yàn)関s2013默認(rèn)值為空,其他編譯器給的默認(rèn)值可能是隨機(jī)值。我們可以直接在拷貝構(gòu)造函數(shù)加一個(gè)參數(shù)列表,給臨時(shí)對(duì)象賦值為空

    還有一種引用計(jì)數(shù)的方式,采用引用計(jì)數(shù)來解決淺拷貝的問題
    寫時(shí)拷貝

    總結(jié)

    以上是生活随笔為你收集整理的详解string容器(应用+模拟实现,string练习题)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。