【C++初阶】STL之学习string的用法

news2024/9/24 19:21:16

目录

  • 前言:
  • 一、认识下string
    • 1.1 什么是string
    • 1.2 为什么要有string
  • 二、string 类的接口使用
    • 2.1 初始化与析构
      • 2.1.1 初始化
      • 2.1.2 析构
    • 2.2 容量操作
      • 2.2.1 长度大小——size和length
      • 2.2.2 空间总大小——capacity
      • 2.2.3 判空——empty
      • 2.2.4 清空——clear
      • 2.2.5 预留空间——reserve
      • 2.2.6 改变有效字符个数、填充多余空间——resize
    • 2.3 遍历访问
      • 2.3.1 下标遍历——operator[]
      • 2.3.2 范围for
      • 2.3.3 迭代器遍历——iterator
    • 2.4 修改操作
      • 2.4.1 尾插字符——push_back
      • 2.4.2 尾插字符串——append
      • 2.4.3 字符串追加字符串——operator+=
      • 2.4.4 赋值——assign
      • 2.4.5 插入——insert
      • 2.4.6 删除——erase
      • 2.4.7 查找——find
      • 2.4.8 替换——replace
      • 2.4.9 返回C格式字符串——c_str
      • 2.4.10 截取字符串——substr
    • 2.5 输入操作
      • 2.5.1 获取一行字符串——getline

前言:

STL是C++的标准模板库,里面包含了许多算法和数据结构,例如我们熟悉的顺序表、链表、栈和队列以及一些常见的算法等等,编程者想使用这些就可以直接从库中调用,不必再自己造轮子了。

下面为STL内容的一张图:
在这里插入图片描述
接下来,我们要学习STL中的string。

一、认识下string

1.1 什么是string

string 是C++的一个类模板,字符串的类模板。要定义一个对象为字符串,就可以用string类型,说明它是一个字符串,相当于字符数组。

int main()
{
	string s1("hello yss");
	return 0;
}

1.2 为什么要有string

以前我们用C语言写代码的时候,假如字符串如果要计算它的长度,必须要调用C标准库中的函数才行。但是这些函数与字符串本身是分开的,与C++面向对象的思想不契合,而且很容易出现越界等错误,所以C++提供了string类,类里就有我们想使用的函数来操作字符串,我们只需要调用类的接口(函数)即可,更加简洁。

二、string 类的接口使用

string类有许多接口,这里只介绍一些常见的

2.1 初始化与析构

2.1.1 初始化

1️⃣无参与有参
在这里插入图片描述
在这里插入图片描述

int main()
{
	string s1();//无参 空字符串

	string s2("hello yss");//有参
	cout << s2 << endl;
	return 0;
}

在这里插入图片描述

注意:括号里字符串也可以是一个字符,但是必须要 " y " 这样写,不能 ’ y ’ 这种写法,否则会报错。

2️⃣字符填充
在这里插入图片描述
前面的参数表示字符串的长度,后面的参数是要填充的字符。

int main()
{
	string s1(5, 'y');
	cout << s1 << endl;
	return 0;
}

在这里插入图片描述

3️⃣拷贝构造
在这里插入图片描述

int main()
{
	string s1("hello yss");
	string s2(s1);
	cout << s2 << endl;
	return 0;
}

在这里插入图片描述
另一种写法:

int main()
{
	string s1("hello yss");
	string s2 = s1;//用已经存在的对象去拷贝构造刚未存在的对象
	cout << s2 << endl;
	return 0;
}

在这里插入图片描述

4️⃣拷贝子字符串
在这里插入图片描述
pos是从这位置开始拷贝,len是拷贝的个数

int main()
{
	string s1("hello yss");
	string s2(s1, 3, 5);//如果最后一个参数的值大于后面的
	  //长度,那么就直接把从pos位置开始的字符串全部拷贝构造
	cout << s2 << endl;
	return 0;
}

一个空格也算一个字符
在这里插入图片描述
我们发现len=npos,说明这是一个半缺省,也就是说最后的参数可以不写。

string s2(s1, 3);

