深入篇【C++】string类的常用接口介绍:标准库中的string类 【万字总结】

news2024/11/16 17:59:23

深入篇【C++】string类的常用接口介绍:标准库中的string类

  • Ⅰ.string类介绍
  • Ⅱ.string类的常用接口
      • ①.string类对象的常用构造
          • 1.string()
          • 2.string(const char*ch)
          • 3.string(const string& str)
          • 4.string(size_t n,char c)
          • 5.string(const string& str,size_t pos,size_t len=npos)
        • 【总结】
      • ②.string类对象的容量操作
          • 1.size
          • 2.capacity
          • 3.clear
          • 4.empty
          • 5.reserve
          • 6.resize
        • 【总结】
      • ③.string类的对象的访问与遍历
          • 1.opeartor[]
          • 2.begin/end
          • 3.rbegin/rend
          • 4.范围for
        • 【总结】
      • ④.string类对象查看与修改操作
          • 1.push_back
          • 2.append
          • 3.operator+=
          • 4.insert
          • 5.erase
          • 6.replace
          • 7.c_str
          • 8.substr
          • 9.find
          • 10.rfind
        • 【总结】
      • ⑤.string类非成员函数
  • Ⅲ.牛刀小试:练习string类
    • 1.字符串相加
    • 2.字符串最后一个单词的长度

Ⅰ.string类介绍

string类文档介绍----cplusplus
在这里插入图片描述

1.C语言中,strxxx 是系列库函数而在C++中string是一个类。
2.string是管理字符数组的类
3.标准的字符串类提供了对此类对象的字符类型,其接口类似于标准字符容器的接口,但添加了专门操作单字节字符字符串的设计特性。
4.string类其实是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数。
5.这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字节的序列,这个类的所有成员以及它的迭代器,将仍然按照字节来操作,而不是实际编码的字符。

总结:
1.string其实表示字符串的字符串类
2.string在底层其实是basic_string模板的实例化。

typedef basic_string<char, char_traits, allocator> string;

3.在使用string类时必须要包含头文件和using namespace std;

Ⅱ.string类的常用接口

①.string类对象的常用构造

在这里插入图片描述

1.string()

无参构造函数,不需要参数就可以构造出一个对象,该对象其实就是一个空字符串。
所以可以用空字符串来构造string对象。

int main()
{
	//无参构造函数
	string s1;
	cout << s1 << endl;
}

在这里插入图片描述

2.string(const char*ch)

该构造函数的参数是一个字符串。这说明我们可以用一个字符串来构造string对象。

int main()
{
	string s2("小陶");//用字符串来构造对象
	string s3("hello world");
	cout << s2 << endl;
	cout << s3 << endl;
}

在这里插入图片描述

3.string(const string& str)

该构造函数的参数是string类对象,这说明我们可以用一个string对象来构造string对象。

int main()
{
	string s2("小陶");
	string s3("hello world");
	string s4(s2);
	cout << s4 << endl;
	string s5(s3);
	cout << s5 << endl;
}

在这里插入图片描述

4.string(size_t n,char c)

该构造函数的参数有两个,一个是正数n一个是字符c。
该构造函数实现的功能是用n个字符c构造对象。这说明我们可以用n个字符c来构造string对象。

int main()
{
	
	string s4(10, '*');
	//用10个'*'来构造对象s4
	cout << s4 << endl;

	string s5(10, 'x');
	//用10个'x'来构造对象s4
	cout << s5 << endl;
}

在这里插入图片描述

5.string(const string& str,size_t pos,size_t len=npos)

从参数上我们就可以推断出该构造函数的功能是什么了。
从字符串str第pos位置上拷贝长度为len的字符串用来构造对象
注意最后一个参数给了缺省值npos,npos是一个很大的数值,当我们给定长度时,就从pos位置截取len长度,当我们不给定长度时,就默认从pos位置一直往后截取完。

int main()
{
	string s3("hello world");//字符串
	
    string s6(s3, 6, 5);///从某个字符串某个位置拷贝n各字符
	//从字符串s3第六个位置往后拷贝五个字符
	cout << s6 << endl;

	//当给定长度为5时,就截取5个字符,当不给定长度时,从pos位置一直往后截取
	//因为缺省参数是一个很大的数值。
	
	string s7(s3, 6);
	cout << s6 << endl;
	//
}

