C++ —— STL容器——string类

1. 前言

本篇博客将会介绍 string 中的一些常用的函数,在使用 string 中的函数时,需要加上头文件 string

2. string 中的常见成员函数

2.1 初始化函数

string 类中的常用的初始化函数有以下几种:

  1. string() 作用:用空字符串初始化string类对象

  2. string(const char* s) 作用:以s为指向的以空结尾的字符串初始化string类对象

  3. string(size_t n, char c) 作用:用n个字符c初始化string类对象

  4. string(const string&s) 作用:拷贝构造函数,用一个string类对象去初始化另一个新传建的对象

下面就来使用这些函数:

cpp 复制代码
string str1;                  // 对应函数1
string str2("hello world");   // 对应函数2
string str3(10, '$');         // 对应函数3
string str4(str3);            // 对应函数4

cout << "str1 = " << str1 << endl;
cout << "str2 = " << str2 << endl;
cout << "str3 = " << str3 << endl;
cout << "str4 = " << str4 << endl;

运行结果:



接下来介绍 string 类中一个十分重要的成员变量 ------ npos,npos 是 string 类中的一个静态成员变量 ------ static const size_t npos = -1 。它表示的是整型的最大值,因为它是 size_t 类型的。

2.2 operator = 函数

operator = 函数的原型为:

string& operator= (const string& str) ------ 作用: 用对象 str 中的数据替换调用该函数的对象中的数据

string& operator= (const char* s) ------ 作用: 用字符串 s 替换掉调用该函数的对象中的数据

下面就来使用这两个函数:

cpp 复制代码
string str1("hello cplusplus");
string str2 = str1;
string str3 = "hello world";

cout << "str2 = " << str2 << endl;
cout << "str3 = " << str3 << endl;

运行结果:



2.3 size 和 length 函数

既然是字符串,就免不了要求字符串的长度,那么在 string 中是否存在着能求取字符串长度的函数呢?当然有,而且还有两个。

size 函数和 length 函数的函数原型分别为:

size_t size() const; 作用:返回字符串有效字符长度

size_t length() const; 作用:返回字符串有效字符长度

这两个函数的计算结果均不包括字符 '\0' ,下面就来使用这两个函数:

cpp 复制代码
string str1("hello world");
cout << "size = " << str1.size() << endl;
cout << "length = " << str1.length() << endl;

运行结果:



既然这两个函数都可以求取字符串的长度大小,那么在实际的使用过程中使用哪个函数呢?其实都可以,根据容器的不同去使用更好的,当然也可以直接使用通用的 ------ size 函数。在后续的其它STL容器的学习中,求容器的数据个数一般使用 size 函数。

2.4 operator[ ] 函数

在 string 类用多种可以访问对象中的数据的方法,其中一种就是通过重载下标引用操作符(即 [ ] )来访问,不仅可以访问数据,还可以修改数据。该函数的函数原型为:

char& operator[ ] (size_t pos)

const char& operator[ ] (size_t pos) const

一个普通函数,一个是 const 函数,普通对象调用普通的重载函数,const修饰对象调用const的重载函数。

下面就来使用这个函数:

cpp 复制代码
string str("hello world");
// 访问
for (size_t i = 0; i < str.size(); i++)
{
	cout << str[i] << " ";
}
cout << endl;
// 修改
for (size_t i = 0; i < str.size(); i++)
{
	str[i] += 1;
	cout << str[i] << " ";
}
cout << endl;

运行结果:



在数组中若越界访问了,编译器可能会报错也可能不会报错;但是在sting类中的[ ],若访问字符串数组时,下标越界了,则会报错。这是因为在 string 类中下标引用操作符被重载了,重载的函数中加上了关于下标大小的断言操作。下面以具体的例子来理解这二者的区别:



2.5 迭代器相关的函数

除了上述的方法可以访问和修改容器中的数据之外,还有一种方法就是使用迭代器。迭代器是什么?迭代器的名字是:iterator,它是容器中的一个类型,在使用它的时候要指明容器类域;也可以将它想象成像指针一样的类型对象。使用迭代器时,需要获取区间范围,这种区间都是左闭右开(右区间 - 左区间 就是当前字符串的长度)的,以便知道迭代器从哪里开始迭代,从哪里结束迭代。这就需要用到迭代器相关函数了。此外迭代器可以分成很多种类,不同种类的迭代器的获取迭代区间的函数有所不同。迭代器可以分为正向迭代器和反向迭代器,而这两种迭代器又可以分为普通迭代器和 const 迭代器。