npos表示size_t的最大值,作用是返回一个字符串中不存在的位置,可以判断某个子字符串是否存在。

2.1.2 析构

了解下即可
在这里插入图片描述
作用就是清理。

2.2 容量操作

2.2.1 长度大小——size和length

有两个操作函数,都可以计算字符串的有效长度
在这里插入图片描述
在这里插入图片描述

int main()
{
	string s1("hello yss");
	cout << s1.size() << endl;
	cout << s1.length() << endl;
	return 0;
}

在这里插入图片描述
一般计算大小使用size更好,因为size表示大小即长度,length表示长度,链表、顺序表有长度的说法,但是后面要学习到的树就没有所谓的长度了,只有大小,所以,为了方便且统一,计算的大小都使用size更好些。

2.2.2 空间总大小——capacity

在这里插入图片描述
给对象预分配好一定大小的空间。如果字符串的有效长度小于预分配的空间,空间大小不变;否则再次分配一定大小的空间

int main()
{
	string s1("hello yss");
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	string s2("hello yssxxxxxxxxxxxxxxxx");
	cout << s2.size() << endl;
	cout << s2.capacity() << endl;
	return 0;
}

在这里插入图片描述

2.2.3 判空——empty

在这里插入图片描述

int main()
{
	string s1("hello yss");
	cout << s1.empty() << endl;
	string s2;
	cout << s2.empty() << endl;
	return 0;
}

在这里插入图片描述

2.2.4 清空——clear

在这里插入图片描述
清空的是有效字符,总空间大小不变

int main()
{
	string s1("hello yss");
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	s1.clear();
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	return 0;
}

在这里插入图片描述

2.2.5 预留空间——reserve

在这里插入图片描述
1️⃣参数是缺省值,所以参数可写可不写,不写默认缺省值为0,小于空间大小(capacity()的预留空间大小),空间大小不变,不改变字符串中的内容。

int main()
{
	string s1("hello yss");
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	s1.reserve();
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	return 0;
}

在这里插入图片描述

2️⃣参数的值大于0,小于有效字符的个数

int main()
{
	string s1("hello yss");
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	s1.reserve(6);
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	return 0;
}

在这里插入图片描述
小于空间总大小,所以空间总大小不变,不影响字符串的内容。

3️⃣参数的值大于等于有效字符个数,小于空间总大小

int main()
{
	string s1("hello yss");
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	s1.reserve(12);
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	return 0;
}

在这里插入图片描述
还是因为预留的空间小于空间总大小,所以空间总大小不变,且不影响字符串的内容。

4️⃣参数的值大于空间总大小

int main()
{
	string s1("hello yss");
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	s1.reserve(20);
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	return 0;
}

在这里插入图片描述
当预留空间大于空间总大小时,就会再分配新的空间大小,字符串的内容还是不受影响。

5️⃣调用两次,第二次参数比第一次小

int main()
{
	string s1("hello yss");
	s1.reserve(111);
	cout << s1.capacity() << endl;
	s1.reserve(6);
	cout << s1.capacity() << endl;
	return 0;
}

在这里插入图片描述
第一次调用预留空间的大小扩容后,第二次比第一次要小,不会改变,说明reserve没有缩容的功能。

总结:
1.当reserve预留的空间小于等于空间总大小时,空间总大小不变;
2.reserve预留空间不影响字符串的内容
3.reserve不能缩容。

reserve预留的空间大于空间总大小就会重新分配新的空间总大小,那么这空间总大小的增长规律是怎样的呢,看一下代码:

int main()
{
	string s1("hello yss");
	size_t len = s1.capacity();
	for (int i = 0; i < 100; i++)
	{
		s1.push_back('x');
		while (len != s1.capacity())
		{
			len = s1.capacity();
			cout << len << endl;
		}
	}
	return 0;
}

在这里插入图片描述
大概是以1.5倍的大小增长,不同的编译器可能不同。

2.2.6 改变有效字符个数、填充多余空间——resize

在这里插入图片描述
可支持两种写法,一个参数的表示有效字符个数,两个参数的分别为有效字符个数和要填充的字符。