在这里插入图片描述

【总结】

常见构造函数功能
string()用空来构造string对象,即空字符串
string(const char* ch)用C-string来构造string对象
string(const string& str)用string类对象来构造string对象,即拷贝构造函数
string (size_t n,char c)对象中包含n个字符c,即用n个字符c来构造对象
string(const stirng&str,size_t pos,size_t len=npos)从对象str的pos位置上截取长度为len的字符串来构造

②.string类对象的容量操作

在这里插入图片描述

1.size

用来计算对象的有效长度。它是string类的成员函数,所以调用它只需要对象即可。
C++中其实还有一个成员函数length也是用来计算对象长度的,与size功能是完全一样,只是名字不一样。
类似的成员函数还有max_size,这是用来计算对象可以拥有的最大长度。
在这里插入图片描述


int main()
{
	string s1("hello xiaotao");
	cout << s1.size() << endl;
	cout << s1.length() << endl;
	cout << s1.max_size() << endl;
}

在这里插入图片描述

2.capacity

用来计算对象的容量大小,它是string类的成员函数,对象可以直接调用。

int main()
{
	string s1("hello xiaotao");
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;

	string s2;
	cout << s2.size() << endl;
	cout << s2.capacity() << endl;

}

在这里插入图片描述

我们可以发现对象s1和对象s2的容量都为15,这说明对象的起始容量就为15。
当一个对象被创建时,系统就会给它申请15大小的空间。而当我们的对象的长度大于对象本身容量的大小时,就需要对象扩容。
那string类对象的扩容方式是如何的呢?每次对象扩容多少呢?

int main()
{
	string s1;
	cout <<"大小:"<< s1.size() << endl;

	cout <<"起始容量:"<< s1.capacity() << endl;

	size_t old = s1.capacity();
	for (size_t i = 0; i < 100; i++)
	{
		s1 += 'x';
		if (old != s1.capacity())
		{
			cout << "扩容" << s1.capacity() << endl;
			old = s1.capacity();
		}
	}
}

在这里插入图片描述
我们可以看到在VS下string对象的每次扩容申请的空间都是不一样的,比较奇怪。
第一次扩容16大小,第二次扩容26大小,第三次扩容23大小,第4次扩容35大小。

3.clear

用来清空对象的有效字符
要注意clear只是清空了有效字符的大小(size)变成0,而容量空间大小(capacity)是不变的。

int main()
{
	string s1("hello xiaotao");
    cout << s1.size() << endl;
    cout << s1.capacity() << endl;
     s1.clear();
     //清理数据,但内存空间还在
     cout << s1.size() << endl;
     cout << s1.capacity() << endl;
}

在这里插入图片描述

4.empty

用来检查字符串是否被释放成空串,如果是空串则返回true、否则返回false。

int main()
{
	string s1("hello xiaotao");
    
	cout << s1.empty() << endl;
     s1.clear();
     //清理数据,但内存空间还在
     
	 cout << s1.empty() << endl;
}

在这里插入图片描述

5.reserve

用来为对象预留空间。
可以提前为对象申请n大小的空间。
当n比原空间(capacity)大时,就会进行扩容。
当n比原空间(capacity)小时,不一定会缩容,这取决于不同的平台。

而reserve的好处就是当我们知道需要多少空间时,就可以提前将空间开好,这样就可以避免不断扩容,就不存在扩容问题了。

int main()
{
	string s1("hello world");
	//开空间
	s1.reserve(100);
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
}

在这里插入图片描述
用reserve提前开辟的空间不一定准确,可能会开大点,但不可能开小的。就比如reserve(100)提前申请100个空间,系统分配了111个空间给它。

void TestPushBackReserve()
{
	string s;
	s.reserve(100);//提前开辟100大小空间
	size_t sz = s.capacity();
	cout << "now capacity:" << sz << '\n';

	cout << "making a grow:'\n";
	for (int i = 0; i < 100; i++)
	{
		s.push_back('c');
		if (sz != s.capacity())
		cout << "capacity changed:" << sz << '\n';
	}
	
	cout << "later capacity:" << sz << '\n';
	s.reserve(10);
	cout << s.capacity() << endl;
}

