STL中的string你了解嗎
STL(standard template libaray
-標(biāo)準(zhǔn)模板庫):是C++標(biāo)準(zhǔn)庫的重要組成部分,不僅是一個(gè)可復(fù)用的組件庫,而且是一個(gè)包羅數(shù)據(jù)結(jié)構(gòu)與算法的軟件框架。
STL的六大組件:容器、迭代器、適配器、空間配置器、仿函數(shù)、算法。
string的行為與普通容器類似,但是并不能說它是個(gè)容器,因?yàn)闊o法接受所有類型的數(shù)據(jù)。
string是表示字符串的字符串類。
string在底層實(shí)際是:basic_string模板類的別名
typedef basic_string<char, char_traits, allocator>string;
頭文件: #include<string>
模擬實(shí)現(xiàn)一個(gè)string類
首先成員變量最少需要一個(gè)字符類型的指針、字符串的大小、總共能存多少有效字符。
其次還需要構(gòu)造函數(shù)、遍歷的方法、增刪查改、運(yùn)算符重載等。
成員變量
class MyString { private: char *_str;//字符串指針 size_t _size;//字符串大小 size_t _capacity;//總共能存多少有效字符,不包括'\0' static size_t npos;//迭代器相關(guān) } size_t MyString:: npos = -1;
構(gòu)造函數(shù)
//構(gòu)造函數(shù) MyString(const char* str = "")//缺省參數(shù) { _size = strlen(str);//初始化 _capacity = _size; _str = new char[_capacity + 1];//'\0'的空間+1 strcpy(_str, str); } //析構(gòu)函數(shù) ~MyString() { delete[] _str;//釋放內(nèi)存 _str = nullptr;//將指針置空 _size = 0;//清理工作 _capacity = 0; } //拷貝構(gòu)造函數(shù) MyString(const MyString& str) { _size = str._size; _capacity = str._capacity; _str = new char[_capacity + 1]; strcpy(_str, str._str); } //賦值運(yùn)算符重載 MyString& operator=(const MyString& str) { if (_str != str._str) { delete[] _str; _size = str._size; _capacity = str._capacity; _str = new char[_capacity + 1]; strcpy(_str, str._str); } return *this; }
遍歷
1、[ ]的重載
我們在C語言中使用字符串時(shí)是可以通過[ ]進(jìn)行隨機(jī)訪問的,所以在設(shè)計(jì)string類時(shí),通過重載[ ]實(shí)現(xiàn)相同的效果。
char& operator[](size_t index) { assert(index < _size&&index >= 0); return _str[index]; } const char& operator[](size_t index)const { assert(index < _size&&index >= 0); return _str[index]; }
需要兩種類型的operator[ ],一個(gè)是針對非const類型對象,一個(gè)是針對const類型對象。const類型的對象是沒有辦法調(diào)用非const修飾*this的成員函數(shù)和重載,原因:權(quán)限擴(kuò)大了。
2、迭代器
除了用[ ]來遍歷類里面的字符串以外,另外的方法就是通過迭代器。
對于string的迭代器我們只需要宏定義一下
typedef char* iterator; iterator begin() { return _str; } iterator end() { return _str + _size; }
測試一下代碼
void test_string() { MyString ms; ms = "123"; MyString::iterator it = ms.begin(); while (it != ms.end()) { cout << *it << endl; it++; } }
rbegin與rend是反向迭代器,即反向遍歷字符串。
前面帶c的cbegin、cend等等是常字符串類型的對象
const iterator cbegin()const { return _str; } const iterator cend()const { return _str + _size; }
與容量相關(guān)的成員函數(shù)
實(shí)現(xiàn)幾個(gè)比較常用的函數(shù)接口
//返回字符串大小 size_t size()const { return _size; } size_t capacity()const { return _capacity; } //判斷是否為空字符串 bool empty()const { return _size == 0; } //更改容量 void reserve(size_t n = 0) { if (n > _capacity) { char* tmp = new char[n + 1]; strcpy(tmp, _str); delete[] _str; _str = tmp; _capacity = n; } } //更改大小 //resize分三種情況 void resize(size_t n = 0,char ch = '\0') { if (n >= 0 && n <= _size) { _size = n; _str[_size] = '\0'; } else if (n > _size && n <= _capacity) { for (size_t i = _size; i < n; i++) _str[i] = ch; _size = n; _str[_size] = '\0'; } else if (n > _capacity) { reserve(n); for (size_t i = _size; i < n; i++) { _str[i] = ch; } _size = n; _str[_size] = '\0'; } else assert(0); }
size
、capacity
、empty
只需要設(shè)置成const類型,因?yàn)椴恍枰薷膬?nèi)容。
reserve只修改_capacity的大小。
resize的實(shí)現(xiàn)需要分三種情況,當(dāng)n的長度小于等于_size的時(shí)候,只需要修改一下_size的大小,然后把_size的位置設(shè)置為'\0'。當(dāng)n的長度大于_size且小于_capacity的時(shí)候,需要新插入n-_size個(gè)ch;如果大于_capacity,說明需要重新開辟空間了,并插入n-_size個(gè)ch。
運(yùn)算符的重載
1、+=的重載
平常用string類的時(shí)候發(fā)現(xiàn)+=進(jìn)行字符串拼接很方便。
MyString& operator+=(const char* str) { int len = strlen(str); if (len + _size > _capacity)//判斷是否超出容量 { reserve(len + _size); } strcpy(_str + _size, str); _size += len; return *this; } MyString& operator+=(char ch) { if (_size == _capacity)//擴(kuò)容 { size_t newcapacity = (_capacity) == 0 ? 2 : _capacity * 2; reserve(newcapacity); } _str[_size] = ch; _size++; _str[_size] = '\0';//尾插過后會(huì)把'\0給覆蓋了,重新在最后一個(gè)位置補(bǔ)一個(gè)'\0' return *this; }
2、<< 和 >>的重載
為了保持和標(biāo)準(zhǔn)輸入輸出的使用形式是一樣的,建議在類外面重載<<和>>。
//需要在類外面重載 //輸出流 ostream& operator<<(ostream& out, const MyString& str) { for (size_t i = 0; i < str.size(); i++) { out << str[i]; } return out; } //輸入流 istream& operator>>(istream& in, MyString& str) { while (1) { char ch = in.get(); if (ch != ' '&&ch != '\n')//cin遇到空格和'\n'會(huì)結(jié)束 { str += ch; } else break; } return in; }
補(bǔ)充getline函數(shù):遇到'\n'才結(jié)束
用法:getline(cin,對象);
//getline是遇到'\n'才結(jié)束 istream& getline(istream& in, MyString& s) { while (1) { char ch; ch = in.get();//從緩存去讀入所有輸入字符 if (ch != '\n') { s += ch; } else break; } return in; }
修改器
push_back尾插
void push_back(char ch)//插入一個(gè)字符,尾插 { if (_size == _capacity) { size_t newcapacity = (_capacity) == 0 ? 2 : _capacity * 2; reserve(newcapacity); } _str[_size] = ch; _size++; _str[_size] = '\0';//尾插過后會(huì)把'\0給覆蓋了,重新在最后一個(gè)位置補(bǔ)一個(gè)'\0' }
insert任意位置插入字符或者字符串
MyString& insert(size_t pos, const char ch) { assert(pos <= _size && pos >= 0); if (_size == _capacity) { size_t newcapacity = _capacity == 0 ? 2 : 2 * _capacity; reserve(newcapacity); } int end = _size; while (end >= (int)pos)//為什么要強(qiáng)轉(zhuǎn),如果是頭插,end最終=-1, { //-1和無符號(hào)比較會(huì)向無符號(hào)轉(zhuǎn)變成一個(gè)32位的最大值,成為死循環(huán) _str[end + 1] = _str[end]; end--; } _str[pos] = ch; _size++; return *this; } MyString& insert(size_t pos, const char* str) { assert(pos <= _size && pos >= 0); size_t len = strlen(str); if (_size+ len > _capacity) { reserve(_capacity + len); } int end = _size; while (end >= (int)pos)//往后挪 { _str[end + len] = _str[end]; end--; } for (size_t i = 0; i < len; i++) { _str[pos + i] = str[i]; } _size += len; return *this; }
erase刪除
//npos = -1(無符號(hào)整型最大值) MyString& erase(size_t pos, size_t len = npos) { assert(pos >= 0 && pos < _size); if (pos + len >= _size || len == npos) { _size = pos; _str[_size] = '\0'; } else { for (size_t i = 0; i < _size - len - pos; i++) { _str[i + pos] = _str[i + pos + len]; } _size -= len; } _str[_size] = '\0'; return *this; }
可以看出刪除和任意位置插入還是挺費(fèi)時(shí)間的,需要整體挪動(dòng)字符串。
常用的幾個(gè)字符串函數(shù)
find
、substr
、c_str
也得掌握
find的接口比較多,可以查找string類、查找char*的字符串也可以查找單個(gè)字符
返回值為對應(yīng)的下標(biāo),沒找到返回npos。
substr獲得一個(gè)子串,返回值為string類型
pos表示從哪里開始,len表示子串長度。
c_str 將C++的字符串類轉(zhuǎn)化成C語言中char*類型。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
c語言生成隨機(jī)數(shù)的方法(獲得一組不同的隨機(jī)數(shù))
c語言生成一組不同的隨機(jī)數(shù),大家參考使用吧2013-12-12vector,map,list,queue的區(qū)別詳細(xì)解析
如果我們需要隨機(jī)訪問一個(gè)容器則vector要比list好得多。如果我們已知要存儲(chǔ)元素的個(gè)數(shù)則vector 又是一個(gè)比list好的選擇。如果我們需要的不只是在容器兩端插入和刪除元素則list顯然要比vector好2013-09-09C++發(fā)送HTTP請求的實(shí)現(xiàn)代碼
這篇文章主要介紹了C++發(fā)送HTTP請求的實(shí)現(xiàn)代碼,需要的朋友可以參考下2014-06-06詳解VisualS tudio Code開發(fā)Arm嵌入式Linux應(yīng)用
本文介紹如何在 Visual Studio Code 中使用 Yocto Project 生成的 Linux SDK,并針對 Arm 處理器進(jìn)行 C/C++ 應(yīng)用交叉編譯和調(diào)試,感興趣的朋友跟隨小編一起看看吧2021-04-04C語言中求和、計(jì)算平均值、方差和標(biāo)準(zhǔn)差的實(shí)例
這篇文章主要介紹了C語言中求和、計(jì)算平均值、方差和標(biāo)準(zhǔn)差的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12