接下来就来一一介绍和使用这几种迭代器:

  1. 正向迭代器 ------ 普通迭代器

获取迭代区间的函数:begin 函数和 end 函数,这两个函数的原型分别为:

begin ------ iterator begin() const_iterator begin() const

end ------ iterator end() const_iterator end() const

普通迭代器使用的都是未被 const 修饰的函数,那么这两个函数的作用分别是什么呢?

begin ------ 作用:返回指向字符串的第一个字符迭代器

end ------ 作用:返回指向容器末尾(最后一个元素之后,即'\0')的迭代器

普通的迭代器不仅可以访问容器中的数据,还可以修改容器中的数据。下面就来使用该迭代器:

cpp 复制代码
string str("hello cplusplus");
string::iterator it1 = str.begin(); 	//指明类域
// 访问
while (it1 != str.end())
{
	cout << *it1 << " ";
	// 向后迭代
	it1++;
}
cout << endl;
// 修改
it1 = str.begin();
while (it1 != str.end())
{
    // 修改 ------ 让每个字符都加1
	(*it1)++;
	cout << *it1 << " ";
    // 向后迭代
	it1++;
}
cout << endl;

运行结果:



  1. 正向迭代器 ------ const 迭代器

由于 begin 函数和 end 函数均有 const 修饰的函数的原型,所以在获取迭代器的区间范围时,也可以使用 begin 和 end 函数。但是在 C++11 中,为了区分这是在使用 const 迭代器,引入两个新的函数 cbegin 和 cend 函数,它们两个函数的原型分别为:

cbegin ------ const_iterator cbegin() const noexcept

cend ------ const_iterator cend() const noexcept

不必考虑这里的 nonexcept 是什么意思,有什么作用。cbegin 和 cend 函数的作用与 begin 和 end 函数的作用一致。需要注意的是 const 迭代器并不是直接在 iterator 的 前面加上 const ,如:const iterator ,而是 const_iterator 。const iterator 中 const 修饰的是迭代器本身,表示迭代器本身不能修改,也就说明迭代器不能迭代,这在实践中根本没法使用;const_iterator 表示迭代器指向的数据的内容不能被修改,可以做到迭代的功能。const 迭代器只能访问容器中的数据,不可以修改容器中的数据。下面就来使用该迭代器:

cpp 复制代码
// 使用 begin 和 end 函数
string str1("hello cplusplus");
string::const_iterator it1 = str1.begin();
while (it1 != str1.end())
{
	cout << *it1 << " ";
	it1++;
}
cout << endl;

// 使用 rbegin 和 rend 函数
string str2("hello cplusplus");
string::const_iterator it2 = str2.cbegin();
while (it2 != str2.cend())
{
	cout << *it2 << " ";
	it2++;
}
cout << endl;
  1. 反向迭代器 ------ 普通迭代器

反向迭代器顾名思义就是反着遍历字符串,获取迭代器区间的函数为 rbegin 和 rend ,这里与 begin 和 end 函数名的前面多了一个 r ,这个 r 表示的反向 reverse 的首字母,且反向迭代器的名字就是 reverse_iterator 。rbegin 和 rend 函数原型分别为:

rbegin ------ reverse_iterator rbegin() const_reverse_iterator rbegin() const

rend ------ reverse_iterator rend() const_reverse_iterator rend() const

这两个函数的作用分别是:

rbegin ------ 作用:返回指向字符串最后一个字符的迭代器

rend ------ 作用:返回指向字符串的首字符的前一个字符的迭代器

并且迭代时的++,是从 rbegin 开始,从后往前++,直到等于 rend ,这也是为什么该迭代器被称为反向迭代器。下面就来使用该迭代器:

cpp 复制代码
string str("24680");
string::reverse_iterator it1 = str.rbegin();
while (it1 != str.rend())
{
	cout << *it1 << " ";
	it1++;
}
cout << endl;

string::reverse_iterator it2 = str.rbegin();
while (it2 != str.rend())
{
	(*it2)++;
	cout << *it2 << " ";
	it2++;
}

运行结果:



  1. 反向迭代器 ------ const 迭代器