在这里插入图片描述
可以通过上面的代码知道reserve确实为对象开辟的空间,并且当开辟空间小于原空间大小时,原空间大小是不变的。

6.resize

在这里插入图片描述

将对象原来的有效字符的个数改成n个,多出来的空间用字符c来填充。
该成员函数有两种重载形式,一种是resize(size_t n)一种是resize(size_t n,char c);
这两个区别在于多出来的空间,resize(size_t n)是用0来填充
resize(size_t n,char c)是用字符c来填充。

int main()
{
	string s1("hello world");
	s1.resize(20);
	cout << s1 << endl;

	string s2("hello world");
	s2.resize(20,'x');
	cout << s2 << endl;
}

reserve和resize都是可以操纵空间大小的,那它们有什么区别呢?
1.reserve是单纯开空间
2.resize是开空间+填值初始化
3.reserve是只能影响到capacity容量大小,影响不到size的大小。
而resize既能影响capacity容量大小,又能影响size的大小。
因为当resize中的n大于size时,则会扩大size的大小至n,并且容量capacity也会跟着变化。
但当resize中的n小于size时,则只会缩数据个数,不会缩空间大小,也就是只缩小size大小,不改变capacity的大小。

int main()
{
	string s1("hello world");
	//单纯开空间
	s1.reserve(100);
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;

	//开空间+填值初始化
	s1.resize(200, 'x');
	cout << s1 << endl;
	//当resize在改变元素个数时,如果元素的个数增多,可能会改变
	//底层容量的大小,如果是将元素个数减少。底层空间总大小不变
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;

	s1.resize(20);
	cout << s1.size() << endl;//这个数据大小改变
	cout << s1.capacity() << endl;//但容量不会改变
}

【总结】

成员函数功能
size计算字符串的字符长度
capacity计算空间总大小
clear清空对象数据
empty判断字符串是否被清空
reserve为字符串预留空间
resize将字符串的大小更改成n

1.size()和length()底层实现原理是一样的,出现size()原因是为了于其他容器的接口保持一致,一般都用size().
2.clear()只是清空数据的个数,不会改变capacity的大小的。
3.resize(n)和resize(n,char c)都是用来更改字符大小的。不同的是,当n大于size时,多出来的空间rezie(n)用0初始化,resize(n,char c)用字符c来初始化。当n小于size时,size的大小会改变,但capacity的大小不会改变
4.想单纯的开空间就使用reserve、要想即开空间又初始化,那就用resize。

③.string类的对象的访问与遍历

1.opeartor[]

该成员函数其实就是对[]进行运算符重载。返回pos位置的字符,使用方法跟数组是一样的。都是根据下标来进行访问。

int main()
{
	char ch[] = "hello world";
	cout << ch[2] << endl;
	string s1("hellor world");
	cout << s1[2] << endl;
}

在这里插入图片描述
虽然看起来很像,但它们的底层实现是不一样的,不能混成一块。
char ch[2]的底层实现的原理是*(ch+2).
而s1[2]底层实现的原理是s1.operator[](2).

//如何遍历string对象呢?
  cout << s1.size() << endl;
	for (int i = 0; i < s1.size(); i++)
	{
		s1[i]++;
	}
	
	s1[0]--;//可以根据下标一样来修改string对象
	//下标+[]
	for (int i = 0; i < s1.size(); i++)
	{
		cout << s1[i] << endl;;
	}

注意:下标+[ ]这种访问方式只能用于string和vector,list是无法使用的,因为只有顺序表类型的才可以用这种方式访问,而链表类型的是无法使用该方式访问。但是使用迭代器访问是通用的,什么类型都可以使用迭代器进行访问。

这样还要注意一点,当使用下标访问时,如果访问越界了,即非法访问了。它是会断言报错的。

int main()
{
	string s1("hello world");
	
	for (int i = 0; i < 20; i++)
	{
		s1[i]++;
	}
	
}

在这里插入图片描述

