通州企業(yè)網(wǎng)站建設公司營銷策劃方案案例
目錄
前置說明
一. 構造函數(shù)和析構函數(shù)的模擬實現(xiàn)
1.1?構造函數(shù)
1.2?析構函數(shù)
二.?string類對象容量及成員相關的函數(shù)
2.1?獲取字符串有效字符數(shù)、容量及_str成員變量獲取相關函數(shù)
2.2?擴容及變長相關函數(shù)
2.3?字符串清空和判空函數(shù)
三.?運算符重載函數(shù)
3.1?賦值運算符重載函數(shù)
3.2?成員訪問操作符[]重載函數(shù)
3.3 +=運算符重載函數(shù) ——?尾插字符串或字符
四.?增刪查改相關函數(shù)
4.1?插入字符串(字符)相關函數(shù)
4.2?子字符串刪除函數(shù)
4.3?子串查找函數(shù)
五.?迭代器相關函數(shù)
六.?關于string的全局函數(shù)
6.1?字符串比較相關函數(shù)
6.2?字符串輸出和輸入相關函數(shù)
6.3?字符串與數(shù)值之間的相互轉換
附錄:string類模擬實現(xiàn)完整版
前置說明
模擬實現(xiàn)的string類定義了四個成員函數(shù),分別為(1)char* str --?指向字符串的指針、(2)size_t size --?字符串中的字符數(shù) 、(3)size_t?capacity --?字符串最大可容納的字符數(shù)量、(4)size_t _npos --?size_t類型的-1
一. 構造函數(shù)和析構函數(shù)的模擬實現(xiàn)
1.1?構造函數(shù)
這里實現(xiàn)兩種形式的構造函數(shù),一種是通過字符串來構造,第二種是通過一個string類進行拷貝構造。注意:定義拷貝構造函數(shù)要進行深拷貝而不是淺拷貝(值拷貝),否則,會使兩個string類對象中的_str指向同一塊內(nèi)存區(qū)域,在調用析構函數(shù)時對同一塊空間連續(xù)兩次釋放,從而導致程序崩潰。

