C++《string》

news2024/10/3 23:28:20

在之前的C语言学习当中我们已经了解了一系列的字符以及字符串函数,虽然这些函数也能实现对字符串进行求长度、拷贝、追加等操作,但是C语言当中的这些函数是与字符串分离的,并且最主要的是在使用这些函数时原字符串的底层空间是需要我们自己来管理的,这就很繁琐,稍不小心就会造成越界等问题。因此为了解决C语言中str系列函数的不足,在此我们就要来学习C++中提供的string类,string是用来管理字符串的类,能实现多种对字符串的操作并且在使用时不用我们显示的去扩容。在本篇中我们会来了解学习标准库中string类的各种函数以及其功能,之后会试着使用这些函数。接下来就开始本篇的学习吧!


1.string简介

其实SLT中有以下多种的容器,但是这是你可能就会疑惑这些容器当中为什么没有string呢?

Reference - C++ Reference (cplusplus.com) 

其实strin严格来说不属于STL,这是因为string在STL 之前就产生了,因此就没有再将string放在容器当中,当从string的结构来看是可以将string也归为STL的

那么我们为什么要学习string呢?它的重要性如何?

其实string本质就是管理字符的数组,在此string如此重要是因为在现实当中我们许多的信息都需要使用字符串来表示,因此在掌握string的使用之后将大大提高我们代码的编写效率

在此我们使用的string其实是被typedef的模板

并且除了以上我们通常使用的string外还存在管理2字节或者4字节长度字符数组的string

当开始string等STL的学习之后我们要试着自己尝试读相应的文档,因为英文的文档才能让我们了解到第一手的资料,而如果是只通过他人翻译后就可以会有一些歧义,例如以下就是string的文档

string - C++ Reference (cplusplus.com) 

在大致了解了string后接下来就来了解string类中的各个成员函数以及其使用

注:在string当中的成员函数有许多种,在以下当中有一些只需了解即可,但有一些需要我们重点的掌握,在文章以下的讲解当中有标注⭐就是要重点掌握的

2.string

2.1构造函数

在string中构造函数提供了多种的接口来完成初始化的工作,在细致了解各个接口的功能前,先大致的去猜其的功能之后再去根据文档验证自己的猜想是否正确

string::string - C++ Reference (cplusplus.com)

通过文档就可以看出各个接口的功能如下所示:
string() 的功能是构造空的string类对象,即空字符串 

string (const string& str) 的功能是将string类型对象str拷贝给新创建的类对象完成初始化

string (const string& str, size_t pos, size_t len = npos) 的功能是将string类型的对象str从pos位置开始拷贝len个字符给新的类对象完成初始化

注:在此的缺省参数npos表示的是字符串的最大值,由于参数len的类型是size_t也就是无符号的整型因此将其赋值为-1时表示的是一个非常大的数,因此当用户不传len的参数时就可以实现将pos下标之后的全部字符进行拷贝到新对象当中

string(const char* s) 的功能是将指针char所指向的字符串拷贝给新创建的类对象当中

string (const char* s, size_t n) 的功能是使用指针所指向的字符串中的前n个字符来完成新创建的类对象的初始化
string(size_t n, char c) 的功能是使用n的字符c来完成新创建类对象的初始化

接下来就来试着在程序当中使用string的构造函数
注:string也是在命名空间std内的,因此在使用string时可以使用展开命名空间std或者在使用string实例化出对象时声明命名空间域

使用命名空间域展开: 

#include<iostream>
#include<string>
using namespace std;

int main()
{
    string s1;
   
    return 0;
}

 声明命名空间域:

#include<iostream>
#include<string>

int main()
{
    std::string s1;
   
    return 0;
}

例如以下就是使用string的各种接口来完成字符串的初始化:

#include<iostream>
#include<string>

using namespace std;

int main()
{
	string a;
	string b("Hello World!");
	string c(b);
	string d(b, 6);
	string e("Hello World!", 5);
	string f(10, 'x');

	cout << "a:" << a<<endl;
	cout << "b:" << b << endl;
	cout << "c:" << c << endl;
	cout << "d:" << d << endl;
	cout << "e:" << e << endl;
	cout << "f:" << f;

	return 0;
}

代码输出结果如下所示:

 2.2析构与赋值运算符的重载

首先是在string中析构函数会在对象销毁时自动调用,不需要我们去显示的调用

赋值运算符的重载支持以下的多个接口