int main()
{
	try {
		string s1("hello world");
		s1.at(0) = 'x';//在某个位置修改
		cout << s1 << endl;
		s1[0] = 'h';
		cout << s1 << endl;
		//s1[15];//如果越界非法访问了,这样会assert警告的。
		///暴力处理
		s1.at(15);//温和的错误处理
	}//会抛异常
	catch (const exception& e)
	{
		cout << e.what() << endl;
	}
}
2.begin/end

begin可以获得第一个字符的迭代器,end可以获得最后一个字符下一个位置的迭代器。
什么是迭代器呢?
迭代器(iterator)就像一个指针,我们可以暂且将它看作指针类型,但有时候不一定是指针类型。
使用迭代器的方法:

int main()
{
	string s1("hello xiaotao");
	//迭代器--->指针
	string::iterator it = s1.begin();
	while (it != s1.end())
	{
		//写
		(*it)--;
		++it;//类似于指针
	}
	while (it != s1.end())
	{
		//读
		cout << *it << " ";
		++it;
	}
}

begin和end又称为正向迭代器,是从开头到结尾进行访问的。

3.rbegin/rend

rbegin是获取最后一个字符的迭代器,rend是获取第一个字符前一个位置的迭起器。
rbegin和rend可以用来进行从后往前遍历,所以又称为反向迭代器。

int main()
{
	string s1("hello world");
	string::reverse_iterator rit = s1.rbegin();//反向迭代器
	while (rit != s1.rend())
	{
		
		cout << (*rit) << endl;//反向遍历
		++rit;
	}
}

在这里插入图片描述

4.范围for

范围for是C++11支持更简洁的新遍历方式。

int main()
{
	string s1("hello xiaotao");
	for (auto ch : s1)
	{
		cout << ch << endl;
	}
}

它会依次将s1中的字符赋给ch,ch会自动识别类型。

1.范围for的底层本质上其实就是替换成迭代器。如果不支持迭代器的用法就不能支持范围for。
为什么范围for可以使用呢?
因为任何容器都支持迭代器的用法,并且用法都是类似的。

	任何容器都支持迭代器,并且用法是类似的。
	vector<int> v;
	vector<int>::iterator vit = v.begin();
	while (vit != v.end())
	{
		cout << *vit << endl;
		++vit;
	}
	
	list<int> lit;
	list<int>::iterator lit = lit.beign();
	while (lit != lit.end())
	{
		cout << (*lit) << endl;
		++lit;
	}

2.所以迭代器(iterator)提供了一种统一的方式进行访问和修改容器的数据。
3.迭代器可以跟算法进行配合。
因为数据封装在容器里面。算法是无法对容器进行修改的,所以要利用迭代器。这样算法就可以通过迭代器去处理容器中的数据,比如reverse和sort。

	//迭代器跟算法进行配合
	reverse(s1.begin(), s1.end());
	sort(s1.beign(), s1.end());

4.迭代器的类型有多种。
比如const修饰的对象就无法使用普通的迭代器来遍历。
而需要使用const迭代器。