与正向迭代器中的 const 迭代器一致,反向迭代器中的 const 迭代器并不是简单的在reverse_iterator 前面加上 const ,而是 const_reverse_iterator。基于 rbegin 和 rend 函数都有 const 修饰的函数原型,所以在获取迭代器的迭代区间的时候可以使用这两个函数。但是在 C++11 中,为了区分这是在使用 const 迭代器,引入两个新的函数 crbegin 和 crend 函数,它们两个函数的原型分别为:

crbegin ------ const_reverse_iterator crbegin() const noexcept

cend ------ const_reverse_iterator crend() const noexcept

crbegin 和 crend 函数的作用与 rbegin 和 rend 函数的作用一致。下面就来使用该迭代器:

cpp 复制代码
string str("13579");
// 使用 rbegin 和 rend
string::const_reverse_iterator it1 = str.rbegin();
while (it1 != str.rend())
{
	cout << *it1 << " ";
	it1++;
}
cout << endl;

// 使用 rbegin 和 rend
string::const_reverse_iterator it2 = str.crbegin();
while (it2 != str.crend())
{
	cout << *it2 << " ";
	it2++;
}
cout << endl;

运行结果:



  1. 总结:

了解了迭代器之后,我们就可以直到另外一种可以访问和修改对象中的数据的方法。在实际的使用过程中,正向迭代器使用的更多。若想要逆置字符串中的数据,可以使用算法库(algorithm)中的 reverse 函数。

2.6 push_back 函数和 pop_back 函数

push_back 和 pop_back 的函数原型分别为:

push_back ------ void push_back(char c)

pop_back ------ void pop_back()

基于前面的数据结构的学习可以知道,这两个函数的作用分别为尾插字符和尾删字符。下面就来使用这两个函数:

cpp 复制代码
string str1("hello world");
cout << "插入前: ";
for (size_t i = 0; i < str1.size(); i++)
{
	cout << str1[i] << " ";
}
cout << endl;

str1.push_back('$');
cout << "插入后: ";
for (size_t i = 0; i < str1.size(); i++)
{
	cout << str1[i] << " ";
}
cout << endl;


string str2("hello cplusplus");
cout << "删除前: ";
for (size_t i = 0; i < str2.size(); i++)
{
	cout << str2[i] << " ";
}
cout << endl;

str2.pop_back();
cout << "删除后: ";
for (size_t i = 0; i < str2.size(); i++)
{
	cout << str2[i] << " ";
}
cout << endl;

运行结果:



2.7 capacity 函数

前面有提到 string 类的底层实际上是一个存储字符类型的顺序表,由此也可以知道它的结构是:指向数组的指针,存储当前有效数据个数,当前数组的内存空间的大小。在前面介绍了 size 函数可以获取当前字符串的长度,那么 string 类中有没有函数可以获取当前字符串的容量大小呢?当然存在,那就是接下来要介绍的 capacity 函数。该函数的原型和作用分别为:

capacity ------ size_t capacity() const ------ 作用:返回当前字符串的空间大小,单位是字节

这里求得的结果并不包含 '\0' ,与 size 函数一致。需要注意的是内存的大小不一定与当前字符串的长度相等,可能相等,可能较大。当相等的时候,就会扩容,但是具体的扩容机制 C++ 标准并没有规定,根据编译器的不同而不同,根据操作系统的不同而不同。下面就来看看在 Vs 编译器下的扩容机制:

cpp 复制代码
string str("gon");
cout << "old caapcity: " << str.capacity() << endl;
size_t old = str.capacity();

// 不断的往 str 中插入100个数据
for (size_t i = 0; i < 100; i++)
{
	str.push_back('*');
	// 判断是否需要扩容
	// 当 old 的大小与当前字符串的capacity的大小不等时
	// 就会触发扩容机制
	if (str.capacity() != old)
	{
		cout << "new capacity: " << str.capacity() << endl;
	}
	old = str.capacity();
}

运行结果:



有运行结果可以知道,除了第一次的扩容不是1.5倍扩容之外,后续的扩容都是1.5倍扩容。另外可以知道,在 Linux 中,后续的扩容是2倍扩容。

2.8 empty 函数和 clear 函数

这两个函数就较为简单了,这两个函数的函数原型分别是:

empty ------ bool empty() const

clear ------ void clear()

empty 和 clear 函数的作用分别为:

empty ------ 检查当前的字符串是否是空串,若是则返回 true ,若不是则返回 false