string::operator= - C++ Reference (cplusplus.com)

 string& operator= (const string& str) 的功能是使用一个string的对象完成新创建对象的拷贝构造
string& operator= (const char* s) 的功能是使用一个指针s指向的字符串完成新创建对象的拷贝构造
string& operator= (char c) 的功能是使用一个字符c完成新创建对象的拷贝构造

使用例如以下示例: 

#include<iostream>
#include<string>

using namespace std;

int main()
{
	string a;
	string b("Hello World!");
	string c(b);
	string d(b, 6,3);
	a = b;
	c = "XXXX";
	d = 'L';

	cout << "a:" << a<<endl;
	cout << "b:" << b << endl;
	cout << "c:" << c << endl;
	cout << "d:" << d << endl;

	return 0;
}

以下代码输出结果如下所示:

2.3 容量操作

string类对象的容量操作如下所示,接下来我们就来一一介绍

string - C++ Reference (cplusplus.com)

size 与capacity

string::size - C++ Reference (cplusplus.com)

string::length - C++ Reference (cplusplus.com)

在此string中的size和capacity函数返回值都是字符串有效字符长度,但在此我们更多用的是size,这是因为在string底层存储的是字符串就可以得到字符串的长度,但在STL其他的容器当中有些就没有了字符串长度这个概念,但都有元素的有效个数这个概念,因此size有着更高的通用性,之后要得到一个string对象的字符串长度通常使用的都是size

例如以下示例:

#include<iostream>
#include<string>

using namespace std;

int main()
{
	string a;
	string b("Hello World!");

	cout << "a.size():" << a.size() << endl;
	cout << "b.size():" << b.size() << endl;
	cout << "b.length():" << b.length() << endl;

	return 0;
}

  max_size

string::max_size - C++ Reference (cplusplus.com)

max_size是用于求string当中能开出的最大字符个数,但是这个函数在实践当中基本没有意义,这是因为在不同平台下、在不同的内存环境下能开出的最大字符个数都不同。

例如以下示例:
在VS当中在x86与x64环境下就大不相同

#include<iostream>
#include<string>

using namespace std;


int main()
{

	string a;
	cout << a.max_size();

	return 0;
}

 在x64和x86环境下输出结果依次如下所示:

capacity

string::capacity - C++ Reference (cplusplus.com)

在string类中的capacity函数是用来得到类对象当中的空间大小也就是容量,这和我们之前学习的顺序表当中定义的capacity属性是相同的

#include<iostream>
#include<string>

using namespace std;

int main()
{
	string a("Hello World!!!!");
	cout << a.size()<<endl;
	cout << a.capacity();

	return 0;
}

以上代码输出如下所示: 

 

我们知道在字符串的结尾还有一个\0,因此使用对象.capacity得到的值其实是实际的空间减一的结果。就例如以上示例当对象a当中存储15个字符时,再加上\0实际的空间大小就为16,这时使用capacity得到的值为15这就验证了以上的说法

当我们再将对象a变为以下形式时,capacity会发生什么变化呢?

#include<iostream>
#include<string>

using namespace std;

int main()
{
	string a("Hello World!!!!!");
	cout << a.size()<<endl;
	cout << a.capacity();

	return 0;
}

 通过输出的结果就可以发现capacity扩容了

 

resize 

https://legacy.cplusplus.com/reference/string/string/resize/ 

在string类中的capacity函数是用来将string类型的对象内的将有效字符的个数该成n个,多出的空间用字符c填充,但实参没有显示传c时就使用\0来填充

在使用resize时可能会出现·以下三种情况:

1.resize内参数值小于size
2.resize内参数值大于size小于capacity
3.resize内参数值大于capacity
 

 在使用resize时在以上三种不同的情况下变化是不同的,例如以下示例:

#include<iostream>
#include<string>

using namespace std;
int main()
{

	string a("Hello World!");

	a.resize(14);
	cout << a.size() << endl;
	cout << a.capacity()<<endl;

	a.resize(30);
	cout << a.size() << endl;
	cout << a.capacity()<<endl;

	a.resize(5);
	cout << a.size() << endl;
	cout << a.capacity() << endl;


	return 0;
}

以上代码输出结果如下所示:

通过以上就可以发现当使用resize将string对象的有效元素个数减少时,该对象的内存大小不会缩小 ,在以上代码中其实在将三次使用resize时,对象a内部的元素变化如下所示:

reserve

string::reserve - C++ Reference (cplusplus.com) 

在string中reverse的功能是为字符串预留空间,当我们一开始就确定空间的大小时就可以使用reserve来将对象内的caoacity空间改变

