??string類,想必大家都不陌生,這是一個用來管理字符串的類。讓我們使用字符串時更方便,更遍歷。所以今天我們就來簡單的實現(xiàn)一下string類。
我們要管理一個字符串,那么首先得有一個字符串。所以我們用char* 類型的指針,來指向一個塊存儲字符串的地址。_size則記錄字符串的長度,_cacpcity 為字符串的空間容量
private:
char* _str;
size_t _size;
size_t _cacpcity;
構(gòu)造函數(shù)
構(gòu)造函數(shù)我們在實例化一個string對象的時候,可以string s("hello world");
直接創(chuàng)建,也可以string s();
使它初始時為空,所以我們可以用缺省的構(gòu)造函數(shù)。如果不傳參數(shù),那么默認初始化為空。
//缺省的構(gòu)造函數(shù)
string(const char* str = "")
: _size(strlen(str))
,_cacpcity(_size)
{ //開辟一塊內(nèi)存
_str = new char[_cacpcity + 1];//有效容量是cacpcity,要多一個用來存放\0
strcpy(_str, str);
}
析構(gòu)函數(shù)析構(gòu)函數(shù)我們只需要釋放 _str指向的空間即可。
//析構(gòu)函數(shù)
~string()
{ delete[] _str;
_str = nullptr;
_size = _cacpcity = 0;
}
拷貝構(gòu)造函數(shù)拷貝構(gòu)造,就是拷貝一個字符串 例如:string s1("hello world"); string s2(s1);
。所以我們開辟一塊與要拷貝字符串一樣大小的空間,再把它一一復(fù)制給新字符串即可。
//拷貝構(gòu)造
string(const string& s)
:_size(s._size)
, _cacpcity(s._cacpcity)
{ //開辟一塊和s一樣的空間
_str = new char[_cacpcity+1];
strcpy(_str, s._str);
}
操作符重載
賦值操作符重載如果我們想用 = 操作符來給字符串賦值。那我們可以重載 = 操作符。
//賦值操作符重載
string& operator=(const string& s)
{ //如果不是自己給自己賦值
if (this != &s)
{ //創(chuàng)建一塊新空間
char* tmp = new char[s._cacpcity+1];
//拷貝
strcpy(tmp, s._str);
//銷毀舊空間
delete[] _str;
_str = tmp;
_size = s._size;
_cacpcity = s._cacpcity;
}
return *this;
}
當然也可以復(fù)用拷貝構(gòu)造函數(shù)。
比較操作符重載<重載
//字符串比較函數(shù)重載
bool operator<(const string& s)
{ return strcmp(_str, s._str)< 0;
}
== 重載
bool operator==(const string& s)
{ return strcmp(_str, s._str) == 0;
}
<= 重載
bool operator<=(const string& s)
{ return (*this< s) || (*this == s);
}
? >重載
bool operator>(const string& s)
{ return !((*this)<= s);
}
?>=重載
bool operator>=(const string& s)
{ return !(*this< s);
}
!=重載
bool operator!=(const string& s)
{ return !(*this == s);
}
獲取字符串長度直接返回_size 即可
//獲取長度
size_t size()
{ return _size;
}
下標訪問字符串也可以進行下標訪問,所以我們重載[]即可
//下標訪問
char& operator[](size_t pos)
{ return _str[pos];
}
當然,如果訪問的是const修飾的字符串,那我們只能讀,不能寫。
//只讀
const char& operator[](size_t pos) const
{ return _str[pos];
}
迭代器//定義2個迭代器,一個是可讀可寫,一個是只讀
typedef char* iterator;
typedef const char* const_iterator;
//迭代器開始位置
iterator begin()
{ return _str;
}
const_iterator begin() const
{ return _str;
}
//迭代器末尾位置
iterator end()
{ return _str + _size;
}
const_iterator end()const
{ return _str + _size;
}
尾插一個字符就是在字符串末端插入一個字符,我們只需要在_size的位置插入,隨后_size++即可。不過要保證容量必須充足。
//尾插一個字符
void push_back(char c)
{ //檢查容量
if (_size == _cacpcity)
{ AddCacpcity(_cacpcity == 0 ? 15 : _cacpcity * 2);
}
_str[_size] = c;
_size++;
_str[_size] = '\0';
}
擴容函數(shù)
void AddCacpcity(size_t newCacpcity)
{ //末尾位置留一個\0,所以+1
char* str = new char[newCacpcity + 1];
//舊字符串的內(nèi)容拷貝到新字符串
strcpy(str, _str);
//銷毀舊字符串
delete[] _str;
_str = str;
_cacpcity = newCacpcity;
}
追加字符串如果想在尾部追加字符串的話,我們可以實現(xiàn)一個 append()函數(shù)。
//追加一個字符串
void append(const char* str)
{ //檢查容量
if (_cacpcity< (_size)+strlen(str))
{ AddCacpcity(_size + strlen(str));
}
//直接在末尾的位置加上str
strcpy(_str + _size, str);
_size += strlen(str);
}
然后我們可以重載 +=運算符,拿來復(fù)用 append()函數(shù)。
string& operator+=(const char* str)
{ append(str);
return *this;
}
然后我們重載 +運算符,但需要注意的是,+運算符不改變當前字符串,所以我們要值返回。
//+重載
string operator+(const char* str)
{ string s(*this);
s += str;
return s;
}
字符串清空直接把第一個字符改成\0即可
//清空
void clear()
{ _str[0] = '\0';
_size = 0;
}
字符串交換我們用std命名空間里面的swap函數(shù),對每個成員進行交換。
//字符串交換
void swap(string& s)
{ std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_cacpcity, s._cacpcity);
}
以C的方式返回字符c語言的字符串其實就是一個char*指針,遇到\0結(jié)束,所以我們直接返回str就可以了。
//以c的方式返回字符串
const char* c_str()const
{ return _str;
}
判斷字符串是否為空直接判斷第一個元素是否是 \0
//判斷字符串是否為空
bool empty()const
{ return _str[0] == '\0';
}
修改長度修改長度我們要分多種情況,一般長度減少時,我們不改變現(xiàn)有容量。容量不夠時,我們才增容。 如果 長度減少,或者不變,我們只需要把 減少的新長度給_size,然后把當前位置變成\0。如果是增加長度,我們要考慮容量,不夠的話需要增容,然后memset函數(shù)把增容的部分改成你指定的字符(默認\0)。
//修改長度
void resize(size_t n, char c = '\0')
{ //如果修改的值比當前長度小
if (n<= _size)
{ //截斷
_size = n;
_str[_size] = '\0';
}
//如果修改的值比當前長度大
else
{ //擴容
if(n >_cacpcity)
{AddCacpcity(n);
}
//從size位置到n的位置設(shè)置為c
memset(_str + _size, c, n - _size);
//最后位置填上\0
_size = n;
_str[_size] = '\0';
}
}
指定大小擴容之前寫過一個擴容函數(shù),直接把指定的大小傳過去即可。還是老規(guī)矩,減少不處理。
//指定容量。只增加,減少不處理
void reserve(size_t n)
{ if (n >_cacpcity)
{ AddCacpcity(n);
}
}
查找字符該查找只會找到從指定位置開始,第一個出現(xiàn)的字符。如果要查找第二個,那么就在第一個字符的后面開始查找。
// 返回c在string中第一次出現(xiàn)的位置
size_t find(char c, size_t pos = 0) const
{ for (int i = pos; i< _size; i++)
{ if (_str[i] == c)
return i;
}
return nops;
}
nops是一個無符號的數(shù),代表找不到返回的值。
static const size_t nops = -1;
查找子串C語言中有strstr函數(shù),我們可以復(fù)用。
// 返回子串s在string中第一次出現(xiàn)的位置
size_t find(const char* s, size_t pos = 0) const
{ char* tmp = strstr(_str, s);
if (tmp == NULL)
return nops;
return tmp - _str;
}
指定位置插入字符只需要把pos位置后面的字符都往后移動一格,隨后把字符放進pos位置。
// 在pos位置上插入字符c/字符串str,并返回該字符的位置
string& insert(size_t pos, char c)
{ //判斷容量
if (_size == _cacpcity)
{ AddCacpcity(_cacpcity == 0 ? 15 : _cacpcity * 2);
}
//pos位置后往后移
size_t end = _size + 1;
while (pos< end)
{ _str[end] = _str[end - 1];
end--;
}
_str[pos] = c;
_size++;
return *this;
}
指定位置插入字符串插入字符是都往后移動一格,插入字符串那就是把pos位置后面的字符都像后 移動字符串的長度格。然后把字符串從pos位置開始寫入。
//插入字符串
string& insert(size_t pos, const char* str)
{ size_t len = strlen(str);
//判斷容量
if (_cacpcity< (len + _size))
{ AddCacpcity(len + _size);
}
//移動len格
size_t end1 = _size+1;
size_t end2 = _size + len ;
while (pos< end1 )
{ _str[end2] = _str[end1-1] ;
end1--;
end2--;
}
int i = pos;
while (*str)
{ _str[i++] = *str++;
}
_size += len;
return *this;
}
刪除指定區(qū)間從pos位置開始,刪除len個空間。那么我們需要先判斷 len是否大于pos后面的長度,如果大于那就是后面全部刪除,那么我們只需要把pos位置置空成\0即可。如果不大于就說明在中間刪除,那么就從pos的第len個位置開始往pos后面的位置覆蓋,覆蓋到\0結(jié)束。
// 刪除
string& erase(size_t pos, size_t len)
{ //如果要刪除的長度大于后面的剩余長度
if (len >= _size - pos)
{ len = _size - pos;
_size -= len;
_str[pos] = '\0';
return *this;
}
//把后面的往前移,覆蓋式刪除
size_t begin = pos+len;
while (_str[begin])
{ _str[begin-len] = _str[begin];
begin++;
}
_size -= len;
return *this;
}
全部代碼:
namespace wyl
{class string
{public:
typedef char* iterator;
typedef const char* const_iterator;
//缺省的構(gòu)造函數(shù)
string(const char* str = "")
: _size(strlen(str))
,_cacpcity(_size)
{ //開辟一塊內(nèi)存
_str = new char[_cacpcity + 1];
strcpy(_str, str);
}
//析構(gòu)函數(shù)
~string()
{ delete[] _str;
_str = nullptr;
_size = _cacpcity = 0;
}
//拷貝構(gòu)造
string(const string& s)
:_size(s._size)
, _cacpcity(s._cacpcity)
{ //開辟一塊和s一樣的空間
_str = new char[_cacpcity+1];
strcpy(_str, s._str);
}
//賦值操作符重載
string& operator=(const string& s)
{ //如果不是自己給自己賦值
if (this != &s)
{ //創(chuàng)建一塊新空間
char* tmp = new char[s._cacpcity+1];
//拷貝
strcpy(tmp, s._str);
//銷毀舊空間
delete[] _str;
_str = tmp;
_size = s._size;
_cacpcity = s._cacpcity;
}
return *this;
}
//獲取長度
size_t size()
{ return _size;
}
//下標訪問
char& operator[](size_t pos)
{ return _str[pos];
}
//只讀
const char& operator[](size_t pos) const
{ return _str[pos];
}
//迭代器開始位置
iterator begin()
{ return _str;
}
const_iterator begin() const
{ return _str;
}
//迭代器末尾位置
iterator end()
{ return _str + _size;
}
const_iterator end()const
{ return _str + _size;
}
// 擴容
void AddCacpcity(size_t newCacpcity)
{ char* str = new char[newCacpcity + 1];
strcpy(str, _str);
delete[] _str;
_str = str;
_cacpcity = newCacpcity;
}
//尾插一個字符
void push_back(char c)
{ //檢查容量
if (_size == _cacpcity)
{ AddCacpcity(_cacpcity == 0 ? 15 : _cacpcity * 2);
}
_str[_size] = c;
_size++;
_str[_size] = '\0';
}
string& operator+=(char c)
{ push_back(c);
return *this;
}
//追加一個字符串
void append(const char* str)
{ if (_cacpcity< (_size)+strlen(str))
{ AddCacpcity(_size + strlen(str));
}
strcpy(_str + _size, str);
_size += strlen(str);
}
string& operator+=(const char* str)
{ append(str);
return *this;
}
//+重載
string operator+(const char* str)
{ string s(*this);
s += str;
return s;
}
string operator+(const string& str)
{ string s(*this);
s += str._str;
return s;
}
//清空
void clear()
{ _str[0] = '\0';
_size = 0;
}
//字符串交換
void swap(string& s)
{ std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_cacpcity, s._cacpcity);
}
//以c的方式返回字符串
const char* c_str()const
{ return _str;
}
//判斷字符串是否為空
bool empty()const
{ return _str[0] == '\0';
}
//修改長度
void resize(size_t n, char c = '\0')
{ //如果修改的值比當前長度小
if (n<= _size)
{ //截斷
_size = n;
_str[_size] = '\0';
}
//如果修改的值比當前長度大
else
{ //擴容
if(n >_cacpcity)
{AddCacpcity(n);
}
//從size位置到n的位置設(shè)置為c
memset(_str + _size, c, n - _size);
//最后位置填上\0
_size = n;
_str[_size] = '\0';
}
}
//指定容量。只增加,減少不處理
void reserve(size_t n)
{ if (n >_cacpcity)
{ AddCacpcity(n);
}
}
//字符串比較函數(shù)重載
bool operator<(const string& s)
{ return strcmp(_str, s._str)< 0;
}
bool operator<=(const string& s)
{ return (*this< s) || (*this == s);
}
bool operator>(const string& s)
{ return !((*this)<= s);
}
bool operator>=(const string& s)
{ return !(*this< s);
}
bool operator==(const string& s)
{ return strcmp(_str, s._str) == 0;
}
bool operator!=(const string& s)
{ return !(*this == s);
}
// 返回c在string中第一次出現(xiàn)的位置
size_t find(char c, size_t pos = 0) const
{ for (int i = pos; i< _size; i++)
{ if (_str[i] == c)
return i;
}
return nops;
}
// 返回子串s在string中第一次出現(xiàn)的位置
size_t find(const char* s, size_t pos = 0) const
{ char* tmp = strstr(_str, s);
if (tmp == NULL)
return nops;
return tmp - _str;
}
// 在pos位置上插入字符c/字符串str,并返回該字符的位置
string& insert(size_t pos, char c)
{ //判斷容量
if (_size == _cacpcity)
{ AddCacpcity(_cacpcity == 0 ? 15 : _cacpcity * 2);
}
//pos位置后往后移
size_t end = _size + 1;
while (pos< end)
{ _str[end] = _str[end - 1];
end--;
}
_str[pos] = c;
_size++;
return *this;
}
//插入字符串
string& insert(size_t pos, const char* str)
{ size_t len = strlen(str);
//判斷容量
if (_cacpcity< (len + _size))
{ AddCacpcity(len + _size);
}
//移動len格
size_t end1 = _size+1;
size_t end2 = _size + len ;
while (pos< end1 )
{ _str[end2] = _str[end1-1] ;
end1--;
end2--;
}
int i = pos;
while (*str)
{ _str[i++] = *str++;
}
_size += len;
return *this;
}
// 刪除
string& erase(size_t pos, size_t len)
{ //如果要刪除的長度大于后面的剩余長度
if (len >= _size - pos)
{ len = _size - pos;
_size -= len;
_str[pos] = '\0';
return *this;
}
//把后面的往前移,覆蓋式刪除
size_t begin = pos+len;
while (_str[begin])
{ _str[begin-len] = _str[begin];
begin++;
}
_size -= len;
return *this;
}
private:
char* _str;
size_t _size;
size_t _cacpcity;
static const size_t nops = -1;
};
}
總結(jié):string類的細節(jié)還有很多,在這里只能簡單實現(xiàn)一下。在實現(xiàn)的過程中需要注意的幾點。
1.避免內(nèi)存越界,否則析構(gòu)時銷毀會出錯。
2.釋放new出來的內(nèi)存,避免內(nèi)存泄漏。
3.需要深拷貝,否則會出現(xiàn)析構(gòu)多次的情況。
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧
網(wǎng)頁標題:【C++】STL---string類的模擬實現(xiàn)-創(chuàng)新互聯(lián)
網(wǎng)站地址:http://bm7419.com/article14/hdgge.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供關(guān)鍵詞優(yōu)化、網(wǎng)站導航、Google、網(wǎng)站改版、面包屑導航、企業(yè)建站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容