clear ------ 清楚当前字符串中的所有字符,即将 size 变为 0 ,但是不改变 capacity 的大小

下面就来使用这两个函数:

empty 函数:

cpp 复制代码
string str1;
string str2("");
string str3(" ");
string str4("hello");

cout << str1.empty() << endl;
cout << str2.empty() << endl;
cout << str3.empty() << endl;
cout << str4.empty() << endl;

运行结果:



clear 函数:

cpp 复制代码
string str("hello world");
cout << "size: " << str.size() << endl;
cout << "capacity: " << str.capacity() << endl;
cout << endl;

// 调用 clear 函数
str.clear();
cout << "size: " << str.size() << endl;
cout << "capacity: " << str.capacity() << endl;

运行结果:



2.9 shrink_to_fit 函数

shrink_to_fit 函数是 C++11 出现的,该函数的作用是缩容,不改变 size ,改变capacity的大小,将capacity的大小减少到合适的大小,但是该过程的结果是不确定的,根据平台的不同而不同,可能缩容成功,也可能缩容失败,即便缩容成功了,其结果 capacity 仍然大于 size。该函数的函数原型为:

shrink_to_fit ------ void shrink_to_fit()

下面来使用该函数:

cpp 复制代码
// 缩容失败
string str;
size_t old = str.capacity();
cout << "******缩容失败******" << endl;
// 不断的往 str 中插入100个数据
for (size_t i = 0; i < 100; i++)
{
	str.push_back('*');
}
cout << "size = " << str.size() << endl;
cout << "capacity = " << str.capacity() << endl;
cout << endl;

str.shrink_to_fit();
cout << "size = " << str.size() << endl;
cout << "capacity = " << str.capacity() << endl;
cout << endl;

// 缩容成功
cout << "******缩容成功******" << endl;
//尾删 50 个字符
for (size_t i = 0; i < 50; i++)
{
	str.pop_back();
}
cout << "size = " << str.size() << endl;
cout << "capacity = " << str.capacity() << endl;
cout << endl;

str.shrink_to_fit();
cout << "size = " << str.size() << endl;
cout << "capacity = " << str.capacity() << endl;

运行结果:



shrink_to_fit 函数的底层缩容原理是异地缩容,先开一块新的较小的内存空间,将原空间的数据拷贝到新的空间,然后释放旧空间。在实际的编程中很少执行缩容操作,因为缩容的代价是很大的,需要重新开辟空间,是以时间换空间的做法。

2.10 reserve 函数 和 resize 函数

reserve 函数的函数原型为:

reverse ------ void reserve(size_t n = 0)

该函数的作用是扩容,为字符串预留空间,将字符串的 capacity 的大小改变到 n ,但是根据 n 的大小的不同会产生不同的结果。

当 size < n < capacity 时,那么 reserve 可能会让当前容器的 capacity 缩小至 n 或 更大 亦或者是不变。下面来使用该函数:

cpp 复制代码
string str("hello world");
cout << "size = " << str.size() << endl;
cout << "capacity = " << str.capacity() << endl;
cout << endl;
str.reserve(13);
cout << "size = " << str.size() << endl;
cout << "capacity = " << str.capacity() << endl;

运行结果:



当 size > capacity 时,那么 reserve 就会让当前容器的capacity 增长至 n 或者更大。下面来使用该函数:

cpp 复制代码
string str("hello world");
cout << "size = " << str.size() << endl;
cout << "capacity = " << str.capacity() << endl;
cout << endl;
str.reserve(20);
cout << "size = " << str.size() << endl;
cout << "capacity = " << str.capacity() << endl;

运行结果:



在之前了解 capacity 函数时,有频繁的扩容,但是使用 reserve 函数,先确定需要开多大的内存空间,提前开辟好,这样可以避免扩容,提高效率。如下代码所示:

cpp 复制代码
string str("hello world");
cout << "old caapcity: " << str.capacity() << endl;
size_t old = str.capacity();
str.reserve(100);

for (size_t i = 0; i < 100; i++)
{
	str.push_back('*');
	if (str.capacity() != old)
	{
		cout << "new capacity: " << str.capacity() << endl;
	}
	old = str.capacity();
}

运行结果:



resize 函数的函数原型为:

resize ------ void resize (size_t n) void resize (size_t n, char c)

该函数的作用是将字符串的长度 size 改变至 n,有时也会改变 capacity 的大小。与 reserve 函数一致,改变的结果与 n 的大小有关。