在一些平台下使用可以会存在内存对齐,因此使用reserve扩容的大小不一定和capacity的大小相同

#include<iostream>
#include<string>

using namespace std;

int main()
{
	string a("Hello World!");

	a.reserve(100);
	cout << a.size() << endl;
	cout << a.capacity() << endl;

	return 0;
}

例如以上代码在VS下的输出结果就如下所示: 

 

clear

string::clear - C++ Reference (cplusplus.com) 

在string中clear的功能是清空有效字符

一般在使用clear时是只会将有元素清空,而内存空间一般不会清空,在VS下是这样的。但在其他编译器下就不一定是这样的,这是因为C++标准只规定使用claer是要将有效元素清空,但没有规定是否要将空间清空

例如以下示例:

#include<iostream>
#include<string>

using namespace std;

int main()
{
	string a("Hello World!");
	a.clear();
	cout << a.size() << endl;
	cout << a.capacity() << endl;

	return 0;
}

以上代码在VS下输出结果如下所示:

 

empty

 string::empty - C++ Reference (cplusplus.com)

在string中clear的作用是用于判断string对象的有效元素是否为空,为空时就会返回true;不为空就返回false

 shrink_to_fit

string::shrink_to_fit - C++ Reference (cplusplus.com) 

在string当中shrink_to_fit的作用是将string的对象的内存空间capacity缩小到和有效元素个数size一样大

2.4 访问及遍历操作

 下标+[ ]

string::operator[] - C++ Reference (cplusplus.com)

在string当中提供了operator[ ]运算符重载来实现下标的访问,有了该函数我们就可以通过元素的下标来查找元素或者改变对应元素的的值

例以下示例:

#include<iostream>
#include<string>

using namespace std;

int main()
{
	string a("Hello World!");

	for (int i = 0; i < a.size(); i++)
	{
    //a.operator[](i);
		cout<<a[i]<<" ";
	}
	cout << endl;
	for (int i=0; i < a.size(); i++)
	{
    //a.operator[](i)++;
		a[i]++;
		i++;
	}
	cout << endl;
	for (int i = 0; i < a.size(); i++)
	{
		cout << a[i] << " ";
	}

	return 0;
}

以上代码输出结果如下所示:
 

 迭代器

正向迭代器 

在访问string对象的下标时,除了可以用以上下标+[ ]的方式来实现访问外,还可以使用迭代器来实现访问,在string当中由于底层是数组才重载了operator[ ],但是之后当我们学习到链表或者是二叉树等数据结构时,由于这些结构各个元素在物理结构上是不一定连续的,这就无法使用下标+[ ]来实现遍历了,在此就要用到迭代器了。那么在使用迭代器之前可以认为迭代器是像指针一样的东西,以下我们先来了解迭代器的使用,之后再模拟实现string再来细致的讲解其是如何实现的

例如以下示例:

#include<iostream>
#include<string>

using namespace std;
int main()
{
	string a("Hello World!");

	string::iterator st1 = a.begin();
	while (st1!=a.end() )
	{
		cout << *st1<<" ";
		st1++;
	}

	return 0;
}

 

以上代码就是使用迭代器来实现字符串每个元素的遍历,在此我们创建了一个iterator类型的变量st1,在此要注意iterator是存在string类域内的,因此在使用时要加上::。再通过文档就可以发现函数begin和end返回类型都是iterator

在以上的代码当中begin和end一开始的指向如下所示:

 以上除了可以使用迭代器来实现字符串的遍历外,还可以使用迭代器来修改字符串内的元素

#include<iostream>
#include<string>

using namespace std;
int main()
{
	string a("Hello World!");

	string::iterator st1 = a.begin();
	while (st1 != a.end())
	{
		 (*st1)++;
		st1++;
	}
	st1 = a.begin();
	while (st1 != a.end())
	{
		cout << *st1 << " ";
		st1++;
	}

	return 0;
}

当string对象是使用const修饰的,这时就需要使用const的迭代器

#include<iostream>
#include<string>

using namespace std;
int main()
{
	const string b("Hello");

	string::const_iterator st2 = b.begin();
	while (st2 != b.end())
	{
		cout << *st2 << " ";
		st2++;
	}

	return 0;
}

注:在此由于const修饰的变量是不能修改的,因此在不能使用迭代器对对象内的元素进行修改

反向迭代器

当我们要从末位置开始遍历原string的对象时以上的普通迭代器就无法满足我们的要求了,这时就需要用到反向迭代器