string(const char* str = "") //通過字符串構造和默認構造: _size(strlen(str)), _capacity(_size){_str = new char[_capacity + 1];strcpy(_str, str);}//explicit string(const string& str) //拷貝構造//一般寫法 -- 正常完成深拷貝//string(const string& str) //拷貝構造// : _size(str._size)// , _capacity(str._capacity)//{// _str = new char[_capacity + 1];// strcpy(_str, str._str);//}//拷貝構造復用寫法 -- 臨時對象string(const string& str): _str(nullptr), _size(str._size), _capacity(str._capacity){if (this != &str) //排除自己給自己拷貝的情況{string tmp(str._str);std::swap(_str, tmp._str);}}
1.2?析構函數(shù)
析構函數(shù)要完成的工作為:釋放string類對象的成員函數(shù)_str指向的內(nèi)存空間。
~string() //析構函數(shù){delete _str;_str = nullptr;_size = _capacity = 0;}
二.?string類對象容量及成員相關的函數(shù)
2.1?獲取字符串有效字符數(shù)、容量及_str成員變量獲取相關函數(shù)
- size函數(shù)和length函數(shù):獲取字符串長度(末尾'\0'不包含在內(nèi))。
- capacity函數(shù):獲取當前string類對象的容量。
- c_str函數(shù):獲取string對象的成員變量_str。
size_t size() const //有效字符個數(shù){return _size;}size_t length() const{return _size;}size_t capacity() //獲取容量{return _capacity;}const char* c_str() const //獲取字符串類對象變量_str{return _str;}
2.2?擴容及變長相關函數(shù)
這里主要涉及兩個函數(shù):
- reserve:將string類對象的字符容量擴大到n,如果給定的n小于原來的_capacity,則容量不發(fā)生改變。
- resize:將字符串的長度變?yōu)閚,并將新增的空間的內(nèi)容初始化為ch。
reserve函數(shù)進行的工作:
- 檢查n是否大于_capacity,如果否,函數(shù)不進行任何工作。
- 如果n大于_capacity,那么開辟一塊能容納n+1個字符的內(nèi)存空間,將類對象原來的字符串復制到新開辟的這塊空間。
- 釋放原來的字符串內(nèi)存空間,_str指向新開辟的這塊內(nèi)存空間。
- 更新容量_capacity。
resize函數(shù)進行的工作:
- 如果n小于或等于_size,則將下標為n位置處的元素改為'\0'。
- 如果n大于_size且小于等于_capacity,那么則將下標從_size開始到n-1的元素初始化為ch,然后末尾補'\0'。
- 如果n大于_capacity,那么則要先擴容到n,然后將下標位置>=_size的元素全部初始化為ch,然后末尾補'\0'。
void reserve(size_t n) //容量指定函數(shù){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;std::swap(_str, tmp);_capacity = n;}}void resize(size_t n, char ch = '\0') //字符串長度變長或縮短函數(shù){if (n <= _size) //容量變更后比原有效字符數(shù)小{_size = n;_str[n] = '\0';}else //容量變更后比原有效字符數(shù)大{if (n > _capacity) //容量不足,擴容{reserve(n);}//將_size開始向后的內(nèi)容全部變?yōu)閏hmemset(_str + _size, ch, n - _size);_size = n;_str[n] = '\0';}}
2.3?字符串清空和判空函數(shù)
- clear:將字符串中的有效字符數(shù)清零。
- empty:判斷當前字符串是否為空。
void clear() //清空字符串{_str[0] = '\0';_size = 0;}bool empty() //判斷當前字符串是否為空{return _size == 0;}
三.?運算符重載函數(shù)
3.1?賦值運算符重載函數(shù)
賦值運算符重載函數(shù)完成的功能是將一個string類對象的值賦給另一個類對象,要完成string對象間的賦值有兩種方法:
- 一般方法:規(guī)規(guī)矩矩進行深拷貝
- 通過臨時對象賦值:創(chuàng)建一個與賦值對象的字符串內(nèi)容相同的臨時類對象,交換被賦值對象和臨時對象的_str成員值,這樣在臨時對象生命周期結束自動調用析構函數(shù)時,會釋放被賦值對象_str原來指向的空間。
//一般寫法 -- 正常進行深拷貝string& operator=(const string& str) //賦值運算符重載{//開辟一塊新的內(nèi)存空間用于存儲被復制的字符串char* tmp = new char[str._capacity + 1];strcpy(tmp, str._str);//釋放原內(nèi)存空間,同時更新字符串內(nèi)容delete[] _str;_str = tmp;//更新數(shù)據(jù)量和容量_size = str._size;_capacity = str._capacity;return *this;}//復用寫法 -- 創(chuàng)建臨時對象,調用構造函數(shù)string& operator=(const string& str){if (this != &str) //排除自賦值情況{string tmp(str); //創(chuàng)建臨時對象swap(_str, tmp._str); //交換指針指向_size = str._size;_capacity = str._capacity;}return *this;}
3.2?成員訪問操作符[]重載函數(shù)
函數(shù)功能為獲取下標位置為pos處的字符串,如果pos越界,則斷言報錯。
char& operator[](size_t pos) //下標訪問操作符{assert(pos < _size);return this->_str[pos];}const char& operator[](size_t pos) const //針對const對象的下標訪問操作符{assert(pos < _size);return this->_str[pos];}
3.3 +=運算符重載函數(shù) ——?尾插字符串或字符
函數(shù)所進行的工作包括:
- 檢查當前對象容量是否充足,如果容量不足,就擴容。
- 將字符或字符串尾插到原字符串的后面。
string& operator+=(const char* str) //重載+=操作符:字符串尾插{size_t len = strlen(str); //尾插字符串長度if (_size + len > _capacity){//如果空間不足就擴容reserve(_size + len);}strcpy(_str + _size, str);_size += len;return *this;}string& operator+=(const string& str){(*this) += str._str; //獲取str的成員_str,復用字符串尾插return *this;}string& operator+=(char ch) //重載+=操作符:尾插字符{if (_size + 1 > _capacity) //容量不足就開空間{reserve(_capacity == 0 ? 4 : 2 * _capacity);}_str[_size++] = ch;_str[_size] = '\0';return *this;}
四.?增刪查改相關函數(shù)
4.1?插入字符串(字符)相關函數(shù)
- push_back:尾插字符函數(shù)。
- append:尾插字符串函數(shù)。
- insert:在pos位置插入字符串函數(shù)。
push_back函數(shù)和append函數(shù)與+=完成一樣的操作,直接復用+=即可。insert函數(shù)則需要將從pos位置開始往后的元素向后移動len個單位,len為插入字符串的長度,然后在pos位置插入新字符串。