当 n < size 的大小时,那么 resize 会保留前 n 个字符,删除 n 之后的字符,但是不影响 capacity 的大小。下面开始使用该函数:

cpp 复制代码
string str("hello world");
cout << str << endl;
cout << "size = " << str.size() << endl;
cout << "capacity = " << str.capacity() << endl;
cout << endl;
// n < size
str.resize(7);
cout << str << endl;
cout << "size = " << str.size() << endl;
cout << "capacity = " << str.capacity() << endl;

运行结果:



当 size < n < capacity 时,那么当前字符串的长度会增长至 n 。若没有明确传参,则多出来的长度用 '\0' 来填充。下面开始使用该函数:

cpp 复制代码
string str("hello world");
cout << str << endl;
cout << "size = " << str.size() << endl;
cout << "capacity = " << str.capacity() << endl;
cout << endl;
str.resize(14);
cout << "size = " << str.size() << endl;
cout << "capacity = " << str.capacity() << endl;

运行结果:



调用 resize 后,字符串 str 为:



由编译的结果可以看出多出来的长度全由' \0' 填充。

当 size < n < capacity 时,且明确传参字符 c ,则多出来的长度全由字符 c 来填充。下面开始使用该函数:

cpp 复制代码
string str("hello world");
cout << str << endl;
cout << "size = " << str.size() << endl;
cout << "capacity = " << str.capacity() << endl;
cout << endl;
str.resize(14, '@');
cout << "size = " << str.size() << endl;
cout << "capacity = " << str.capacity() << endl;
cout << str << endl;

运行结果:



当 n > capacity 的大小时,那么当前字符串的长度会增加至 n,capacity 的大小也会增加。若没有明确传参,则多出来的长度用 '\0' 来填充。下面开始使用该函数:

cpp 复制代码
string str("hello world");
cout << str << endl;
cout << "size = " << str.size() << endl;
cout << "capacity = " << str.capacity() << endl;
cout << endl;
str.resize(20);
cout << "size = " << str.size() << endl;
cout << "capacity = " << str.capacity() << endl;
cout << str << endl;

运行结果:



调用 resize 后,字符串 str 为:



当 n > capacity 时,且明确传参字符 c ,则多出来的长度全由字符 c 来填充。下面开始使用该函数:

cpp 复制代码
string str("hello world");
cout << str << endl;
cout << "size = " << str.size() << endl;
cout << "capacity = " << str.capacity() << endl;
cout << endl;
str.resize(20, '@');
cout << "size = " << str.size() << endl;
cout << "capacity = " << str.capacity() << endl;
cout << str << endl;

运行结果:



2.11 append 函数和 operator += 函数

append 函数的函数原型和作用分别为:

string& append (const string& str) ------ 作用:在字符串的尾部追加 str

string& append (const char* s) ------ 作用:在字符串的尾部追加 s

string& append (size_t n, char c) ------ 作用:在字符串的尾部追加 n 个字符 c

下面就来使用这些函数:

cpp 复制代码
string str("hello world ");
cout << str << endl;
str.append(str);          // 原型1
cout << str << endl;
str.append("and space");  // 原型2
cout << str << endl;    
str.append(10, '@');      // 原型3
cout << str << endl;

运行结果:



operator += 函数的函数原型和作用分别为:

string& operator+= (const string& str) ------ 作用:在字符串的末尾加上 str

string& operator+= (const char* s) ------ 作用:在字符串的末尾加上字符串 s

string& operator+= (char c) ------ 作用:在字符串的末尾加上字符 c

下面就来使用这些函数:

cpp 复制代码
string str("hello world ");
cout << str << endl;
str += str;            // 原型1
cout << str << endl;
str += " and space";   // 原型2
cout << str << endl;
str += '@';            // 原型3
cout << str << endl;

运行结果:



相较于append 函数,operator+= 函数使用的最多.

2.12 insert 函数,erase 函数和 replace 函数

在 string 类中并没有提供头插和头删以及其它除了尾插和尾删的插入操作,这是因为 string 类提供了一个更好的函数 ------ insert 函数。insert 函数的函数原型和作用分别为:

string& insert (size_t pos, const char* s) ------ 作用:在 pos 位置前插入字符串 s

string& insert (size_t pos, size_t n, char c) ------ 作用:在 pos 位置前插入 n 个字符 c