以上的示例使用反向迭代器就如下所示:

#include<iostream>
#include<string>

using namespace std;
int main()
{
	string a("Hello World!");
	string::reverse_iterator st= a.rbegin();
	while (st != a.rend())
	{
		cout << *st << " ";
		st++;
	}
    cout << endl;
    st = a.rbegin();
    while (st != a.rend())
    {
	    (*st)++;
	    st++;
    }
    st = a.rbegin();
    while (st != a.rend())
    {
	    cout << *st << " ";
	    st++;
    }
	return 0;
}

通过以下的文档可以看出在此使用到的rbegin和rend的函数返回值都是reverse_iterator,因此以上我们创建的变量st类型也是reverse_iterator

在反向遍历string对象时当string对象是使用const修饰的,这时就需要使用const的反向迭代器

#include<iostream>
#include<string>

using namespace std;
int main()
{
	const string b("Hello");

	string::const_reverse_iterator st2 = b.rbegin();
	while (st2 != b.rend())
	{
		cout << *st2 << " ";
		st2++;
	}

	return 0;
}

范围for

在了解范围for之前我们首先要来了解在C++11中提供的auto,auto的作用是能自动的推导变量的类型

例如以下示例:

#include<iostream>
using namespace std;

int main()
{
	
	int i = 5;
	double j=6;
	//自动推导类型
	auto a = i;//int
	auto b = j;//double
	auto c = &i;//int*


	return 0;
}

注意:在使用auto给变量进行定义时,必须要初始化否则会出现错误

那么auto在我们的使用当中有什么作用呢?

首先就时在我们之前迭代器的使用当中,在const修饰的反向迭代器当中,类型比较长写的时候就较为繁琐,那么有了auto就可以大大简化代码

例如以下示例:

#include<iostream>
#include<string>

using namespace std;
int main()
{
	const string b("Hello");

	auto st2= b.rbegin();
	//string::const_reverse_iterator st2 = b.rbegin();
	while (st2 != b.rend())
	{
		cout << *st2 << " ";
		st2++;
	}

	return 0;
}

auto这种使用叫做语法糖,这种就是没有创建新的语法,而是使用一种方法来替代旧的方式,用起来更加的方便 

在此在了解了auto就可以来了解范围for了,之前我们遍历的方式学习了下标+[ ]和迭代器,接下来要学习的范围for在遍历时就更加简洁

例如以下的string对象要遍历每个元素就可以使用范围for:

#include<iostream>
#include<string>

using namespace std;

int main()
{
	const string b("Hello");

	for (auto i: b)
	{
		cout << i<<" ";
	}

	return 0;
}

在此以上的形式就是范围for,范围for能自动++;自动判断结束,自动取容器的数据赋值给变量左边的对象

其实在C++当中范围for的底层就是通过调用迭代器来实现的,例如以上代码:

 当我们要使用范围for来修改string对象内的值时,这时的范围for就与以上的形式有所不同了,这时需要在auto之后加上&让其变为引用而不再是拷贝

#include<iostream>
#include<string>

using namespace std;

int main()
{
	string b("Hello");

	for (auto& i : b)
	{
		i++;
	}
	for (auto i: b)
	{
		cout << i<<" ";
	}

	return 0;
}

2.5 修改操作

push_back

string::push_back - C++ Reference (cplusplus.com) 

在string当中提供了push_back来实现尾插,当push_back只能实现一个字符的尾插

例如以下示例:

#include<iostream>
#include<string>

using namespace std;

int main()
{
    string b("Hello");

	b.push_back(' ');
	b.push_back('a');
	b.push_back('b');
	b.push_back('c');
    cout<<b;


	return 0;
}

以上代码输出结构如下所示:
 

append

string::append - C++ Reference (cplusplus.com)

在string还提供了append来实现字符串尾插到原字符串当中,并且支持以上的多个接口,在此这些接口和我们之前学习的构造函数的接口类似

#include<iostream>
#include<string>
using namespace std;

int main()
{
    string b("Hello");
    string c("World");
  	b.append("anc");
	b.append(c, 2, 3);
	b.append(4, 'q');
	cout << b;

	return 0;
}

 以上代码输出结构如下所示:

 

 insert

 

string::insert - C++ Reference (cplusplus.com) 

注:insert在使用时当要在原字符串当中插入字符或者字符串时,这时使用insert就会使得原字符串在要插入位置之后的字符都要向后移动,这时效率就会很低,因此insert在实践当中不可多用 

