当前位置:   article > 正文

C++ string用法详解_string c++ 用法

string c++ 用法

目录

一.为什么要学习string类

1.1 C语言中的字符串

二. string类的常用操作

2.1 string类的初始化

2.2 string类常用的容量操作

2.2.1 size()

 2.2.2 length() 函数

2.2.3   capacity() 函数

2.2.4    empty()函数

 2.2.5 resize()函数和reserve()函数

 2.2.5 clear() 函数

2.3 string类对象的访问及遍历操作函数

2.3.1 []  (operator[])

 2.3.2 begin() 和 end()

  2.3.3 rbegin() 和 rend()

 2.3.4 范围for

 2.4. string类对象的修改操作

2.4.1 push_back() 函数

 2.4.2  append() 函数

  2.4.3 +=(operator+=)

 2.4.4 c_str

 2.4.5 find() + npos

  2.4.6 rfind()

 2.4.7 substr()

 2.5  常用string类非成员函数

2.5.1 operator+

2.5.2  >>和<<

2.5.3 getline

 2.5.4 relational operators()


一.为什么要学习string类

1.1 C语言中的字符串

   在C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。

  为了弥补这些C语言中的部分设计缺陷,C++研发出了string类,更好的服务于程序员。

重点:

在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本都使用string类,很少有人去使用C库中的字符串操作函数。为了找到好Offer,熟练掌握string类是我们C艹程序员的必要工作。

二. string类的常用操作

  string类的文档链接:https://cplusplus.com/reference/string/string/

  同时,使用string类大多数情况还需要头文件#include<string>

2.1 string类的初始化

  string对象的初始化和普通类型变量的初始化基本相同,只是string作为类,还有类的一些特性:使用构造函数初始化。

  String类的常用初始化

函数名称(红色为重点)功能说明
string   s() 构造空的string类对象,即空字符串
string   s(const char* s) 用C-string来构造string类对象
string   s(size_t n, char c)string类对象中包含n个字符c
string   s(const string&s) 拷贝构造函数

如:

  1. //常用构造函数
  2. #include<iostream>
  3. //用string类的话需要包含头文件#include<string>
  4. using namespace std;
  5. int main()
  6. {
  7. string s1;
  8. string s2("abcdefg");
  9. string s3(99, 'a');
  10. string s4(s2);
  11. cout << s2 << endl;
  12. cout << s3 << endl;
  13. cout << s4 << endl;
  14. return 0;
  15. }

代码结果为:

2.2 string类常用的容量操作

函数名称(红色为重点)功能说明
size()返回字符串有效字符长度,(有效空间)
length()返回字符串有效字符长度,(有效空间)
capacity()返回空间总大小
empty()检测字符串释放为空串,是返回true,否则返回false
clear()清空有效字符
reserve(size_t n=0)为字符串预留空间
resize(size_t n,char c)将有效字符的个数该成n个,多出的空间用字符c填充

如:

2.2.1 size()

 

  1. //容量操作
  2. #include<iostream>
  3. using namespace std;
  4. // size()函数
  5. int main()
  6. {
  7. string s1(99, 'a');
  8. cout << s1.size() << endl;
  9. return 0;
  10. }

代码结果为:

 

 2.2.2 length() 函数

  1. //容量操作
  2. #include<iostream>
  3. using namespace std;
  4. //length()函数
  5. int main()
  6. {
  7. string s1(99, 'a');
  8. cout << s1.length() << endl;
  9. return 0;
  10. }

代码结果为:

 注意:
 size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。(这个属于C++的早期设计缺陷)

2.2.3   capacity() 函数

  1. //容量操作
  2. #include<iostream>
  3. using namespace std;
  4. //capacity()函数
  5. int main()
  6. {
  7. string s1(10,'a');
  8. cout << s1.capacity() << endl;
  9. return 0;
  10. }

代码结果为:

 根据vs 开辟空间的规则,创建string类时初始分配十五个字节的总空间,但实际上这里的有效空间为10。

