从陌生到熟练使用string类

简介: 从陌生到熟练使用string类

一、构造函数

string库的学习:传送门


在库中我们可以看到,string类的构造函数是很丰富的.


重点掌握牛牛框起来的四个哦,其他的忘记了咱可以查文档.

6d9f0ecfd04844bfaf6641afd40494cc.png

构造函数使用演示:

void test1()
{
  //无参构造  string();
  string s1; 
  cout << "s1=  " << s1 << endl;
  //拷贝构造, string (const string& str);
  s1 += "HELLO CSDN!!!";//下面讲,这里是为了s1里面有数据,方便拷贝构造
  string s2(s1);
  cout << "s2=  " << s2 << endl;
  //用另一个string类的字串初始化 string (const string& str, size_t pos, size_t len = npos);
  string s3(s1, 6,4);
  cout << "s3=  " << s3 << endl;
  //使用字符串进行初始化  string (const char* s);
  string s4("CJN Rush Rush Rush");
  cout << "s4=  " << s4 << endl;
  //string(const char* s, size_t n);
  string s5("CJN Rush Rush Rush",7);//不常用
  cout << "s5=  " << s5 << endl;
  //string(size_t n, char c);
  string s6(5, 'X');//不常用
  cout << "s6=  " << s6 << endl;  
}

运行结果:

s1=
s2= HELLO CSDN!!!
s3= CSDN
s4= CJN Rush Rush Rush
s5= CJN Rus
s6= XXXXX

460f8b65039645ec9966f21a280bbd64.png

二、容量(capacity)相关的操作

我们看一下库中对capacity(容量)的相关操作有哪些.

71c39a63db374923a08fb6592b4d279f.png

(1)size()和length()

其实size()和length()并没有本质区别.

都是用于返回string中字符串的有效字符长度.

但是,由于string实现的比较早,当时设计的是length(),后来STL出来以后,为了统一,增加了size()接口.

  string s1;
  string s2("hello");
  //size和length并没有什么区别.
  cout << s1.size() << "  " << s1.length() << endl;
  cout << s2.size() << "  " << s2.length() << endl;
0 0
5 5

(2)resize()与reserve()

resize()用于改变字符串的有效字符长度.不够的地方用第二个参数填充.

  string s3("HELLO CSDN!!!");
  s3.resize(5);   //将字符串的有效字符长度改为5
  cout << s3 << endl;
  string s4("HELLO CSDN!!!");
  s4.resize(25,'x');  //将字符串的有效字符长度改为25,不够的地方用字符'x'填充
  cout << s4 << endl;

运行结果:

HELLO
HELLO CSDN!!!xxxxxxxxxxxx

resize()的改变会影响capacity(容量)吗?

  string s5("HELLO CSDN!!!");
  cout << "s5.capacity=" << s5.capacity() << endl;
  s5.resize(25, 'x');
  cout << "s5.capacity=" << s5.capacity() << endl;
  s5.resize(5, 'x');
  cout << "s5.capacity=" << s5.capacity() << endl;//并没有缩容

运行结果:

s5.capacity=15
s5.capacity=31
s5.capacity=31

当然,如果容量太小,不足以存储有效字符,必然是会扩容的!


扩容选择:(扩容方式是未定义的)

扩容是按有效字符长度扩容.

按之前容量的1.5倍扩容,更或者是2倍扩容.


reserve():请求改变容量的大小.

  string s6("HELLO CSDN!!!");
  cout << "s6.capacity=" << s6.capacity() << endl;
  s6.reserve(50);
  cout << "s6.capacity=" << s6.capacity() << endl;
  s6.reserve(30);
  cout << "s6.capacity=" << s6.capacity() << endl;//并没有缩容
  //一般都是不缩容的,缩容行为是未定义的.
  s6.clear();
  s6.reserve(0);
  cout << "s6.capacity=" << s6.capacity() << endl;//这里缩容了
s6.capacity=15
s6.capacity=63
s6.capacity=63
s6.capacity=15

是否缩容是未定义行为,取决于编译器,这里如果不清楚数据,直接将reserve(0),依旧不会缩容.

(3)clear()和empty()

  string s7;
  cout << s7.empty() << endl;
  s7 += "HELLO";
  cout << s7.empty() << endl;
  cout << "s7.size=" << s7.size() << endl;
  cout << "s7.capacity" << s7.capacity() << endl;
  s7.clear();
  cout << "s7.size=" << s7.size() << endl;
  cout << "s7.capacity" << s7.capacity() << endl;

运行结果:

1
0
s7.size=5
s7.capacity15
s7.size=0
s7.capacity15

显然clear只是清除有效字符,将字符清零,并不会影响capacity容量.


(4)小结:


1.size()和length()底层实现原理是一样的,都是返回有效的字符个数.只是为了STL的接口相统一.


2.resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。

 注意:resize在改变元素个数时.

 (1)如果是将元素个数增多,可能会改变底层容量的大小,不然存储不了那么多有效字符.

 (2)如果是将元素个数减少,底层空间总大小不变。


3.reserve((size_t res_arg=0))函数是请求改变string的容量.

 (1)当res_arg大于当前的容量的时候,会进行扩容.

 (1)当res_arg小于当前的容量的时候,一般不会缩容.


4.clear只是清除有效字符,将字符清零,并不会影响capacity容量.

三、访问与遍历

正向迭代器与反向迭代器:(这里对C++11的用法暂时不介绍)

4e873973f65c49638fdf7a1a98477083.png

下标访问符 方括号[ ]重载

baa91cfa7c3940fb8704c51848ce830e.png

例:

void test3()
{
  string s1("This is a little boy");
  string::iterator it = s1.begin(); //s1.begin()会返回有效字符串中第个元素的位置
  while (it != s1.end())        //s1.end()会返回有效字符串最后一个元素的位置的后一个位置
  {
    cout << *it ;
    it++;
  }
  cout << endl;
  string::reverse_iterator rit = s1.rbegin();//反向迭代器
  while (rit != s1.rend())        //s1.end()会返回有效字符串最后一个元素的位置的后一个位置
  {
    cout << *rit;
    rit++;
  }
  cout << endl;
  cout << "s1.begin=" << *(s1.begin()) << endl;
  cout << "s1.end=" << *(s1.end()-1) << endl;   //不可直接访问s1.end(),因为不是有效字符,而是最后一个有效字符的下一个位置.
  cout << "s1.rbegin=" << *(s1.rbegin()) << endl;
  cout << "s1.rend=" << *(s1.rend()-1) << endl; //这里为什么是+1而不是-1,留在后面的专门反向迭代器讲解
  //可以像数组一样用下标直接访问
  cout << s1[0] << endl;
  cout << s1[3] << endl;
  cout << s1[8] << endl;
}

四、增删改查

(1)追加字符/字符串(append)

06df7dcfaa5e48c7961b365598521d96.png

void test4()
{
  string s1("hello C");
  cout << "s1=" << s1 << endl;
  //尾插一个字符
  s1.push_back('S');
  s1.push_back('D');
  s1.push_back('N');
  cout << "s1=" << s1 << endl;
  cout << "----------------------------------" << endl;
  string s2("hello C");
  cout << "s2=" << s2 << endl;
  s2.append("SDN");   //追加字符串
  cout << "s2=" << s2 << endl;
  cout << "----------------------------------" << endl;
  string s3("hello C");
  cout << "s3=" << s3 << endl;
  s3 += "SDN";            //最喜欢使用这个,易读也简单
  cout << "s3=" << s3 << endl;
}

个人感想:

push_back一次插入一个字符太麻烦了,append虽然可以追加字符串,但是终究是没有+=来的香.


其它的以assign为例,一般用不到(因为实现的有些冗余,可以用别的函数代替),实在要用查库即可:

void test5()
{
  string str("This is a little boy");
  string s1,s2,s3;
  s1.assign(str);
  s2.assign(str, 8, string::npos);
  s3.assign(5, 'c');
  cout << "s1=" << s1 << endl;
  cout << "s2=" << s2 << endl;
  cout << "s3=" << s3 << endl;
}

运行结果:

s1=This is a little boy
s2=a little boy
s3=ccccc

(2)查找(find)/切割(substr)

be55ab8ad1674e82afdf50ea4bcdb195.png

c_str:为了与C语言兼容,返回C形式的常量字符串.

find:可以查找目标字符/字符串.

string substr (size_t pos = 0, size_t len = npos) const:从pos往后len个字符,返回这段被切割的字符串的副本.

void test6()
{
  string s1("This is a little boy");
  const char* arr = s1.c_str();   //返回C形式的常量字符串
  cout << "arr=" << arr << endl;
  string s2("This is a little boy");
  cout << s2.find('i') << endl;   //查找目标字符
  cout << s2.find("little") << endl;  //查找目标字符串
  string s3("321xxxxxxx@qq.com");
  int pos1 = s3.find('@');
  int pos2 = s3.find(".com");
  string s4, s5, s6;
  s4 = s3.substr(0, pos1-1);      //从0位置开始,往后pos-1个字符
  s5 = s3.substr(pos1, s3.size() - pos2 - 1);
  s6 = s3.substr(pos2);       //第二个参数为往后的字符个数,不写,默认为npos
  cout << "s4= " << s4 << endl;
  cout << "s5= " << s5 << endl;
  cout << "s6= " << s6 << endl;
}