void push_back(char ch) //尾插字符{(*this) += ch;}void append(const char* str) //尾插字符串{(*this) += str;}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; //找到ch就返回下標}}//找不到就返回nposreturn _npos;}string& insert(size_t pos, const char* str) //特定位置插入字符串{assert(pos <= _size);size_t len = strlen(str); //獲取插入字符串長度if (_size + len > _capacity) {//容量不足時擴容reserve(_size + len);}size_t end = _size + len;//按從后往前的順序,讓pos位置開始往后的字符后移len個單位while (end >= pos + len){_str[end] = _str[end - len];--end;}memcpy(_str + pos, str, len); //pos位置插入字符串_size += len; //更新有效字符數(shù)return *this;}string& insert(size_t pos, const string& str){assert(pos <= _size);return insert(pos, str._str);}
4.2?子字符串刪除函數(shù)
erase函數(shù):從pos位置開始刪除len個函數(shù)。
- 檢查pos是否越界,如果越界,則斷言報錯。
- 將從下標位置pos+len開始的元素向前移動len個單位(包含末尾的'\0'),如果len>_size-pos成立,那么說明要將pos往后的元素全部刪除,只需將pos位置處的元素改為'\0'即可。
- 更新_size的值。
string& insert(size_t pos, const char* str) //特定位置插入字符串{assert(pos <= _size);size_t len = strlen(str); //獲取插入字符串長度if (_size + len > _capacity) {//容量不足時擴容reserve(_size + len);}size_t end = _size + len;//按從后往前的順序,讓pos位置開始往后的字符后移len個單位while (end >= pos + len){_str[end] = _str[end - len];--end;}memcpy(_str + pos, str, len); //pos位置插入字符串_size += len; //更新有效字符數(shù)return *this;}string& insert(size_t pos, const string& str){assert(pos <= _size);return insert(pos, str._str);}
4.3?子串查找函數(shù)
find函數(shù):從pos位置處開始查找子串,如果找到,就返回子串第一個元素的下標,如果找不到,就返回_npos。
size_t find(const char* str, size_t pos = 0) //查找一個字符串{assert(pos < _size);char* ptr = strstr(_str + pos, str); //獲取子字符串首字符地址if (ptr != nullptr){return ptr - _str;}else{return _npos;}}size_t find(const string& str, size_t pos = 0) //在string類對象中查找子字符串{assert(pos < _size);return find(str._str, pos); //復用}
五.?迭代器相關函數(shù)
普通對象迭代器和const屬性對象迭代器本質上都為char*/const char*:
- typedef char*?iteratior
- typedef const char* const_iterator
- begin:獲取首字符元素地址。
- end:獲取字符串末尾'\0'的地址。
typedef char* iterator;typedef const char* const_iterator;iterator begin() //頭指針{return _str;}iterator end() //尾指針{return _str + _size;}const_iterator begin() const //const對象頭指針{return _str;}const_iterator end() const //const對象尾指針{return _str + _size;}
六.?關于string的全局函數(shù)
6.1?字符串比較相關函數(shù)
關于比較,總共有六種形式:>、==、>=、<、<=、!=,我們只需要模擬實現(xiàn)其中的兩個,然后其余4個復用已經(jīng)模擬實現(xiàn)完成的兩個即可。
bool operator<(const string& s1, const string& s2) //比較s1是否小于s2{size_t i1 = 0, i2 = 0;size_t len1 = s1.size(); //字符串s1長度size_t len2 = s2.size(); //字符串s2長度while (i1 < len1 && i2 < len2){if (s1[i1] < s2[i2]){return true;}else if (s1[i1] == s2[i2]){++i1;++i2;}else{return false;}}//如果s1長度小于s2,就成立,否則不成立return i2 < len2;}bool operator==(const string& s1, const string& s2) //兩字符串是否相等{size_t i1 = 0, i2 = 0;while (i1 < s1.size() && i2 < s2.size()){if (s1[i1] != s2[i2]){return false;}else{++i1;++i2;}}return i1 == s1.size() && i2 == s2.size();}bool operator<=(const string& s1, const string& s2){return (s1 == s2) || (s1 < s2);}bool operator>(const string& s1, const string& s2){return !((s1 < s2) || (s1 == s2));}bool operator>=(const string& s1, const string& s2){return !(s1 < s2);}bool operator!=(const string& s1, const string& s2){return !(s1 == s2);}
6.2?字符串輸出和輸入相關函數(shù)
- ostream& operator<<(ostream& out, const string& s) --?流插入操作符重載函數(shù)
- istream& operator>>(istream& in, string& s) --?流輸出操作符重載函數(shù)
注意重載流插入操作符時,不能使用out << s.c_str,因為這樣遇到'\0'就會截止輸出,從而不一定輸出s.size()個字符。
ostream& operator<<(ostream& out, const string& s){//寫法1:范圍for循環(huán)/*for (auto ch : s) {out << ch;}*///寫法2:普通for循環(huán)for (size_t i = 0; i < s.size(); ++i){out << s[i];}//out << s.c_str(); //不能這么寫,因為此時遇到\0停止讀取,而不是讀s.size()個字符return out;}istream& operator>>(istream& in, string& s){s.clear();char ch = in.get();while (ch != ' ' && ch != '\n'){s += ch;ch = in.get();}return in;}
6.3?字符串與數(shù)值之間的相互轉換
- stoi:字符串轉換為int型數(shù)據(jù)。
- stod:字符串轉換為double型數(shù)據(jù)。
int stoi(const string& s){size_t len = s.size(); //字符串長度long long flag = 1; //正負號標識符size_t i = 0;long long retVal = 0;//排除空格while (i < len && s[i] == ' '){++i;}//檢查正負號if (i < len && s[i] == '+'){++i;}else if (i < len && s[i] == '-'){++i;flag = -flag;}//排除0while (i < len && s[i] == '0'){++i;}//計算結果while (i < len && (s[i] <= '9' && s[i] >= '0')){retVal = retVal * 10 + (s[i] - '0') * flag;//檢查是否越界if (retVal >= INT_MAX){return INT_MAX;}else if (retVal <= INT_MIN){return INT_MIN;}++i;}return (int)retVal;}double stod(const string& s){size_t i = 0;size_t len = s.size(); //字符串長度//最終返回值 = 整數(shù)部分 + 小數(shù)部分double integerRet = 0; //返回值的整數(shù)部分double decimalRet = 0; //返回值的小數(shù)部分int flag = 1; //正負號標識符while (i < len && s[i] == ' ') //排除空格{++i;}if (i < len && s[i] == '+') //確定返回值是正數(shù)還是負數(shù){++i;}else if (i < len && s[i] == '-'){flag = -flag;++i;}//計算整數(shù)部分while (i < len && (s[i] >= '0' && s[i] <= '9')){integerRet = integerRet * 10 + (s[i] - '0') * flag;++i;}//計算小數(shù)部分if (i < len && s[i] == '.'){double factorial = 0.1; //系數(shù)++i; //跳過小數(shù)點while (i < len && (s[i] >= '0' && s[i] <= '9')){decimalRet += (s[i] - '0') * factorial * flag;factorial *= 0.1;++i;}}return integerRet + decimalRet;}
附錄:string類模擬實現(xiàn)完整版
#include<iostream>
#include<assert.h>
#include<string.h>
#include<stdbool.h>
#include<limits>using namespace std;namespace zhang
{class string{public://1.創(chuàng)建和銷毀相關string(const char* str = "") //通過字符串構造和默認構造: _size(strlen(str)), _capacity(_size){_str = new char[_capacity + 1];strcpy(_str, str);}//explicit string(const string& str) //拷貝構造//一般寫法 -- 正常完成深拷貝//string(const string& str) //拷貝構造// : _size(str._size)// , _capacity(_size)//{// _str = new char[_capacity + 1];// strcpy(_str, str._str);//}//拷貝構造復用寫法 -- 臨時對象string(const string& str): _str(nullptr), _size(str._size), _capacity(str._capacity){if (this != &str) //排除自己給自己拷貝的情況{string tmp(str._str);std::swap(_str, tmp._str);}}~string() //析構函數(shù){delete _str;_str = nullptr;_size = _capacity = 0;}//2.類對象成員和容量相關size_t size() const //有效字符個數(shù){return _size;}size_t length() const{return _size;}size_t capacity() //獲取容量{return _capacity;}const char* c_str() const //獲取字符串類對象變量_str{return _str;}void reserve(size_t n) //容量指定函數(shù){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;std::swap(_str, tmp);_capacity = n;}}void resize(size_t n, char ch = '\0') //容量變更函數(shù){if (n <= _size) //容量變更后比原有效字符數(shù)小{_size = n;_str[n] = '\0';}else //容量變更后比原有效字符數(shù)大{if (n > _capacity) //容量不足,擴容{reserve(n);}//將_size開始向后的內(nèi)容全部變?yōu)閏hmemset(_str + _size, ch, n - _size);_size = n;_str[n] = '\0';}}void clear() //清空字符串{_str[0] = '\0';_size = 0;}bool empty() //判斷當前字符串是否為空{return _size == 0;}//3.運算符重載相關//一般寫法 -- 正常進行深拷貝//string& operator=(const string& str) //賦值運算符重載//{// //開辟一塊新的內(nèi)存空間用于存儲被復制的字符串// char* tmp = new char[str._capacity + 1];// strcpy(tmp, str._str);// //釋放原內(nèi)存空間,同時更新字符串內(nèi)容// delete[] _str;// _str = tmp;// //更新數(shù)據(jù)量和容量// _size = str._size;// _capacity = str._capacity;// return *this;//}//復用寫法 -- 調用構造函數(shù)string& operator=(const string& str){if (this != &str) //排除自賦值情況{string tmp(str); //創(chuàng)建臨時對象swap(_str, tmp._str); //交換指針指向_size = str._size;_capacity = str._capacity;}return *this;}char& operator[](size_t pos) //下標訪問操作符{assert(pos < _size);return this->_str[pos];}const char& operator[](size_t pos) const //針對const對象的下標訪問操作符{assert(pos < _size);return this->_str[pos];}string& operator+=(const char* str) //重載+=操作符:字符串尾插{size_t len = strlen(str); //尾插字符串長度if (_size + len > _capacity){//如果空間不足就擴容reserve(_size + len);_capacity = _size + len;}strcpy(_str + _size, str);_size += len;return *this;}string& operator+=(const string& str){(*this) += str._str;return *this;}string& operator+=(char ch) //重載+=操作符:尾插字符{if (_size + 1 > _capacity) //容量不足就開空間{reserve(_capacity == 0 ? 4 : 2 * _capacity);}_str[_size++] = ch;_str[_size] = '\0';return *this;}//4.迭代器typedef char* iterator;typedef const char* const_iterator;iterator begin() //頭指針{return _str;}iterator end() //尾指針{return _str + _size;}const_iterator begin() const //const對象頭指針{return _str;}const_iterator end() const //const對象尾指針{return _str + _size;}//5.增刪查改void push_back(char ch) //尾插字符{(*this) += ch;}void append(const char* str) //尾插字符串{(*this) += str;}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; //找到ch就返回下標}}//找不到就返回nposreturn _npos;}size_t find(const char* str, size_t pos = 0) //查找一個字符串{assert(pos < _size);char* ptr = strstr(_str + pos, str); //獲取子字符串首字符地址if (ptr != nullptr){return ptr - _str;}else{return _npos;}}size_t find(const string& str, size_t pos = 0) //在string類對象中查找子字符串{assert(pos < _size);return find(str._str, pos); //復用}string& insert(size_t pos, const char* str) //特定位置插入字符串{assert(pos <= _size);size_t len = strlen(str); //獲取插入字符串長度if (_size + len > _capacity) {//容量不足時擴容reserve(_size + len);}size_t end = _size + len;//按從后往前的順序,讓pos位置開始往后的字符后移len個單位while (end >= pos + len){_str[end] = _str[end - len];--end;}memcpy(_str + pos, str, len); //pos位置插入字符串_size += len; //更新有效字符數(shù)return *this;}string& insert(size_t pos, const string& str){assert(pos <= _size);return insert(pos, str._str);}string& erase(size_t pos = 0, size_t len = _npos) //子串刪除函數(shù){assert(pos < _size);if (pos + len > _size) //pos后面的所有字符都會被刪除{_str[pos] = '\0';_size = pos;}else //pos向后的字符沒有被刪完{for (size_t i = pos; i <= _size; ++i){_str[i] = _str[i + len];}_size -= len;}return *this;}private:char* _str; //指向存儲字符串內(nèi)存的指針size_t _size; //有效字符數(shù)size_t _capacity; //當前類對象容量(最多幾個有效字符)static size_t _npos;};size_t string::_npos = -1;bool operator<(const string& s1, const string& s2) //比較s1是否小于s2{size_t i1 = 0, i2 = 0;size_t len1 = s1.size(); //字符串s1長度size_t len2 = s2.size(); //字符串s2長度while (i1 < len1 && i2 < len2){if (s1[i1] < s2[i2]){return true;}else if (s1[i1] == s2[i2]){++i1;++i2;}else{return false;}}//如果s1長度小于s2,就成立,否則不成立return i2 < len2;}bool operator==(const string& s1, const string& s2) //兩字符串是否相等{size_t i1 = 0, i2 = 0;while (i1 < s1.size() && i2 < s2.size()){if (s1[i1] != s2[i2]){return false;}else{++i1;++i2;}}return i1 == s1.size() && i2 == s2.size();}bool operator<=(const string& s1, const string& s2){return (s1 == s2) || (s1 < s2);}bool operator>(const string& s1, const string& s2){return !((s1 < s2) || (s1 == s2));}bool operator>=(const string& s1, const string& s2){return !(s1 < s2);}bool operator!=(const string& s1, const string& s2){return !(s1 == s2);}ostream& operator<<(ostream& out, const string& s){//寫法1:范圍for循環(huán)/*for (auto ch : s) {out << ch;}*///寫法2:普通for循環(huán)for (size_t i = 0; i < s.size(); ++i){out << s[i];}//out << s.c_str(); //不能這么寫,因為此時遇到\0停止讀取,而不是讀s.size()個字符return out;}istream& operator>>(istream& in, string& s){s.clear();char ch = in.get();while (ch != ' ' && ch != '\n'){s += ch;ch = in.get();}return in;}int stoi(const string& s){size_t len = s.size(); //字符串長度long long flag = 1; //正負號標識符size_t i = 0;long long retVal = 0;//排除空格while (i < len && s[i] == ' '){++i;}//檢查正負號if (i < len && s[i] == '+'){++i;}else if (i < len && s[i] == '-'){++i;flag = -flag;}//排除0while (i < len && s[i] == '0'){++i;}//計算結果while (i < len && (s[i] <= '9' && s[i] >= '0')){retVal = retVal * 10 + (s[i] - '0') * flag;//檢查是否越界if (retVal >= INT_MAX){return INT_MAX;}else if (retVal <= INT_MIN){return INT_MIN;}++i;}return (int)retVal;}double stod(const string& s){size_t i = 0;size_t len = s.size(); //字符串長度//最終返回值 = 整數(shù)部分 + 小數(shù)部分double integerRet = 0; //返回值的整數(shù)部分double decimalRet = 0; //返回值的小數(shù)部分int flag = 1; //正負號標識符while (i < len && s[i] == ' ') //排除空格{++i;}if (i < len && s[i] == '+') //確定返回值是正數(shù)還是負數(shù){++i;}else if (i < len && s[i] == '-'){flag = -flag;++i;}//計算整數(shù)部分while (i < len && (s[i] >= '0' && s[i] <= '9')){integerRet = integerRet * 10 + (s[i] - '0') * flag;++i;}//計算小數(shù)部分if (i < len && s[i] == '.'){double factorial = 0.1; //系數(shù)++i; //跳過小數(shù)點while (i < len && (s[i] >= '0' && s[i] <= '9')){decimalRet += (s[i] - '0') * factorial * flag;factorial *= 0.1;++i;}}return integerRet + decimalRet;}
};