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

article/2025/8/11 12:58:17

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类对象去初始化另一个新传建的对象

下面就来使用这些函数:

string str1;                  // 对应函数1
string str2("hello world");   // 对应函数2
string str3(10, '$');         // 对应函数3
string str4(str3);            // 对应函数4cout << "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 替换掉调用该函数的对象中的数据

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

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' ,下面就来使用这两个函数:

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的重载函数。

下面就来使用这个函数:

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')的迭代器

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

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;

运行结果:



2. 正向迭代器 —— 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_iteratorconst iterator 中 const 修饰的是迭代器本身,表示迭代器本身不能修改,也就说明迭代器不能迭代,这在实践中根本没法使用;const_iterator 表示迭代器指向的数据的内容不能被修改,可以做到迭代的功能。const 迭代器只能访问容器中的数据,不可以修改容器中的数据。下面就来使用该迭代器:

// 使用 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;

3. 反向迭代器 —— 普通迭代器

反向迭代器顾名思义就是反着遍历字符串,获取迭代器区间的函数为 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 ,这也是为什么该迭代器被称为反向迭代器。下面就来使用该迭代器:

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++;
}

运行结果:



4. 反向迭代器 —— 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 函数的作用一致。下面就来使用该迭代器:

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;

运行结果:



5. 总结:

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

2.6 push_back 函数和 pop_back 函数

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

push_back —— void push_back(char c)

pop_back —— void pop_back()

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

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 编译器下的扩容机制:

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 函数:

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 函数:

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()

下面来使用该函数:

// 缩容失败
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 或 更大 亦或者是不变。下面来使用该函数

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 或者更大。下面来使用该函数:

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 函数,先确定需要开多大的内存空间,提前开辟好,这样可以避免扩容,提高效率。如下代码所示:

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 的大小。下面开始使用该函数:

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' 来填充。下面开始使用该函数:

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 来填充。下面开始使用该函数:

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' 来填充。下面开始使用该函数:

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 来填充。下面开始使用该函数:

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

下面就来使用这些函数:

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

下面就来使用这些函数:

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

下面开始使用这些函数:

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' 结束之后的字符串的长度,那么有多少删除多少。下面开始使用该函数:

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。下面开始使用该函数:

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个字符,然后将其返回

下面开始使用该函数:

// 获取空格之后部分的字符串
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。下面开始使用函数:

// 将字符串中的空格字符替换成"%%"
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才停止读取。下面就来使用该函数:

// 求一个字符长串中最后一个单词的长度
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 函数。 


http://www.hkcw.cn/article/hHUxyTklFP.shtml

相关文章

DFS每日刷题

目录 P1605 迷宫 P1451 求细胞数量 P1219 [USACO1.5] 八皇后 Checker Challenge P1605 迷宫 #include <iostream> using namespace std; int n, m, t; int a[20][20]; int startx, starty, endx, endy; bool vis[20][20]; int res; int dx[] {0, 1, 0, -1}; int dy[]…

USART 串口通信全解析:原理、结构与代码实战

文章目录 USARTUSART简介USART框图USART基本结构数据帧起始位侦测数据采样波特率发生器串口发送数据 主要代码串口接收数据与发送数据主要代码 USART USART简介 一、USART 的全称与基本定义 英文全称 USART&#xff1a;Universal Synchronous Asynchronous Receiver Transmi…

C# winform 教程(一)

一、安装方法 官网下载社区免费版&#xff0c;在线下载安装 VS2022官网下载地址 下载后双击启动&#xff0c;选择需要模块&#xff08;net桌面开发&#xff0c;通用window平台开发&#xff0c;或者其他自己想使用的模块&#xff0c;后期可以修改&#xff09;&#xff0c;选择…

ZLG ZCANPro,ECU刷新,bug分享

文章目录 摘要 📋问题的起因bug分享 ✨思考&反思 🤔摘要 📋 ZCANPro想必大家都不陌生,买ZLG的CAN卡,必须要用的上位机软件。在汽车行业中,有ECU软件升级的需求,通常都通过UDS协议实现程序的更新,满足UDS升级的上位机要么自己开发,要么用CANoe或者VFlash,最近…

Matlab作图之 subplot

1. subplot(m, n, p) 将当前图形划分为m*n的网格&#xff0c;在 p 指定的位置创建坐标轴 matlab 按照行号对子图的位置进行编号 第一个子图是第一行第一列&#xff0c;第二个子图是第二行第二列......... 如果指定 p 位置存在坐标轴&#xff0c; 此命令会将已存在的坐标轴设…

【STM32F1标准库】理论——外部中断

目录 一、中断介绍 二、外部引脚EXTI申请的中断 三、外部中断的适用场景 四、其他注意事项 一、中断介绍 STM32可以触发中断的外设有外部引脚(EXTI)、定时器、ADC、DMA、串口、I2C、SPI等 中断同一由NVIC管理 n表示一个外设可能同时占用多个中断通道 优先级的值越小优先…

SAP学习笔记 - 开发18 - 前端Fiori开发 应用描述符(manifest.json)的用途

上一章讲了 Component配置&#xff08;组件化&#xff09;。 本章继续讲Fiori的知识。 目录 1&#xff0c;应用描述符(Descriptor for Applications) 1&#xff09;&#xff0c; manifest.json 2&#xff09;&#xff0c;index.html 3&#xff09;&#xff0c;Component.…