在string当中还提供了insert来实现任意位置的插入,在此的insert也支持多个接口

例如以下示例:

#include<iostream>
#include<string>

using namespace std;
int main()
{
    string b("Hello");
	string c("World");

	b.insert(1, "xxx");
	b.insert(0, c);
	b.insert(2, 1, 'n');

	cout << b;

	return 0;
}

 以上代码输出结构如下所示:


 

 erase

string::erase - C++ Reference (cplusplus.com)

注:erase在使用时当要删除原字符串当中的字符时,这时使用rease就会使得原字符串在要删除位置之后的字符都要向前移动,这时效率就会很低,因此rease在实践当中不可多用

在string当中还提供了erase来实现任意位置的删除,在此的erase也支持多个接口

例如以下示例:

#include<iostream>
#include<string>

using namespace std;
int main()
{
    string b("Hello");

	b.erase(2, 1);
	b.erase(b.begin());
    cout<<b;

	return 0;
}

 以上代码输出结构如下所示:

operator+=

string::operator+= - C++ Reference (cplusplus.com)

在此在string当中还提供了+=的运算符重载,+=相比之前的push_back和append就简洁很多了,因此在以后string尾插字符或者是字符串时我们更多的是使用+=

例如以下示例:

#include<iostream>
#include<string>

using namespace std;
int main()
{
    string b("Hello");
	string c("World");


	b += '!';
	b += "!!!";
    cout << b;
	return 0;
}

 以上代码输出结构如下所示:

 replace

在string当中提供了replace来实现对string对象内一段字符的替代

注:replace在使用时当原字符串当中要被替代的字符个数不与替代之后的字符数相等时,这时使用replace就会使得原字符串的底层出现大量的字符移动,这时效率就会很低,因此replace在实践当中不可多用

例如以下示例:

clude<iostream>
#include<string>

using namespace std;
int main()
{
    string b("Hello");
	string c("World");

	b.replace(0, 2, "AAA");
	b.replace(1, 3, " World", 1, 5);
	b.replace(b.begin(), b.begin() + 1, "Yes");

	cout << b;
	return 0;
}

 以上代码输出结构如下所示:

⭐find

string::find - C++ Reference (cplusplus.com)

在string提供了find来实现从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置,当查找的字符或者字符串在string对象当中不存在时会返回string::npos

例如以下示例:

要将string对象中的空格字符都替换成%%,这时就可以使用find来查找空格字符,之后再创建一个新的string对象来存储改变之后的字符,之后再将该对象赋值给原对象就可以将原字符串当中的空格字符都替换为%%

#include<iostream>
#include<string>

using namespace std;
int main()
{
	string a("Hello World ");
	string b;//创建新string类型对象
	size_t i = a.find(' ');
	for(auto i:a)//使用范围for遍历a
	{
		if (i != ' ')
		{
			b += i;
		}
		else
		{
			b += "%%";

		}
	}
    a=b;
	cout<<a;
	return 0;
}

 以上代码输出结构如下所示:

⭐rfind

string::rfind - C++ Reference (cplusplus.com)

在string提供了find来实现从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置,当查找的字符或者字符串在string对象当中不存在时会返回string::npos

find_first_of

 string::find_first_of - C++ Reference (cplusplus.com)

在string提供了find_first_of来实现从字符串pos位置开始往后找含有字符串内任意字符的位置,返回该字符在字符串中的位置,当查找的字符或者字符串在string对象当中不存在时会返回string::npos

例如以下示例:

#include<iostream>
#include<string>

using namespace std;
int main()
{
    string str("Please, replace the vowels in this sentence by asterisks.");
	size_t found = str.find_first_of("aeiou");
	while (found != string::npos)
	{
		str[found] = '*';
		found = str.find_first_of("aeiou", found + 1);
	}

	cout << str << '\n';

	return 0;
}

在以上代码中就是使用find_first_of将string对象当中的从前往后所有位置的aeiou字符都替换为字符*

以上代码输出结果如下所示:

find_last_of

string::find_last_of - C++ Reference (cplusplus.com)

在string提供了find_last_of来实现从字符串pos位置开始往前找含有字符串内任意字符的位置,返回该字符在字符串中的位置,当查找的字符或者字符串在string对象当中不存在时会返回string::npos

例如以下示例:

nclude<iostream>
#include<string>

