string类的函数讲解

简介: string类的函数讲解

标准库中的string类

首先关于string类的了解,我先给出官方的string类的讲解,以便于大家的学习:链接: http://www.cplusplus.com/reference/string/string/?kw=string

这个网站是C++官方网站,里面对于各个关键字和库函数的讲解都是很官方的,大家有需要的时候可以参考

我们对string类进行一个简单的总结:

  1. string是表示字符串的字符串类
  2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
  3. string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator> string;
  4. 不能操作多字节或者变长字符的序列。

这里有一个需要注意的点:

在使用string类时,必须包含#include头文件以及using namespace std;

下面我们就对string类的一些常用的接口进行讲解:

string类的常用接口说明
string类对象的常见构造

首先我们看看创建一个空的string类,就是一个空的字符串:

#include<iostream>
using namespace std;
int main()
{
  string s1;
  cout << s1 << endl;
  return 0;
}

输出为空:

构造string类对象:

#include<iostream>
using namespace std;
int main()
{
  string s1("hello world");
  cout << s1 << endl;
  return 0;
}

拷贝构造:

#include<iostream>
using namespace std;
int main()
{
  string s1("hello world");
  cout << s1 << endl;
  string s2(s1);
  cout << s2 << endl;
  return 0;
}

将n个字符放入一个string类中:

#include<iostream>
using namespace std;
int main()
{
  string s1(5,'a');
  cout << s1 << endl;
  return 0;
}

去一个string类中的字符存入另一个string类:

例如,将s1中第六个字符开始往后取三个字符放入s2

这里注意:

如果这里的要取字符的数量大于字符串的字符个数的话,能取多少取多少

#include<iostream>
using namespace std;
int main()
{
  string s1("hello world");
  cout << s1 << endl;
  string s2(s1, 6, 3);
  cout << s2 << endl;
  return 0;
}

string类对象的容量操作

我们这里的size和lenth的作用是一样的,只是在后期的语言发展中为了适应需要,例如,如果是一个二叉树,用lenth合适吗,所以就引出了size

注意,这里计算出来的是有效字符个数,也就是说不包括’\0’

用法如下:

#include<iostream>
using namespace std;
int main()
{
  string s1("hello world");
  cout << s1.length() << endl;
  cout << s1.size() << endl;
  return 0;
}

capacity是返回空间的大小:

至于容量为什么是15,这就是底层实现的原因了,一些编译器是基于1.5倍的扩容,比如我们的vscode,而linux的终端里是以2倍的扩容,其实不必太过于纠结这一点,我们只需要了解到这一点即可

但是各自的容量起点也不一样!

#include<iostream>
using namespace std;
int main()
{
  string s1("hello world");
  cout << s1.capacity() << endl;
  return 0;
}

empty函数的用法很简单:

例如,不为空返回0

#include<iostream>
using namespace std;
int main()
{
  string s1("hello world");
  cout << s1.capacity() << endl;
  cout << s1.empty() << endl;
  return 0;
}

clear的作用就是清空字符串:

清理之后输出空行,字符串被清空

#include<iostream>
using namespace std;
int main()
{
  string s1("hello world");
  cout << s1 << endl;
  s1.clear();
  cout << s1 << endl;
  return 0;
}

这里有一个重点内容:

reserve和resize的区别

其实二者都是用来提前开空间的,因为扩容会影响程序的效率

例如:

可以看到二者都成功地开辟了空间

并且使用resize时还可以填充多余的空间:

但其实这不是重点,重点在于:

这是resize:

#include<iostream>
using namespace std;
int main()
{
  string s1("hello world");
  cout << s1.capacity() << endl;
  cout << s1.size() << endl;
  s1.resize(30);
  cout << s1.capacity() << endl;
  cout << s1.size() << endl;
  return 0;
}

这是reserve:

#include<iostream>
using namespace std;
int main()
{
  string s1("hello world");
  cout << s1.capacity() << endl;
  cout << s1.size() << endl;
  s1.reserve(30);
  cout << s1.capacity() << endl;
  cout << s1.size() << endl;
  return 0;
}

大家可以发现:

用reserve来提前开辟空间,capacity改变,size不变,而用resize则是capacity和size都会发生改变!

下面给大家一个小的总结:

注意:

  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_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于
    string的底层空间总大小时,reserver不会改变容量大小。
string类对象的访问及遍历操作

operator[],就是返回该位置的字符,其实就是用于循环:

但是要注意一点,如果访问越界,就会直接报错,导致程序终止
并且该函数一般只适用于数组结构

#include<iostream>
using namespace std;
int main()
{
  string const s1("hello world");
  for (int i = 0; i < s1.length(); i++)
  {
    cout << s1[i];
  }
  cout << endl;
  return 0;
}

迭代器:

迭代器有两种,还有一个叫做反向迭代器,就是从尾部开始遍历

在这里我们暂且把begin认为是指针来理解

我们使用正向的迭代器的时候要引出string类里面的iterator

begin就默认是从零开始输出记得用解引用,指针向后移动

我们给出一张对比图:

#include<iostream>
using namespace std;
int main()
{
  string s1("hello world");
  for (string::iterator i = s1.begin(); i != s1.end(); i++)
  {
    cout << *i;
  }
  return 0;
}

而反向迭代器就是从后开始往前移动:

这里要引出的是 reverse_iterator 其实这里的rbegin已经不在字符串的第一个位置了二者是有区别的,并且,这里的指针也是++,不然怎么会叫做反向迭代器呢?

#include<iostream>
using namespace std;
int main()
{
  string s1("hello world");
  for (string::reverse_iterator i = s1.rbegin(); i != s1.rend(); i++)
  {
    cout << *i;
  }
  return 0;
}

