南宁市规划建设局 网站,广告公司网站源码,建设第二个北京在哪里,个人做网站有什么坏处目录
前置说明
一. 构造函数和析构函数的模拟实现
1.1 构造函数
1.2 析构函数
二. string类对象容量及成员相关的函数
2.1 获取字符串有效字符数、容量及_str成员变量获取相关函数
2.2 扩容及变长相关函数
2.3 字符串清空和判空函数
三. 运算符重载函数
3.1 赋值运算…目录
前置说明
一. 构造函数和析构函数的模拟实现
1.1 构造函数
1.2 析构函数
二. string类对象容量及成员相关的函数
2.1 获取字符串有效字符数、容量及_str成员变量获取相关函数
2.2 扩容及变长相关函数
2.3 字符串清空和判空函数
三. 运算符重载函数
3.1 赋值运算符重载函数
3.2 成员访问操作符[]重载函数
3.3 运算符重载函数 —— 尾插字符串或字符
四. 增删查改相关函数
4.1 插入字符串字符相关函数
4.2 子字符串删除函数
4.3 子串查找函数
五. 迭代器相关函数
六. 关于string的全局函数
6.1 字符串比较相关函数
6.2 字符串输出和输入相关函数
6.3 字符串与数值之间的相互转换
附录string类模拟实现完整版 前置说明
模拟实现的string类定义了四个成员函数分别为(1)char* str -- 指向字符串的指针、(2)size_t size -- 字符串中的字符数 、(3)size_t capacity -- 字符串最大可容纳的字符数量、(4)size_t _npos -- size_t类型的-1
一. 构造函数和析构函数的模拟实现
1.1 构造函数
这里实现两种形式的构造函数一种是通过字符串来构造第二种是通过一个string类进行拷贝构造。注意定义拷贝构造函数要进行深拷贝而不是浅拷贝值拷贝否则会使两个string类对象中的_str指向同一块内存区域在调用析构函数时对同一块空间连续两次释放从而导致程序崩溃。 图1.1 采用浅拷贝左和深拷贝右的内存指向情况示意图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 析构函数
析构函数要完成的工作为释放string类对象的成员函数_str指向的内存空间。 ~string() //析构函数{delete _str;_str nullptr;_size _capacity 0;}
二. string类对象容量及成员相关的函数
2.1 获取字符串有效字符数、容量及_str成员变量获取相关函数
size函数和length函数获取字符串长度末尾\0不包含在内。capacity函数获取当前string类对象的容量。c_str函数获取string对象的成员变量_str。size_t size() const //有效字符个数{return _size;}size_t length() const{return _size;}size_t capacity() //获取容量{return _capacity;}const char* c_str() const //获取字符串类对象变量_str{return _str;}
2.2 扩容及变长相关函数
这里主要涉及两个函数
reserve将string类对象的字符容量扩大到n如果给定的n小于原来的_capacity则容量不发生改变。resize将字符串的长度变为n并将新增的空间的内容初始化为ch。
reserve函数进行的工作
检查n是否大于_capacity如果否函数不进行任何工作。如果n大于_capacity那么开辟一块能容纳n1个字符的内存空间将类对象原来的字符串复制到新开辟的这块空间。释放原来的字符串内存空间_str指向新开辟的这块内存空间。更新容量_capacity。
resize函数进行的工作
如果n小于或等于_size则将下标为n位置处的元素改为\0。如果n大于_size且小于等于_capacity那么则将下标从_size开始到n-1的元素初始化为ch然后末尾补\0。如果n大于_capacity那么则要先扩容到n然后将下标位置_size的元素全部初始化为ch然后末尾补\0。void reserve(size_t n) //容量指定函数{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) //字符串长度变长或缩短函数{if (n _size) //容量变更后比原有效字符数小{_size n;_str[n] \0;}else //容量变更后比原有效字符数大{if (n _capacity) //容量不足扩容{reserve(n);}//将_size开始向后的内容全部变为chmemset(_str _size, ch, n - _size);_size n;_str[n] \0;}}
2.3 字符串清空和判空函数
clear将字符串中的有效字符数清零。empty判断当前字符串是否为空。void clear() //清空字符串{_str[0] \0;_size 0;}bool empty() //判断当前字符串是否为空{return _size 0;}
三. 运算符重载函数
3.1 赋值运算符重载函数
赋值运算符重载函数完成的功能是将一个string类对象的值赋给另一个类对象要完成string对象间的赋值有两种方法
一般方法规规矩矩进行深拷贝通过临时对象赋值创建一个与赋值对象的字符串内容相同的临时类对象交换被赋值对象和临时对象的_str成员值这样在临时对象生命周期结束自动调用析构函数时会释放被赋值对象_str原来指向的空间。//一般写法 -- 正常进行深拷贝string operator(const string str) //赋值运算符重载{//开辟一块新的内存空间用于存储被复制的字符串char* tmp new char[str._capacity 1];strcpy(tmp, str._str);//释放原内存空间同时更新字符串内容delete[] _str;_str tmp;//更新数据量和容量_size str._size;_capacity str._capacity;return *this;}//复用写法 -- 创建临时对象调用构造函数string operator(const string str){if (this ! str) //排除自赋值情况{string tmp(str); //创建临时对象swap(_str, tmp._str); //交换指针指向_size str._size;_capacity str._capacity;}return *this;}
3.2 成员访问操作符[]重载函数
函数功能为获取下标位置为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 运算符重载函数 —— 尾插字符串或字符
函数所进行的工作包括
检查当前对象容量是否充足如果容量不足就扩容。将字符或字符串尾插到原字符串的后面。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;}
四. 增删查改相关函数
4.1 插入字符串字符相关函数
push_back尾插字符函数。append尾插字符串函数。insert在pos位置插入字符串函数。
push_back函数和append函数与完成一样的操作直接复用即可。insert函数则需要将从pos位置开始往后的元素向后移动len个单位len为插入字符串的长度然后在pos位置插入新字符串。 图4.1 insert函数实现的功能图解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; //更新有效字符数return *this;}string insert(size_t pos, const string str){assert(pos _size);return insert(pos, str._str);}
4.2 子字符串删除函数
erase函数从pos位置开始删除len个函数。
检查pos是否越界如果越界则断言报错。将从下标位置poslen开始的元素向前移动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; //更新有效字符数return *this;}string insert(size_t pos, const string str){assert(pos _size);return insert(pos, str._str);}
4.3 子串查找函数
find函数从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); //复用}
五. 迭代器相关函数
普通对象迭代器和const属性对象迭代器本质上都为char*/const char*
typedef char* iteratiortypedef const char* const_iteratorbegin获取首字符元素地址。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的全局函数
6.1 字符串比较相关函数
关于比较总共有六种形式、、、、、!我们只需要模拟实现其中的两个然后其余4个复用已经模拟实现完成的两个即可。 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 字符串输出和输入相关函数
ostream operator(ostream out, const string s) -- 流插入操作符重载函数istream operator(istream in, string s) -- 流输出操作符重载函数
注意重载流插入操作符时不能使用out s.c_str因为这样遇到\0就会截止输出从而不一定输出s.size()个字符。 ostream operator(ostream out, const string s){//写法1范围for循环/*for (auto ch : s) {out ch;}*///写法2普通for循环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 字符串与数值之间的相互转换
stoi字符串转换为int型数据。stod字符串转换为double型数据。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(); //字符串长度//最终返回值 整数部分 小数部分double integerRet 0; //返回值的整数部分double decimalRet 0; //返回值的小数部分int flag 1; //正负号标识符while (i len s[i] ) //排除空格{i;}if (i len s[i] ) //确定返回值是正数还是负数{i;}else if (i len s[i] -){flag -flag;i;}//计算整数部分while (i len (s[i] 0 s[i] 9)){integerRet integerRet * 10 (s[i] - 0) * flag;i;}//计算小数部分if (i len s[i] .){double factorial 0.1; //系数i; //跳过小数点while (i len (s[i] 0 s[i] 9)){decimalRet (s[i] - 0) * factorial * flag;factorial * 0.1;i;}}return integerRet decimalRet;}
附录string类模拟实现完整版
#includeiostream
#includeassert.h
#includestring.h
#includestdbool.h
#includelimitsusing namespace std;namespace zhang
{class string{public://1.创建和销毁相关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() //析构函数{delete _str;_str nullptr;_size _capacity 0;}//2.类对象成员和容量相关size_t size() const //有效字符个数{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) //容量指定函数{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) //容量变更函数{if (n _size) //容量变更后比原有效字符数小{_size n;_str[n] \0;}else //容量变更后比原有效字符数大{if (n _capacity) //容量不足扩容{reserve(n);}//将_size开始向后的内容全部变为chmemset(_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) //赋值运算符重载//{// //开辟一块新的内存空间用于存储被复制的字符串// char* tmp new char[str._capacity 1];// strcpy(tmp, str._str);// //释放原内存空间同时更新字符串内容// delete[] _str;// _str tmp;// //更新数据量和容量// _size str._size;// _capacity str._capacity;// return *this;//}//复用写法 -- 调用构造函数string operator(const string str){if (this ! str) //排除自赋值情况{string tmp(str); //创建临时对象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; //更新有效字符数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) //子串删除函数{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; //指向存储字符串内存的指针size_t _size; //有效字符数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循环/*for (auto ch : s) {out ch;}*///写法2普通for循环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(); //字符串长度//最终返回值 整数部分 小数部分double integerRet 0; //返回值的整数部分double decimalRet 0; //返回值的小数部分int flag 1; //正负号标识符while (i len s[i] ) //排除空格{i;}if (i len s[i] ) //确定返回值是正数还是负数{i;}else if (i len s[i] -){flag -flag;i;}//计算整数部分while (i len (s[i] 0 s[i] 9)){integerRet integerRet * 10 (s[i] - 0) * flag;i;}//计算小数部分if (i len s[i] .){double factorial 0.1; //系数i; //跳过小数点while (i len (s[i] 0 s[i] 9)){decimalRet (s[i] - 0) * factorial * flag;factorial * 0.1;i;}}return integerRet decimalRet;}
};