摘要:目錄類對(duì)象的常見(jiàn)構(gòu)造類對(duì)象的訪問(wèn)及遍歷操作迭代器介紹類對(duì)象的修改操作深淺拷貝問(wèn)題深拷貝傳統(tǒng)寫(xiě)法深拷貝的現(xiàn)代寫(xiě)法模擬實(shí)現(xiàn)構(gòu)造函數(shù)拷貝構(gòu)造函數(shù)交換函數(shù)拷貝賦值運(yùn)算符獲取對(duì)象的成員屬性重載可讀可寫(xiě)和可讀定義迭代器增容處理和函
介紹常用的幾個(gè)string接口函數(shù),如果需要學(xué)習(xí)更多的請(qǐng)參考官方文檔: string構(gòu)造函數(shù).
函數(shù)名稱 | 功能說(shuō)明 |
---|---|
string() (重點(diǎn)) | 構(gòu)造空的string類對(duì)象,即空字符串 |
string(const char* s) (重點(diǎn)) | 用C-string來(lái)構(gòu)造string類對(duì)象 |
string(size_t n, char c) | string類對(duì)象中包含n個(gè)字符c |
string(const string&s) (重點(diǎn)) | 拷貝構(gòu)造函數(shù) |
string (const string& str, size_t pos, size_t len = npos) | 從str對(duì)象中由pos位置開(kāi)始截取len個(gè)長(zhǎng)度的字符,len > str長(zhǎng)度就結(jié)束 |
string (const char* s, size_t n) | 從s指向的字符數(shù)組中復(fù)制前n個(gè)字符。 |
void functest() { //函數(shù)原型:string() string s1; //調(diào)用默認(rèn)構(gòu)造函數(shù)創(chuàng)建一個(gè)string對(duì)象,對(duì)象的內(nèi)容是空字符串 //類似于這種初始化方式:string s1("") //函數(shù)原型:string(const char* s) string s2("hello cpp"); //調(diào)用string的構(gòu)造函數(shù)用字符串去初始化一個(gè)string對(duì)象 //函數(shù)原型:string(const string&s) string s3(s2); //調(diào)用string類的拷貝構(gòu)造函數(shù)創(chuàng)建s3對(duì)象 //函數(shù)原型:string (const string& str, size_t pos, size_t len = npos) string s4(s3, 0, 5); //從s3對(duì)象中由0位置開(kāi)始截取5個(gè)長(zhǎng)度的字符 char arr[] = "https://blog.csdn.net/m0_53421868?spm=1000.2115.3001.5343"; //函數(shù)原型:string (const char* s, size_t n) string s5(arr, 5); //截取字符數(shù)組的n個(gè)長(zhǎng)度字符 cout << s1 << endl; cout << s2 << endl; cout << s3 << endl; cout << s4 << endl; cout << s5 << endl;}
打印結(jié)果:
函數(shù)名稱 | 功能說(shuō)明 |
---|---|
operator[] (重點(diǎn)) | 返回pos位置的字符,const string類對(duì)象調(diào)用 |
begin+ end | begin獲取第一個(gè)字符的迭代器 + end獲取最后一個(gè)字符下一個(gè)位置的迭代器 |
rbegin + rend | begin獲取第一個(gè)字符的迭代器 + end獲取最后一個(gè)字符下一個(gè)位置的迭代器 |
范圍for | C++11支持 |
使用正向迭代器遍歷string對(duì)象
void functest() { string s1; string s2("hello cpp"); //返回字符串首字符的迭代器給sc,讓sc指向這個(gè)字符 string::iterator sc = s2.begin(); while (sc != s2.end()) { cout << *sc << " "; sc++; }}
使用反向迭代器遍歷string對(duì)象
void functest() { string s1; string s2("abcdefg"); //返回最后一個(gè)字符的迭代器讓sc指向 string::reverse_iterator sc = s2.rbegin(); while (sc != s2.rend()) { cout << *sc << " "; ++sc; }}
而以上兩種迭代器都是可以去修改對(duì)象的值的,還有一種只讀的迭代器不允許修改對(duì)象的值
void functest() { string s1; string s2("abcdefg"); string::const_iterator sc = s2.begin(); while (sc != s2.end()) { //可讀但不能修改 cout << *sc++ ; }}
反向只讀迭代器遍歷string對(duì)象
void functest() { string s1; string s2("abcdefg"); //返回const_reverse_iterator 的迭代器支持反向遍歷操作, //但不支持修改 string::const_reverse_iterator sc = s2.rbegin(); while (sc != s2.rend()) { cout << *sc++; }}
總結(jié):以上幾種迭代器的操作比較簡(jiǎn)單,讀者可以結(jié)合文檔自己去使用
鏈接: 做題.
題目描述:
給定一個(gè)字符串,找到它的第一個(gè)不重復(fù)的字符,并返回它的索引。如果不存在,則返回 -1。
測(cè)試用例:
實(shí)現(xiàn)思路:
找出字符串中只出現(xiàn)一次的字符可以采用計(jì)數(shù)的方法,記錄每個(gè)字符在數(shù)組中出現(xiàn)的位置統(tǒng)計(jì)他出現(xiàn)的次數(shù),最后只出現(xiàn)一次的字符就是我們要找的字符
范圍for + operator[]
class Solution {public: int firstUniqChar(string s) { int count[26] = {0}; for(auto e : s) { //記錄每個(gè)字符在count數(shù)組中出現(xiàn)的次數(shù)(相對(duì)映射) count[e - "a"]++; } for(size_t i = 0; i < s.size(); i++) { //檢查某個(gè)字符映射在數(shù)組中出現(xiàn)的次數(shù), //如果等于1就表示只出現(xiàn)一次 if(count[s[i] - "a"] == 1) { return i; } } return -1; }};
使用迭代器遍歷對(duì)象的源字符串中的字符再通過(guò)count數(shù)組計(jì)數(shù)
class Solution {public: int firstUniqChar(string s) { int count[26] = { 0 }; string::iterator sc = s.begin(); //sc接受s.begin返回的迭代器 while (sc != s.end()) { count[*sc - "a"]++; sc++; } for (size_t i = 0; i < s.size(); i++) { if (count[s[i] - "a"] == 1) { return i; } } return -1; }};
函數(shù)名稱 | 功能說(shuō)明 |
---|---|
push_back | 在字符串后尾插字符c |
append | 在字符串后追加一個(gè)字符串 |
operator+= (重點(diǎn)) | 在字符串后追加字符串str |
c_str(重點(diǎn)) | 返回C格式字符串 |
find + npos(重點(diǎn)) | 從字符串pos位置開(kāi)始往后找字符c,返回該字符在字符串中的位置 |
rfind | 在字符串中搜索由參數(shù)指定的序列的最后一次出現(xiàn)時(shí)的下標(biāo)位置。 |
substr | 在str中從pos位置開(kāi)始,截取n個(gè)字符,然后將其返回 |
insert | 指定位置pos處插入一個(gè)字符串 |
erase | 從指定pos位置開(kāi)始刪除len個(gè)長(zhǎng)度的字符 |
插入操作:
void functest2() { string s; s.push_back("h"); s.push_back("e"); s.push_back("l"); s.push_back("l"); s.push_back("o"); cout << s << endl;// hello s.append("word");// helloword cout << s << endl; //append還可以指定一個(gè)迭代器區(qū)間, //將這段區(qū)間的字符串追加到s對(duì)象// 函數(shù)原型:string& append (const string& str, size_t subpos, size_t sublen); string s3("defgh"); s.append(s3, 2,3); //從字符串中下標(biāo)位置為2的字符起開(kāi)始截取3個(gè)字符追加到s對(duì)象 cout << s << endl;//hellowordfgh //string成員函數(shù)operator+=同樣也支持追加字符串的操作 s += "abc"; cout << s << endl; //hellowordfghabc //指定位置插入 //函數(shù)原型:string& insert (size_t pos, const char* s); string s("abcdefg"); s.insert(0,"c");//err,參數(shù)是字符串,這樣使用不對(duì) s.insert(0, "x"); //0位置處插入一個(gè)x,整體字符串往后挪動(dòng),不推薦使用,挪動(dòng)數(shù)據(jù)的效率太低}
需要注意的一些string成員函數(shù)c_str
string s("hello word"); cout << s << endl; //自定義類型的s在輸出的時(shí)候會(huì) //調(diào)用重載的 operator<< (ostream& os, const string& str); cout << s.c_str() << endl; //s.c_str()函數(shù)返回的是一個(gè)c風(fēng)格的字符串他是內(nèi)置類型, //使用的是全局的operator<<(cout, const char *) cout << "------------------" << endl; //所以會(huì)在輸出的時(shí)候各不相同 s.resize(20); s += "!!!"; cout << s << endl; cout << s.c_str() << endl;
效果:
1、調(diào)用內(nèi)置類型的operator<<(cout, const char *) 輸出字符串的時(shí)候遇到‘/0’就會(huì)停止
2、調(diào)用自定義類型的operator<< (ostream& os, const string& str)即使遇到‘/0’也不會(huì)停止,只有把字符串給完全遍歷完了才會(huì)停止遍歷
刪除操作:
void functest3() { string s("abcdefg"); //函數(shù)原型:string& erase (size_t pos = 0, size_t len = npos); //函數(shù)功能:指定pos位置處開(kāi)始,刪除len個(gè)長(zhǎng)度的字符 s.erase(1,2); cout << s << endl;//adefg}
查找操作:
從前往后
//string拷貝構(gòu)造函數(shù)原型: 這里會(huì)給缺省值//string (const string& str, size_t pos, size_t len = npos);string buff1("test.cpp");int pos = buff1.find(".");if (pos != string::npos) //npos值是-1,類型是無(wú)符號(hào)整形,所以是整形的最大值,字符串并不會(huì)存儲(chǔ)這么長(zhǎng){ string buff2(buff1,pos, buff1.size() - pos); //調(diào)用拷貝構(gòu)造函數(shù)創(chuàng)建buff2對(duì)象, //從pos位置開(kāi)始截取len個(gè)長(zhǎng)度的字符串創(chuàng)建一個(gè)string對(duì)象 //也可以使用這種寫(xiě)法去截取后綴: //即使使用了函數(shù)提供的缺省值也并不用過(guò)于擔(dān)心,npos是最大值也好 //只會(huì)截取有效內(nèi)容,超過(guò)不管 string buff3(buff1,pos); //不調(diào)用拷貝構(gòu)造函數(shù)同樣也能做到, substr截取 //函數(shù)原型:string substr (size_t pos = 0, size_t len = npos) const; string buff4 = buff1.substr(pos); cout << buff2 << endl;//.cpp}
從后往前
//函數(shù)原型://size_t rfind (const string& str, size_t pos = npos) const;//函數(shù)功能是返回指定參數(shù)在字符串中最后一次出現(xiàn)的位置string buff1("test.cpp.zip");int pos = buff1.rfind(".");if (pos != string::npos) { string buff2(buff1, pos); cout << buff2 << endl;}
使用string成員函數(shù)查找網(wǎng)絡(luò)域名跟協(xié)議使用舉例,詳細(xì)解釋請(qǐng)看注釋
//返回協(xié)議名string GetAgreeMent(const string& s){ //查找"://",找到返回該字符串的起始下標(biāo)位置 size_t pos = s.find("://"); if (pos != string::npos) { //由于是左閉右開(kāi)區(qū)間【0,5),所以只需要pos - 0就能計(jì)算出協(xié)議名的長(zhǎng)度 return s.substr(0, pos - 0); } else { //找不到返回空串 return string(); }}//返回域名string GetDomain(const string& s) { //查找"://",找到返回該字符串的起始下標(biāo)位置 size_t pos = s.find("://"); if (pos != string::npos) { //計(jì)算出域名的起始下標(biāo)位置,從這個(gè)位置開(kāi)始查找"/" size_t start = pos + 3; size_t end = s.find("/", start); if (end != string::npos) { //同樣的左閉右開(kāi)區(qū)間,開(kāi)區(qū)間的位置減去閉區(qū)間的位置就是字符串的長(zhǎng)度 return s.substr(start, end - start); } else { //找不到返回空串 return string(); } } else { //找不到返回空串 return string(); } }void functest4() { string url1 = "https://blog.csdn.net/m0_53421868?spm=1000.2115.3001.5343"; string url2 = "https://bbs.csdn.net/forums/mzt"; cout << GetDomain(url1) << endl; cout << GetAgreeMent(url1) << endl; cout << GetDomain(url2) << endl; cout << GetAgreeMent(url2) << endl;}
string類對(duì)象的容量操作
函數(shù)名稱 | 功能說(shuō)明 |
---|---|
size(重點(diǎn)) | 統(tǒng)計(jì)字符個(gè)數(shù) |
length | 返回字符串有效字符長(zhǎng)度 |
capacity | 返回空間總大小 |
empty (重點(diǎn)) | 檢測(cè)字符串釋放為空串,是返回true,否則返回false |
clear (重點(diǎn)) | 清空有效字符,將size置零 |
reserve (重點(diǎn)) | 為字符串預(yù)留空間 |
resize (重點(diǎn)) | 將有效字符的個(gè)數(shù)該成n個(gè),多出的空間用字符c填充 |
測(cè)試:
string s;s.resize(10);//插入10個(gè)"/0",默認(rèn)以"/0"填充cout << s << endl;string s1;s1.resize(10,"x");//指定插入10個(gè)字符,以"x"填充cout << s1 << endl;string s3("hello word");s3.resize(20,"x"); //將空間擴(kuò)容到20,多出來(lái)的空間用"x"填充,并且是尾插的方式cout << s3 << endl;
需要注意的一些增容函數(shù)
與resize函數(shù)相似的有reserve 他并不會(huì)改變空間的內(nèi)容,只做增容
淺拷貝一般都是在拷貝構(gòu)造一個(gè)對(duì)象的時(shí)候完成值拷貝的一個(gè)過(guò)程,因?yàn)槲覀儾粚?xiě)編譯器默認(rèn)的生成的拷貝構(gòu)造函數(shù)完成的是淺拷貝,這樣對(duì)象出了作用域開(kāi)始調(diào)用析構(gòu)函數(shù)的時(shí)候會(huì)導(dǎo)致同一塊空間被釋放兩次,就會(huì)引發(fā)程序崩潰
namespace mzt { class string { public: //重載operator<< friend ostream &operator<< (ostream &out, string &str) { out << str._str << endl; return out; } string(const char* str = "") : _str(new char[strlen(str) + 1]) , _size(0) ,_capacity(0) { strcpy(_str, str); } //我們不寫(xiě)編譯器會(huì)默認(rèn)生成一個(gè)拷貝構(gòu)造函數(shù)完成淺拷貝 /* string(const string & str) : _str(new char[strlen(str._str) + 1]) { strcpy(_str, str._str); }*/ ~string() { delete[] _str; _str = nullptr; } private: char* _str; size_t _capacity; size_t _size; }; void stringtest() { mzt::string s("hello world"); mzt::string s1(s); cout << s; cout << s1; }}
即使打印出了hello world,但是這個(gè)程序還是存在問(wèn)題,因?yàn)閮蓚€(gè)對(duì)象的_str指針指向的是同一塊空間所以當(dāng)被delete的時(shí)候就會(huì)被析構(gòu)兩次,這是不被允許的,解決辦法深拷貝,重新創(chuàng)建一個(gè)空間,并把值存過(guò)去,讓兩個(gè)對(duì)象之間的內(nèi)容互不影響
namespace mzt { class string { public: friend ostream &operator<< (ostream &out, string &str) { out << str._str << endl; return out; } string(const char* str = "") : _str(new char[strlen(str) + 1]) , _size(0) ,_capacity(0) { strcpy(_str, str); } //我們不寫(xiě)編譯器會(huì)默認(rèn)生成一個(gè)拷貝構(gòu)造函數(shù)完成淺拷貝 //解決辦法深拷貝,開(kāi)辟一塊新的空間,把值拷貝過(guò)去 string(const string & str) : _str(new char[strlen(str._str) + 1]) { strcpy(_str, str._str); } //重載operator=也是一樣的做法, //開(kāi)空間拷貝值避免出現(xiàn)淺拷貝的問(wèn)題 string& operator=(const string& s) { if (this != &s) { delete[] _str; _str = new char[strlen(s._str) + 1]; strcpy(_str, s._str); } return *this; } ~string() { delete[] _str; _str = nullptr; } private: char* _str; size_t _capacity; size_t _size; }; void stringtest() { mzt::string s("hello world"); mzt::string s1(s); cout << s; cout << s1; }}
推薦使用現(xiàn)代深拷貝的方法:
原因1: 代碼簡(jiǎn)潔
原因2:可讀性強(qiáng)
//我們不寫(xiě)編譯器會(huì)默認(rèn)生成一個(gè)拷貝構(gòu)造函數(shù)完成淺拷貝//解決辦法做深拷貝string(const string &s) : _str(nullptr) //_str必須初始化為nullptr,才去交換tmp指針, //否則_str就是野指針了,當(dāng)tmp出了作用域析構(gòu)野指針會(huì)有非法內(nèi)存訪問(wèn){ //調(diào)用構(gòu)造函數(shù)利用s._str做參數(shù)構(gòu)造臨時(shí)對(duì)象 string tmp(s._str); //將臨時(shí)對(duì)象的指針_str和this._str一交換 swap(tmp._str, _str); //臨時(shí)對(duì)象出了作用域就銷毀了,會(huì)自動(dòng)調(diào)用它的析構(gòu)函數(shù)}//拷貝賦值運(yùn)算符現(xiàn)代寫(xiě)法string& operator=(string s)//s通過(guò)調(diào)用拷貝構(gòu)造函數(shù)完成的深拷貝{ //還是一樣的思路,由于拷貝構(gòu)造函數(shù)已經(jīng)被我們實(shí)現(xiàn)了, //所以就不會(huì)存在淺拷貝的問(wèn)題,所以通過(guò)值傳遞,即使 //棧幀被銷毀了,兩個(gè)對(duì)象也互不影響,這也是一種復(fù)用的方法 //直接上手交換指針this._str和s._str swap(_str, s
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/123192.html
摘要:本文介紹了類的常用接口的使用,并對(duì)其進(jìn)行了模擬實(shí)現(xiàn),對(duì)模擬實(shí)現(xiàn)中涉及到的深淺拷貝問(wèn)題進(jìn)行了解析。在此之前,必須提到一個(gè)經(jīng)典問(wèn)題。為了解決淺拷貝問(wèn)題,所以中引入了深拷貝。但是實(shí)際使用中需要是第一個(gè)形參對(duì)象,才能正常使用。 本文介紹了string類的常用接口的使用,并對(duì)其進(jìn)行了模擬實(shí)現(xiàn),對(duì)模擬實(shí)...
摘要:探索專為而設(shè)計(jì)的將探討進(jìn)行了何種改進(jìn),以及這些改進(jìn)背后的原因。關(guān)于最友好的文章進(jìn)階前言之前就寫(xiě)過(guò)一篇關(guān)于最友好的文章反響很不錯(cuò),由于那篇文章的定位就是簡(jiǎn)單友好,因此盡可能的摒棄復(fù)雜的概念,只抓住關(guān)鍵的東西來(lái)講,以保證大家都能看懂。 周月切換日歷 一個(gè)可以進(jìn)行周月切換的日歷,左右滑動(dòng)的切換月份,上下滑動(dòng)可以進(jìn)行周,月不同的視圖切換,可以進(jìn)行事件的標(biāo)記,以及節(jié)假日的顯示,功能豐富 Andr...
摘要:編寫(xiě)測(cè)試用例代碼打開(kāi)框架自動(dòng)生成的測(cè)試代碼文件編寫(xiě)測(cè)試用例,測(cè)試增刪改查效果,測(cè)試代碼如下注釋,它可以對(duì)類成員變量方法及構(gòu)造函數(shù)進(jìn)行標(biāo)注,完成自動(dòng)裝配的工作。 文章系列 【從零入門(mén)系列-0】Sprint Boot 之 Hello World 【從零入門(mén)系列-1】Sprint Boot 之 程序結(jié)構(gòu)設(shè)計(jì)說(shuō)明 【從零入門(mén)系列-2】Sprint Boot 之 數(shù)據(jù)庫(kù)實(shí)體類 前言 前一章...
摘要:拷貝構(gòu)造函數(shù)示例構(gòu)造無(wú)參構(gòu)造函數(shù)總結(jié)容器和容器的構(gòu)造方式幾乎一致,靈活使用即可賦值操作功能描述給容器進(jìn)行賦值函數(shù)原型重載等號(hào)操作符將區(qū)間中的數(shù)據(jù)拷貝賦值給本身。清空容器的所有數(shù)據(jù)刪除區(qū)間的數(shù)據(jù),返回下一個(gè)數(shù)據(jù)的位置。 ...
閱讀 4361·2021-11-22 09:34
閱讀 2690·2021-11-12 10:36
閱讀 742·2021-08-18 10:23
閱讀 2636·2019-08-30 15:55
閱讀 3111·2019-08-30 15:53
閱讀 2081·2019-08-30 15:44
閱讀 1361·2019-08-29 15:37
閱讀 1401·2019-08-29 13:04