1.先来一个参数的写法:
1️⃣参数的值小于有效字符个数

int main()
{
	string s1("hello yss");
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	s1.resize(3);
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	return 0;
}

在这里插入图片描述
有效字符个数改变,字符串的内容也改变,空间总大小不变。

2️⃣参数的值大于有效字符个数、小于空间总大小

int main()
{
	string s1("hello yss");
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	s1.resize(12);
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	return 0;
}

在这里插入图片描述
有效字符个数改变,字符串内容不变(没有填充字符),空间总大小不变。

3️⃣参数的值大于空间总大小

int main()
{
	string s1("hello yss");
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	s1.resize(20);
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	return 0;
}

在这里插入图片描述
有效字符个数改变,字符串内容不变(没有填充字符),空间总大小改变。

2.有第二个参数(填充字符)的写法:
1️⃣参数的值小于有效字符个数

int main()
{
	string s1("hello yss");
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	s1.resize(3, 'a');
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	return 0;
}

在这里插入图片描述
有效字符个数改变,字符串内容受影响,空间总大小不变。

2️⃣参数的值大于有效字符个数、小于空间总大小

int main()
{
	string s1("hello yss");
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	s1.resize(12, 'a');
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	return 0;
}

在这里插入图片描述
有效字符个数改变,字符串增加的空间填充字符,空间总大小不变。

3️⃣参数的值大于空间总大小

int main()
{
	string s1("hello yss");
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	s1.resize(20, 'a');
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	return 0;
}

在这里插入图片描述
有效字符个数改变,字符串增加的空间填充字符,空间总大小增加。

总结:
1.resize影响有效字符个数,小于原来有效字符个数时,字符串内容随之改变;
2.当n的值(第一个参数)大于原来的有效字符个数会在后面填充字符;
3.n小于空间总大小,空间总大小不变;否则会扩容。

2.3 遍历访问

2.3.1 下标遍历——operator[]

在这里插入图片描述
有两种写法,一个是operator关键字+运算符,另一个是直接方括号下标。

int main()
{
	string s1("hello yss");
	for (size_t i = 0; i < s1.size(); i++)
	{
		cout << s1.operator[](i) << " ";
		//cout << s1[i] << " ";
	}
	cout << endl;
	return 0;
}

在这里插入图片描述

2.3.2 范围for