下面开始使用这些函数:

cpp 复制代码
string str("hello world");
cout << str << endl;
str.insert(6, "space and ");
cout << str << endl;
str.insert(6, 10, '*');
cout << str << endl;

运行结果:



insert函数要谨慎使用,因为insert的底层涉及数据的挪动,效率低下.

erase 函数的函数原型为:

erase ------ string& erase (size_t pos = 0, size_t len = npos)

该函数的作用为:删除字符串中从字符位置pos开始len个字符的部分,若 len 的大小大于从 pos 位置开始到 '\0' 结束之后的字符串的长度,那么有多少删除多少。下面开始使用该函数:

cpp 复制代码
string str1("hello world");
cout << "删除前: " << str1 << endl;
str1.erase();
cout << "删除后: " << str1 << endl;
cout << endl;

string str2("cplusplus");
cout << "删除前: " << str2 << endl;
str2.erase(4);
cout << "删除后: " << str2 << endl;
cout << endl;

string str3("watergraphiclaly");
cout << "删除前: " << str3 << endl;
str3.erase(4, 5);
cout << "删除后: " << str3 << endl;
cout << endl;

运行结果:



erase要谨慎使用,因为erase的底层涉及数据的挪动,效率低下。

replace 函数的函数原型为:

replace ------ string& replace (size_t pos, size_t len, const char* s)

该函数的作用为:从pos位置开始,将长度为len的字符串替换成字符串s。下面开始使用该函数:

cpp 复制代码
string str1("hello world");
cout << str1 << endl;
str1.replace(6, 3, "$");
cout << str1 << endl;
cout << endl;

string str2("hello world");
cout << str2 << endl;
str2.replace(6, 3, "abcdef");
cout << str2 << endl;

运行结果:



replace函数要谨慎使用,因为replace的底层涉及数据的挪动,效率低下。

这以上三个函数都并不常用,也不好用。

2.13 c_str 函数和 substr 函数

c_str 函数的函数原型和作用为:

c_str ------ const char* c_str() const ------ 作用:返回string指向底层数组的指针

获取了 string 指向底层数组的指针后,可以通过该指针打印该指针指向的数组中的数据。下面开始使用该函数以及其运行结果:



substr 函数的函数原型和作用分别为:

string substr (size_t pos = 0, size_t len = npos) const ------ 作用:在str中从pos位置开始,截取len个字符,然后将其返回

下面开始使用该函数:

cpp 复制代码
// 获取空格之后部分的字符串
string str("hello world");
cout << str << endl;
cout << "size = " << str.size() << endl;
cout << endl;
string ret = str.substr(6, str.size() - 6);
cout << ret << endl;
cout << "size = " << ret.size() << endl;

运行结果:



当 len 不传参数时,默认 len 的大小为 npos。

2.14 find 函数和 rfind 函数

find 函数的函数原型为:

find ------ size_t find (char c, size_t pos = 0) const

该函数的作用为:从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置;如果没有找到字符串c,则函数返回string::npos。下面开始使用函数:

cpp 复制代码
// 将字符串中的空格字符替换成"%%"
string str("water geographically @ g . mail");
cout << str << endl;
// 默认从下标为 0 的位置开始找
size_t pos = str.find(' ');
while (pos != string::npos)
{
	str.replace(pos, 1, "%%");
	// 继续往后找,不需要再从下标为 0 的位置开始找了
	// 从下标为 pos + 2 的位置开始找
	pos = str.find(' ', pos + 2);
}

cout << str << endl;

运行结果:



rfind 函数的函数原型为:

rfind ------ size_t rfind(char c, size_t pos = npos) const

该函数的作用为:从字符串 str 的 pos 位置开始,向后找字符 c ,如果没有找到字符 c,函数返回string::npos。该函数的使用与 find 一致,这里就不多赘述。

3. string 中的常见非成员函数

3.1 relational operators 函数

relational operators 函数是一系列的字符串比较函数,它们的作用均为字符串的比较。这些函数的函数原型为:

小于运算符 ------ bool operator<(const string& str1, const string& str2)

小于等于运算符 ------ bool operator<=(const string& str1, const string& str2)

大于运算符 ------ bool operator>(const string& str1, const string& str2)

大于等于运算符 ------ bool operator>=(const string& str1, const string& str2)

等于运算符 ------ bool operator==(const string& str1, const string& str2)