另外大家记住一个点:

for循环的底层实现就是迭代器!

string类对象的修改操作

尾插字符:

尾插很简单

#include<iostream>
using namespace std;
int main()
{
  string s1("hello world");
  s1.push_back('!');
  cout << s1 << endl;
  return 0;
}

追加字符串:

相比较push_back,append只能追加字符串,而前者只能追加字符

#include<iostream>
using namespace std;
int main()
{
  string s1("hello world");
  s1.append(" hhhh!");
  cout << s1 << endl;
  return 0;
}

但是operator+=能够把上面两个函数一起实现,并且函数的可读性更高,所以我们一般选择使用+=来实现对对象的追加:

#include<iostream>
using namespace std;
int main()
{
  string s1("hello world");
  s1+=(" hhhh!");
  cout << s1 << endl;
  s1 += ('x');
  cout << s1 << endl;
  return 0;
}

返回C字符串:

#include<iostream>
using namespace std;
int main()
{
  string s1("hello world");
  cout << s1.c_str() << endl;
  return 0;
}

返回字符串中的位置:

返回位置既可以从前往后找又可以从后往前找

find是从前往后,rfind是从后往前,npos是字符串的长度

如果找不到的话这里的npos是-1

但是find函数返回的是无符号整形,所以-1进行了转换

截取字符:

从pos位置开始往后截取n个字符

如果n大于length-pos,能截取多少就截取多少

#include<iostream>
using namespace std;
int main()
{
  string s1("hello world");
  cout << s1.substr(3, 4) << endl;
  cout << s1.substr(3, 12) << endl;
}

下面我们对于string类的修改操作做一个小总结:

  1. 在string尾部追加字符时,s.push_back© / s.append(1, c) / s += 'c’三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。
  2. 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。
string类非成员函数

其实这里用的不多,不做过多的讲解

但是这个getline函数是可以用到一些题目中来读取字符串的,他遇到换行符就会停止读取,遇到空格不会:

int main()
{
  std::string name;
  std::cout << "Please, enter your full name: ";
  std::getline(std::cin, name);
  std::cout << "Hello, " << name << "!\n";
  return 0;
}

好了,今天的分享到这里就结束了,谢谢大家的支持!

相关文章
|
3月前
|
Java 索引
java基础(13)String类
本文介绍了Java中String类的多种操作方法,包括字符串拼接、获取长度、去除空格、替换、截取、分割、比较和查找字符等。
40 0
java基础(13)String类
|
2月前
|
Java
【编程基础知识】(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性
本文深入探讨了Java中方法参数的传递机制,包括值传递和引用传递的区别,以及String类对象的不可变性。通过详细讲解和示例代码,帮助读者理解参数传递的内部原理,并掌握在实际编程中正确处理参数传递的方法。关键词:Java, 方法参数传递, 值传递, 引用传递, String不可变性。
62 1
【编程基础知识】(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性
|
2月前
|
安全 Java 测试技术
Java零基础-StringBuffer 类详解
【10月更文挑战第9天】Java零基础教学篇,手把手实践教学!
38 2
|
3月前
|
安全 Java
String类-知识回顾①
这篇文章回顾了Java中String类的相关知识点,包括`==`操作符和`equals()`方法的区别、String类对象的不可变性及其好处、String常量池的概念,以及String对象的加法操作。文章通过代码示例详细解释了这些概念,并探讨了使用String常量池时的一些行为。
String类-知识回顾①
|
2月前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
23 1
|
2月前
|
数据可视化 Java
让星星月亮告诉你,通过反射创建类的实例对象,并通过Unsafe theUnsafe来修改实例对象的私有的String类型的成员属性的值
本文介绍了如何使用 Unsafe 类通过反射机制修改对象的私有属性值。主要包括: 1. 获取 Unsafe 的 theUnsafe 属性:通过反射获取 Unsafe类的私有静态属性theUnsafe,并放开其访问权限,以便后续操作 2. 利用反射创建 User 类的实例对象:通过反射创建User类的实例对象,并定义预期值 3. 利用反射获取实例对象的name属性并修改:通过反射获取 User类实例对象的私有属性name,使用 Unsafe`的compareAndSwapObject方法直接在内存地址上修改属性值 核心代码展示了详细的步骤和逻辑,确保了对私有属性的修改不受 JVM 访问权限的限制
57 4
|
2月前
|
存储 安全 Java
【一步一步了解Java系列】:认识String类
【一步一步了解Java系列】:认识String类
28 2
|
2月前
|
安全 C语言 C++
【C++篇】探寻C++ STL之美:从string类的基础到高级操作的全面解析
【C++篇】探寻C++ STL之美:从string类的基础到高级操作的全面解析
38 4
|
2月前
|
存储 编译器 程序员
【C++篇】手撕 C++ string 类:从零实现到深入剖析的模拟之路
【C++篇】手撕 C++ string 类:从零实现到深入剖析的模拟之路
71 2
|
3月前
|
存储 安全 Java
Java——String类详解
String 是 Java 中的一个类,用于表示字符串,属于引用数据类型。字符串可以通过多种方式定义,如直接赋值、创建对象、传入 char 或 byte 类型数组。直接赋值会将字符串存储在串池中,复用相同的字符串以节省内存。String 类提供了丰富的方法,如比较(equals() 和 compareTo())、查找(charAt() 和 indexOf())、转换(valueOf() 和 format())、拆分(split())和截取(substring())。此外,还介绍了 StringBuilder 和 StringJoiner 类,前者用于高效拼接字符串,后者用于按指定格式拼接字符串
65 1
Java——String类详解