int main()
{
	string s1("hello yss");
	for (auto e : s1)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

在这里插入图片描述

2.3.3 迭代器遍历——iterator

在这里插入图片描述
它是可以检查容器内的元素并遍历元素的数据类型,写法先看以下代码:

int main()
{
	string s1("hello yss");
	string::iterator s = s1.begin();
	while (s != s1.end())
	{
		cout << *s << " ";
		s++;
	}
	cout << endl;
	return 0;
}

s相当于一个指针,首先得到的是字符串的第一个字符,只要它不等于斜杠0,循环打印出每个字符,等于斜杠0跳出。

那么begin()和end()又是什么呢?
在这里插入图片描述
在这里插入图片描述
begin返回容器的首元素,end返回容器的最后一个元素的下一个地址。
在这里插入图片描述
还有加const的写法,用于函数调用时为了不改变字符串的内容形参加const,对应的迭代器也要加const

void Func(const string& ss)
{
	string::const_iterator s = ss.begin();
	while (s != ss.end())
	{
		cout << *s << " ";
		s++;
	}
	cout << endl;
}
int main()
{
	string s1("hello yss");
	Func(s1);
	return 0;
}

注意:是const_iterator,中间是下划线,与const iterator是不同的。const_iterator限制的指针指向的内容,所以指针指向的内容不能修改const iterator限制的是指针本身,也就是说地址不能修改。

如果要逆置字符串该怎样操作呢
1️⃣先用以前的方法:

int main()
{
	string s1("hello yss");
	string::iterator s = s1.begin();
	while (s != s1.end())
	{
		cout << *s << " ";
		s++;
	}
	cout << endl;
	size_t begin = 0;
	size_t end = s1.size() - 1;
	while (begin < end)
	{
		char tmp = s1[begin];
		s1[begin] = s1[end];
		s1[end] = tmp;
		begin++;
		end--;
	}
	s = s1.begin();
	while (s != s1.end())
	{
		cout << *s << " ";
		s++;
	}
	return 0;
}

在这里插入图片描述
这里交换两个元素时要自己写,感觉有点麻烦,可以使用模板

2️⃣交换模板:

template<class T>
void Swap(T& a, T& b)
{
	T t = a;
	a = b;
	b = t;
}
int main()
{
	string s1("hello yss");
	string::iterator s = s1.begin();
	while (s != s1.end())
	{
		cout << *s << " ";
		s++;
	}
	cout << endl;
	size_t begin = 0;
	size_t end = s1.size() - 1;
	while (begin < end)
	{
		Swap(s1[begin], s1[end]);
		begin++;
		end--;
	}
	s = s1.begin();
	while (s != s1.end())
	{
		cout << *s << " ";
		s++;
	}
	return 0;
}

不看顶上的交换模板函数,循环里的代码比前面简洁了一些,但是还是感觉挺繁琐的

3️⃣逆置算法函数:
在这里插入图片描述

int main()
{
	string s1("hello yss");
	string::iterator s = s1.begin();
	while (s != s1.end())
	{
		cout << *s << " ";
		s++;
	}
	cout << endl;
	reverse(s1.begin(), s1.end());
	s = s1.begin();
	while (s != s1.end())
	{
		cout << *s << " ";
		s++;
	}
	return 0;
}

在这里插入图片描述

不用逆置算法函数,也可以逆序遍历
在这里插入图片描述
在这里插入图片描述

int main()
{
	string s1("hello yss");
	string::reverse_iterator s = s1.rbegin();
	while (s != s1.rend())
	{
		cout << *s << " ";
		s++;
	}
	cout << endl;
	return 0;
}

在这里插入图片描述
这两个接口的也有const,与前面的同理

void Func(const string& ss)
{
	string::const_reverse_iterator s = ss.rbegin();///
	while (s != ss.rend())
	{
		cout << *s << " ";
		s++;
	}
	cout << endl;
}
int main()
{
	string s1("hello yss");
	Func(s1);
	return 0;
}

有没有发现其中一段代码太长了,所以这里就就可以用以前学过的auto来简化代码

auto s = ss.rbegin();//自动推导类型

2.4 修改操作

2.4.1 尾插字符——push_back

在这里插入图片描述

int main()
{
	string s1("hello yss");
	s1.push_back('x');
	cout << s1 << endl;
	return 0;
}

在这里插入图片描述

2.4.2 尾插字符串——append

这个接口的可实现方式比较多,所以这里只介绍常见的
在这里插入图片描述

int main()
{
	string s1("hello yss");
	s1.append("a");
	cout << s1 << endl;
	s1.append("vvvv");
	cout << s1 << endl;
	return 0;
}

在这里插入图片描述
因为是字符串,所以要双引号,但是双引号里也可以是一个字符。

2.4.3 字符串追加字符串——operator+=

在这里插入图片描述
这个比前面两个都要实用得多了,既可以尾插字符串,也可以尾插字符。而且写起来也方便。

int main()
{
	string s1("hello yss");
	s1 += "vvvv";
	cout << s1 << endl;
	string s2("hello yss");
	s2 += 'd';
	cout << s2 << endl;
	string s3("hello yss");
	s3 += s1;
	cout << s3 << endl;
	return 0;
}

在这里插入图片描述

2.4.4 赋值——assign

在这里插入图片描述
1️⃣用一个字符串赋给另一个字符串

int main()
{
	string s1("hello yss");
	string s2 = s1.assign(s1);
	cout << s2 << endl;
	return 0;
}

在这里插入图片描述

2️⃣从一个字符串中提取子字符串赋给另一个字符串

int main()
{
	string s1("hello yss");
	string s2;
	s2.assign(s1,2,5);
	cout << s2 << endl;
	return 0;
}

在这里插入图片描述

3️⃣一个字符串赋给另一个字符串

int main()
{
	string s2;
	s2.assign("yyyyyyyy");
	cout << s2 << endl;
	return 0;
}

在这里插入图片描述

4️⃣一个字符串赋给另一个字符串,限定个数

int main()
{
	string s2;
	s2.assign("yyyyyyyy", 3);
	cout << s2 << endl;
	return 0;
}

在这里插入图片描述

5️⃣字符赋给一个字符串,有个数控制

int main()
{
	string s3;
	s3.assign(10, 'x');
	cout << s3 << endl;
	return 0;
}

在这里插入图片描述

2.4.5 插入——insert

1️⃣
在这里插入图片描述
从pos位置插入一个字符串,和可以限制插入字符串的个数。

int main()
{
	string s1("hello yss");
	s1.insert(1, "ccc");
	cout << s1 << endl;

	string s2("hello yss");
	s2.insert(3, "cccccc",3);
	cout << s2 << endl;
	return 0;
}

在这里插入图片描述
2️⃣
在这里插入图片描述
从pos位置插入一个字符串。第二个有点长,在第一个的基础上可以选择要插入的字符串的起始的位置,并且限制插入的个数。

int main()
{
	string s3("hello yss");
	string s4("hello world");
	s4.insert(5, s3);
	cout << s4 << endl;

	string s5("hello yss");
	string s6("hello world");
	s6.insert(5, s5,2, 3);
	cout << s6 << endl;
	return 0;
}

在这里插入图片描述
3️⃣
在这里插入图片描述
插入字符,可以控制个数

int main()
{
	string s7("hello yss");
	s7.insert(5, 4, 'x');
	cout << s7 << endl;
	return 0;
}

在这里插入图片描述

2.4.6 删除——erase

在这里插入图片描述
1️⃣从pos位置开始删除len个字符,这两个参数都是缺省值,如果不写参数,就是一个字符串全部删除;
2️⃣删除某个位置的字符;
3️⃣删除从一个位置到另一个位置的字符串。

int main()
{
	string s1("hello yss");
	s1.erase();
	cout << s1 << endl;

	string s2("hello yss");
	s2.erase(3,5);
	cout << s2 << endl;

	string s3("hello yss");
	s3.erase(s3.begin());
	cout << s3 << endl;

	string s4("hello yss");
	s4.erase(s4.begin() + 1, s4.end() - 1);
	cout << s4 << endl;

	return 0;
}

在这里插入图片描述

2.4.7 查找——find

在这里插入图片描述
查找有一个字符串或者字符,后面没有参数就默认从字符串的起始位置开始找,有写参数从pos位置开始找

int main()
{
	string s1("hello yss");
	size_t pos = s1.find(" ");
	cout << pos << endl;
	return 0;
}

在这里插入图片描述

2.4.8 替换——replace

在这里插入图片描述
用len个90#替换pos位置的字符

int main()
{
	string s1("hello yss");
	s1.replace(5, 1, "90#");
	cout << s1 << endl;
	return 0;
}

在这里插入图片描述

小练习:把一个字符串内的所有空格替换成20%
1️⃣做法1:

int main()
{
	string s1("hello yss hello world");
	size_t pos = s1.find(" ");
	while (pos != string::npos)
	{
		s1.replace(pos, 1, "20%");
		pos = s1.find(" ", pos + 3);
	}
	cout << s1 << endl;
	return 0;
}

在这里插入图片描述

假如一个字符串内有多个空格,先用pos记录第一个空格的位置,当pos不等于npos成立,说明在字符串中找到了这个pos位置,然后在这个位置替换成20%。因为前面的pos已经用过一次了,所以这里要重新定义新的pos位置找后面的空格。参数为pos+3是因为20%有3个字符,所以要跳过这3个字符开始查找。直到后面没有空格,找不到,返回整型的最大值,为-1,然后跳出循环。

find()接口的一个说明:找不到返回npos
在这里插入图片描述

这里再介绍下npos:
在这里插入图片描述
它是静态成员常量,值为-1,是无符号类型的,所以也是整型的最大值。

2️⃣做法2:

int main()
{
	string s1("hello yss hello world");
	string s2;
	for (auto e : s1)
	{
		if (e == ' ')
		{
			s2 += "20%";
		}
		else
		{
			s2 += e;
		}
	}
	s1.swap(s2);//交换
	cout << s1 << endl;
	return 0;
}

在这里插入图片描述
创建一个临时字符串,遍历原来的字符串,如果是空格,在临时的字符串+=空格,否则+=原来字符串中的字符。如果不想用临时字符串打印出来,可以交换。

2.4.9 返回C格式字符串——c_str

在这里插入图片描述
可以将 const string* 类型 转化为 const char* 类型,因为在c语言中没有string,所以要把它转变成C语言中字符串的形式。

在文件操作中C语言和C++混着用:

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

在这里插入图片描述

2.4.10 截取字符串——substr

在这里插入图片描述
因为两个参数都有缺省值,两个都不写,就相当于直接取整个字符串了;后面的参数不写,从pos位置开始截取剩下的全部字符串。

1️⃣截取 . 和它后面的字符串

int main()
{
	string s1("test.cpp");
	size_t pos = s1.find('.');
	if (pos != string::npos)
	{
		string s2 = s1.substr(pos);
		cout << s2 << endl;
	}
	return 0;
}

在这里插入图片描述

2️⃣如果一个字符串内有多个点,要截取最后一个点以及后面的字符串

int main()
{
	string s1("test.cpp.xxx");
	size_t pos = s1.rfind('.');
	if (pos != string::npos)
	{
		string s2 = s1.substr(pos);
		cout << s2 << endl;
	}
	return 0;
}

在这里插入图片描述
用原来的find()要从头开始找,比较麻烦。所以string还提供了另一个查找的函数——rfind(),可以逆向查找,即从后向前。

3️⃣分割网址

int main()
{
	string s("https://cplusplus.com/reference/string/string/substr/");
	string s1, s2, s3;
	size_t pos1 = s.find(':');
	if (pos1 != string::npos)
	{
		s1 = s.substr(0, pos1);
		cout << s1 << endl;
	}
	size_t pos2 = s.find('/', pos1 + 3);
	if (pos2 != string::npos)
	{
		s2 = s.substr(pos1 + 3, pos2 - pos1 - 3);
		cout << s2 << endl;
	}
	s3 = s.substr(pos2 + 1);
	cout << s3 << endl;

	return 0;
}

在这里插入图片描述

网址的格式:
<协议>://<服务器名称>.<域名>/<目录>/<文件名>

我们是想分割成3个部分,所以定义3个string 对象,一个一个分割。首先分割出协议,先要找到冒号的位置,冒号的位置的pos1的值即为前面字符串的有效个数,所以截取字符串从起始位置开始截取pos1个。第二个分割出服务器名称和域名,要找的截至位置是 / ,但是要注意从pos1+3的位置开始找,找到后也是从pos1+3的位置开始截取,截取pos2 - pos1 - 3个。最后一个不必多说。

2.5 输入操作

2.5.1 获取一行字符串——getline

在这里插入图片描述
istream& is表示一个输入流,例如cin;char delim表示终止符,例如回车,或者别的符号。

1️⃣自己定义终止符

int main()
{
	string s1;
	getline(cin, s1,'#');
	cout << s1 << endl;
	return 0;
}

在这里插入图片描述

2️⃣自己没有定义终止符

int main()
{
	string s1;
	getline(cin, s1);
	cout << s1 << endl;
	return 0;
}

在这里插入图片描述
自己没有写终止符,默认的终止符为回车

那么这个有什么用呢?在输入一行字符串的时候,如果我们使用的是cin,它的默认终止符为空格或者换行,所以如果我们输入的字符串中有空格,打印出来的结果就不会是一行。

看以下代码:

int main()
{
	string s1;
	cin >> s1;
	cout << s1 << endl;
	return 0;
}

在这里插入图片描述
所以如果在做题中还是在其他写代码的场景要求输出一整行字符串,getline就是一个好的选择。

在这里插入图片描述

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

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

相关文章

使用v-md-editor开发sql查看器--实战

v-md-editor markdown编辑器 文档&#xff1a;https://code-farmer-i.github.io/vue-markdown-editor/zh/ echo 创建一个空目录&#xff0c;使用vscode打开此空目录&#xff0c;进入终端&#xff0c;输入如下命令 npm create vitelatest . -- --template vue echo 选择 vue 和 …

Linux:gdb调试器的解析+使用(超详细版)

Linux调试器-gdb 背景&#xff1a; 程序的发布方式有两种&#xff0c;debug模式和release模式 debug模式&#xff1a;可以被调试&#xff1b; release模式&#xff1a;不可以被调试。 为什么需要debuy和release这两个模式呢&#xff1f; 答&#xff1a;程序员在开发的时候需要…

git提交报错error: failed to push some refs to ‘git url‘

1.产生错误原因 想把本地仓库提交到远程仓库&#xff0c;报错信息如下 git提交报错信息 error: src refspec master does not match any error: failed to push some refs to git url 错误原因&#xff1a; 我们在创建仓库的时候&#xff0c;都会勾选“使用Reamdme文件初始化…

论文导读 | 10月专题内容精选:人的预测

编者按 本次论文导读&#xff0c;编者选择了10月份OR和MS上与"人的预测"有关的三篇文章&#xff0c;分别涉及群体智慧的提取&#xff0c;个体序列预测的评估&#xff0c;以及决策者对风险的扭曲感知在分布式鲁棒优化中的应用。其中&#xff0c;从基于"生成式可能…

【LeetCode】挑战100天 Day14(热题+面试经典150题)

【LeetCode】挑战100天 Day14&#xff08;热题面试经典150题&#xff09; 一、LeetCode介绍二、LeetCode 热题 HOT 100-162.1 题目2.2 题解 三、面试经典 150 题-163.1 题目3.2 题解 一、LeetCode介绍 LeetCode是一个在线编程网站&#xff0c;提供各种算法和数据结构的题目&…

用SOLIDWORKS画个高尔夫球,看似简单的建模却大有学问

SOLIDWORKS软件提供了大量的建模功能&#xff0c;如果工程师能灵活使用这些功能&#xff0c;就可以绘制得到各式各样的模型&#xff0c;我们尝试使用SOLIDWORKS绘制高尔夫球模型&#xff0c;如下图所示。 为什么选用solid works进行建模&#xff1f; solid works是一款功能强大…

N-134基于java实现捕鱼达人游戏

开发工具eclipse,jdk1.8 文档截图&#xff1a; package com.qd.fish;import java.awt.Graphics; import java.io.File; import java.util.ArrayList; import java.util.List;import javax.imageio.ImageIO;public class Fishes {//定义一个集合来管理鱼List<Fish> fish…

vue005——vue组件入门(非单文件组件和单文件组件)

一、非单文件组件 1.1、单文件组件的使用 1.1.1、局部注册 1、第一步&#xff1a;创建school组件 2、第二步&#xff1a;注册组件&#xff08;局部注册&#xff09; 3、第三步&#xff1a;使用组件&#xff08;编写组件标签&#xff09; <!DOCTYPE html> <html>…

VBA即用型代码手册之工作薄的关闭保存及创建

我给VBA下的定义&#xff1a;VBA是个人小型自动化处理的有效工具。可以大大提高自己的劳动效率&#xff0c;而且可以提高数据的准确性。我这里专注VBA,将我多年的经验汇集在VBA系列九套教程中。 作为我的学员要利用我的积木编程思想&#xff0c;积木编程最重要的是积木如何搭建…

【教学类-06-07】20231124 (55格版)X-X之间的加法、减法、加减混合题

背景需求 在大四班里&#xff0c;预测试55格“5以内、10以内、20以内的加法题、减法题、加减混合题”的“实用性”。 由于只打印一份20以内加法减法混合题。 “这套20以内的加减法最难”&#xff0c;我询问谁会做&#xff08;摸底幼儿的水平&#xff09; 有两位男孩举手想挑…

pairplot

Python可视化 | Seaborn5分钟入门(七)——pairplot - 知乎 (zhihu.com) Seaborn是基于matplotlib的Python可视化库。它提供了一个高级界面来绘制有吸引力的统计图形。Seaborn其实是在matplotlib的基础上进行了更高级的API封装&#xff0c;从而使得作图更加容易&#xff0c;不需…

Mybatis一级缓存和二级缓存原理剖析与源码详解

Mybatis一级缓存和二级缓存原理剖析与源码详解 在本篇文章中&#xff0c;将结合示例与源码&#xff0c;对MyBatis中的一级缓存和二级缓存进行说明。 MyBatis版本&#xff1a;3.5.2 文章目录 Mybatis一级缓存和二级缓存原理剖析与源码详解⼀级缓存场景一场景二⼀级缓存原理探究…

mac VScode 添加PHP debug

在VScode里面添加PHP Debug 插件,根据debug描述内容操作 1: 随意在index里面写个方法,然后用浏览器访问你的hello 方法,正常会进入下边的内容 class IndexController {public function index(){return 您好&#xff01;这是一个[api]示例应用;}public function hello() {phpin…

【ArcGIS Pro微课1000例】0036:栅格影像裁剪与提取(矢量范围裁剪dem高程数据)

本实验讲解在ArcGIS Pro中进行栅格影像裁剪与提取(矢量范围裁剪dem高程数据)的方法。DEM、DOM、DSM等栅格数据方法也可以实现。 文章目录 一、加载实验数据二、裁剪工具的使用1. 裁剪栅格2. 按掩膜提取一、加载实验数据 加载配套实验数据包中的0036.rar中的dem数据和矢量裁剪…

【21年扬大真题】编写程序,去除掉字符串中所有的星号。

【21年扬大真题】 编写程序&#xff0c;去除掉字符串中所有的星号。 int main() {int i 0;int j 0;char arr[30] {0};char brr[30] {0};printf("请输入一个字符串:");gets(arr);for (i 0;i < 30;i){if (arr[i] ! *) {brr[j] arr[i];j;}}int tmp j;for (i …

RK3399 板子烧录Armbian

本来不想写在CSDN这里的。帮有需要的同学了吧。 板子上面标记型号为&#xff1a; GC18-108-RK3399-V2.0TEAN E120339 94V-OML1没有HDMI接口&#xff08;我也是汗&#xff0c;买的时候注意到&#xff0c;坑了&#xff09;&#xff0c;配置信息。 CPU : RK3399RAMROM: 4G16G无…

高性能计算HPC所面临的问题

一、电力墙问题 能源动力领域关注高性能计算主要关注其能效和功耗等问题&#xff0c;也就是在高性能计算&#xff08;High-Performance Computing, HPC&#xff09;领域中&#xff0c;所谓的"电力墙"&#xff08;Power Wall&#xff09;&#xff0c;电力墙是一个描述…

ddns-go部署在linux虚拟机

ddns-go部署ubuntu1804 1.二进制部署 1.虚拟机部署 1.下载linux的x86二进制包 wget https://github.com/jeessy2/ddns-go/releases/download/v5.6.3/ddns-go_5.6.3_linux_x86_64.tar.gz2.解压 tar -xzf ddns-go_5.6.3_linux_x86_64.tar.gz3.拷贝执行文件到PATH下&#xff0c…

VMware虚拟机安装华为OpenEuler欧拉系统

首先去欧拉官方网站下载openEuler的安装镜像&#xff1a; openEuler下载 | 欧拉系统ISO镜像 | openEuler社区官网 我下载的是最新的23.03长期维护版本&#xff0c;架构选择x86_64。 创建新虚拟机&#xff1a;选择典型配置&#xff0c;点击下一步&#xff1a;选择下载的镜像文…

html table样式的设计 表格边框修饰

<!DOCTYPE html> <html> <head> <meta http-equiv"Content-Type" content"text/html; charsetutf-8" /> <title>今日小说排行榜</title> <style> table {border-collapse: collapse;border: 4px double red; /*…