void Func(const string& s)
{
	string::const_iterator it = s.begin();
	while (it !=s.end())
	{
		cout << *it << endl;
		++it;
	}
void Func(const string& s)
{
	string::const_reverse_iterator rit = s.rbegin();
	auto rit = s.rbegin();
	while (rit != s.rend())
	{
		cout << *rit << endl;
		++rit;
	}
}

在这里插入图片描述

【总结】

成员函数功能
operator[ ]返回pos位置的字符,利用下标进行访问和遍历
begin/end正向迭代器,可以用来遍历和访问
rbegin/rend反向迭代器,可以倒着遍历
范围forC++11支持的更简洁的遍历方式,任何容器都可以使用

④.string类对象查看与修改操作

1.push_back

在字符串后面尾插一个字符
在这里插入图片描述

int main()
{
	//增操作
	string s1("helllo");
	//尾插一个字符
	s1.push_back('6');
}
2.append

在字符串后面尾插一个字符串
在这里插入图片描述

int main()
{
	//增操作
	string s1("helllo");
	//尾插一个字符
	s1.push_back('6');
	//尾插一个字符串
	s1.append("world");
}
3.operator+=

operator+=是对+=运算符重载
它比push_back和append尾插更方便。而且接口很多
可以尾插一个字符,一个字符串,一个stirng对象等。


int main()
{
	//增操作
	string s1("helllo");
	//尾插一个字符
	s1.push_back('6');
	//尾插一个字符串
	s1.append("world");
	//push_back是用来尾插字符的
	//append是用来插入字符串的
	//但是还有一种方法直接尾插,+=
	s1 += '6';
	s1 += "6666";

问题: 如何将整形转化成string类型呢?

int main()
{	//要求将x转化为string对象?
	size_t x = 0;
	cin >> x;

	string xstr;
	while (x)
	{
		size_t val = x % 10;
		xstr += (val + '0');
		x /= 10;
	}
	//逆转
	reverse(xstr.begin(), xstr.end());
	cout << xstr << endl;
}
4.insert

在字符串的头部插入字符/字符串
在这里插入图片描述

int main()
{
	string s1("hello world");
	//往头部插入10个’x
	s1.insert(0, 10, 'x');
	//insert(位置,个数,字符);
	cout << s1 << endl;
	
	//从第五个位置插入world
	s1.insert(5, "world");
	//insert(位置,字符串)
	cout << s1 << endl;
	
	s1.insert(0, 10, 'x');
	//从第十个位置插入10个y
	s1.insert(s1.begin() + 10, 10, 'y');
	cout << s1 << endl;
}
5.erase

删除字符串
在这里插入图片描述
默认从第第一个位置开始删除。
erase(位置,删除的长度),注意删除的长度给了缺省值npos,这说明当不给定长度时,会默认将pos位置后面的字符全部删除掉。
erase也可以使用迭代器进行删除。删除的是迭代器位置上的字符。

int main()
{
	string s1("hello world");
	s1.erase(5, 1);
	//从第5个位置删除1个字符
	cout << s1 << endl;

	
	//从第五个位置往后全部删除
	s1.erase(5);
	cout << s1 << endl;
	//erase(位置,n个字符=nps缺省值很大的数

	string s2("hello world");
	s2.erase(0, 1);//相当于头删了
	cout << s2 << endl;
	
	s2.erase(s2.begin());
	//删除这个迭代器位置上的字符
	cout << s2 << endl;

  
}
6.replace

替换字符串中的字符
replace(替换的位置,要替换的长度,替换成的字符串)
在这里插入图片描述

int main()
{
	//将world替换成xxxxxxxxxxxx
	string s1("hello world hello xiaotao");
	s1.replace(6, 5, "xxxxxxxxxxxxxxxxxxx");
	//replace(位置,替换的个数,替换成的字符串)
	s1.replace(6, 20, "666");
	cout << s1 << endl;

	//将s2中所以空格全部替换成20%
	string s2 = "hello world hello xiaotao";
	string s3;
	for (auto ch : s2)
	{
		if (ch != ' ')
		{
			s3 += ch;
		}
		else
		{
			s3 += "20%";
		}
	}
	s2 = s3;
	cout << s2 << endl;
}
7.c_str

返回C格式的字符串
这个接口有什么用呢?为什么要返回C格式的字符串呢?
因为在做项目时我们要和C的一些接口函数进行配合才可以使用。
比如某个函数必须要使用C格式的字符串,那么就需要将string类型的字符串转化成C格式的字符串

int main()
{
	//适用于一些C的一些接口函数配合
	string filename = "test.cpp";
	filename += ".zip";
	FILE* fout = fopen(filename.c_str(), "r");//
	//调用这个函数必须要C的字符类型
}
8.substr

从字符串pos位置开始截取n个字符,如何将其返回
substr(位置,长度)注意长度参数给了缺省值,所以如果不给定长度,则默认从pos位置往后一直截取字符。

在这里插入图片描述

int main()
{
	string  s1("hello xiaotao");
	string s2, s3;
	s2 = s1.substr(6);
	//不给位置,则默认从该位置往后一直截取字符,直到截取完毕
	cout << s2 << endl;
	s3 = s1.substr(6, 7);
	//从第6个位置截取7个字符
	cout << s3 << endl;

}

在这里插入图片描述

9.find

从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置。
find(字符,位置),如果不给位置,默认从第一个位置开始往后找。

在这里插入图片描述

int main()
{
	string s1("hello xiaotao");
	cout << s1.find('x') << endl;
	//不给位置,则默认从第一个位置开始往后面找

	cout << s1.find('o', 5);
	//从第5个位置往后找字符'o'找到后返回该字符的位置
}

在这里插入图片描述

我们利用一个题目来深入理解find。
【切割字符串】
将任何一个网站的协议,域名,资源名分割处理:


int main()
{
	string url = "ftp://www.baidu.com/?tn=65081411_1_oem_dg";

	//协议  域名  资源名

	size_t pos1 = url.find("://");
	string protocol;
	if (pos1 != string::npos)
	{
		protocol = url.substr(0, pos1);
		//从位置0这个地方截取pos1长度的字符串赋给protocol
	}
	cout << protocol << endl;
	size_t pos2 = url.find('/', pos1 + 3);
	string domain;//域名
	string uri;//资源名
	if (pos2 != string::npos)
	{
		domain = url.substr(pos1 + 3, pos2 - (pos1 + 3));
		uri = url.substr(pos2+1);
	}
	cout << domain << endl;
	cout << uri << endl;
}

在这里插入图片描述

10.rfind

与find类似但不同的是find是从前往后找,而rfind是从后往前找。
从字符串pos位置往前找字符c,找到了返回该字符所在位置。

如果不给位置,默认从最后一位开始往前找。
在这里插入图片描述

int main()
{
	string s1("hello xiaotao");
	cout << s1.rfind(' ') << endl;
	//找到' '返回该字符的位置
}

【总结】

成员函数功能
push_back在字符串后面尾插一个字符
append在字符串后面追加一个字符串
operatro+=在字符串后面追加str
insert头插字符/字符串
erase尾删字符/字符串
replace替换字符串中的字符
c_str返回C格式的zifc
substr从pos位置截取长度为n的字符串
find从pos开始往后查找字符c,返回该字符的位置
rfind从pos位置开始往前查找字符c,返回该字符的位置

⑤.string类非成员函数

非成员函数功能
operator+对运算符+的重载,尽量少用,因为传值返回,深拷贝效率低
operator<<输入运算符符重载,使string类对象可以直接输入
operator>>输出运算符重载,使string类对象可以直接输出
getline可以获取一行字符串,坚持一行不结束,遇到换行才结束
relational operators各种大小比较运算符重载,使string对象可以直接比较
to_string将其他类型转化为字符串类型

在这里插入图片描述

int main()
{
	//将整形转化成字符类型
	string stri = to_string(1234);
	//将浮点型转化成字符类型
	string strd = to_string(6.11);
}

Ⅲ.牛刀小试:练习string类

1.字符串相加

字符串相加—力扣
第一种:头插方式

class Solution {
public:
    string addStrings(string num1, string num2) {
     int end1=num1.size()-1,end2=num2.size()-1;
     int carry=0;
     string strRet;
     while(end1>=0||end2>=0)
     {
        int val1=end1>=0?(num1[end1]-'0'):0;
        int val2=end2>=0?(num2[end2]-'0'):0;

        int ret=val1+val2+carry;
        carry=ret/10;
        ret%=10;

      strRet.insert(strRet.begin(),ret+'0');
       --end1;
       --end2;
     }
     if(carry==1)
     {
         strRet.insert(strRet.begin(),'1');
     }
     return strRet;
    }
};

第二种:尾插+逆转

class Solution {
public:
    string addStrings(string num1, string num2) {
     int end1=num1.size()-1,end2=num2.size()-1;
     int carry=0;
     string strRet;
     while(end1>=0||end2>=0)
     {
        int val1=end1>=0?(num1[end1]-'0'):0;
        int val2=end2>=0?(num2[end2]-'0'):0;

        int ret=val1+val2+carry;
        carry=ret/10;
        ret%=10;

       strRet+=ret+'0';
      
       --end1;
       --end2;
     }
     if(carry==1)
     {
         strRet+='1';
     }
     reverse(strRet.begin(),strRet.end());
     return strRet;
    }
};

2.字符串最后一个单词的长度

字符串最后一个单词的长度—牛客

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

int main()
{
    string s1;
    while(getline(cin,s1))
    {
       size_t pos=s1.rfind(' ');
       cout<< s1.size()-(pos+1)<<endl;
    }
    return 0;
}

不能使用流输入cin来输入s1,因为cin和scan遇到空格和换行都会结束,无法完全读取成功,还有一部分会留在缓冲区。所以必须要使用getline来获取完整的一行字符串。

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

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

相关文章

想开发测试工具,应该如何入手?

何为测试工具&#xff1f;就是能辅助测试同学来完成特定的操作的工具&#xff0c;比如常见的如postman、Fiddler、Charles、jira&#xff0c;包括jmeter等&#xff0c;当然还包括公司自己开发的用例转换工具&#xff0c;造数工具&#xff0c;Mock工具或是平台等等。一般以应用程…

测试在“鸡头”和“凤尾”间如何选择?

经常在知乎上碰到这样的问题&#xff1a;同时拿到多个offer&#xff0c;公司有大有小&#xff0c;有创业型有成熟性&#xff0c;怎么在“鸡头”和“凤尾”间做选择&#xff1f; 为什么会纠结呢&#xff1f;通常创业型公司&#xff0c;给优秀的测试员的薪酬远高于市场平均值&…

“我只想找个测试岗,你却百般刁难我!”给我们带来的思考

最近看到一篇帖子&#xff0c;讲的是一个七八年的大龄测试员被公司补偿性裁员后&#xff0c;找工作的糟心经历。 原文是酱紫的&#xff1a; ---------------------------------------- 不管怎么说&#xff0c;我做测试也有七八年了&#xff0c;一直觉得自己的技术还是可以的&…

MongoDB实际场景应用

你要构建一个在线零售商店&#xff0c;这个店铺需要处理会员数据、订单数据以及商品数据等。为了保存和管理这些数据&#xff0c;你可以使用MongoDB。 目录 1. 设计数据模式 2. 插入数据 3. 查询数据 1. 设计数据模式 对于在线零售商店的数据&#xff0c;你可以设计三个Mo…

3年经验,面试测试岗20k都拿不到了吗?

我的情况 大概介绍一下个人情况&#xff0c;女&#xff0c;本科&#xff0c;三年多测试工作经验&#xff0c;懂python&#xff0c;会写脚本&#xff0c;会selenium&#xff0c;会性能&#xff0c;然而到今天都没有收到一份offer&#xff01;从年后就开始准备简历&#xff0c;年…

C#基于云计算SaaS模式的医学检验云LIS系统全套源码

一、云LIS系统概述&#xff1a; 云LIS系统是一种基于云计算技术的实验室信息管理系统&#xff0c;它的主要功能是管理实验室中的各种信息数据&#xff0c;包括样品数据、检测结果、仪器设备管理、质控管理等。 二、与传统的LIS系统相比&#xff0c;云LIS系统具有以下优势&…

考完PMP后,还有必要考NPDP吗?

PMP证书目前在国内有很高的知名度&#xff0c;报考人数也在逐年上升&#xff0c;可以说&#xff0c;几乎所有的项目经理都有过考PMP的计划。 但随着PMP的持证人数越来越多&#xff0c;不少考完PMP的项目经理&#xff0c;开始考虑要不要报名NPDP考试。 那么考完PMP后有必要考N…

软件测试项目拿到不知道从哪里下手?今天我手把手教你

1.登录页面 2.首页 3.项目管理 4.测试环境 1>设置headers&#xff1b;可以每个url设置共同的header&#xff0c;可以存在变量&#xff1b;执行时&#xff0c;指定接口补全header&#xff1b; 5.接口管理 swagger导入功能&#xff1b;根据指定的测试环境url&#xff0c;导入s…

基于javaweb jsp+SSM 网红书店图书借阅系统的设计与实现

一.项目介绍 本系统分为管理员和读者两类 管理员&#xff1a;维护管理员账号和读者账号信息、维护书籍分类信息、维护书籍信息、维护书籍借阅信息、维护书籍预约信息、邮件管理、书籍阅读量统计、系统管理 读者&#xff1a;书籍借阅、书籍预约、预约邮件管理以及个人信息 …

Kubernetes的kubectl命令补全

Kubernetes的kubectl命令补全 环境准备 首先我们需要安装一个kubernetes的集群&#xff0c;可以参考我写的教程&#xff1a; 文档教程&#xff1a;https://blog.csdn.net/m0_51510236/article/details/130842122视频教程&#xff1a;https://space.bilibili.com/34615738341…

【springboot 实践】断点续传这么搞--附代码

目录 背景开搞RandomAccessFileAPI 代码文件分块断点续传、文件秒传分块上传、文件合并 总结 今天给大家分享的又是一篇实战文章&#xff0c;也是最近私活里遇到的&#xff0c;万能的互联网给了我办法&#xff0c;分享一下。 背景 最近接到一个新的需求&#xff0c;需要上传2…

chatgpt赋能python:Python中如何居中输入文字

Python中如何居中输入文字 Python是一种流行的编程语言&#xff0c;因其易学易用而闻名。尽管Python的主要用途是开发程序&#xff0c;但是有时需要在输出中使用美观的文本格式。本文将详细介绍如何在Python中居中输入文字。 什么是文本居中&#xff1f; 文本居中是指将文本…

35 # 模块的断点调试 require 语法实现过程

虚拟机模块&#xff1a;可以创建沙箱环境 const k 100;const vm require("vm"); vm.runInThisContext("console.log(a)");node 中如何实现代码的调试 node 调试指南 1. 可以在浏览器中进行调试&#xff08;比如调试 webpack 等模块可以使用&#xff0…

Arrays.asList()得到的是真的ArrayList?操作修改集合大坑

一、前言 今天在看阿里Java规范的时候看到一条规范&#xff0c;经常使用&#xff0c;却一直没有注意的一条&#xff01; 相信大家应该踩过这个坑&#xff0c;下面来看一看阿里规范里的内容&#xff1a; 【强制】使用工具类 Arrays.asList() 把数组转换成集合时&#xff0c;不…

SpringBoot——SpringBoot服务启动过程源码详解剖析!

文章目录 引言主要流程启动类剖析启动类示例SpringApplication.run()方法 创建SpringApplication对象过程创建对象源码流程整体分析不服就debug 创建对象核心过程分解流程1&#xff1a;deduceFromClasspath()获取主程序类和应用类型流程2&#xff1a; setInitializers()设置初始…

人工智能的崛起:将导致大量工人流离失所

人工智能&#xff08;AI&#xff09;正在迅猛发展&#xff0c;并且已经开始改变世界。过去5到10年间&#xff0c;AI取得了巨大的进步&#xff0c;在某些领域甚至达到了人类水平&#xff0c;例如语音识别。AI的应用范围越来越广泛&#xff0c;其影响已经渗透到社会的方方面面。 …

DataSecurity Plus:强大的企业数据安全解决方案

企业数据安全是当今数字化时代中至关重要的一个议题。随着企业数字化转型的加速和数据泄露事件的频繁发生&#xff0c;保护和管理企业数据变得愈发关键。在这个背景下&#xff0c;DataSecurity Plus作为一款领先的数据安全解决方案&#xff0c;为企业提供了强大的保护机制和全面…

Deeplearing.AI 课程笔记(DLAI)

课程地址&#xff1a; https://learn.deeplearning.ai/chatgpt-prompt-eng OpenAI & Deeplearing.ai Lesson 2&#xff1a;准则 Prompting 的两个基本原则&#xff1a; write clear and specific instructions&#xff0c;第一原则是写清楚提示并给出具体说明to give t…

频谱分辨率、功率密度谱psd

问题&#xff1a; 频谱分辨率的作用是什么&#xff1f; 如频谱分辨率为3HZ,其物理意义是什么 功率密度谱是什么&#xff1f; 功率密度谱和功率的关系是什么&#xff1f; 频率分辨率的定义 DFT后频域相邻刻度之间的实际频率之差&#xff0c;还一般解释为能够分辨出的两个最小的…

Zotero PDF翻译插件自定义翻译功能实现

Zotero PDF翻译插件自定义翻译功能实现 一 需求二、实现演示三、Zetero翻译插件的功能定制3.1 开发环境3.2 开发步骤3.3 插件开发实现3.3.1 添加服务3.3.2 编写任务处理程序3.3.3 导入任务处理程序3.3.4 添加服务名称3.3.5 构建 四、服务器的开发4.1 环境4.2 代码实现 一 需求 …