STL中的string你了解嗎
STL(standard template libaray-標準模板庫):是C++標準庫的重要組成部分,不僅是一個可復(fù)用的組件庫,而且是一個包羅數(shù)據(jù)結(jié)構(gòu)與算法的軟件框架。
STL的六大組件:容器、迭代器、適配器、空間配置器、仿函數(shù)、算法。
string的行為與普通容器類似,但是并不能說它是個容器,因為無法接受所有類型的數(shù)據(jù)。
string是表示字符串的字符串類。
string在底層實際是:basic_string模板類的別名
typedef basic_string<char, char_traits, allocator>string;


頭文件: #include<string>
模擬實現(xiàn)一個string類
首先成員變量最少需要一個字符類型的指針、字符串的大小、總共能存多少有效字符。
其次還需要構(gòu)造函數(shù)、遍歷的方法、增刪查改、運算符重載等。
成員變量
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);
}
//賦值運算符重載
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è)計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類型的對象是沒有辦法調(diào)用非const修飾*this的成員函數(shù)和重載,原因:權(quán)限擴大了。
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ù)

實現(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只需要設(shè)置成const類型,因為不需要修改內(nèi)容。
reserve只修改_capacity的大小。
resize的實現(xiàn)需要分三種情況,當n的長度小于等于_size的時候,只需要修改一下_size的大小,然后把_size的位置設(shè)置為'\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'會結(jié)束
{
str += ch;
}
else
break;
}
return in;
}
補充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)//插入一個字符,尾插
{
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)//為什么要強轉(zhuǎn),如果是頭插,end最終=-1,
{ //-1和無符號比較會向無符號轉(zhuǎn)變成一個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*的字符串也可以查找單個字符

返回值為對應(yīng)的下標,沒找到返回npos。
substr獲得一個子串,返回值為string類型

pos表示從哪里開始,len表示子串長度。
c_str 將C++的字符串類轉(zhuǎn)化成C語言中char*類型。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
C++程序中main(int argc, char *argv[])函數(shù)的參數(shù)意義
這篇文章主要介紹了C++程序中main(int argc, char *argv[])函數(shù)的參數(shù)意義,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2018-09-09