不等于运算符 ------ bool operator!=(const string& str1, const string& str2)

这些函数的比较方式与 strcmp 函数类似,比较的是 ascii 码,而不是长度。若结果为真则返回大于0的数字,若结果为假,则返回小于 0 的数字。

3.2 流提取运算符和流插入运算符

string 类并不是内置类型,而是自定义类型,那为什么仍然可以使用流插入运算符和流提取运算符呢?这是因为在 string 类中重载了这两个操作符。那么这两个重载函数的函数原型为:

流提取运算符 ------ ostream& operator<< (ostream& os, const string& str)

流插入运算符 ------ istream& operator>> (istream& is, string& str)

3.3 getline 函数

在 C++ 中,可以使用 cin 往 string 类对象中输入数据,但有些字符串当中是存在空格的,而当读取到空格字符时,cin 会停止读取。那若想要输入带空格的字符串,应该怎么办呢?唉!这就不都得不提 getline 函数了。该函数的原型为:

istream& getline(istream& is, string& str, char delim)

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

getline 函数的作用为:从is中提取字符并将其存储到str中,直到找到分隔字符delim。在用户未自定义分隔字符delim时,默认分割字符为'\n',若用户自定义分隔字符delim时,则分隔字符delim使用的就是用户自定义的;与cin不同的是,cin遇到'\0'或'\n'时就停止读取,getline遇到分隔符delim才停止读取。下面就来使用该函数:

cpp 复制代码
// 求一个字符长串中最后一个单词的长度
string str;
getline(cin, str);
size_t pos = str.rfind(' ');
if (pos != string::npos)
{
	cout << str.size() - pos - 1 << endl;
}
else
{
	cout << str.size() << endl;
}

运行结果:



4. 范围 for

除了以上提到的两种可以访问和修改对象中的数据的方法之外,还有一种方法是 ------ 范围 for 。在了解范围 for 之前先来了解 auto 关键字。

4.1 auto 关键字

auto 可以自动推导数据的类型,如下图所示:



对于引用类型,若想要 auto 推导出的数据类型为引用类型,需要在 auto 的后面加上 & 。

对于指针,若想要 auto 推导出的数据类型为指针,可以在 auto 的后面加上解引用操作符( * ),也可以不加。

4.2 范围 for

了解了 auto 关键字后,接下来介绍范围 for。范围 for 为:

for( : )

{}

for循环后的括号由冒号" :"分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围,范围 for 的特点是:自动迭代,自动取数据,自动判断结束。下面就来使用范围 for :



但是上面的范围 for 只能访问容器中的数据,不能修改容器中的数据。若要想修改容器中的数据,可以使用引用,如下图所示:



这里的类型不一定要写成auto,也可以写成确定的类型。但是确定的类型应该与容器中的数据类型相等。范围for支持所有的容器,因为范围for的底层就是迭代器。

5. 结言

以上介绍的函数中有些是十分重要的,如:一系列的初始化函数, size 函数, empty 函数, clear 函数, reserve 函数, resize 函数, operator[ ] 函数, c_str 函数, find 函数, 流插入和流提取函数, getline 函数, relational operators 函数。

相关推荐
好好学习O(∩_∩)O16 分钟前
QT6引入QMediaPlaylist类
前端·c++·ffmpeg·前端框架
whoarethenext17 分钟前
C/C++ OpenCV 矩阵运算
c语言·c++·opencv·矩阵运算
虾球xz39 分钟前
CppCon 2014 学习:C++ Memory Model Meets High-Update-Rate Data Structures
java·开发语言·c++·学习
弥彦_1 小时前
线段树刷题记录
数据结构·c++·算法
凤年徐1 小时前
【数据结构初阶】顺序表的应用
c语言·开发语言·数据结构·c++·笔记·算法·顺序表
海码0072 小时前
【Hot 100】70. 爬楼梯
数据结构·c++·算法·leetcode·动态规划·hot100
凌康ACG2 小时前
易语言使用OCR
c++·yolo·c#·ocr·易语言
范纹杉想快点毕业3 小时前
C++多重继承详解与实战解析
开发语言·c++
太空1号4 小时前
飞腾D2000,麒麟系统V10,docker,ubuntu1804,小白入门喂饭级教程
linux·c++·docker
@蓝莓果粒茶5 小时前
LeetCode第244题_最短单词距离II
c++·笔记·学习·算法·leetcode·职场和发展·c#