前言:在上一篇中我們講到了string類的使用方法,今天我們將進一步的去學習string類,去底層看看它順帶模擬實現(xiàn)部分的內容。
?? 博主CSDN主頁:衛(wèi)衛(wèi)衛(wèi)的個人主頁 ??
?? 專欄分類:高質量C++學習 ??
??代碼倉庫:衛(wèi)衛(wèi)周大胖的學習日記??
??關注博主和博主一起學習!一起努力!
模擬實現(xiàn)string類
string類的默認成員函數(shù)
class string
{
public:
static const int npos;
string(const char* str = "")//默認有參構造
:_size(strlen(str))
{
_capacity = _size;//空間等于字節(jié)數(shù)+1
_str = new char[_capacity + 1];//深度拷貝
strcpy(_str, str);//作用域結束會自動調用析構
}
~string()//析構函數(shù)
{
delete[] _str;
_str = nullptr;
_capacity = 0;
_size = 0;
}
private:
char* _str = nullptr;
size_t _size = 0;//記錄空間字符個數(shù)
size_t _capacity = 0;//空間容量
};
static const int npos = -1;
構造函數(shù)
- 我們在這里構造默認構造時候,我們之所以默認的是" "而不是’\0’和’空指針’,是為了防止strlen是的調用的時候對空指針的解引用。
- 開辟空間的時候要額外開辟一個,用于存放’\0’。
string(const char* str = "")//默認有參構造
:_size(strlen(str))
{
_capacity = _size;//空間等于字節(jié)數(shù)+1
_str = new char[_capacity + 1];//深度拷貝
strcpy(_str, str);//作用域結束會自動調用析構
}
拷貝構造函數(shù)
- 記住在string類拷貝構造的時候一定要是深拷貝,不然在出了作用域以后會自動調用析構函數(shù),就會照成對一塊空間進行兩次析構。
- 開辟一塊空間,讓原本的對象指向新開辟的空間,再將拷貝對象的內容拷貝過來,就可以完成深度拷貝(目前我就寫一個傳統(tǒng)寫法,現(xiàn)代寫法后面會講)了。
string(const string& s)//深度拷貝構造-傳統(tǒng)寫法
{
_str = new char[s._capacity + 1];
strcpy(_str, s._str);
_size = s._size;
_capacity = s._capacity;
}
析構函數(shù)
- 析構函數(shù)就比較簡單了,對原本的指針的空間進行釋放即可。
~string()//析構函數(shù)
{
delete[] _str;
_str = nullptr;
_capacity = 0;
_size = 0;
}
operator=賦值運算符重載
- 這里我們的賦值運算符重載同樣的是一種深拷貝。
- 同理我們先開辟一塊同樣大小的空間,然后在把拷貝的內容拷貝過去
- 這里我需要強調一共點,至于為什么我們要開辟一塊空間,因為這種寫法我們可以理解成是最暴力最簡單的,因為我們在檢查空間容量的時候,沒有縮容這個寫方法,如果我們想讓他直接對原本的空間進行擴容的話,我們還需要考慮原本的空間是否足夠大和或者多了需要縮容,這種寫法可以完美的解決這些問題。
string& operator=(const string& s)//賦值運算符重載-深度拷貝
{
if (this != &s)//防止自己給自己賦值
{
char* tmp = new char[s._capacity + 1];
strcpy(tmp, s._str);
delete _str;
_str = tmp;//深拷貝,通過新開辟的空間讓,防止結束后被析構兩次
_capacity = s._capacity;
_size = s._size;
}
return *this;
}
容量大小相關的函數(shù)
size( )函數(shù)
- 我們直接返回size中的個數(shù)即可,不包括\0
size_t size()const //返回字節(jié)數(shù)
{
return _size;
}
capacity()函數(shù)
- 同理返回capacity中的個數(shù)即可
size_t capacity()const //返回內存容量
{
return _capacity;
}
reserve()函數(shù)-查看空間是否足夠,不夠就擴容
- 我們先查看傳過來的字符是否比空間容量大,大就擴容,小的話就不用管他
- 在C++中我們沒有像rellaco這樣的函數(shù)(不代表我們不能用,只是通常不喜歡用),我們就用new開辟一塊同樣大小的空間,然后拷貝過去即可。
void reserve(size_t n)//檢查內存,查看是否n個字符能否存入該空間中
{
if (n > _capacity)
{
char* tmp = new char[n + 1];//C++中沒有rellaco這樣的函數(shù),所以通常不會直接追加
strcpy(tmp, _str);//先把原本的字符拷貝到新開辟的空間
delete[] _str;
_str = tmp;
_capacity = n;//空間擴容到n,記住擴容的時候size是沒變的,size是查看有多少個有效字符
}
}
resize()函數(shù)- 調整空間大小
- 我們需要查看調整的大小以后,是否比原來的空間大小還小,如果比原來的空間還小我們直接在n的位置賦值給’\0’即可,我們不需要考慮把后面的元素刪了,因為我們調整了size以后無法訪問到后面的元素。
- 如果需要調整的空間更大了,我們就i將后面的元素全部擴容成’\0’或者指定的元素,然后將最后一個元素賦值成’\0’。
void resize(size_t n, char ch = '\0')//擴容
{
if (n < _size)
{
_str[n] = '\0';
_size = n;
}
else
{
reserve(n);//查看是否需要擴容
for (size_t i = _size; i < n; i++)
{
_str[i] = ch;//后面的元素如果沒有指定就全部賦值成'\0'
}
_str[n] = '\0';//最后一個元素賦值成\0
_size = n;
}
}
函數(shù)測試:
void test_string1()
{
string s1("wei wei");
cout << s1 << endl;
s1.resize(10, 'z');
cout << s1 << endl;
}
clear()函數(shù)
void clear()
{
_size = 0;
_str[_size] = '\0';
}
下標訪問元素
- 因為對象中的_str就是一個指針,所以我們直接引用返回pos位置的值即可。
char& operator[](size_t pos)
{
assert(pos < _size);//防止越界
return _str[pos];//返回pos位置的引用,相當于就是把那個字符給返回了
}
//const版本
const char& operator[](size_t pos)
{
assert(pos > 0 && pos < _size);
return _str[pos];
}
函數(shù)測試:
void test_string1()
{
string s1("wei wei");
cout << s1 << endl;
s1.resize(10, 'z');
cout << s1 << endl;
cout << s1[2] << endl;
}
查找相關函數(shù)
find()函數(shù) – 查找字符
- 我們先判斷傳過來的pos位置是不是在字符串的長度范圍內。
- 我們通過半缺省,可以指定從pos位置查找,如果找到了返回Pos位置的下標即可,沒找到返回npos(即我們前面定義的一個靜態(tài)變量,-1);
size_t find(char ch, size_t pos = 0)//查找ch這個字符,pos指代從什么位置開始查找
{
assert(pos < _size);
for (size_t i = pos; i < _size; i++)
{
if (_str[i] == ch)
{
return i;
}
}
return npos;
}
函數(shù)測試:
void test_string1()
{
string s1("wei wei");
cout << s1 << endl;
s1.resize(10, 'z');
cout << s1.find('w', 2) << endl;
}
find()函數(shù) – 查找字符串
- 同理我們先判斷傳過來的pos位置是不是在字符串的長度范圍內。
- 我們通過半缺省,可以指定從pos位置查找,如果找到了返回Pos位置的下標即可,沒找到返回npos(即我們前面定義的一個靜態(tài)變量,-1);
- 但是注意我們這里找的是字符串,所以我們可以通過strstr這個庫函數(shù)去幫助我們在pos的位置開始找。
- 如果找到了,strstr會返回起始位置的地址,因為我們只需要將原本主串的首地址減去字串的首地址就是中間元素的個數(shù),也就是字串第一次出現(xiàn)的位置了。
- 沒有找到我們同理返回npos(-1)。
size_t find(const char* str, size_t pos = 0)const //查找str這個字符串,pos指代從什么位置開始找
{
assert(pos < _size);
const char* p = strstr(_str + pos, str); // 在_str + pos的位置去找str, 如果找到了就返回的是str出現(xiàn)的位置, 否則返回空
if (p)//找到了
{
return p - _str;//即返回字串第一次出現(xiàn)的位置,兩個指針相減就是中間相差元素的個數(shù)
}
else
{
return npos;
}
}
函數(shù)測試:
void test_string1()
{
string s1("weiweizhou");
cout << s1 << endl;
s1.resize(10, 'z');
cout << s1.find("zhou", 2) << endl;
}
迭代器相關的函數(shù)
- 在string類中,我們的底層實際上就是一種指針,我們這里把它typedef一下即可。
- 正向迭代器就是直接返回指針的起始地址。
- 反向迭代器就是返回最后一個字符的地址。
typedef char* iterator;
typedef const char* const_iterator;
const_iterator begin()const//正向迭代器 - 返回初始位置
{
return _str;
}
const_iterator end()const //反向迭代器- 返回末端位置
{
return _str + _size;
}
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
函數(shù)測試:
void test_string1()
{
string s1("weiweizhou");
string::iterator item;
item = s1.begin();
for (size_t i = 0; i < s1.size(); i++)
{
cout << *(item + i) << " ";
}
cout << endl;
string::iterator end;
end = s1.end();
for (size_t i = 0; i < s1.size(); i++)
{
cout << *(end - i - 1) << " ";
}
}
插入字符的相關函數(shù)
push_back(char ch)尾插字符
- 尾插字符實際就是和順序表一樣的寫法,大家不懂的話可以看我之前的文章順序表。
- 我們先查看空間容量夠不夠如果不夠就直接擴容。
- 我們直接找到最后一個\0的位置,直接替換成插入的字符即可。
- 插入以后將size++,在讓最后一個元素題換成\0
void push_back(char ch)//尾插字符
{
if (_size == _capacity)
{
reserve(_capacity == 0 ? 4 : _capacity * 2);//和順序表一樣的寫法
}
_str[_size] = ch;
++_size;
_str[_size] = '\0';
}
函數(shù)測試:
void test_string1()
{
string s1("weiweizhou");
cout <<"追加前: " << s1 << endl;
s1.push_back('c');
cout <<"追加后: " << s1 << endl;
}
void append(const char* str)追加字符串
- 同理我們先查看追加字符串后的空間夠不夠,如果不夠同理我們得先擴容。
- 將追加的字符串通過庫函數(shù)直接拷貝到原本的字符串的’\0’的位置即可。
- 最后調整_size的大小。
void append(const char* str)//追加字符串
{
size_t len = strlen(str);
if (_capacity < _size + len)//查看追加后是否需要擴容
{
reserve(_size + len);
}
strcpy(_str + _size, str);//尾插到之前\0的位置
_size += len;
}
函數(shù)測試:
void test_string1()
{
string s1("weiweizhou");
cout <<"追加前: " << s1 << endl;
s1.append(" hello");
cout <<"追加后: " << s1 << endl;
}
string& operator +=(const char* str)尾插字符串
- 我們前面寫了一個append函數(shù),直接在這里調用即可。
- 需要注意的是我們這里記得引用返回,不然無法連續(xù)賦值,在前面運算符重載種講過了,這里也就不會在提了(這里就不給大家測試了)。
string& operator +=(const char* str)//尾插字符串
{
append(str);
return *this;
}
string& operator +=(const char ch)尾插字符
- 同理我們前面寫了一個push_back尾插字符,這里也是直接調用就好啦。
- 這里也同樣引用返回。
string& operator +=(const char ch)//尾插字符
{
push_back(ch);
return *this;
}
void insert(size_t pos, const char ch)指定位置插入字符
- 同理我們先查看插入以后是否空間容量足夠,不夠就擴容。
- 我們將pos位置后面的值全部往后移動一個,然后在將插入的字符放在pos位置即可,不懂的看下圖。
- 這里作者認為最難的就是控制循環(huán)結束條件了,這里我們需要知道是插入到pos的位置,因此當end走到pos的位置時候即停止循環(huán),進行插入。
void insert(size_t pos, const char ch)//指定位置插入字符
{
assert(pos <= _size);
if (_capacity == _size)//查看追加后是否需要擴容
{
reserve(_capacity == 0 ? 4 : _capacity * 2);//和順序表一樣的寫法
}
size_t end = _size + 1;
while (end > pos)
{
_str[end] = _str[end - 1];//將pos后的字符全部移動到插入后的位置
end--;
}
_str[pos] = ch;
_size += 1;
}
函數(shù)測試:
void test_string1()
{
string s1("weiweizhou");
cout <<"追加前: " << s1 << endl;
s1.insert(1, 'c');
//s1.append(" hello");
cout <<"追加后: " << s1 << endl;
}
void insert(size_t pos, const char* str)指定位置插入字符串
- 同理我們依然先判斷容量夠不夠,如果不夠依然是擴容那套方法。
- 這次我們需要注意的是追加是字符串而不是單單一個字符了。
- 因為追加的是一個字符串,我們這里讓pos位置以后的字符全部往后移動len個(插入字符串的長度),然后將字符串插入到Pos的位置即可。(如下圖所示)
void insert(size_t pos, const char* str)//指定位置插入字符串
{
assert(pos <= _size);
size_t len = strlen(str);
if (_capacity < _size + len)//查看追加后是否需要擴容
{
reserve(_size + len);
}
size_t end = _size + len; //找到最后一個位置
while (end > pos + len - 1)//當End走到插入字符串的最后一個時候,全部移動完成
{
_str[end] = _str[end - len];//將pos后的字符串全部移動到插入后的位置
end--;
}
strncat(_str + pos, str,len); // 拷貝到_str + pos的位置
_size = _size + len;
}
函數(shù)測試:
void test_string1()
{
string s1("weiweizhou");
cout <<"追加前: " << s1 << endl;
s1.insert(2, "dapang");
//s1.append(" hello");
cout <<"追加后: " << s1 << endl;
}
刪除字符和字符串
void erase(size_t pos, size_t len = npos)從pos的位置往后刪len個字符
- 在刪除我們考慮兩種情況,一種是使用的人并沒有指定刪除多長的字符,就默認把它全部刪除。 第二種就是使用的人選擇刪除的長度比他從pos位置指定的后面的所有的字符刪除都長。對于這兩種情況,我們都可以直接在pos的位置賦值為’\0’,然后改變size的大小就行。
2.如果指定刪除的長度,小于Pos后面所有字符串的長度,我們只需要把pos位置加上要刪除的長度這一塊空間后面的字符串拷貝到pos的位置來即可。(如下圖)
void erase(size_t pos, size_t len = npos)//從pos的位置往后刪len個字符,len默認是-1
{
assert(pos < _size);
if (pos == npos || len > _size - pos)//如果沒有指定pos,或者從pos位置往后刪除的長度比整個字符串都長,就默認全部刪除
{
_str[pos] = '\0';
_size = pos;
}
else
{
strcpy(_str + pos, _str + pos + len);
_size = _size - len;
}
}
函數(shù)測試:
void erase(size_t pos, size_t len = npos)//從pos的位置往后刪len個字符,len默認是-1
{
assert(pos < _size);
if (pos == npos || len > _size - pos)//如果沒有指定pos,或者從pos位置往后刪除的長度比整個字符串都長,就默認全部刪除
{
_str[pos] = '\0';
_size = pos;
}
else
{
strcpy(_str + pos, _str + pos + len);
_size = _size - len;
}
}
查找字串
string substr(size_t pos = 0, size_t len = npos)找字串
- 通過半缺省,如果不指定pos就從開始開始找,一直往后len個都是屬于字串。如果不知道len,就是從pos位置一直到最后都是字串。
- 同理我們需要判斷從讀取的長度是不是比Pos位置后面所有的字符都要長,如果是的那么從pos位置開始,后面都是字串,全部保存到我們的對象中即可。
- 如果沒有比pos后面的字符長,我們只需要加到pos+len的位置就停下來即可。
- 我們這里注意返回的是一個對象。
string substr(size_t pos = 0, size_t len = npos)//找字串
{
string sub;
if (len >= _size - pos)//如果讀取的長度比pos往后的所有字符加起來都長,就后面所有的都是字串
{
for (size_t i = pos; i < _size; i++)
{
sub += _str[i];
}
}
else
{
for (size_t i = pos; i < len + pos; i++)
{
sub += _str[i];
}
}
return sub;
}
函數(shù)測試:
void test_string1()
{
string s1("weiweizhou");
cout <<"主串: " << s1 << endl;
string sub = s1.substr(3, 3);
cout <<"子串: " << sub << endl;
}
流插入 流提取 重載
流提取
- 在C++中,可以將流插入和流提取操作符(<<和>>)重載為string類的成員函數(shù),也可以將它們重載為全局函數(shù)。選擇將它們重載為成員函數(shù)還是全局函數(shù)取決于設計者的個人偏好和具體需求。
- 將流插入和流提取操作符重載為成員函數(shù)的一個優(yōu)勢是可以直接訪問類的私有成員和保護成員。這意味著在重載的函數(shù)中可以直接使用類的成員變量和成員函數(shù),而無需通過訪問器或其他方式來獲取或修改數(shù)據(jù)。這種直接訪問對于操作字符串類中的數(shù)據(jù)非常方便。但是這種會破壞程序的封裝性,不推薦。
- 另一方面,將流插入和流提取操作符重載為全局函數(shù)可以提高代碼的可讀性和靈活性。全局函數(shù)可以將string類的實例作為參數(shù),并具有更通用的用法。例如,可以使用全局函數(shù)重載流插入操作符來將string對象插入到任何類型的輸出流中,而不僅僅是標準輸出流。同樣,可以使用全局函數(shù)重載流提取操作符從任何類型的輸入流中提取字符串。
ostream& operator<<(ostream& out, const string& s)
{
for (auto ch : s)//out是內置類型數(shù)據(jù),可以直接輸出類型
{
out << ch;
}
return out;
}
流插入
- 我們先開辟一個數(shù)組,在我們讀取數(shù)據(jù)后,如果數(shù)據(jù)不超過128個就先全部存放在這個數(shù)組中。
- 當數(shù)組中元素到了128個,我把數(shù)組中的數(shù)據(jù)轉移到對象中,在把數(shù)組中的數(shù)據(jù)給清0即可。
- 如果數(shù)組本身就讀不到128個在數(shù)據(jù)讀取完成后,直接放在對象中即可。
istream& operator>>(istream& in, string& s)
{
s.clear();
char ch;
ch = in.get();
char buff[128];//開辟一個數(shù)組,將一開始讀取的數(shù)據(jù)全部放在數(shù)組中
size_t i = 0;
while (ch != ' ' && ch != '\n')
{
buff[i++] = ch;
if (i == 127)//數(shù)組超過了127個以后,再將讀取的數(shù)據(jù)放在對象中
{
buff[127] = '\0';
s += buff;
i = 0;
}
ch = in.get();
}
if (i > 0)//如果不足128就直接通過數(shù)組放在了對象中
{
buff[i] = '\0';
s += buff;
}
return in;
}
函數(shù)測試:
void test_string1()
{
string s2;
cin >> s2;
cout <<"輸入的數(shù)據(jù): " << s2 << endl;
}
getline輸入數(shù)據(jù)
- 這里我們和剛剛流插入一樣的玩法就可以了,不懂的就看上面的講解就行了。
istream& getline(istream& in, string& s)
{
s.clear();
char ch;
ch = in.get();
char buff[128];
size_t i = 0;
while (ch != ' ' && ch != '\n')
{
buff[i++] = ch;
if (i == 127)
{
buff[127] = '\0';
s += buff;
i = 0;
}
ch = in.get();
}
if (i > 0)
{
buff[i] = '\0';
s += buff;
}
return in;
}
關系運算符重載
1.關于關系運算符重載由于比較簡單,這里作者就不全部詳細講解了。
bool operator==(const bit::string& s1, const bit::string& s2)
{
int ret = strcmp(s1.c_str(), s2.c_str());
return ret == 0;
}
bool operator<(const bit::string& s1, const bit::string& s2)
{
int ret = strcmp(s1.c_str(), s2.c_str());
return ret < 0;
}
bool operator>(const bit::string& s1, const bit::string& s2)
{
int ret = strcmp(s1.c_str(), s2.c_str());
return ret > 0;
}
bool operator<=(const bit::string& s1, const bit::string& s2)
{
return s1 < s2 || s1 == s2;
}
bool operator>=(const bit::string& s1, const bit::string& s2)
{
return s1 > s2 || s1 == s2;
}
bool operator!=(const bit::string& s1, const bit::string& s2)
{
return !(s1 == s2);
}
全部接口的整體代碼
#include<iostream>
#include <assert.h>
#include <string.h>
namespace bit
{
class string
{
public:
typedef char* iterator;
typedef const char* const_iterator;
static const int npos;
const_iterator begin()const//正向迭代器 - 返回初始位置
{
return _str;
}
const_iterator end()const //反向迭代器- 返回末端位置
{
return _str + _size;
}
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
string(const char* str = "")//默認有參構造
:_size(strlen(str))
{
_capacity = _size;//空間等于字節(jié)數(shù)+1
_str = new char[_capacity + 1];//深度拷貝
strcpy(_str, str);//作用域結束會自動調用析構
}
~string()//析構函數(shù)
{
delete[] _str;
_str = nullptr;
_capacity = 0;
_size = 0;
}
string(const string& s)//深度拷貝構造-傳統(tǒng)寫法
{
_str = new char[s._capacity + 1];
strcpy(_str, s._str);
_size = s._size;
_capacity = s._capacity;
}
const char* c_str()const //以C語言的形式返回字符串
{
return _str;
}
string& operator=(const string& s)//賦值運算符重載-深度拷貝
{
char* tmp = new char[s._capacity + 1];
strcpy(tmp, s._str);
delete _str;
_str = tmp;//深拷貝,通過新開辟的空間讓_Str拷貝兩次,防止結束后被析構兩次
_capacity = s._capacity;
_size = s._size;
return *this;
}
size_t size()const //返回字節(jié)數(shù)
{
return _size;
}
size_t capacity()const //返回內存容量
{
return _capacity;
}
const char& operator[](size_t pos)
{
assert(pos > 0 && pos < _size);
return _str[pos];
}
void reserve(size_t n)//檢查內存,查看是否n個字符能否存入該空間中
{
if (n > _capacity)
{
char* tmp = new char[n + 1];//C++中沒有rellaco這樣的函數(shù),所以通常不會直接追加
strcpy(tmp, _str);//先把原本的字符拷貝到新開辟的空間
delete[] _str;
_str = tmp;
_capacity = n;//空間擴容到n,記住擴容的時候size是沒變的,size是查看有多少個有效字符
}
}
void resize(size_t n, char ch = '\0')//擴容
{
if (n < _size)
{
_str[n] = '\0';
_size = n;
}
else
{
reserve(n);//查看是否需要擴容
for (size_t i = _size; i < n; i++)
{
_str[i] = ch;//后面的元素如果沒有指定就全部賦值成'\0'
}
_str[n] = '\0';//最后一個元素賦值成\0
_size = n;
}
}
void push_back(char ch)//尾插字符
{
if (_size == _capacity)
{
reserve(_capacity == 0 ? 4 : _capacity * 2);//和順序表一樣的寫法
}
_str[_size] = ch;
++_size;
_str[_size] = '\0';
}
void append(const char* str)//追加字符串
{
size_t len = strlen(str);
if (_capacity < _size + len)//查看追加后是否需要擴容
{
reserve(_size + len);
}
strcpy(_str + _size, str);//尾插到之前\0的位置
_size += len;
}
string& operator +=(const char* str)//尾插字符串
{
append(str);
return *this;
}
string& operator +=(const char ch)//尾插字符
{
push_back(ch);
return *this;
}
void insert(size_t pos, const char ch)//指定位置插入字符
{
assert(pos <= _size);
if (_capacity == _size)//查看追加后是否需要擴容
{
reserve(_capacity == 0 ? 4 : _capacity * 2);//和順序表一樣的寫法
}
size_t end = _size + 1;
while (end > pos)
{
_str[end] = _str[end - 1];//將pos后的字符全部移動到插入后的位置
end--;
}
_str[pos] = ch;
_size += 1;
}
void insert(size_t pos, const char* str)//指定位置插入字符串
{
assert(pos <= _size);
size_t len = strlen(str);
if (_capacity < _size + len)//查看追加后是否需要擴容
{
reserve(_size + len);
}
size_t end = _size + len; //找到最后一個位置
while (end > pos + len - 1)//當End走到插入字符串的最后一個時候,全部移動完成
{
_str[end] = _str[end - len];//將pos后的字符串全部移動到插入后的位置
end--;
}
strncpy(_str + pos, str,len); // 拷貝到_str + pos的位置
_size = _size + len;
}
void erase(size_t pos, size_t len = npos)//從pos的位置往后刪len個字符,len默認是-1
{
assert(pos < _size);
if (pos == npos || len > _size - pos)//如果沒有指定pos,或者從pos位置往后刪除的長度比整個字符串都長,就默認全部刪除
{
_str[pos] = '\0';
_size = pos;
}
else
{
strcpy(_str + pos, _str + pos + len);
_size = _size - len;
}
}
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
void swap(string& x, string& y)
{
x.swap(y);
}
size_t find(char ch, size_t pos = 0)const //查找ch這個字符,pos指代從什么位置開始查找
{
assert(pos < _size);
for (size_t i = pos; i < _size; i++)
{
if (_str[i] == ch)
{
return i;
}
}
return npos;
}
size_t find(const char* str, size_t pos = 0)const //查找str這個字符串,pos指代從什么位置開始找
{
assert(pos < _size);
const char* p = strstr(_str + pos, str); // 在_str + pos的位置去找str, 如果找到了就返回的是str出現(xiàn)的位置, 否則返回空
if (p)//找到了
{
return p - _str;//即返回字串第一次出現(xiàn)的位置,兩個指針相減就是中間相差元素的個數(shù)
}
else
{
return npos;
}
}
string substr(size_t pos = 0, size_t len = npos)//找字串
{
string sub;
if (len >= _size - pos)//如果讀取的長度比pos往后的所有字符加起來都長,就后面所有的都是字串
{
for (size_t i = pos; i < _size; i++)
{
sub += _str[i];
}
}
else
{
for (size_t i = pos; i < len + pos; i++)
{
sub += _str[i];
}
}
return sub;
}
void clear()
{
_size = 0;
_str[_size] = '\0';
}
private:
char* _str = nullptr;
size_t _size = 0;
size_t _capacity = 0;
};
const int string::npos = -1;
bool operator==(const bit::string& s1, const bit::string& s2)
{
int ret = strcmp(s1.c_str(), s2.c_str());
return ret == 0;
}
bool operator<(const bit::string& s1, const bit::string& s2)
{
int ret = strcmp(s1.c_str(), s2.c_str());
return ret < 0;
}
bool operator>(const bit::string& s1, const bit::string& s2)
{
int ret = strcmp(s1.c_str(), s2.c_str());
return ret > 0;
}
bool operator<=(const bit::string& s1, const bit::string& s2)
{
return s1 < s2 || s1 == s2;
}
bool operator>=(const bit::string& s1, const bit::string& s2)
{
return s1 > s2 || s1 == s2;
}
bool operator!=(const bit::string& s1, const bit::string& s2)
{
return !(s1 == s2);
}
ostream& operator<<(ostream& out, const string& s)
{
for (auto ch : s)
{
out << ch;
}
return out;
}
istream& operator>>(istream& in, string& s)
{
s.clear();
char ch;
ch = in.get();
char buff[128];
size_t i = 0;
while (ch != ' ' && ch != '\n')
{
buff[i++] = ch;
if (i == 127)
{
buff[127] = '\0';
s += buff;
i = 0;
}
ch = in.get();
}
if (i > 0)
{
buff[i] = '\0';
s += buff;
}
return in;
}
istream& getline(istream& in, string& s)
{
s.clear();
char ch;
ch = in.get();
char buff[128];
size_t i = 0;
while (ch != ' ' && ch != '\n')
{
buff[i++] = ch;
if (i == 127)
{
buff[127] = '\0';
s += buff;
i = 0;
}
ch = in.get();
}
if (i > 0)
{
buff[i] = '\0';
s += buff;
}
return in;
}
好啦,今天的內容就到這里啦,下期內容預告vector的使用,博主最近比較忙可能更新的會比較慢請見諒文章來源:http://www.zghlxwxcb.cn/news/detail-842156.html
結語:今天的內容就到這里吧,謝謝各位的觀看,如果有講的不好的地方也請各位多多指出,作者每一條評論都會讀的,謝謝各位。文章來源地址http://www.zghlxwxcb.cn/news/detail-842156.html
到了這里,關于【C++】string類的模擬實現(xiàn)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!