我们可以用size求出s1的有效空间    如:

  1. #include<iostream>
  2. using namespace std;
  3. //capacity()函数
  4. int main()
  5. {
  6. string s1(10,'a');
  7. cout << s1.capacity() << endl;
  8. cout << s1.size() << endl;`
  9. return 0;
  10. }

 

2.2.4    empty()函数

  1. //容量操作
  2. #include<iostream>
  3. using namespace std;
  4. // empty()函数
  5. int main()
  6. {
  7. string s1;
  8. string s2("12345");
  9. cout << s1.empty() << endl;
  10. cout << s2.empty() << endl;
  11. return 0;
  12. }

代码结果为:

 2.2.5 resize()函数和reserve()函数

一.resize() 重新规划string的大小,但是注意,这里实际上规划的是有效空间的大小。

通过前边的知识,我们可以用size()求出有效空间的大小,用resize进行重新规划。

如:

  1. //容量操作
  2. #include<iostream>
  3. using namespace std;
  4. //resize()函数和reserve()函数
  5. int main()
  6. {
  7. string s1("Hello World");
  8. cout << s1.size() << endl;
  9. cout << s1.capacity() << endl;
  10. s1.resize(5);//通过resize把有效空间改为5
  11. cout << s1.size() << endl;
  12. cout << s1.capacity() << endl;
  13. cout << s1 << endl;
  14. return 0;
  15. }

输出结果为:

这时候就分两种情况

1.缩小有效空间:

  这种情况下,容器中长度在n之外的部分会被截取掉,只保留n长度内的元素,但是容器的容量却没有改变,更不会出现扩容的状况,上段代码体现了这一点。

2.扩大有效空间:

  这种情况下,容器为了能够放的下更多的元素,会发生扩容,扩容之后,其容量会比原来大,这时候就会出现没有用过的有效空间,此时我们通过函数的第二个元素 c 进行剩余空间的初始化。

  也就是说,当扩容时,扩容的空间内存放的元素全都是第二个元素 C。如果没有指定第二个元素c,那就用string的默认初始化了,这种情况下,容器一定是分配了内存并全部发生了初始化的。

如:

  1. //容量操作
  2. #include<iostream>
  3. using namespace std;
  4. int main()
  5. {
  6. string s1("Hello World");
  7. cout << s1 << endl;
  8. cout << s1.size() << endl;
  9. cout << s1.capacity() << endl;
  10. s1.resize(20, 'x');
  11. cout << s1 << endl;
  12. cout << s1.size() << endl;
  13. cout << s1.capacity() << endl;
  14. return 0;
  15. }

代码结果为:

 注意:有效空间的变化可能会影响最大空间的变化,最大空间的变化也可能影响有效空间的变化。

二.reserve() 函数改变最大空间。
 

  1. 容量操作
  2. #include<iostream>
  3. using namespace std;
  4. int main()
  5. {
  6. string s1("Hello World");
  7. cout << s1.capacity() << endl;
  8. s1.reserve(20);
  9. cout << s1.capacity() << endl;
  10. return 0;
  11. }

 代码结果为:

 注意:这里代码结果不同预想也是因为VS 的容量规则

 2.2.5 clear() 函数

  1. 容量操作
  2. #include<iostream>
  3. using namespace std;
  4. int main()
  5. {
  6. string s1("Hello World");
  7. cout << s1.size() << endl;
  8. s1.clear();
  9. cout << s1.size() << endl;
  10. cout << s1.capacity() << endl;
  11. return 0;
  12. }

代码结果为:

注意:clear()只是将string中有效字符清空,不改变底层空间大小。

2.3 string类对象的访问及遍历操作函数

函数名称  (重点为红色)功能说明
[]  (operator[])返回pos位置的字符,const string类对象调用
begin()获取第一个字符位置的迭代器
end()获取最后一个字符下一个位置的迭代器
rbegin()获取最后一个元素的反向迭代器
rend()获取第一个位置之前一个位置的反向迭代器
范围forC++11支持更简洁的范围for的新遍历方式

2.3.1 []  (operator[])

实际上就是数组的[],可以随机访问元素,底层是操作符重载(不讲)。

  1. //string类对象的访问及遍历操作函数
  2. #include<iostream>
  3. using namespace std;
  4. // []
  5. int main()
  6. {
  7. string s1("abcde");
  8. cout << s1[0] << endl;
  9. cout << s1[s1.size()-1] << endl;
  10. cout << s1[2] << endl;
  11. return 0;
  12. }

代码结果为:

 2.3.2 begin() 和 end()

  1. //string类对象的访问及遍历操作函数
  2. #include<iostream>
  3. using namespace std;
  4. //begin()和end()
  5. int main()
  6. {
  7. string s1("12345");
  8. string::iterator it = s1.begin();
  9. while (it != s1.end())
  10. {
  11. cout << *it << endl;
  12. it++;
  13. }
  14. return 0;
  15. }

代码结果为:

 两图解迭代器原理(狗头保命):

 

 

 

 C++中,迭代器就是一个类似于指针的对象,它能够用来遍历C++标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。

  但在string中,我们最常用的还是数组的下标访问,故不在多描述。

  2.3.3 rbegin() 和 rend()

  1. //string类对象的访问及遍历操作函数
  2. #include<iostream>
  3. using namespace std;
  4. //rbegin()和rend()
  5. int main()
  6. {
  7. string s1("12345");
  8. string::reverse_iterator it = s1.rbegin();
  9. while (it != s1.rend())
  10. {
  11. cout << *it << endl;
  12. it++;
  13. }
  14. return 0;
  15. }

结果为:

 2.3.4 范围for

  1. //string类对象的访问及遍历操作函数
  2. #include<iostream>
  3. using namespace std;
  4. //for(auto )
  5. int main()
  6. {
  7. string s1("12345");
  8. for (auto it : s1)
  9. {
  10. cout << it << endl;
  11. }
  12. return 0;
  13. }

代码结果为:

 是不是看起来很高端:

一图解范围for:

 2.4. string类对象的修改操作

函数名称功能说明
push_back(c)在字符串后尾插字符c
append(s)在字符串后追加一个字符串
+=(operator+= )在字符串后追加字符串str
c_str返回C格式字符串
find + npos从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
rfind从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
substr在str中从pos位置开始,截取n个字符,然后将其返回

2.4.1 push_back() 函数

类似于链表的尾插

  1. //string类对象的访问及遍历操作函数
  2. #include<iostream>
  3. using namespace std;
  4. int main()
  5. {
  6. string s1("Hello ");
  7. cout << s1 << endl;
  8. s1.push_back('W');
  9. s1.push_back('o');
  10. s1.push_back('r');
  11. s1.push_back('l');
  12. s1.push_back('d');
  13. cout << s1 << endl;
  14. return 0;
  15. }

结果为:

 2.4.2  append() 函数

也类似于链表的尾插,但是插入的是一个字符串。

  1. //string类对象的访问及遍历操作函数
  2. #include<iostream>
  3. using namespace std;
  4. int main()
  5. {
  6. string s1("Hello ");
  7. cout << s1 << endl;
  8. s1.append("World");
  9. cout << s1 << endl;
  10. return 0;
  11. }

结果为:

  2.4.3 +=(operator+=)

本质上是一个符号重载,依旧类似于链表的尾插。

  1. //string类对象的访问及遍历操作函数
  2. #include<iostream>
  3. using namespace std;
  4. int main()
  5. {
  6. string s1("Hello ");
  7. cout << s1 << endl;
  8. s1 += "World";
  9. cout << s1 << endl;
  10. return 0;
  11. }

结果为:

注意:
 在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。 

 2.4.4 c_str

  在C语言中,字符串是以'\0'结尾的一些字符的集合。但在C++中,string类不以'\0'结尾,而是根据有效空间的大小结束。

  这个函数的本质作用是:将 const string* 类型 转化为 const char* 类型

 2.4.5 find() + npos

find有很多函数重载,我们只学一种就好了。

     size_t find  (const string &s,int pos=0);

s是需要查找的字符串,pos是从哪个位置查找 , 如果未查找到则返回npos(size_t 的最大值)。

如:

  1. //string类对象的访问及遍历操作函数
  2. #include<iostream>
  3. using namespace std;
  4. int main()
  5. {
  6. string s1("fghasdabc");
  7. cout << s1.find('a') << endl;
  8. string s2("abc");
  9. cout << s1.find(s2) << endl;
  10. cout << s1.find('e') << endl;
  11. return 0;
  12. }

代码结果为:

  2.4.6 rfind()

同样,rfind()和find()只有一个往前找,一个像后找的区别:

size_t find  (const string &s,int pos=npos);

 

  1. //string类对象的访问及遍历操作函数
  2. #include<iostream>
  3. using namespace std;
  4. int main()
  5. {
  6. string s1("fghasdabc");
  7. cout << s1.rfind('a') << endl;
  8. string s2("abc");
  9. cout << s1.rfind(s2) << endl;
  10. cout << s1.rfind('e') << endl;
  11. return 0;
  12. }

 此时 第一个打印结果就会发生变化:

 2.4.7 substr()

函数定义为: string substr(size_t pos=0,size_t len=npos) const;

作用为:在string的pos位置截取n个字符,然后返回

  1. //string类对象的访问及遍历操作函数
  2. #include<iostream>
  3. using namespace std;
  4. int main()
  5. {
  6. string s1("Hello World");
  7. cout << s1 << endl;
  8. string s2(s1.substr(0, 5));
  9. cout << s1 << endl;
  10. cout << s2 << endl;
  11. return 0;
  12. }

结果为:

 2.5  常用string类非成员函数

函数名字 (红色为重点)作用说明
operator+尽量少用,因为传值返回,导致深拷贝效率低
operator>> 输入运算符重载
operator<< 输出运算符重载
getline 获取一行字符串
relational operators字符串大小比较

2.5.1 operator+

这个大家根据  + 和 +=的特性 ,再结合类的知识点,自己推一下为什么效率低(绝对不是因为我懒!!!)。

2.5.2  >>和<<

  重载输入输出。

2.5.3 getline

函数定义为:

istream& getline (istream & is,string& str);

注意:
cin输入会自动吃点前置换行和空格,即cin输入得到的不可能是空串。而getline不会吃掉换行符号和空格,可能会使得输入出现意料之外的错误。

比如说:

  1. #include<iostream>
  2. #include<string>//需要头文件
  3. using namespace std;
  4. int main()
  5. {
  6. string s1;//输入个Hello World 看看
  7. cin >> s1;
  8. cout <<endl<< s1 << endl;
  9. //string s2;
  10. //getline(cin, s2);
  11. //cout << endl << s2 << endl;
  12. return 0;
  13. }

代码结果为:

 可见,cin遇见空格就结束了,可能会使得输入出现意料之外的错误。

正确的做法是使用getline();

  1. //string类对象的访问及遍历操作函数
  2. #include<iostream>
  3. #include<string>//需要头文件
  4. using namespace std;
  5. int main()
  6. {
  7. //string s1;//输入个Hello World 看看
  8. //cin >> s1;
  9. //cout <<endl<< s1 << endl;
  10. string s2;
  11. getline(cin, s2);
  12. cout << endl << s2 << endl;
  13. return 0;
  14. }

 2.5.4 relational operators()

 

 就是符号重载了关系运算符;

使得>=,<=等运算符可以用于字符串比较

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/490482
推荐阅读
相关标签
  

闽ICP备14008679号