如何在个人网上建网站,网站开发一般用什么软件,公司展示类网站模板免费下载,云酒店网站建设目录
关于string类
string类的常用接口
string类常用接口的简单模拟实现 关于string类
string类在cplusplus.com的文档介绍 1. string是表示字符串的字符串类 2. 该类的接口与常规容器的接口基本相同#xff0c;再添加了一些专门用来操作string的常规操作。 3. string在…
目录
关于string类
string类的常用接口
string类常用接口的简单模拟实现 关于string类
string类在cplusplus.com的文档介绍 1. string是表示字符串的字符串类 2. 该类的接口与常规容器的接口基本相同再添加了一些专门用来操作string的常规操作。 3. string在底层实际是basic_string模板类的别名typedef basic_stringchar, char_traits, allocatorstring; 4. 不能操作多字节或者变长字符的序列。 在使用 string 类时必须包含 #includestring 头文件以及 using namespace std; string类的常用接口 string 类对象的常见构造/析构 void Teststring()
{string s1; // 构造空的string类对象s1string s2(hello world); // 用C格式字符串构造string类对象s2string s3(s2); // 拷贝构造s3
} string 类对象的容量操作 #include iostream
using namespace std;#include string//-----------------------------------------------------------------------
//测试string容量相关接口
//size / capacity / clear / resizevoid Teststring()
{//注意string类对象支持直接用cin和cout进行输入和输出string s1(hello world);cout s1.size() endl;cout s1.length() endl;cout s1.capacity() endl;cout s1 endl;//将s1中的字符串清空注意清空时只是将size清0不改变底层空间的大小s1.clear();cout s1.size() endl;cout s1.capacity() endl;//将s1中的有效字符个数增加到6个并且使用*来进行填充s1.resize(6, *);cout s1.size() endl;cout s1.capacity() endl;cout s1 endl;// 将s1中有效字符个数增加到15个多出位置用缺省值\0进行填充// 注意此时s中有效字符个数已经增加到15个s1.resize(15);cout s1.size() endl;cout s1.capacity() endl;cout s1 endl;//另外resize也有删除有效字符的功能,但是不会改变底层空间的大小s1.resize(1);cout s1.size() endl;cout s1.capacity() endl;cout s1 endl;
}//-----------------------------------------------------------------------
//测试reserve
//1.是否改变string类中间的有效元素个数
//2.当reserve参数小于string底层空间时是否会将空间缩小void TestReserve()
{string s1;s1.reserve(100);cout s1.size() endl;cout s1.capacity() endl;s1.reserve(10);cout s1.size() endl;cout s1.capacity() endl;
}int main()
{Teststring();TestReserve();return 0;
} 注意 1. size()与length()方法底层实现原理完全相同引入size()的原因是为了与其他容器的接口保持一致一般情况下基本都是用size()。 2. clear()只是将string中有效字符清空不改变底层空间大小。 3. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个不同的是当字符个数增多时resize(n)用0来填充多出的元素空间resize(size_t n, char c)用字符c来填充多出的元素空间。注意resize在改变元素个数时如果是将元素个数增多可能会改变底层容量的大小如果是将元素个数减少底层空间总大小不变。 4. reserve(size_t res_arg0)为string预留空间不改变有效元素个数当reserve的参数小于string的底层空间总大小时reserver不会改变容量大小。 string 类对象的访问及遍历操作 #include iostream
using namespace std;#include string//---------------------------------------------------------------------
// string的遍历及访问
// 1.迭代器:begin()end() / rbegin() rend() ...
// 2.foroperator[]
// 3.范围for:底层实现是使用迭代器实际上是迭代器的封装 范围forC11后才支持)void Teststring()
{string s1(hello world);//1.string::iterator it s1.begin();while (it ! s1.end()){cout *it;it;}cout endl;//2.for (size_t i 0; i s1.size(); i){cout s1[i];}cout endl;//3.for (auto ch : s1){cout ch;}cout endl;
}int main()
{Teststring();return 0;
} string 类对象的修改操作 #include iostream
using namespace std;#include string//---------------------------------------------------------------------
//string的测试与修改
//1.插入(拼接方式push_back / append / operator
//2.任意位置插入insert
//3.查找 / 反向查找find / rfind
//4.替换字符replace
//5.截取子串 substr
//6.读取字符geline
//7.删除:erase
//8.返回c形式字符串 c_strvoid TestString()
{string s1(hello world);//插入一个字符s1.push_back( );s1.push_back(i); cout s1 endl;//插入一串字符s1.append( );s1.append(love);cout s1 endl;//c更喜欢使用s1 ;s1 you;cout s1 endl;
}void TestInsert()
{string s1(hello);//任意位置插入s1.insert(5, 1, );s1.insert(6, world);cout s1 endl;//使用迭代器s1.insert(s1.begin(), !);s1.insert(s1.begin()1, );cout s1 endl;
}void TestFind_Replace()
{//笔试题将下列所有空格都改成 %20//思路1.string str(hello world i love you);size_t pos str.find( );while (pos ! string::npos){str.replace(pos, 1, %20);pos str.find( );}cout str endl;////优化//string str(hello world i love you);1.提前开空间减少扩容消耗的效率//size_t num 0;//for (auto ch : str)//{// if (ch )// {// num;// }//}//str.reserve(str.size() 2 * num);//size_t pos str.find( );//while (pos ! string::npos)//{// str.replace(pos, 1, %20);// //2.避免重复访问数据提高效率// pos str.find( , pos3);//}//cout str endl;////思路2.//string str(hello world i love you);//string newStr;//size_t num 0;//for (auto ch : str)//{// if (ch )// {// num;// }//}//newStr.reserve(newStr.size() 2 * num);//for (auto ch : str)//{// if (ch ! )// {// newStr ch;// }// else// {// newStr %20;// }//}//cout newStr endl;}void TestFind_Substr()
{//笔试题获取ulr中的域名string url(http://www.cplusplus.com/reference/string/);cout url endl;size_t start url.find(://);if (start string::npos){cout invalid url endl;return;}start 3;size_t finish url.find(/, start);string address url.substr(start, finish - start);cout address endl;}void TestRfind_Getline()
{//笔试题求字符串最后出现单词的长度string str;//注意为什么这里使用 getline 而不使用 cin //因为 cin 类似于scanf 读取字符遇到空格或者\0就会终止无法读取后面的字符//使用c提供了 getline 遇到换行符才会终止读取getline(cin, str);size_t pos str.rfind( );if (pos ! string::npos){cout str.size() - pos - 1 endl;}else{//只有一个单词的情况cout str.size() endl;}}void TestErase()
{string str(hello world);str.erase(5, 1);cout str endl;str.erase(5, 10);cout str endl;str.erase(1);cout str endl;
}void TestC_str()
{string str(hello world);cout str endl;cout str.c_str() endl;cout str endl;cout (void*)str.c_str() endl;str ;str \0;str ******;cout str endl;cout str.c_str() endl;
}int main()
{TestString();TestInsert();TestFind_Replace();TestFind_Substr();TestRfind_Getline();TestErase();TestC_str();return 0;
} 注意 1. 在string尾部追加字符时s.push_back(c) / s.append(1, c) / s c三种的实现方式差不多一般情况下string类的操作用的比较多操作不仅可以连接单个字符还可以连接字符串。 2. 对string操作时如果能够大概预估到放多少字符可以先通过reserve把空间预留好。 string类常用接口的简单模拟实现 #include iostreamusing namespace std;#include assert.h
#includestringclass _string
{public://模拟实现常用接口//...private:char* _str;size_t size;size_t capacity;static const size_t npos;
};const size_t string::npos -1; 注npos 关于npos 这里建议类里面声明类外面定义不建议在类里面给缺省值。因为成员变量给缺省值是因为会在初始化列表进行初始化但是strtic修饰的静态成员变量不能给缺省值因为静态成员变量存储位置在静态区属于整个工程。 另外c11有一个值得吐槽的地方就是开了一个特例如果加const 那么整型静态成员变量可以给缺省值如下图 1.构造函数 _string():_str(new char[1]), _size(0),_capacity(0){_str[0] \0;}_string(const char* str):_size(strlen(str)){_capacity _size;_str new char[_capacity 1];strcpy(_str, str);} 问为什么无参的字符串构造函数 _str(new char[1]) 初始化不给 nullptr 要给一个空间且加上[ ] 答因为如果给nullptr的话cout是会对_str进行解引用这样会导致程序崩溃所以才会给一个空间。而给[ ]是为了在析构的时候与delete[ ] 保持一致。 问为什么 _str new char[_capacity 1] 中要1 答因为_capacity是容量字符指的是能够存取多少个有效字符而vs认为 \0属于标识符不属于有效字符的范畴所以1是为了给\0预留空间。 优化以上两个函数可以优化为缺省函数 _string(const char* str \0):_size(strlen(str)){_capacity _size;_str new char[_capacity 1];strcpy(_str, str);} 1.1拷贝构造 _string(const _string str):_size(str._size),_capacity(str._capacity){_str new char[_capacity 1];strcpy(_str, str._str);} 2.赋值 _string operator(const _string str){delete[] _str;_str new char[str._capacity 1];strcpy(_str, str._str);_size str._size;_size str._capacity;return *this;} 上述代码有一个问题就是程序开始就将_str的空间进行释放这样可能会导致数据的丢失所以需要进行优化。 _string operator(const _string str){if (this ! str){char* tmp new char[str._capacity 1];strcpy(tmp, str._str);delete[] _str;_str tmp;_size str._size;_capacity str._capacity;}return *this;} 3.析构函数 ~ ~_string(){delete[] _str;_str nullptr;_size _capacity 0;} 4.成员访问 char operator[](size_t pos){assert(pos _size);return _str[pos];}const char operator[](size_t pos) const{assert(pos _size);return _str[pos];}size_t size() const{return _size;}size_t capacity() const{return _capacity;}const char* c_str(){return _str;} 5.简单迭代器 iterator typedef char* iterator;iterator begin(){return _str;}iterator end(){return _str _size;} 6.关系运算符relational operatorsstring bool operator(const _string str) const{return strcmp(_str, str._str) 0;}bool operator(const _string str) const{return strcmp(_str, str._str) 0;}bool operator(const _string str) const{return *this str || *this str;}bool operator(const _string str) const{return !(*this str);}bool operator(const _string str) const{return !(*this str);}bool operator!(const _string str) const{return !(*this str);} 7.reserve void reserve(size_t n){if (n _capacity){char* tmp new char[n 1];strcpy(tmp, _str);delete[] _str;_str tmp;_capacity n;}} 问这里为什么要加个 if 进行判断 答因为如果不进行判断当 n _capacity 的时候会导致缩容的问题对程序的安全造成隐患因此要加个判断避免出现缩容的情况。 8.push_back void push_back(char ch){if (_size 1 _capacity){reserve(_capacity * 2);}_str[_size] ch;_size;_str[_size] \0;} 上述代码有一个隐藏的问题那就是如果 _capacity 如果为 0 这个时候进行push_back代码就会越界从而崩溃。解决办法有两个一是修改一下构造函数而是进行判断如果_capacity 为 0 就直接进行赋值。 优化 _string(const char* str \0):_size(strlen(str)){_capacity _size 0 ? 3 : _size;_str new char[_capacity 1];strcpy(_str, str);} 9.append void append(const char* str){if (_size 1 _capacity){reserve(_capacity * 2);}size_t len strlen(str);strcpy(_str _size, str);_size len;} 问这里为什么不适用strcat 答因为 strcat 是自己去寻找 \0 的位置而 _str len 就是 \0 的位置 strcpy 函数会把需要拷贝的字符串最后的位置的 \0拷贝过来。 10. _string operator(char ch){push_back(ch);return *this;}_string operator(const char* str){append(str);return *this;} 11.resize void resize(size_t n, char ch \0)
{if (n _size){//保留前n个 - 删除数据_size n;_str[_size] \0;}else //n size{if (n _capacity){reserve(n);}size_t i _size;while (i n){_str[i] ch;}_size n;_str[_size] \0;}
} 12.insert void insert(size_t pos, char ch){assert(pos _size);if (_size 1 _capacity){reserve(_capacity * 2);}size_t end _size;while (end pos){_str[end 1] _str[end];--end;}_str[pos] ch;_size;} 以上代码有个问题那就是 end 属于无符号整型而 pos 也属于无符号整型这里会造成程序的死循环。即使把 end 置成 int 类型但是也会发生隐式类型转换有符号会转换成无符号。也不建议进行强转所以解决办法的话就是修改挪动数据的逻辑。 优化 void insert(size_t pos, char ch){assert(pos _size);if (_size 1 _capacity){reserve(_capacity * 2);}size_t end _size 1;while (end pos){_str[end] _str[end - 1];--end;}_str[pos] ch;_size;} 当然insert 还需要重载插入字符串 void insert(size_t pos, const char* str){assert(pos _size);size_t len strlen(str);if (_size len _capacity){reserve(_capacity * 2 len);}size_t end _size len;while (end pos len - 1){_str[end] _str[end - len];--end;}strncpy(_str pos, str, len);_size len;} 这里之所以选择 strncpy 而不是 strcpy 因为 strcpy 会拷贝字符串结尾的标识符 \0。 13.erase void erase(size_t pos, size_t len npos){//尾部直接删除if (pos len _size || len npos){_str[pos] \0;_size pos;}else //挪动数据{strcpy(_str pos, _str pos len);_size - len;}} 14.swap void swap(_string str){std::swap(_str, str._str);std::swap(_size, str._size);std::swap(_capacity, str._capacity);} 15.find size_t find(char ch, size_t pos 0){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);char* p strstr(_str pos, str); //strstr : 返回第一次指针匹配的位置if (p nullptr){return npos;}else{return p - _str;}} 17. ostream operator(ostream out, const string str)
{for (auto ch : str){out str;}return out;
} 注因为在类域中存在this指针而友元函数又会增加耦合度破环封装所以这里建议流插入或者流提取的实现不写在类域之中。 18. istream operator(istream in, string str)
{char ch;in ch;while (ch ! ch ! \n){str ch;in ch;}return in;
} 问为什么如果输入多组字符中间用空格或者换行隔开的话编译器只能拿到第一组字符拿不到后面的字符。 答因为cin或者sancf读取的时候会默认忽然空格或者换行不进行识别默认空格或者换行是多个值之间的间隔。流提取并未在输入中获取字符而是在缓冲区获取字符而空格或者换行未进入缓冲区c/c 规定值与值之间的区分必须是空格或者换行所以输入空格或者换行会被认为是多个字符之间的间隔不会被cin 或者 scanf 拿到。 优化 istream operator(istream in, string str)
{str.clear(); //清除掉之前的字符char ch in.get(); //get()函数不区分间隔while (ch ! ch ! \n){str ch;ch in.get();}return in;
} 上述版本只是一个简单的版本实际实现可能有些复杂 istream operator(istream in, string str)
{str.clear(); //清除掉之前的字符char ch in.get(); //get()函数不区分间隔char buff[128];size_t i 0;while (ch ! ch ! \n){buff[i] ch;if (i 127){buff[127] \0;str buff;i 0;}ch in.get();}if (i ! 0) //防止最后的数据没有添加进去{buff[i] \0;str buff;}return in;
} 接口实现代码 #define _CRT_SECURE_NO_WARNINGS 1
#include iostreamusing namespace std;#include string
#include assert.hclass _string
{public:typedef char* iterator;iterator begin(){return _str;}iterator end(){return _str _size;}//模拟实现 //_string()// :_str(new char[1])// , _size(0)// ,_capacity(0)//{// _str[0] \0;//}_string(const char* str \0):_size(strlen(str)){_capacity _size 0 ? 3 : _size;_str new char[_capacity 1];strcpy(_str, str);}_string(const _string str):_size(str._size), _capacity(str._capacity){_str new char[_capacity 1];strcpy(_str, str._str);}_string operator(const _string str){if (this ! str){char* tmp new char[str._capacity 1];strcpy(tmp, str._str);delete[] _str;_str tmp;_size str._size;_capacity str._capacity;}return *this;}char operator[](size_t pos){assert(pos _size);return _str[pos];}const char operator[](size_t pos) const{assert(pos _size);return _str[pos];}size_t size() const{return _size;}size_t capacity() const{return _capacity;}const char* c_str(){return _str;}bool operator(const _string str) const{return strcmp(_str, str._str) 0;}bool operator(const _string str) const{return strcmp(_str, str._str) 0;}bool operator(const _string str) const{return *this str || *this str;}bool operator(const _string str) const{return !(*this str);}bool operator(const _string str) const{return !(*this str);}bool operator!(const _string str) const{return !(*this str);}void reserve(size_t n){if (n _capacity){char* tmp new char[n 1];strcpy(tmp, _str);delete[] _str;_str tmp;_capacity n;}}void push_back(char ch){if (_size 1 _capacity){reserve(_capacity * 2);}_str[_size] ch;_size;_str[_size] \0;}void append(const char* str){if (_size 1 _capacity){reserve(_capacity * 2);}size_t len strlen(str);strcpy(_str _size, str);_size len;}_string operator(char ch){push_back(ch);return *this;}_string operator(const char* str){append(str);return *this;}void resize(size_t n, char ch \0){if (n _size){//保留前n个 - 删除数据_size n;_str[_size] \0;}else //n size{if (n _capacity){reserve(n);}size_t i _size;while (i n){_str[i] ch;}_size n;_str[_size] \0;}}void insert(size_t pos, char ch){assert(pos _size);if (_size 1 _capacity){reserve(_capacity * 2);}size_t end _size 1;while (end pos){_str[end] _str[end - 1];--end;}_str[pos] ch;_size;}void insert(size_t pos, const char* str){assert(pos _size);size_t len strlen(str);if (_size len _capacity){reserve(_capacity * 2 len);}size_t end _size len;while (end pos len - 1){_str[end] _str[end - len];--end;}strncpy(_str pos, str, len);_size len;}void erase(size_t pos, size_t len npos){//尾部直接删除if (pos len _size || len npos){_str[pos] \0;_size pos;}else //挪动数据{strcpy(_str pos, _str pos len);_size - len;}}void swap(_string str){std::swap(_str, str._str);std::swap(_size, str._size);std::swap(_capacity, str._capacity);}size_t find(char ch, size_t pos 0){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);char* p strstr(_str pos, str); //strstr : 返回第一次指针匹配的位置if (p nullptr){return npos;}else{return p - _str;}}void clear(){_str[0] \0;_size 0;}~_string(){delete[] _str;_str nullptr;_size _capacity 0;}private:char* _str;size_t _size;size_t _capacity;//static const size_t npos;static const size_t npos -1;
};//const size_t string::npos -1;ostream operator(ostream out, const string str)
{for (auto ch : str){out str;}return out;
}istream operator(istream in, string str)
{str.clear(); //清除掉之前的字符char ch in.get(); //get()函数不区分间隔char buff[128];size_t i 0;while (ch ! ch ! \n){buff[i] ch;if (i 127){buff[127] \0;str buff;i 0;}ch in.get();}if (i ! 0) //防止最后的数据没有添加进去{buff[i] \0;str buff;}return in;
} 以上仅代表个人看法欢迎讨论