using namespace std;
int main()
{
    string str("Please, replace the vowels in this sentence by asterisks.");
	size_t found = str.find_last_of("aeiou");
	while (found != string::npos)
	{
		str[found] = '*';
		found = str.find_last_of("aeiou", found + 1);
	}

	cout << str << '\n';

	return 0;
}

在以上代码中就是使用find_first_of将string对象当中的从后往前所有位置的aeiou字符都替换为字符*

substr

string::substr - C++ Reference (cplusplus.com) 

在string中提供了substr来实现在str中从pos位置开始,截取n个字符,然后将其返回

例如以下示例:

我们要实现一段代码将一个文件名的最后的后缀取出来,在此就存在一个问题了一个文件名可能会有多个后缀比如test.cpp、test.cpp.exe等,那么我们就不能从文件名的字符串第一个.开始取字符,而是要从字符串的末尾开始找.直到找到为止,从该位置之后的字符就是该文件名的最后一个后缀

#include<iostream>
#include<string>

using namespace std;
int main()
{
	string str("test.cpp.exe");
	size_t found = str.rfind('.');
	if (found != string::npos)
	{
		string tmp = str.substr(found);
		cout << tmp ;
	}
		
	return 0;
}

以上代码输出如下所示:

 

c_str

string::c_str - C++ Reference (cplusplus.com)

在string中提供了c_str来返回string对象底层的字符串,在此在string提供这个函数是因为在编写程序有时候是同时使用C和C++混合编程的。就例如在编写C++的代码有时候我们会调用C语言的库,这时因为C++是兼容C语言的,这就使得C++不是完全面向对象,而是即面向对象也面向过程

 

就例如在使用C++编写的程序当中要调用C语言的库来打开一个string类型的文件,这时就存在问题了,问题是在使用fopen时函数第一参数需要是char* 的指针而我们这时候参数使用类string对象就无法编译通过

在此就需要使用到c_str使string对象的底层字符串指针作为fopen的第一个参数

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>

int main()
{
	string str("test.cpp");
	FILE* p = fopen(str.c_str(), "r");
	char ch = fgetc(p);
	while (ch != EOF)
	{
		cout << ch;
		ch = fgetc(p);
	}
	return 0;
    fclose(p);

}

2.6非成员函数

operator+

operator+ (string) - C++ Reference (cplusplus.com)

在string中提供了operator+来实现两个字符串的相加,在此将该函数设置为非成员函数是为了在string对象在使用该操作符时对象不一定要在操作符的左边

注:在此的operator+在实践当中尽量少用,这时因为opreator+是类类型传值返回,会调用拷贝构造,在此导致深拷贝效率低

例如以下示例:

#include<iostream>
#include<string>

using namespace std;
int main()
{
	string a("World");
	string b;

	b = "Hello " + a;
	cout << b;

	return 0;
}

以上代码输出结果如下所示:

operator>>

operator>> (string) - C++ Reference (cplusplus.com) 

在string当中实现string对象的流插入

operator<<

在string当中实现string对象的流输出

operator<< (string) - C++ Reference (cplusplus.com) 

relational operators

relational operators (string) - C++ Reference (cplusplus.com) 

在string当中提供了以上多个比较大小的运算符重载函数 

getline

 在string中提供了getline这个流输入函数来实现获取一行字符串或者是获取任意字符之前的字符串,在此提供该函数是因为在一些地方之前我们学习过的cin无法满足我们的要求,这是因为用户输入的信息都先是存放在缓冲区的,在之后再从缓冲区读取数据,但cin每次用到空白字符也就是空格或者是换行就停止了,但当我们要将一段包含空白字符的字符串读取输入到string对象或者是数组时cin就无法实现了,这时就要用到getline了

在此getline函数的第一个参数是istream类型的对象,在我们的日常使用当中就是cin,第二个参数是要将信息输入的对象,第三个参数是读取缓冲区数据的停止符号,当用户未输入时默认是换行符


例如以下示例就需要用到getline:

字符串最后一个单词的长度_牛客题霸_牛客网 (nowcoder.com)

在以上的算法题当中要输出最后一个单词的长度也就是要输出最后一个空格之后的字符串,这时你可能就会直接想到先创建一个string的对象,之后再使用rfind查找字符'  ',最后再输出size减rfind位置的值就可以解决以上的算法题了,你大体的想法是没问题的,但是按照以上想法该算法题无法提供是为什么呢

