企业门户网站的主要技术指标,宁波网站推广优化联系电话,掼蛋网站建设,网站成功案例设计1.string简介
string不是STL的一部分#xff0c;但是和STL一起学习会更加容易融会贯通。
而实际上string是一个类模板#xff0c;使用字符的顺序容器实现#xff08;也就是字符的顺序表#xff09;#xff0c;string整个系列支持char的动态增长#xff08;字符编码有几…1.string简介
string不是STL的一部分但是和STL一起学习会更加容易融会贯通。
而实际上string是一个类模板使用字符的顺序容器实现也就是字符的顺序表string整个系列支持char的动态增长字符编码有几篇文章值得看一下是耗子哥推荐的。 String are objects represent sequences of characters.字符串是表示字符序列的对象。 string实际上是由basic_traits类实例化而来 typedef basic_stringchar string;在string类中至少有三个成员变量 class string{private:char* _str;//指向由new开辟出来的动态空间该空间存储字符串size_t _size;//string对象对应字符串的大小size_t _capacity;//string对象的容量在存储的时候会多存储一个空字符方便转化为C风格的字符串在不同的环境扩容机制有些许不同有的直接2倍有的1.5倍};2.类构造函数
2.1.string()
调用构造函数后会构造一个长度为0的空字符串但是有一定的容量。 #include iostream#include stringint main() {std::string str;//使用范围for循环遍历字符串中的每个字符std::cout 大小 str.size() std::endl;std::cout 容量 str.capacity() std::endl;//size()是string类内部的成员函数//可以求得string对象内部存储的字符串大小//而capacity()则是求得容量大小//后续还会继续讲解return 0;}2.2.string (const string str)
构造一个str的副本也就是复制str构造一个新的string对象。
2.3.string (const string str, size_t pos, size_t len npos)
复制string对象的部分的字符从pos开始到len的部分来构造一个新的string对象。
或者复制到str结束部分即str太短了或者len值为string::pos。 补充什么是string::pos呢string::pos实际上是string内部的常量成员下面是其定义 static const size_t npos -1;我们知道size_t是无符号整数类型的别名因此npos取得了有符号的一个最大值这基本不可能是str的长度也可能是字符串的索引值。 len默认值为npos的目的是如果没有给予len的值将会一直读取到字符串的末尾这一点细节我们实现一个简易的string类再来细细探究。
2.4.string (const char* s)
复制s指针指向的字符序列以空字符\0结尾的C语言风格的字符序列构造出一个string对象。
2.5.string (const char* s, size_t n)
从s指向的字符数组中复制前n个字符。
2.6.string (size_t n, char c)
用n个相同得c字符连续填充字符串。
2.7.template class InputIterator string (InputIterator first, InputIterator last)
以和原string对象相同的顺序来复制原string对象中范围为[first,last)迭代器的字符序列构造新的string对象。由于我们还没有学过迭代器因此我们直接上代码观看迭代器的时候会更加好一下。 #include iostream#include stringint main(){//直接初始化一个字符串std::string str1(Hello World);std::cout str1(\Hello World\) str1 std::endl;//使用迭代器范围构造一个新的字符串std::string str2(str1.begin(), str1.begin() 7);//输出Hellostd::cout str2(str1.begin(), str1.begin() 7) str2 std::endl; return 0;}这里begin()就是迭代器的使用您可以简单理解为有一个指针指向了这个string对象的字符串开头位置迭代器的出现就是为了能是使得一些对象可以类似指针一样使用。
2.8.string (initializer_listchar il)
以列表il中的每个字符来构造string对象这和使用string(const string str)构造有些许不同。 #include iostream#include stringint main(){//使用列表方式初始化字符串std::string str{ Hello };//输出Hellostd::cout str: str std::endl;return 0;}补充std::initializer_list 是一个模板类它允许创建一个包含任意数量元素的列表。它类似于数组可以通过下标访问其中的元素但与数组不同的是std::initializer_list 是不可变的不能进行元素的添加或删除操作。但是这不是初始化列表的意思 2.9.string (string str) noexcept
这个函数被称为“移动构造”可以将源string对象转移到目标string对象中。
移动构造函数通常是浅拷贝它将源对象的资源所有权转移给目标对象而不是创建新的资源副本。这种机制能够提高性能并确保在源对象析构时不会重复释放资源。
下面代码如果没能看懂可以以后再来查看 #include iostream#include stringint main(){//使用构造函数构造源string对象std::string source Hello World;//使用移动构造函数转移资源std::string target(std::move(source));std::cout target target std::endl;//输出target Hello Worldstd::cout source source std::endl;//输出source source的内容已被移动return 0;}注意源对象的状态会变为有效但未指定的状态并且应该避免继续使用移动后的对象或访问其值上述代码在大部分编译器比如VS2022中有可能在打印source的时候提示出类似下面的警告使用已移动的 from 对象: source (lifetime.1)。 2.10.英文备注 以下是参考CPlusPlus网站的英文解释 (1) empty string constructor (default constructor) Constructs an empty string, with a length of zero characters. (2) copy constructor Constructs a copy of str. (3) substring constructor Copies the portion of str that begins at the character position pos and spans len characters (or until the end of str, if either str is too short or if len is string::npos). (4) from c-string Copies the null-terminated character sequence (C-string) pointed by s. (5) from buffer Copies the first n characters from the array of characters pointed by s. (6) fill constructor Fills the string with n consecutive copies of character c. (7) range constructor Copies the sequence of characters in the range [first,last), in the same order. (8) initializer list Copies each of the characters in il, in the same order. (9) move constructor Acquires the contents of str. str is left in an unspecified but valid state. 3.类析构函数
~string()会释放所有存储容量该存储容量由字符串所使用的分配器分配。
也就是说string类的析构函数~string()主要是释放掉string类产生的string对象的资源因为string的本质是一个顺序表。
4.赋值符号重载函数
类别函数声明string (1)string operator (const string str);c-string (2)string operator (const char* s);character (3)string operator (char c);initializer list (4)string operator (initializer_listchar il);move (5)string operator (string str) noexcept;
上述的作用基本都是将一个新值赋给已定义后的string对象来替换其当前string对象的内容。下面是测试例子 #include iostream#include stringint main(){//创建多个string对象std::string str1, str2, str3, str4;str1 hello; //赋值C风格的字符串(2)std::cout str1 std::endl;str2 x; //赋值单字符(3)std::cout str2 std::endl;str3 str1 str2; //赋值string对象(1)std::cout str3 std::endl;str3 { H, E, L, L, O }; //初始化列表(4)std::cout str3 std::endl;str4 std::move(str3); //移动构造(5)std::cout str3 std::endl;std::cout str4 std::endl;return 0;}其中初始化列表函数和普通的赋值只是内部实现细节有点区别其他地方都很类似。
最后一个函数您若是没有看懂暂且先用着我们以后再来解释……
5.迭代器Iterators
如果需要遍历一个string对象需要怎么做呢目前我们有多种方法可以遍历。
类别可读可修改可读不可修改正向迭代器iterator begin() noexcept;iterator end() noexcept;const_iterator begin() const noexcept;const_iterator end() const noexcept;反向迭代器reverse_iterator rbegin() noexcept; reverse_iterator rend() noexcept;const_reverse_iterator rbegin() const noexcept;const_reverse_iterator rend() const noexcept;
类别函数声明普通对象的常量迭代器const_iterator cbegin() const noexcept;const_iterator cend() const noexcept;常量对象的常量迭代器const_reverse_iterator crbegin() const noexcept;const_reverse_iterator crend() const noexcept;
其中iterator是一个类模板 template class T//这里假设T实例化为string class iterator { //1.正向迭代器//迭代器的成员函数和操作符重载定义iterator begin() noexcept;//可以找到string对象的头const_iterator begin() const noexcept;//可以找到const string对象的头iterator end() noexcept;//可以找到string对象的尾const_iterator end() const noexcept;//可以找到const string对象的尾//2.反向迭代器reverse_iterator rbegin() noexcept;const_reverse_iterator rbegin() const noexcept;reverse_iterator rend() noexcept;const_reverse_iterator rend() const noexcept;//...};5.1.正向迭代器begin()和end()
5.1.1.for遍历
这里会使用string类的成员函数size()这个函数专门计算string对象的大小这在后面讲解string类的成员函数时还会进行讲解。 #include iostream#include stringint main(){std::string str(abcd);for (int i 0; i str.size(); i){std::cout str[i] ;//[]运算符重载}return 0;}还需要注意的是[]运算符重载使得string对象能够像数组一样遍历我们之后还会再提一次。
5.1.2.迭代器
迭代器的行为十分类似指针但是不是指针使得string对象可以像数组一样被使用 #include iostream#include stringint main(){std::string str(abcd);std::string::iterator it str.begin();//这里如果类型名字太长可以使用auto来自动推导while (it ! str.end())//这里不推荐使用符号{std::cout *it ;(*it);it;}std::cout std::endl str std::endl;return 0;}在while (it ! str.end())这里不推荐使用符号尽管在string对象里使用或许不会出错但是在其他类里可能就不满足了。之前说过迭代器的行为类似指针因此string的底层很有可能就是指针因此使用不会出太多错
但是迭代器不仅仅是string类使用基本所有库里的类都可以使用迭代器遍历迭代器有几种便利之处 通用在一些不支持[]重载的结构也可使用迭代器 是无需考虑差1问题 屏蔽底层实现细节可以直接使用
而其他类底层的迭代器是靠纯指针实现的例如链表因此使用会有风险。
实际上迭代器就是C封装的一种体现。
5.1.3.范围for #include iostream#include stringint main() {std::string str Hello;//使用范围for循环遍历字符串中的每个字符for (auto ch : str) {std::cout ch ;}return 0;}实际上范围for的底层代码就是迭代器只不过范围for封装得更加厉害罢了在一些编译器内部调试的时候可以切到范围for的汇编语句来检验两者关系。
5.2.反向迭代器rbegin()和rend() #include iostream#include stringint main(){std::string str(abcd);std::string::reverse_iterator rit str.rbegin();while (rit ! str.rend()){std::cout *rit ;(*rit);rit;//注意依旧是而不是--}std::cout std::endl str std::endl;return 0;}5.3.常量迭代器
常量迭代器也没有什么声明的只是将上述两种迭代器从“可读可写”设置为“只可读不可写”这点我们就不再深入讲解了。 #include iostream#include stringusing namespace std;int main(){//const string str1 abcdef;//auto it str1.begin();//while (it ! str1.end())//{// cout (*it) ;//// it;//}//cout endl;string str2 abcdef;auto cit str2.cbegin();while (cit ! str2.cend()){cout *cit ;cit;}cout endl;return 0;}6.容积Capacity
类别函数声明获取长度和容量size_t size() const noexcept;size_t length() const noexcept;size_t capacity() const noexcept;改变长度和容量void resize (size_t n);void resize (size_t n, char c);void reserve (size_t n 0);获取环境最大容量数值size_t max_size() const noexcept;清理对象内容void clear() noexcept;判空bool empty() const noexcept;
6.1.size()和length()和capacity()
首先我们有一个问题为什么会有两个计算长度的成员函数呢这是因为string类得诞生比STL早最开始设计的是length()后来出现了STL才开始使用了并且建议使用size()。两个都可以计算string对象内部字符串长度在功能上是等效的。 #include iostream#include stringusing namespace std;int main(){string str(abcdefghijklmn);cout str.size() endl;cout str.length() endl;return 0;}补充如果查看其他的结构会发现都是使用size()而没有length() 而另外一个函数capacity()则可以求得当前string对象的容量。
6.2.clear()
这个成员函数会对string对象的字符串作清理但是不会释放空间同时原string的容量不变对象的siez()值置为空。 #include iostream#include stringusing namespace std;int main(){string str(abcdefghijklmn);cout str endl;cout str.size() endl;cout str.capacity() endl;str.clear();cout str endl;cout str.size() endl;cout str.length() endl;return 0;}6.3.max_size()
这个成员函数用于告知用户该环境下的string对象最多可以申请到多少字节的空间。
但是这个值是写死的只是在不同环境下会不同罢了因此基本没怎么用到这个。 #include iostream#include stringusing namespace std;int main(){string str1(abcdefghijklmn);cout str1.max_size() endl;string str2(abcdefghijklmn);cout str2.max_size() endl;return 0;}6.4.resize()
resize()可以将string对象的大小即size()的值有以下集几种情况 如果n小于string对象原有的大小则删除n个字符以外的字符这个操作比较危险 如果n大于string对象原有的大小则尾插任意字符默认表现为空字符\0扩充到当前的内容使得大小达到n。因此如果有填充某个字符串的需求也是可以用这个函数的 如果指定了字符c则多开辟的空间初始化为字符c #include iostream#include stringusing namespace std;int main(){//1.创建一个abcde为内容的string对象size()值为5capacity()默认值为15string str(abcde);cout str endl;cout str.size() endl;cout str.capacity() endl endl;//2.调整size()值为20的string对象而在VS2022中表现为填充15个空字符\0而空字符是没有打印出来的str.resize(20);cout str endl;cout str.size() endl;cout str.capacity() endl endl;//3.调整size()值为30的string对象因此前5个字符为abcde后面有15个\0并且还有10个c字符整体打印出abcdeccccccccccstr.resize(30, c);cout str endl;cout str.size() endl;cout str.capacity() endl endl;//4.缩小size()值并且可以看到扩容的空间依旧有效str.resize(5);cout str endl;cout str.size() endl;cout str.capacity() endl endl;return 0;}6.5.reserve()
这个函数请求改变容量要求将string对象调整到大小为n的容量或者比n更大这个函数对字符串的长度没有影响也不能改变它的内容。
如果使用者做了缩小容量的操作并且影响到原有string对象字符串的存储时该函数会拒绝请求即non-binding无约束力的。 #include iostream#include stringusing namespace std;int main(){//1.创建一个abcde为内容的string对象size()值为5capacity()默认值为15string str(abcde);cout str endl;cout str.size() endl;cout str.capacity() endl endl;//2.调整capacity()值为20的string对象str.reserve(20);cout str endl;cout str.size() endl;cout str.capacity() endl endl;//3.调整capacity()值为30的string对象str.reserve(30);cout str endl;cout str.size() endl;cout str.capacity() endl endl;//4.减小capacity()值为4的string对象失败请求str.reserve(4);cout str endl;cout str.size() endl;cout str.capacity() endl endl;//4.增大capacity()值为10的string对象str.reserve(10);cout str endl;cout str.size() endl;cout str.capacity() endl endl;return 0;} 注意函数名reserve有时候会和单词reversal反转搞混这个注意一下就行……6.6.empty()
该函数返回字符串是否为空即size()是否为0)这个函数不会以任何方式修改字符串的值。 #include iostream#include stringusing namespace std;int main(){string str(abcdef);cout str.empty() endl;str.resize(0);//为空返回truecout str.empty() endl;return 0;}6.7.shrink_to_fit()
shrink to fit这个词的意思就是“缩小以适应”该函数请求减少容量capacity来适应大小size当然这只是一种请求即non-binding无约束力的。 #include iostream#include stringusing namespace std;int main(){string str(abcde);cout str endl;cout str.size() endl;cout str.capacity() endl endl;str.reserve(1000);//明明大小只有5容量确高达1000多浪费资源cout str endl;cout str.size() endl;cout str.capacity() endl endl;str.shrink_to_fit();//使用该函数请求缩小容量非强制cout str endl;cout str.size() endl;cout str.capacity() endl endl;return 0;}7.访问元素Element access
7.1.operator[] //重载形式char operator[] (size_t pos);const char operator[] (size_t pos) const;pos的起始位置为0这意味这和数组的使用形式类似。 #include iostream#include stringusing namespace std;int main(){string str(abcdef);for (int i 0; str[i]; i){cout str[i] ;}return 0;}如果pos等于string对象的size值这个符号重载函数就会返回一个指向空字符的引用该字符位于string对象最后一个字符之后这个字符不可被修改只所以可以被允许访问的其中一个原因就是方便写循环终止条件就像上面的循环例子。 #include iostream#include stringusing namespace std;int main(){string str(abcdef);cout 空字符-[ str[str.size()] ] endl;//可以看到空字符没有办法打印出来return 0;}7.2.at() //重载声明char at (size_t pos);const char at (size_t pos) const;该函数可以获取字符串中的字符返回一个pos指向字符的引用该函数自动检查pos是否是string对象中合法的字符索引非法则抛出异常。那么at()和[]有什么区别呢答案在于自动检查出现非法时例如下面的代码#include iostream#include stringusing namespace std;int main(){try{string str(abcdef);cout str str endl;cout str.size() str.size() endl;//cout str[7] str[7] endl;//第一情况//cout at(7) str.at(7) endl;//第二情况}catch (const std::out_of_range e)//出现异常时执行下面代码{cout error endl;}return 0;}使用[]的报错和使用at的报错不太相同。
总的来说抛异常会更加得安全并且抛异常是面向对象语言的一个显著特征具体的抛异常细节我们以后再来学习……
7.3.back() //重载声明char back();const char back() const;该函数返回最后一个有效字符的引用不是指空字符此函数不能再空string对象上调用。 #include iostream#include stringusing namespace std;int main(){string str1(abcdef);cout str1 str1 endl;cout str1.size() str1.size() endl;cout str1.back() str1.back() endl;string str2();cout str2 str2 endl;cout str2.size() str2.size() endl;//cout str2.back() str2.back() endl;//直接会出现报错return 0;}7.4.front() char front();const char front() const;类似end()的使用不过获取到字符是开头的字符。 #include iostream#include stringusing namespace std;int main(){string str1(abcdef);cout str1 str1 endl;cout str1.size() str1.size() endl;cout str1.front() str1.front() endl;string str2();cout str2 str2 endl;cout str2.size() str2.size() endl;//cout str2.front() str2.front() endl;//直接会出现报错return 0;}8.修改器Modifiers
8.1.operator()
用得比较多。 //重载声明string operator (const string str);string operator (const char* s);string operator (char c);8.2.append()
尾插即便有很多重载但是用的比较少这里只给出声明您可以自己玩玩看。 //重载声明string append (const string str);string append (const string str, size_t subpos, size_t sublen);string append (const char* s);string append (const char* s, size_t n);string append (size_t n, char c);template class InputIterator string append (InputIterator first, InputIterator last);string append (initializer_listchar il);8.3.push_back ()
尾插单字符爷用的比较少您也可以自己玩玩。 //函数声明void push_back (char c);添加字符c到string对象的末尾并且size()长度1。 #include iostream#include stringusing namespace std;int main(){string str(abcdef);cout str str endl;cout str.size() str.size() endl;str.push_back(x);cout str str endl;cout str.size() str.size() endl;return 0;}可以拿尾插类的函数来测试环境的扩容机制 #include iostream#include stringusing namespace std;#define NUMBER 100void test(){string str;size_t old str.capacity();cout Init: old endl;size_t newValue 0;for (size_t i 0; i NUMBER; i){str.push_back(x);//推送newValue str.capacity();//记录新值if (newValue ! old)//新值和旧值对比{cout dilatation newValue ;old newValue;cout endl;}}cout endl;}int main(){test();return 0;}8.4.instert() //重载声明string insert (size_t pos, const string str);//插入string对象内的字符串string insert (size_t pos, const string str, size_t subpos, size_t sublen);//插入子串注意这里后两个参数不是输入子串的首尾索引而是输入子串的起始索引和子串长度string insert (size_t pos, const char* s);//插入C风格的字符串string insert (size_t pos, const char* s, size_t n);插入C风格的字符串并且限定长度string insert (size_t pos, size_t n, char c);//重复插入n个c字符iterator insert (const_iterator p, size_t n, char c);//使用迭代器来插入重复的字符并返回指向第一个插入元素的迭代器iterator insert (const_iterator p, char c);//使用迭代定位插入一个字符并返回指向第一个插入元素的迭代器template class InputIteratoriterator insert (iterator p, InputIterator first, InputIterator last);//将迭代器[first, last)的字符插入到目标string对象的迭代器定位处string insert (const_iterator p, initializer_listchar il);//在迭代器定位处插入字符序列可以看到这个函数有很多重载版本让我们来用一个测试例子研究一下不过这个函数能不用就最好别用效率不高。 #include iostream#include stringusing namespace std;int main(){cout 1.string insert (size_t pos, const string str); endl;string str1(abcdef);cout str1 endl;string sstr1 xxxxx;str1.insert(0, sstr1);cout str1 endl endl;cout 2.string insert (size_t pos, const string str, size_t subpos, size_t sublen); endl;string str2(abcdef);cout str2 endl;string sstr2 ABCDEEEEFGHIJK;str2.insert(str2.size(), sstr2, 4, 4);cout str2 endl endl;cout 3.string insert (size_t pos, const char* s); endl;string str3 abcdef;//这是一个C风格的字符串cout str3 endl;const char* sstr3 __________;str3.insert(str3.size(), sstr3);cout str3 endl endl;;cout 4.string insert (size_t pos, const char* s, size_t n); endl;string str4(abcdef);cout str4 endl;const char* sstr4 bbbbbxxxxxxxxxxxxxx;//只想截取长度为前5个字符的字符str4.insert(1, sstr4, 5);cout str4 endl endl;;cout 5.string insert (size_t pos, size_t n, char c); endl;string str5(ABCDEFG);cout str5 endl;str5.insert(1, 20, );cout str5 endl endl;cout 6.iterator insert(const_iterator p, size_t n, char c); endl;string str6 QWERT;str6.insert(str6.begin() 3, 10, c);cout str6 endl endl;cout 7.iterator insert (const_iterator p, char c); endl;string str7 AAAAAAAAA;str7.insert(str7.end(), c);cout str7 endl endl;cout 8.template class InputIterator endl;cout iterator insert(iterator p, InputIterator first, InputIterator last); endl;string str8 XXXX;string sstr8 |bcde|;str8.insert(str8.begin(), sstr8.begin() 1, sstr8.end() - 1);cout str8 endl endl;cout 9. string insert (const_iterator p, initializer_listchar il); endl;string str9 XXXX;str9.insert(str9.begin() 2, { a, b, c });cout str9 endl endl;return 0;}8.5.erase() string erase (size_t pos 0, size_t len npos);//全部删除默认iterator erase (const_iterator p);//使用迭代器删除指定位置iterator erase (const_iterator first, const_iterator last);//这个函数主要是用来擦除字符串的一部分并减小size()的值直接使用则默认为全部删除这个函数能不用就最好别用也是效率不太高。 string str abcdef;cout str endl;str.erase(str.begin() 3);cout str endl;str.erase(str.begin(), str.end() - 2);cout str endl;str.erase();cout str endl;8.6.replace() //string (1) string replace (size_t pos, size_t len, const string str);string replace (const_iterator i1, const_iterator i2, const string str);//substring (2) string replace (size_t pos, size_t len, const string str, size_t subpos, size_t sublen);//c-string (3) string replace (size_t pos, size_t len, const char* s);string replace (const_iterator i1, const_iterator i2, const char* s);//buffer (4) string replace (size_t pos, size_t len, const char* s, size_t n);string replace (const_iterator i1, const_iterator i2, const char* s, size_t n);//fill (5) string replace (size_t pos, size_t len, size_t n, char c);string replace (const_iterator i1, const_iterator i2, size_t n, char c);//range (6) template class InputIteratorstring replace (const_iterator i1, const_iterator i2, InputIterator first, InputIterator last);//initializer list (7) string replace (const_iterator i1, const_iterator i2, initializer_listchar il);该函数主要用于替换参数也很多您可以稍微玩一下 string str abc def;cout str endl;str.replace(3, 2, %#);//将str索引为3起始的长度为2的子串替换成%#cout str endl;也不太建议使用效率比较低下需要的时候可以使用一下。当然我们也可以自己设计一个算法解决 int main(){//设计一个算法让下面string对象的空格改为20%string str abc def;string strx;cout str endl;//空间换时间for (auto ch : str){if (ch ! ){strx ch;}else{strx 20%;}}//str strx;//或者使用全局的swap()但是使用这个会效率很低内部有一次拷贝构造两次赋值很糟糕str.swap(strx);//string的swap()效率就会高很多这个成员函数只是交换了指针指向效率很高cout str endl;//这样的效率都会比较高//不过需要注意的是就算我们直接使用全局的swap()也不会真的调用到最麻烦的哪一个因为库已经针对全局的swap()进行了重载内部调用的也是成员的swap()return 0;}8.7.swap() void swap (string str);成员交换函数效率比全局的要高就是前面代码使用的那一个函数。后面介绍的全局swap()调用的就是这个成员函数。
9.字符串运算String operations
9.1.c_str()和data() //函数声明const char* c_str() const noexcept;const char* data() const noexcept;有时候为了和C兼容需要使用C风格的字符串以\0。而c_str()可以使得string对象返回底层的C风格的字符串成员变量从这里我们也可以看到虽然string不以\0作为结尾标志但是依旧会在构造string对象的时候存储\0以保证能与C兼容。 #include iostream#include stringusing namespace std;int main(){string str(abcdef);cout str str 类型 typeid(str).name() endl endl;char* ch;cout typeid(ch).name() endl;cout str.c_str() str.c_str() 类型 typeid(str.c_str()).name() endl;cout str.data() str.data() 类型 typeid(str.data()).name() endl;return 0;}而data()和s_str()的使用是等价的没有太大区别。 #include iostream#include string#include cstringusing namespace std;int main(){int length;string str Test string;const char* cstr Test string;if (str.length() strlen(cstr)){cout 1 endl;if (memcmp(cstr, str.data(), str.length()) 0){cout 1 endl;}}return 0;}9.2.cpoy() //函数声明size_t copy (char* s, size_t len, size_t pos 0) const;将string对象当前值从pos位置开始的长度为len子串拷贝到s指向的数组中。#include iostream#include stringint main(){std::string str(abcd);char s[3] { 0 };//如果这里没有加入初始化{ 0 }那么后续打印s数组就会出现乱码原因就是找不到空字符str.copy(s, 2);std::cout s std::endl;return 0;}9.3.find()和rfind() size_t find (const string str, size_t pos 0) const noexcept;size_t find (const char* s, size_t pos 0) const;size_t find (const char* s, size_t pos, size_type n) const;size_t find (char c, size_t pos 0) const noexcept;该函数可以寻找字符串或者string对象中的内容。 #include iostream#include stringusing namespace std;int main(){//1.寻找string子串string str1(abcd-abcd-abcd);string str2(abcd);cout str1.find(str2, 0) endl;cout str1.find(str2, 1) endl;cout str1.find(str2, 6) endl endl;//2.寻找C风格子串string str3(ABCD-ABCD-ABCD);const char* str4 ABCD;cout str3.find(str4, 0) endl;cout str3.find(str4, 1) endl;cout str3.find(str4, 6) endl endl;//3.在范围内寻找C风格子串string str5(ABCD-AB-ABCD-AB-ABCD);const char* str6 ABCD;cout str5.find(str6, 0, 2) endl;cout str5.find(str6, 1, 2) endl;cout str5.find(str6, 6, 2) endl;cout str5.find(str6, 9, 2) endl;cout str5.find(str6, 14, 2) endl endl;//4.寻找字符string str7(xxxxxxx_xxxx_xxxxxxxxxx_);char ch _;int j -1;for (int i 0; i str7.size(); i){int z str7.find(ch, i);if (j ! z){cout z ;j z;}}return 0;}而rfind()就是逆向查找具体定义看下文档就行使用和find()类似。 //重载声明size_t rfind (const string str, size_t pos npos) const noexcept; size_t rfind (const char* s, size_t pos npos) const; size_t rfind (const char* s, size_t pos, size_t n) const;size_t rfind (char c, size_t pos npos) const noexcept;9.4.substr() //函数声明string substr (size_t pos 0, size_t len npos) const;这个函数可以用来生成一个新的子串对象从源string对象的pos开始的长度为len的子字符串。 #include iostream#include stringusing namespace std;int main(){string str(awwwwf);cout str.substr(1, 4) endl;return 0;}9.5.compare() //重载函数int compare (const string str) const noexcept;//比较两个string对象int compare (size_t pos, size_t len, const string str) const;//在源string对象的子串和str对象比较int compare (size_t pos, size_t len, const string str, size_t subpos, size_t sublen) const;//在源string对象的子串内和str对象的子串比较int compare (const char* s) const;//和C风格的字符串比较int compare (size_t pos, size_t len, const char* s) const;//string对象的子串和C风格的字符串比较int compare (size_t pos, size_t len, const char* s, size_t n) const;//string对象的子串和C风格的字符串的子串比较该函数主要是比较字符大小和C语言的strcmp()类似返回指定的字符序列。 #include iostream#include stringusing namespace std;// comparing apples with apples#include iostream#include stringint main(){string str1(green apple);string str2(red apple);//g r g - r 0//green apple red appleif (str1.compare(str2) 0)cout str1 is not str2 endl;//apple appleif (str1.compare(6, 5, apple) 0)cout still, str1 is an apple endl;//apple appleif (str2.compare(str2.size() - 5, 5, apple) 0)cout and str2 is also an apple endl;//apple apple if (str1.compare(6, 5, str2, 4, 5) 0)cout therefore, both are apples endl;const char* str3 green apple;if (str1.compare(str3) 0)cout one and the same endl;return 0;}不过这个函数不怎么使用原因是后面有很多的判断符号重载这些重载更加方便。
9.6.find_first_of() //重载函数size_t find_first_of (const string str, size_t pos 0) const noexcept;size_t find_first_of (const char* s, size_t pos 0) const;size_t find_first_of (const char* s, size_t pos, size_t n) const;size_t find_first_of (char c, size_t pos 0) const noexcept;在字符串中查找第一次出现指定字符集合中任何一个字符的位置。 int main(){string str1 xxx_big_apple_xxx;string str2 be;cout str1.find_first_of(str2, 0) endl;//输出4cout str1.find_first_of(str2, 5) endl;//输出12return 0;}吐槽这个函数的名字真不好理解…… 9.7.find_last_of() //重载函数size_t find_last_of (const string str, size_t pos npos) const noexcept;size_t find_last_of (const char* s, size_t pos npos) const;size_t find_last_of (const char* s, size_t pos, size_t n) const;size_t find_last_of (char c, size_t pos npos) const noexcept;在字符串中查找最后一次出现指定字符集合中任何一个字符的位置。 int main(){string str1 xxx_big_apple_xxx;string str2 be;cout str1.find_last_of(str2, str1.size() - 1) endl;//输出12cout str1.find_last_of(str2, 11) endl;//输出4return 0;}9.8.find_first_not_of() //重载函数size_t find_first_not_of (const string str, size_t pos 0) const noexcept;size_t find_first_not_of (const char* s, size_t pos 0) const;size_t find_first_not_of (const char* s, size_t pos, size_t n) const;size_t find_first_not_of (char c, size_t pos 0) const noexcept;这个函数可以查找不是指定字符集合中的任何一个字符的位置。下面是一个例子制作屏蔽词语
cppint main(){string str(saldgcaslucdgleakjslaejcsfkajsasducgiasfg);size_t index str.find_first_not_of(abcdef, 0);cout str endl;while (index ! string::npos){str[index] *;index str.find_first_not_of(abcdef, index 1);}cout str endl;return 0;}9.9.find_last_not_of() //重载函数size_t find_last_not_of (const string str, size_t pos npos) const noexcept;size_t find_last_not_of (const char* s, size_t pos npos) const;size_t find_last_not_of (const char* s, size_t pos, size_t n) const;size_t find_last_not_of (char c, size_t pos npos) const noexcept;上面这个函数就是从后面开始查找这里就不再举例了……
9.10.get_allocator() //函数声明allocator_type get_allocator() const noexcept;这个函数就比较复杂了您可以先去查看一下文档或者以后我们有机会再来详谈……
9.11.assign() //重载函数string assign (const string str);string assign (const string str, size_t subpos, size_t sublen);string assign (const char* s);string assign (const char* s, size_t n);string assign (size_t n, char c);template class InputIteratorstring assign (InputIterator first, InputIterator last);string assign (initializer_listchar il);string assign (string str) noexcept;这个函数也不经常使用实际在一种赋值的工作
cppint main(){string str1 abcdef;string str2 xxxxxx;str1.assign(str2);cout str1 endl;cout str2 endl;return 0;}10.常量成员Member constants
string类的常量成员也就是前面介绍的npos之前已经简单提到过这里就放一下npos的定义使得本文章足够完整 //常量定义static const size_t npos -1;11.非成员函数重载Non-member function overloads
11.1.operator() string operator (const string lhs, const string rhs);string operator (const string lhs, const char* rhs);string operator (const char* lhs, const string rhs);string operator (const string lhs, char rhs);string operator (char lhs, const string rhs);的代价要比大因此非必要不要轻易使用这里就不演示的使用了您玩一下就行。
11.2.relational operators
一些比较运算符重载 //(1)bool operator (const string lhs, const string rhs);bool operator (const char* lhs, const string rhs);bool operator (const string lhs, const char* rhs);//(2) bool operator! (const string lhs, const string rhs);bool operator! (const char* lhs, const string rhs);bool operator! (const string lhs, const char* rhs);//(3) bool operator (const string lhs, const string rhs);bool operator (const char* lhs, const string rhs);bool operator (const string lhs, const char* rhs);//(4) bool operator (const string lhs, const string rhs);bool operator (const char* lhs, const string rhs);bool operator (const string lhs, const char* rhs);//(5) bool operator (const string lhs, const string rhs);bool operator (const char* lhs, const string rhs);bool operator (const string lhs, const char* rhs);//(6) bool operator (const string lhs, const string rhs);bool operator (const char* lhs, const string rhs);bool operator (const string lhs, const char* rhs);内部使用string::compare()函数来进行比较。
11.3.swap() //重载声明void swap (string str);全局交换函数内部调用了成员函数swap()这个重载是为了防止调用到低效的全局交换函数。
11.4.operator()和operator() istream operator (istream is, string str);ostream operator (ostream os, const string str);这个就是辅助string进行流插入和流输出的重载也是看下就行IO类的函数我们以后还会深入讲解。
11.5.getline() istream getline (istream is, string str, char delim);istream getline (istream is, string str);这个函数使用的频率也比较高主要是从流is中获取一行输入string对象直到遇到文件结束符EOF分隔符由于返回的是流is的引用因此可以重复读取。 //方式1string str1;cin str1;cout str1: str1 endl;//方式2string str2;getline(cin, str2);cout str2: str2 endl;//方式3string str3;getline(cin, str3, $);//遇到$就停止读取抛弃掉$不再进入后续的输入cout str3: str3 endl;方式1不可以输入带有空格的 方式2可以方式3可以指定结束符号。
12.string相关题目练习
12.1.字符串中的第一个唯一字符 class Solution{public:int firstUniqChar(string s){//1.开始计数生成计数表int arr[26] { 0 };//先定义一个数组存储每个字符的出现个数for (auto ch : s){arr[ch - a];//开始计数}//2.根据string对象和计数表寻找索引int i 0;for (i 0; i s.size(); i){if (arr[s[i] - a] 1){return i;}}return -1;}};12.2.将网址分割为协议、域名、资源名 int mian(){//1.输入网址urlstring url;//https-://baidu.com-/limou/file/textcin url;//2.寻找并且拆解urlstring protocol;//协议string domain;//域名string resource;//资源//2.1.寻找协议int index1 url.find(:);//5if (index1 string::npos){cout 没有协议退出程序 endl;exit(-1);}//2.2.寻找域名int index2 url.find(/, index1 3);//17if (index2 string::npos){index2 url.size();}//2.3.赋值三个对象protocol url.substr(0, index1);domain url.substr(index1 3, index2 - (index1 3));//17-5-3 12-3 9if (index2 ! url.size()){resource url.substr(index2 1);}//3.输出结果cout protocol protocol endl;if (domain.size() ! 0){cout domain domain endl;}else{cout 没有域名 endl;}if(resource.size() ! 0){ cout resource resource endl;}else{cout 没有资源 endl;}return 0;}12.3.仅仅反转字母 class Solution {public:bool IsLetter(const char ch){if ((ch a ch z)|| (ch A ch Z)){return true;}return false;}string reverseOnlyLetters(string str){auto begin 0;auto end str.size() - 1;while (begin end){while (!IsLetter(str[begin]) begin end){begin;}while (!IsLetter(str[end]) begin end){end--;}swap(str[begin], str[end]);begin;end--;}return str;}};12.4.字符串最后一个单词的长度 #include iostreamusing namespace std;int main(){//1.输入字符句子string str;getline(cin, str);//hello nowcode//2.逆向寻找size_t index str.rfind( );//得到5cout str.size() - index - 1 endl;//13-5 8 }但是这么做有些不严谨再严谨点就是下面代码 #include iostreamusing namespace std;int main(){//1.输入字符句子string str;getline(cin, str);//hello nowcode//2.逆向寻找size_t index str.rfind( );//得到5if (index ! string::npos){cout str.size() - index - 1 endl;//13-5 8 }else{cout str.size();}}12.5.验证回文串 class Solution{public:bool IsLetterAndNumber(const char ch)//判断是否为字符或者数字{return((ch a ch z)|| (ch A ch Z)|| (ch 0 ch 9));}bool IsOk(char x, char y)//判断是否构成回文的特征{if (x y){return true;}if ((x a x z) (y A y Z)){if (x - a A y){return true;}}else if ((y a x z) (x A x Z)){if (y - a A x){return true;}}return false;}bool isPalindrome(string str){//1.取得首尾索引//str A man, a plan, a canal: Panamaint begin 0;//s[begin] A int end str.size() - 1;//str[end] a//2.循环判断回文while (begin end){while (begin end !IsLetterAndNumber(str[begin])){begin;}while (begin end !IsLetterAndNumber(str[end])){end--;}if (!IsOk(str[begin], str[end]))//如果判断出是相同的就返回true{return false;}begin;end--;}return true;}};