运行结果:

arr=This is a little boy
2
10
s4= 321xxxxxx
s5= @qq
s6= .com

五、运算符重载

小知识点:

npos是-1,只不过类型是const size_t,所以是整数的最大值,通常表示字符串的结尾或无效位置。npos定义在std命名空间中,通常用于字符串的查找操作。

ea41f2ddc4aa4c36a1e40a206c84b224.png51f9b87ddf754f1c9c0e536590a08531.png

fbc8efaae2e24652a344bf73af6ffdf4.png

+运算符重载与getline()

void test7()
{
  string s1("HELLO ");
  string s2("CSDN");
  string s3;
  s3 = s1 + s2;   //因为是传值返回,所以效率不高,建议少用
  cout << s3 << endl;
  string name;
  cout << "Please, enter your full name: ";
  getline(cin, name);
  cout << "Hello, " << name << "!\n";
}

比较运算符这里就不一 一介绍了,字符串按ASCII码值进行比较.

926fcab1f40c47e6b1e418cbb5270634.png

string类的使用还是需要多多练习,可以试着写一下相关的oj题练一下手,后续会模拟实现string类,加深对string类的理解.


string相关习题1


今天就讲到这里了,我们下次模拟实现见.

ac39075238f34900afd649388645ab7e.gif


目录
相关文章
|
2月前
|
编解码 Java 开发者
Java String类的关键方法总结
以上总结了Java `String` 类最常见和重要功能性方法。每种操作都对应着日常编程任务,并且理解每种操作如何影响及处理 `Strings` 对于任何使用 Java 的开发者来说都至关重要。
316 5
|
6月前
|
存储 编译器 C语言
关于string的‘\0‘与string,vector构造特点,反迭代器与迭代器类等的讨论
你真的了解string的'\0'么?你知道创建一个string a("abcddddddddddddddddddddddddd", 16);这样的string对象要创建多少个对象么?你知道string与vector进行扩容时进行了怎么的操作么?你知道怎么求Vector 最大 最小值 索引 位置么?
176 0
|
Java 索引
java基础(13)String类
本文介绍了Java中String类的多种操作方法,包括字符串拼接、获取长度、去除空格、替换、截取、分割、比较和查找字符等。
180 0
java基础(13)String类
|
9月前
|
缓存 安全 Java
《从头开始学java,一天一个知识点》之:字符串处理:String类的核心API
🌱 **《字符串处理:String类的核心API》一分钟速通!** 本文快速介绍Java中String类的3个高频API:`substring`、`indexOf`和`split`,并通过代码示例展示其用法。重点提示:`substring`的结束索引不包含该位置,`split`支持正则表达式。进一步探讨了String不可变性的高效设计原理及企业级编码规范,如避免使用`new String()`、拼接时使用`StringBuilder`等。最后通过互动解密游戏帮助读者巩固知识。 (上一篇:《多维数组与常见操作》 | 下一篇预告:《输入与输出:Scanner与System类》)
267 11
|
9月前
|
Java
课时14:Java数据类型划分(初见String类)
课时14介绍Java数据类型,重点初见String类。通过三个范例讲解:观察String型变量、&quot;+&quot;操作符的使用问题及转义字符的应用。String不是基本数据类型而是引用类型,但使用方式类似基本类型。课程涵盖字符串连接、数学运算与字符串混合使用时的注意事项以及常用转义字符的用法。
283 9
|
9月前
|
存储 JavaScript Java
课时44:String类对象两种实例化方式比较
本次课程的主要讨论了两种处理模式在Java程序中的应用,直接赋值和构造方法实例化。此外,还讨论了字符串池的概念,指出在Java程序的底层,DOM提供了专门的字符串池,用于存储和查找字符串。 1.直接赋值的对象化模式 2.字符串池的概念 3.构造方法实例化
185 1
|
Java
【编程基础知识】(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性
本文深入探讨了Java中方法参数的传递机制,包括值传递和引用传递的区别,以及String类对象的不可变性。通过详细讲解和示例代码,帮助读者理解参数传递的内部原理,并掌握在实际编程中正确处理参数传递的方法。关键词:Java, 方法参数传递, 值传递, 引用传递, String不可变性。
291 1
【编程基础知识】(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
459 2
String类-知识回顾①
这篇文章回顾了Java中String类的相关知识点,包括`==`操作符和`equals()`方法的区别、String类对象的不可变性及其好处、String常量池的概念,以及String对象的加法操作。文章通过代码示例详细解释了这些概念,并探讨了使用String常量池时的一些行为。
String类-知识回顾①
|
安全 Java 测试技术
Java零基础-StringBuffer 类详解
【10月更文挑战第9天】Java零基础教学篇,手把手实践教学!
400 2