定时任务:springboot集成xxl-job-core(一)

springboot:2.7.2 xxl-job-core: 2.3.0 一、集成xxl-job 1. 在gitee上下载xxl-job项目 git clone https://gitee.com/xuxueli0323/xxl-job.git 2. 执行以下目录下的sql /xxl-job-2.3.0/doc/db/tables_xxl_job.sql 3. 在xxl-job-admin的项目中配置数据库信息 ### xxl-job, data…

【STM32开发板】接口部分

一、USB接口 可以看到USBP和USBN与PA12,PA11引脚相接,根据协议&#xff0c;需要添加上拉电阻 二、ADC和DAC 根据原理图找到可以作为ADC和DAC的引脚 ADC和DAC属于模拟部分的&#xff0c;所以要接模拟地 三、指示灯电路 找几个通用的引脚&#xff0c;因为单片机的灌电流比拉电流…

阻塞队列BlockingQueue解析

阻塞队列是一个支持两个附加操作的队列。这两个附加的操作支持阻塞的插入和移除的方法。 阻塞插入&#xff1a;当队列满的时候&#xff0c;队列会阻塞插入元素的线程&#xff0c;直到队列不满。 阻塞移除&#xff1a;当队列空的时候&#xff0c;队列会阻塞移除元素的线程&…

[Redis] Redis命令在Pycharm中的使用

初次学习&#xff0c;如有错误还请指正 目录 String命令 Hash命令 List命令 set命令 SortedSet命令 连接pycharm的过程见&#xff1a;[Redis] 在Linux中安装Redis并连接桌面客户端或Pycharm-CSDN博客 redis命令的使用见&#xff1a;[Redis] Redis命令&#xff08;1&#xf…

车载控制器的“机电一体化”深度集成

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 所谓鸡汤&#xff0c;要么蛊惑你认命&#xff0c;要么怂恿你拼命&#xff0c;但都是回避问题的根源&…

PINN模型相关原理

PINN模型相关原理 目录 PINN模型相关原理原本的物理界的利用神经网络的参数估计PINN 的原理介绍一、基本思想二、PINN 的损失函数三、自动微分&#xff08;Autodiff&#xff09;四、PINN 的优势与挑战 原本的物理界的利用神经网络的参数估计 原本物理界需要确定一个三维流体&a…

计算机基础——宏病毒防御与网络技术

文章目录 宏病毒详解与防范措施宏病毒简介宏病毒的特点宏病毒的传播途径宏病毒的防范措施宏病毒的检测与清除 自治计算机与自治系统解析什么是自治计算机&#xff1f;技术特点 自治系统&#xff08;Autonomous System, AS&#xff09;特点&#xff1a;自治系统类型 总结&#x…

MySql(十一)

目录 准备工作 1&#xff09;准备一张表 2&#xff09;插入数据 分组 1&#xff09;通过性别去统计各组的平局工资 2.limit关键字 不使用limit的关键字 使用limit的关键字 使用limit关键字获取从指定行开始获取 准备工作 1&#xff09;准备一张表 CREATE table role(roleid INT…

论文阅读(六)Open Set Video HOI detection from Action-centric Chain-of-Look Prompting

论文来源&#xff1a;ICCV&#xff08;2023&#xff09; 项目地址&#xff1a;https://github.com/southnx/ACoLP 1.研究背景与问题 开放集场景下的泛化性&#xff1a;传统 HOI 检测假设训练集包含所有测试类别&#xff0c;但现实中存在大量未见过的 HOI 类别&#xff08;如…

使用 SASS 与 CSS Grid 实现鼠标悬停动态布局变换效果

最终效果概述 页面为 3x3 的彩色格子网格&#xff1b;当鼠标悬停任意格子&#xff0c;所在的行和列被放大&#xff1b;使用纯 CSS 实现&#xff0c;无需 JavaScript&#xff1b;利用 SASS 的模块能力大幅减少冗余代码。 HTML 结构 我们使用非常基础的结构&#xff0c;9 个 .i…

linux 后记

Linux Server 下载一个Server的版本&#xff0c;就是那种只有命令行的 学会这个就可以去租一个aliyun服务器&#xff0c;挺便宜的 如果在aliyun买服务器的话就不用管镜像源 但是如果是自己的虚拟机就必须设置镜像源&#xff0c;上网搜索阿里的镜像源&#xff0c;然后手动输入&…

2025年第三届CCF·夜莺开源创新论坛通知

点击蓝字 关注我们 CCF Opensource Development Committee 01 大会简介 由中国计算机学会主办、CCF开源发展委员会及夜莺开源社区承办的第三届CCF夜莺开源创新论坛拟于2025年7月4日在北京召开。本次论坛以“AI 加速可观测”为主题&#xff0c;汇聚了开源夜莺核心开发团队&#…

【2025CCF中国开源大会】RISC-V 开源生态的挑战与机遇分论坛重磅来袭!共探开源芯片未来

点击蓝字 关注我们 CCF Opensource Development Committee 开源浪潮正从软件席卷硬件领域&#xff0c;RISC-V作为全球瞩目的开源芯片架构&#xff0c;正在重塑计算生态的版图&#xff01;相较于成熟的x86与ARM&#xff0c;RISC-V生态虽处爆发初期&#xff0c;却蕴藏着无限可能。…