在此就是典型的cin无法实现我们的要求的情况,就例如以上示例使用cin就只能先将ABSIB输入到对p内,这使得对象p内字符串变为ABSIB,之后再将T输入对象p内,这使得对象p内字符串变为T,这样两次的输入就不是我们一开始想要的。因此在此要使用getline才能解决以上的算法题

#include <iostream>
using namespace std;

int main() {
    string p;
    while (getline(cin,p)) 
    { 
        size_t fount=p.rfind(' ');
        cout<<p.size()-fount-1;
       
    }
}
// 64 位输出请用 printf("%lld")

 

以上就是string各个函数的介绍以及使用方法讲解,接下来我们将在下一篇当中带来string的模拟实现,相信通过自主实现string你将对string有更深的理解,未完待续……

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2187031.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微知-Intel芯片中的QPI是什么?本质是什么?以及其他几个高速总线的速率问题(快速通道互联,CPU之间互联总线)

基础信息 CPU与CPU之间通过QPI总线进行通信&#xff0c;类似CPU与PCI-E设备通过PCIE总线进行通信。 The Intel QuickPath Interconnect (QPI)&#xff1a;快速通道互联&#xff0c;快路径内部互联总线。是Inter-connect&#xff0c;内部互联的。是英特尔开发的一种高速点对点…

SpringBoot精华:打造高效美容院管理系统

第一章 绪论 1.1 选题背景 如今的信息时代&#xff0c;对信息的共享性&#xff0c;信息的流通性有着较高要求&#xff0c;尽管身边每时每刻都在产生大量信息&#xff0c;这些信息也都会在短时间内得到处理&#xff0c;并迅速传播。因为很多时候&#xff0c;管理层决策需要大量信…

BiLSTM模型实现电力数据预测

基础模型见&#xff1a;A020-LSTM模型实现电力数据预测 1. 引言 时间序列预测在电力系统管理、负荷预测和能源优化等领域具有重要意义。传统的单向长短期记忆网络&#xff08;LSTM&#xff09;因其在处理时间序列数据中的优势&#xff0c;广泛应用于此类任务。然而&#xff0…

用友NC service接口信息泄露漏洞

漏洞描述 用友NC service接口信息泄露漏洞&#xff0c;攻击者可通过构造恶意链接获取所有接口链接 公网上大部分服务器都没有修复此漏洞&#xff0c;可刷SRC 用友nc有个接口可以获取数据库账户密码&#xff0c;不过是老版本了 漏洞复现 app"用友-UFIDA-NC" POC …

哪家宠物空气净化器可以高效去除浮毛?希喂、IAM、有哈怎么样

在现代养宠家庭中&#xff0c;随着生活节奏的加快&#xff0c;清理浮毛也是很多家庭周末必须要做的事情。但是如何选择一款吸毛好、还不增加清理负担的宠物空气净化器&#xff0c;在寸土寸金的租房里为全家老小的健康生活保障&#xff1f;又如何通过强大的吸毛、除臭技术和除菌…

【学习笔记】手写一个简单的 Spring IOC

目录 一、什么是 Spring IOC&#xff1f; 二、IOC 的作用 1. IOC 怎么知道要创建哪些对象呢&#xff1f; 2. 创建出来的对象放在哪儿&#xff1f; 3. 创建出来的对象如果有属性&#xff0c;如何给属性赋值&#xff1f; 三、实现步骤 1. 创建自定义注解 2. 创建 IOC 容器…

IO模型介绍

一、理解IO 网络通信的本质就是进程间通信&#xff0c;进程间通信本质就是IO TCP中的IO接口&#xff1a;read / write / send / recv&#xff0c;本质都是&#xff1a;等 拷贝 所以IO的本质就是&#xff1a;等 拷贝 那么如何高效的IO&#xff1f; 减少“等”在单位时间的…

在VS code 中部署C#和avalonia开发环境

要在 Mac 的 VS Code 中配置 C# 和 Avalonia 的开发环境&#xff0c;您可以按照以下步骤进行&#xff1a; 1. 安装 .NET SDK 下载 .NET SDK&#xff1a; 访问 .NET 下载页面。选择适用于 macOS 的最新稳定版本的 .NET SDK&#xff0c;并下载安装程序。安装 .NET SDK&#xff1…

PADS自动导出Gerber文件 —— 6层板

在出GERBER文件之前要给PCB文件铺完铜并且检查连接性和安全间距无错误。进入CAM中之后点自动定义。如果电气层不需要用到2D线&#xff0c;保险起见在电气层中把2D线和文本去掉&#xff08;在DRC检查时2D线不会报错&#xff0c;文本是会报错的&#xff09;&#xff0c;因为有些时…

