1.模擬實(shí)現(xiàn)string
string使用文章
1.1構(gòu)造函數(shù)
??這里我們實(shí)現(xiàn)常用的第四個(gè)string(const char* s)和析構(gòu)函數(shù)
class string {
public:
//初始化列表賦值
//string(const char* str = "\0")
// :_size(strlen(str))
// ,_capacity(_size)
// ,_str(new char[_capacity+1])
//{
// memcpy(_str, str, _size + 1);
//}
//函數(shù)體內(nèi)賦值
string(const char* str = "\0")
{
_size = strlen(str); // 獲取字符串長(zhǎng)度
_capacity = _size; // 設(shè)置容量為長(zhǎng)度
_str = new char[_capacity + 1]; // 分配內(nèi)存空間
memcpy(_str, str, _size + 1); // 復(fù)制字符串內(nèi)容
//strcpy(_str, str);
//這里最好不要使用strcpy,因?yàn)閟trcpy是C語(yǔ)言中的函數(shù)
//在檢測(cè)到/0直接結(jié)束,若字符串中有/0,會(huì)導(dǎo)致部分字符串無(wú)法復(fù)制
}
~string()
{
_size = 0;
_capacity = 0;
delete[] _str;
_str = nullptr;
}
private:
int _size; // 字符串長(zhǎng)度
int _capacity; // 字符串容量
char* _str; // 字符串內(nèi)容
};
?
??拷貝構(gòu)造函數(shù)實(shí)現(xiàn):
??在堆上使用new關(guān)鍵字為當(dāng)前對(duì)象的成員變量_str分配內(nèi)存空間,大小為s._capacity + 1字節(jié),即字符串的容量加上一個(gè)結(jié)束符\0的空間。
??我們使用深拷貝而不是淺拷貝,淺拷貝會(huì)導(dǎo)致兩個(gè)對(duì)象的指針指向同一塊內(nèi)存空間,當(dāng)其中一個(gè)對(duì)象被析構(gòu)時(shí),會(huì)釋放內(nèi)存空間,導(dǎo)致另一個(gè)對(duì)象指向的內(nèi)存變成懸空指針。 因此,在復(fù)制構(gòu)造函數(shù)中使用了深拷貝來(lái)確保每個(gè)對(duì)象都有獨(dú)立的內(nèi)存空間存儲(chǔ)字符串內(nèi)容,避免出現(xiàn)懸空指針和程序崩潰的問(wèn)題。
string(const string& s)
{
this->_size = s._size;
this->_capacity = s._capacity;
//淺拷貝,兩個(gè)指針指向同一塊空間,且調(diào)用兩次析構(gòu)函數(shù),程序崩潰
//this->_str = s._str;
//深拷貝 實(shí)現(xiàn)
this->_str = new char[s._capacity + 1];
//strcpy(_str, s.c_str());
memcpy(_str, s.c_str(), _size + 1);
}
?
1.2迭代器
??我們通過(guò)迭代器來(lái)訪問(wèn)字符串的每個(gè)字符。begin 函數(shù)返回指向字符串的起始位置的迭代器,end 函數(shù)返回指向字符串的結(jié)束位置的迭代器。這樣,就可以使用標(biāo)準(zhǔn)的迭代器操作來(lái)遍歷字符串,如使用循環(huán)來(lái)遍歷每個(gè)字符。
??對(duì)于普通的string類型,編譯器調(diào)用上面兩個(gè)類型iterator的迭代器,表示可以對(duì)該字符串可讀可寫;而對(duì)于const類型的string,編譯器就會(huì)調(diào)用下面兩個(gè)類型const_iterator的迭代器,表示對(duì)該字符串只有可寫權(quán)限。
//實(shí)現(xiàn)迭代器和const迭代器
typedef char* iterator;
typedef const char* const_iterator;
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
const_iterator begin() const
{
return _str;
}
const_iterator end() const
{
return _str + _size;
}
?
1.3運(yùn)算符重載
operator[]
??和上面的迭代器實(shí)現(xiàn)類似,我們也需要實(shí)現(xiàn)兩個(gè)operator[]。
??重載的普通版本的 operator[] 函數(shù)接受一個(gè) size_t 類型的位置參數(shù) pos。它首先使用 assert 斷言來(lái)檢查指定的位置是否位于有效的范圍內(nèi),即小于字符串的長(zhǎng)度 _size。然后,它返回 _str[pos],也就是字符串中指定位置 pos 處的字符的引用。因?yàn)樵摵瘮?shù)返回的是一個(gè)引用,所以可以通過(guò)該引用對(duì)字符進(jìn)行修改。
??重載的const版本的 operator[] 函數(shù)與版本類似,但是函數(shù)本身被聲明為const成員函數(shù),以確保不會(huì)修改對(duì)象的成員變量。這意味著對(duì)const對(duì)象時(shí)operator[]只能進(jìn)行讀的權(quán)限,但不能通過(guò)返回的引用來(lái)修改字符。
??通過(guò)重載 [] 操作符,可以像操作數(shù)組一樣方便地訪問(wèn)類中的字符。例如,對(duì)于字符串對(duì)象 str,可以使用 str[0] 來(lái)訪問(wèn)第一個(gè)字符,str[1] 來(lái)訪問(wèn)第二個(gè)字符,以此類推。
//重載[]操作符
char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
//重載const[]操作符
const char& operator[](size_t pos) const
{
assert(pos < _size);
return _str[pos];
}
?
賦值運(yùn)算符
??傳統(tǒng)寫法中的賦值操作符重載函數(shù)首先進(jìn)行自我賦值的判斷,以確保在自我賦值的情況下不會(huì)出現(xiàn)問(wèn)題。 然后,創(chuàng)建一個(gè)臨時(shí)的字符數(shù)組 tmp,大小為 s._capacity + 1,并使用 memcpy 函數(shù)將 s._str 的內(nèi)容復(fù)制到 tmp 中。接下來(lái),刪除當(dāng)前對(duì)象的 _str 所指向的內(nèi)存空間,并將其指針指向新分配的 tmp。最后,更新當(dāng)前對(duì)象的 _size 和 _capacity。
??現(xiàn)代寫法中的賦值操作符重載函數(shù)使用了拷貝構(gòu)造函數(shù)來(lái)簡(jiǎn)化實(shí)現(xiàn)。 它首先創(chuàng)建一個(gè)臨時(shí)的字符串對(duì)象 tmp,并使用參數(shù) s 初始化 tmp。然后,調(diào)用 swap 函數(shù)來(lái)交換當(dāng)前對(duì)象的成員變量和 tmp 對(duì)象的成員變量。這樣做的好處是,通過(guò)交換指針,可以避免進(jìn)行手動(dòng)的內(nèi)存分配和釋放,并且保證異常安全性。最后,返回當(dāng)前對(duì)象的引用。
//傳統(tǒng)寫法
/*string& operator=(const string& s)
{
if (this != &s)
{
char* tmp = new char[s._capacity + 1];
memcpy(tmp, s._str, s._size + 1);
delete[] _str;
_str = tmp;
_size = s._size;
_capacity = s._capacity;
}
return *this;
}*/
//現(xiàn)代寫法
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
string& operator=(const string& s)
{
if (this != &s)
{
string tmp(s);
//this->swap(tmp);
swap(tmp);
}
return *this;
}
//更簡(jiǎn)單的寫法
//string& operator=(string tmp)
//{
// swap(tmp);
//
// return *this;
//}
?
其他用于string比較的運(yùn)算符重載:
bool operator<(const string& s) const
{
int ret = memcmp(_str, s._str, _size < s._size ? _size : s._size);
return ret == 0 ? _size < s._size : ret < 0;
}
bool operator==(const string& s) const
{
return _size == s._size
&& memcmp(_str, s._str, _size) == 0;
}
bool operator<=(const string& s) const
{
return *this < s || *this == s;
}
bool operator>(const string& s) const
{
return !(*this <= s);
}
bool operator>=(const string& s) const
{
return !(*this < s);
}
bool operator!=(const string& s) const
{
return !(*this == s);
}
?
1.4擴(kuò)容函數(shù)
reserve和resize
??這兩個(gè)函數(shù)的作用是在需要擴(kuò)容或調(diào)整字符串大小的情況下,確保字符串對(duì)象具有足夠的容量和正確的大小。其中,reserve 函數(shù)用于擴(kuò)容容量,resize 函數(shù)用于調(diào)整大小,并在必要時(shí)進(jìn)行內(nèi)存分配和字符填充。
//擴(kuò)容capacity
void reserve(size_t n)
{
if (n >= _capacity)
{
char* tmp = new char[n + 1];
//strcpy(tmp,_str);
memcpy(tmp, _str, _size + 1);
delete[] _str;
_str = tmp;
_capacity = n;
}
}
//擴(kuò)容size
void resize(size_t n, char ch = '\0')
{
if (n < _size)
{
_size = n;
_str[_size] = '\0';
}
else
{
reserve(n);
for (size_t i = _size; i < n; i++)
{
_str[i] = ch;
}
_size = n;
_str[_size] = '\0';
}
}
?
1.5增刪查改
push_back和append和+=運(yùn)算符重載
??這些函數(shù)的作用是向字符串對(duì)象中添加字符或字符數(shù)組。其中,push_back 可以用于逐個(gè)添加字符到字符串末尾,append 可以將字符數(shù)組追加到字符串中,operator+= 運(yùn)算符重載則提供了一種簡(jiǎn)便的方式對(duì)字符串和字符進(jìn)行連接。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-609978.html
//實(shí)現(xiàn)尾插
void push_back(const char ch)
{
//先擴(kuò)容
if (_size == _capacity)
{
reserve(_capacity == 0 ? 4 : _capacity * 2);
}
this->_str[_size] = ch;
++_size;
this->_str[_size] = '\0';
}
//實(shí)現(xiàn)append
void append(const char* str)
{
size_t len = strlen(str);
if (_size + len > _capacity)
{
//至少要擴(kuò)容到_size+len
reserve(_size + len);
}
//strcpy(_str + _size, str);
memcpy(_str + _size, str, len + 1);
_size += len;
}
//復(fù)用實(shí)現(xiàn)+=的運(yùn)算符重載
string& operator+=(const char ch)
{
push_back(ch);
return *this;
}
?
完整實(shí)現(xiàn)(包含insert、erase、find、substr、operator<<、operator>>)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-609978.html
#include<assert.h>
namespace str
{
class string
{
public:
//實(shí)現(xiàn)迭代器和const迭代器
typedef char* iterator;
typedef const char* const_iterator;
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
const_iterator begin() const
{
return _str;
}
const_iterator end() const
{
return _str + _size;
}
構(gòu)造函數(shù)為空值
//string()
// :_size(0)
// , _capacity(_size)
// , _str(new char[1])
//{
// _str[0] = '\0';
//}
構(gòu)造函數(shù)傳字符串
//string(const char* str)
// :_size(strlen(str))
// ,_capacity(_size)
// ,_str(new char[_capacity+1])
//{
// memcpy(_str, str, _size + 1);
//}
//合并string()和string(const char* str)
//并且在函數(shù)體內(nèi)賦值
string(const char* str = "\0")//->"\0"\0
{
_size = strlen(str);
_capacity = _size;
_str = new char[_capacity + 1];
//為空時(shí),實(shí)參未顯示賦值,我們給str缺省參數(shù)"\0"
//str傳給_str"\0",系統(tǒng)設(shè)為空
//"\0"為字符串以指針傳遞、'\0'為單個(gè)字符以單個(gè)字符傳遞
//strcpy(_str, str);
memcpy(_str, str, _size + 1);
}
string(const string& s)
{
this->_size = s._size;
this->_capacity = s._capacity;
//淺拷貝,兩個(gè)指針指向同一塊空間,且調(diào)用兩次析構(gòu)函數(shù),程序崩潰
//this->_str = s._str;
//深拷貝 實(shí)現(xiàn)
this->_str = new char[s._capacity + 1];
//strcpy(_str, s.c_str());
memcpy(_str, s.c_str(), _size + 1);
}
//傳統(tǒng)寫法
/*string& operator=(const string& s)
{
if (this != &s)
{
char* tmp = new char[s._capacity + 1];
memcpy(tmp, s._str, s._size + 1);
delete[] _str;
_str = tmp;
_size = s._size;
_capacity = s._capacity;
}
return *this;
}*/
//現(xiàn)代寫法
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
//string& operator=(const string& s)
//{
// if (this != &s)
// {
// string tmp(s);
//
// //this->swap(tmp);
// swap(tmp);
// }
//
// return *this;
//}
string& operator=(string tmp)
{
swap(tmp);
return *this;
}
//析構(gòu)函數(shù)
~string()
{
_size = 0;
_capacity = 0;
delete[] _str;
_str = nullptr;
}
//const返回c類型的字符串
const char* c_str() const
{
return _str;
}
//const返回str的大小
size_t size() const
{
return _size;
}
//重載[]操作符
char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
//重載const[]操作符
const char& operator[](size_t pos) const
{
assert(pos < _size);
return _str[pos];
}
//擴(kuò)容函數(shù)capacity
void reserve(size_t n)
{
if (n >= _capacity)
{
char* tmp = new char[n + 1];
//strcpy(tmp,_str);
memcpy(tmp, _str, _size + 1);
delete[] _str;
_str = tmp;
_capacity = n;
}
}
//擴(kuò)容size
void resize(size_t n, char ch = '\0')
{
if (n < _size)
{
_size = n;
_str[_size] = '\0';
}
else
{
reserve(n);
for (size_t i = _size; i < n; i++)
{
_str[i] = ch;
}
_size = n;
_str[_size] = '\0';
}
}
//實(shí)現(xiàn)尾插
void push_back(const char ch)
{
//先擴(kuò)容
if (_size == _capacity)
{
reserve(_capacity == 0 ? 4 : _capacity * 2);
}
this->_str[_size] = ch;
++_size;
this->_str[_size] = '\0';
}
//實(shí)現(xiàn)append
void append(const char* str)
{
size_t len = strlen(str);
if (_size + len > _capacity)
{
//至少要擴(kuò)容到_size+len
reserve(_size + len);
}
//strcpy(_str + _size, str);
memcpy(_str + _size, str, len + 1);
_size += len;
}
//復(fù)用實(shí)現(xiàn)+=的運(yùn)算符重載
string& operator+=(const char ch)
{
push_back(ch);
return *this;
}
string& operator+=(const char* str)
{
append(str);
return *this;
}
void insert(size_t pos, size_t n, char ch)
{
assert(pos <= _size);
if (_size + n > _capacity)
{
reserve(_size + n);
}
size_t end = _size;
while (end >= pos && end != npos)
{
_str[end + n] = _str[end];
--end;
}
for (size_t i = 0; i < n; i++)
{
_str[pos + i] = ch;
}
_size += n;
}
void insert(size_t pos, const char* str)
{
assert(pos <= _size);
size_t len = strlen(str);
if (_size + len > _capacity)
{
// 至少擴(kuò)容到_size + len
reserve(_size + len);
}
size_t end = _size;
while (end >= pos && end != npos)
{
_str[end + len] = _str[end];
--end;
}
for (size_t i = 0; i < len; i++)
{
_str[pos + i] = str[i];
}
_size += len;
}
void erase(size_t pos, size_t len = npos)
{
assert(pos <= _size);
if (len == npos || pos + len >= _size)
{
//_str[pos] = '\0';
_size = pos;
_str[_size] = '\0';
}
else
{
size_t end = pos + len;
while (end <= _size)
{
_str[pos++] = _str[end++];
}
_size -= len;
}
}
size_t find(char ch, size_t pos = 0)
{
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)
{
assert(pos < _size);
const char* ptr = strstr(_str + pos, str);
if (ptr)
{
return ptr - _str;
}
else
{
return npos;
}
}
string substr(size_t pos = 0, size_t len = npos)
{
assert(pos < _size);
size_t n = len;
if (len == npos || pos + len > _size)
{
n = _size - pos;
}
string tmp;
tmp.reserve(n);
for (size_t i = pos; i < pos + n; i++)
{
tmp += _str[i];
}
return tmp;
}
void clear()
{
_str[0] = '\0';
_size = 0;
}
//bool operator<(const string& s)
//{
// size_t i1 = 0;
// size_t i2 = 0;
// while (i1 < _size && i2 < s._size)
// {
// if (_str[i1] < s._str[i2])
// {
// return true;
// }
// else if (_str[i1] > s._str[i2])
// {
// return false;
// }
// else
// {
// ++i1;
// ++i2;
// }
// }
// /*if (i1 == _size && i2 != s._size)
// {
// return true;
// }
// else
// {
// return false;
// }*/
// //return i1 == _size && i2 != s._size;
// return _size < s._size;
//}
bool operator<(const string& s) const
{
int ret = memcmp(_str, s._str, _size < s._size ? _size : s._size);
return ret == 0 ? _size < s._size : ret < 0;
}
bool operator==(const string& s) const
{
return _size == s._size
&& memcmp(_str, s._str, _size) == 0;
}
bool operator<=(const string& s) const
{
return *this < s || *this == s;
}
bool operator>(const string& s) const
{
return !(*this <= s);
}
bool operator>=(const string& s) const
{
return !(*this < s);
}
bool operator!=(const string& s) const
{
return !(*this == s);
}
private:
int _size;
int _capacity;
char* _str;
public:
const static size_t npos;
};
const size_t string::npos = -1;
ostream& operator<<(ostream& out, str::string& s)
{
//for (size_t i = 0; i < s.size(); i++)
//{
// out << s[i];
//}
for (auto ch : s)
{
out << ch;
}
return out;
}
istream& operator>>(istream& in, std::string& s)
{
s.clear();
char ch = in.get();
while (ch == ' ' || ch == '\n')
{
ch = in.get();
}
//in >> ch;
char buff[128];
int i = 0;
while (ch != ' ' && ch != '\n')
{
buff[i++] = ch;
if (i == 127)
{
buff[i] = '\0';
s += buff;
i = 0;
}
//in >> ch;
ch = in.get();
}
if (i != 0)
{
buff[i] = '\0';
s += buff;
}
return in;
}
};
到了這里,關(guān)于【C++】STL——string的模擬實(shí)現(xiàn)、常用構(gòu)造函數(shù)、迭代器、運(yùn)算符重載、擴(kuò)容函數(shù)、增刪查改的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!