STL中的string你了解嗎
STL(standard template libaray
-標準模板庫):是C++標準庫的重要組成部分,不僅是一個可復用的組件庫,而且是一個包羅數(shù)據(jù)結構與算法的軟件框架。
STL的六大組件:容器、迭代器、適配器、空間配置器、仿函數(shù)、算法。
string的行為與普通容器類似,但是并不能說它是個容器,因為無法接受所有類型的數(shù)據(jù)。
string是表示字符串的字符串類。
string在底層實際是:basic_string模板類的別名
typedef basic_string<char, char_traits, allocator>string;
頭文件: #include<string>
模擬實現(xiàn)一個string類
首先成員變量最少需要一個字符類型的指針、字符串的大小、總共能存多少有效字符。
其次還需要構造函數(shù)、遍歷的方法、增刪查改、運算符重載等。
成員變量
class MyString { private: char *_str;//字符串指針 size_t _size;//字符串大小 size_t _capacity;//總共能存多少有效字符,不包括'\0' static size_t npos;//迭代器相關 } size_t MyString:: npos = -1;
構造函數(shù)
//構造函數(shù) MyString(const char* str = "")//缺省參數(shù) { _size = strlen(str);//初始化 _capacity = _size; _str = new char[_capacity + 1];//'\0'的空間+1 strcpy(_str, str); } //析構函數(shù) ~MyString() { delete[] _str;//釋放內存 _str = nullptr;//將指針置空 _size = 0;//清理工作 _capacity = 0; } //拷貝構造函數(shù) MyString(const MyString& str) { _size = str._size; _capacity = str._capacity; _str = new char[_capacity + 1]; strcpy(_str, str._str); } //賦值運算符重載 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語言中使用字符串時是可以通過[ ]進行隨機訪問的,所以在設計string類時,通過重載[ ]實現(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[ ],一個是針對非const類型對象,一個是針對const類型對象。const類型的對象是沒有辦法調用非const修飾*this的成員函數(shù)和重載,原因:權限擴大了。
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; }
與容量相關的成員函數(shù)
實現(xiàn)幾個比較常用的函數(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
只需要設置成const類型,因為不需要修改內容。
reserve只修改_capacity的大小。
resize的實現(xiàn)需要分三種情況,當n的長度小于等于_size的時候,只需要修改一下_size的大小,然后把_size的位置設置為'\0'。當n的長度大于_size且小于_capacity的時候,需要新插入n-_size個ch;如果大于_capacity,說明需要重新開辟空間了,并插入n-_size個ch。
運算符的重載
1、+=的重載
平常用string類的時候發(fā)現(xià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)//擴容 { size_t newcapacity = (_capacity) == 0 ? 2 : _capacity * 2; reserve(newcapacity); } _str[_size] = ch; _size++; _str[_size] = '\0';//尾插過后會把'\0給覆蓋了,重新在最后一個位置補一個'\0' return *this; }
2、<< 和 >>的重載
為了保持和標準輸入輸出的使用形式是一樣的,建議在類外面重載<<和>>。
//需要在類外面重載 //輸出流 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'會結束 { str += ch; } else break; } return in; }
補充getline函數(shù):遇到'\n'才結束
用法:getline(cin,對象);
//getline是遇到'\n'才結束 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)//插入一個字符,尾插 { if (_size == _capacity) { size_t newcapacity = (_capacity) == 0 ? 2 : _capacity * 2; reserve(newcapacity); } _str[_size] = ch; _size++; _str[_size] = '\0';//尾插過后會把'\0給覆蓋了,重新在最后一個位置補一個'\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)//為什么要強轉,如果是頭插,end最終=-1, { //-1和無符號比較會向無符號轉變成一個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(無符號整型最大值) 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; }
可以看出刪除和任意位置插入還是挺費時間的,需要整體挪動字符串。
常用的幾個字符串函數(shù)
find
、substr
、c_str
也得掌握
find的接口比較多,可以查找string類、查找char*的字符串也可以查找單個字符
返回值為對應的下標,沒找到返回npos。
substr獲得一個子串,返回值為string類型
pos表示從哪里開始,len表示子串長度。
c_str 將C++的字符串類轉化成C語言中char*類型。
總結
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注腳本之家的更多內容!
相關文章
c語言生成隨機數(shù)的方法(獲得一組不同的隨機數(shù))
c語言生成一組不同的隨機數(shù),大家參考使用吧2013-12-12vector,map,list,queue的區(qū)別詳細解析
如果我們需要隨機訪問一個容器則vector要比list好得多。如果我們已知要存儲元素的個數(shù)則vector 又是一個比list好的選擇。如果我們需要的不只是在容器兩端插入和刪除元素則list顯然要比vector好2013-09-09詳解VisualS tudio Code開發(fā)Arm嵌入式Linux應用
本文介紹如何在 Visual Studio Code 中使用 Yocto Project 生成的 Linux SDK,并針對 Arm 處理器進行 C/C++ 應用交叉編譯和調試,感興趣的朋友跟隨小編一起看看吧2021-04-04