【JAVA开源】基于Vue和SpringBoot的校园资料分享平台

本文项目编号 T 059 &#xff0c;文末自助获取源码 \color{red}{T059&#xff0c;文末自助获取源码} T059&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

(功能测试)熟悉web项目及环境 测试流程

1.环境&#xff1f;有没有考虑过什么是环境&#xff1f; web网站为什么能打开&#xff1f; &#xff08;是因为他的服务器已经在运行了&#xff0c;网站服务器相关环境已部署及运行&#xff09; 所以什么是环境&#xff1f; 环境&#xff1a;就是项目运行所需要的软件及硬件组合…

php与python建站的区别有哪些

php与Python建站的区别&#xff1a; 1、语言层面Python的特性比php好&#xff0c;更加规范。 2、Python的性能比php高。 3、有只需要启动服务的时候执行一次的代码&#xff0c;在php里每个请求都会被执行一次&#xff0c;Python不需要。虽然php可以通过缓存缩短这方面的差距…

CVPR论文《DETRs Beat YOLOs on Real-time Object Detection》读后思维导图

下面欣赏一下论文中的图和表&#xff1a; 1、与YOLOs的性能对比图 2、不同置信度阈值下的框数 3、IoU阈值和置信度阈值对准确性和NMS执行时间的影响 4、混合编码器不同变体 5、模型概述。将骨干网后三个阶段的特征输入到编码器中。高效混合编码器通过基于注意力的尺度内特征交…

Linux网络基础:HTTPS 网络传输协议

HTTPS HTTPS 网络传输协议加密常见的加密方式&#xff08;对称/非对称加密&#xff09;数据摘要、数字签名HTTPS 加密过程探索的方案只使用对称加密&#xff08;效率低下、不安全&#xff09;只使用非对称加密&#xff08;不靠谱、不安全&#xff09;双方都使用非对称加密&…

js中的深拷贝与浅拷贝 手写深拷贝代码

1 什么是深拷贝和浅拷贝&#xff1f; 深拷贝和浅拷贝都是复制对象时常用的两种方式&#xff0c;区别在于对于嵌套对象的处理&#xff0c;浅拷贝只复制属性的第一层属性&#xff0c;双方修改嵌套对象将会互相影响。深拷贝会递归复制每一层的属性&#xff0c;修改任意一方互不影响…

YOLO11项目实战1:道路缺陷检测系统设计【Python源码+数据集+运行演示】

一、项目背景 随着城市化进程的加速和交通网络的不断扩展&#xff0c;道路维护成为城市管理中的一个重要环节。道路缺陷&#xff08;如裂缝、坑洞、路面破损等&#xff09;不仅影响行车安全&#xff0c;还会增加车辆的磨损和维修成本。传统的道路缺陷检测方法主要依赖人工巡检…

[云服务器17] 搭建PMail个性邮箱!我的邮箱我做主

哈喽大家好啊&#xff01; 我们先来看一个邮箱: 123456example163.com你发现了吗&#xff1f;后面有163的域名&#xff01; 这个就标志了邮箱服务提供商的名字&#xff0c;像常见的Outlook 163等。 那么作为一个追求自由主义的人&#xff0c;今天&#xff0c;我们就要使用开…

exe4j安装使用教程

A-XVK258563F-1p4lv7mg7sav A-XVK209982F-1y0i3h4ywx2h1 A-XVK267351F-dpurrhnyarva A-XVK204432F-1kkoilo1jy2h3r A-XVK246130F-1l7msieqiwqnq A-XVK249554F-pllh351kcke50

出口企业财务管理,六款热门产品测评与推荐

本文介绍了ZohoBooks、QuickBooks、Xero等6款外贸管理软件&#xff0c;各有特点如全球化管理、移动应用、自动对账等&#xff0c;适合不同出口企业需求。选择时应考虑企业规模、业务复杂度和预算&#xff0c;建议先试用再购买。 一、Zoho Books Zoho Books是一款适合外贸企业跨…

【C++】迭代器失效问题解析

✨ Blog’s 主页: 白乐天_ξ( ✿&#xff1e;◡❛) &#x1f308; 个人Motto&#xff1a;他强任他强&#xff0c;清风拂山冈&#xff01; &#x1f525; 所属专栏&#xff1a;C深入学习笔记 &#x1f4ab; 欢迎来到我的学习笔记&#xff01; 一、迭代器失效的概念 迭代器的作用…