C++初阶:STL详解(一)——string类

news2024/12/25 9:23:40

✨✨小新课堂开课了,欢迎欢迎~✨✨

🎈🎈养成好习惯,先赞后看哦~🎈🎈

所属专栏:C++:由浅入深篇

小新的主页:编程版小新-CSDN博客

 1.为什么会有string类

C 语言中,字符串是以 '\0' 结尾的一些字符的集合,为了操作方便, C 标准库中提供了一些 str 系列的库函数,但是要实现对字符串的增删查改等操作还是很麻烦的,而且稍不留神可能还会越界访问,所以我们封装了一个string类来处理字符串的各种问题。

2.标准库里的string类

2.1什么是string类

string类的特性:我们可以动态地存储和操作字符串,无需担心内存管理问题,因为它会自动处理字符串的存储和释放,并且支持各种字符串操作,如拼接,比较,查找,替换等。

在使用string类时,必须包含#include头文件以及using namespace std;

下面我们就通过代码的示例了解一些string类的常见用法。

2.2string类的常用接口

1.string类对象的常见构造

void string1()
{
	string s1;  //构建一个空的string对象
	cout << s1 << endl;

	string s2("hello world");//直接用常量字符串来构造
	cout << s2 << endl;

	string s3(5,'x');//用5(n)个字符来构造string对象
	cout << s3 << endl;

	string s4(s2);
	cout << s4 << endl;//拷贝构造

}

运行结果:

2.string类对象的容量操作

函数名称功能说明

size(重点)返回字符串有效字符长度

length返回字符串有效字符长度

capacity返回空间总大小

empty (重点)检测字符串释放为空串,是返回true,否则返回false

clear (重点)清空有效字符

reserve (重点)为字符串预留空间**

resize (重点)将有效字符的个数该成n个,多出的空间用字符c填充

void string2()
{
	string s1("hello world");
	//string s1("hello worldxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
	cout << "s1:" << s1 << endl;

	cout <<"size:" << s1.size() << endl;
	cout << "length:" << s1.length() << endl;
	//size和length没有什么区别,只是size更具有通用性,更推荐使用

	cout << "capacity:" << s1.capacity() << endl;

	//class string
	//{
	//private:
	//	char _buff[16];
	//	char*  _str;
	//
	//	size_t _size;
	//	size_t _capacity;
	//};

	//capcacity就是我们之前所熟知的容量
	//这里补充说明一点:当容量不够时会自动扩容,通常是按1.5倍扩,这个和环境有关
	//在VS中,还特地设有buff存储数据当大于buff时就会将数据拷贝给str,这个过程是按2倍扩的,自后的都是按1.5倍扩

cout <<"empty:"<< s1.empty() << endl;//0表示非空,1表示空

s1.clear();  //清空字符串,不改变底层空间大小
cout << "s1:" << s1 << endl;

s1.reserve(100); //制定开一定的空间(一般都会多开)
cout << "capacity:" << s1.capacity() << endl;

s1.resize(5, 'x');
cout << "s1:" << s1 << endl;//j将有效字符的个数改成5(n)个,多出来的空间,用x填充
cout << "size:" << s1.size() << endl;

s1.resize(20, 'k');
cout << "s1:" << s1 << endl;//j将有效字符的个数改成20(n)个,多出来的空间,用k填充
cout << "size:" << s1.size() << endl;


}

运行结果:

注意:

1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。

2. clear()只是将string中有效字符清空,不改变底层空间大小。

3. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, charc)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。

4. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小。

 小扩展:

我们再来扩展一下与capacity相关的小细节,上面我们即提到1.5倍扩,又提到了2倍扩。具体情况是这样的。

buff的空间开的是16个字节,有一个是‘\0’的位置,我们只能存15个有效字符,当我们要储存的数据小于15字符,该字符串会存到buff里面,而不是str里。

 

当要储存的字符串较大时,就会以buff的容量大小为基础进行扩容,首次是扩容2倍扩,如果空间还是不够,就会1.5倍的进行扩容直至开够足够的空间。 

3. string类对象的访问及遍历操作

函数名称

功能说明

operator[] (重

点)

返回pos位置的字符,const string类对象调用

begin+ endbegin获取一个字符的迭代器 + end获取最后一个字符下一个位

置的迭代器

rbegin + rend

rbegin获取容器最后一个字符 + rend指向容器“反向的开头”,在实际的容器范围之外,它在第一个元素之前。

范围forC++11支持更简洁的范围for的新遍历方式
void string3()
{
	string s1("hello world");
	//三种遍历方法
	//1.下表+[]
	//2.迭代器(正向迭代器  反向迭代器)
	//3.范围for(看起来很高级,底层还是用迭代器实现的)

	//1.下表+[]
	for (int i = 0; i < s1.size(); i++)
	{
		//s[i]+=2;
		cout << s1[i] << ' ';
	}
	//[]能直接访问,修改字符串的内容,把他当成我们所熟知的[]使用即可。

	cout << endl;

	//2.正向迭代器
	string::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << ' ';
		it++;
	}

	cout << endl;

	//3.反向迭代器
	string::reverse_iterator rit = s1.rbegin();
	while (rit != s1.rend())
	{
		cout << *rit << ' ';
		rit++;
	}

	cout << endl;

	//范围for-自动赋值,自动迭代,自动判断结束
	for (auto& ch : s1)
	{
		cout << ch << ' ';
	}

	cout << endl;
}

 运行结果:

在这里补充2个C++11的小语法。

auto关键字

在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,后来这个不重要了。C++11中,标准委员会变废为宝赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。(auto的功能简而言之就是能够自动推导出类型)

用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&,当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

auto不能作为函数的参数,可以做返回值,但是建议谨慎使用

auto不能直接用来声明数组

int func1()
{
	return 10;
} 

//不能做参数
//void func2(auto a)
//{} error

// 可以做返回值,但是建议谨慎使用
auto func3()
{
	return 3;
}

void test()
{
	int a = 10;
	auto b = a;
	auto c = 'a';
	auto d = func1();
	// 编译报错:rror C3531: “e”: 类型包含“auto”的符号必须具有初始值设定项
	//auto e;   推断不出来e的类型 error
	cout << typeid(b).name() << endl;//打印类型名
	cout << typeid(c).name() << endl;
	cout << typeid(d).name() << endl;

	int x = 10;
	auto y = &x;
	auto* z = &x;
	auto& m = x;

	cout << typeid(x).name() << endl;
	cout << typeid(y).name() << endl;
	cout << typeid(z).name() << endl;
	auto aa = 1, bb = 2;
	// 编译报错:error C3538: 在声明符列表中,“auto”必须始终推导为同一类型
	//auto cc = 3, dd = 4.0; error
	// 编译报错:error C3318: “auto []”: 数组不能具有其中包含“auto”的元素类型
	//auto array[] = { 4, 5, 6 }; error

}

运行结果: 

使用场景举例: 

auto在一个变量的类型名很长的时候,就发挥了很大的作用,很便捷,但是也有弊端。

 auto自动推断类型
map<string, string> dict;
map<string, string>::iterator mit = dict.begin();
auto mit = dict.begin();//自动推导出mit的类型
使用起来更加便捷,但是代码的可读性会降低

范围for 

对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。

for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束

范围for可以作用到数组和容器对象上进行遍历,范围for的底层很简单,容器遍历实际就是替换为迭代器,这个从汇编层也可以看到。

void test2()
{
	int array[] = { 1, 2, 3, 4, 5 };
	// C++98的遍历
	for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
	{
		array[i] *= 2;
	}
	
	for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
	{
		cout << array[i]<<" ";
	} 

	cout << endl;

		// C++11的遍历
        //自动迭代,自动取数据,自动判断结束
	for (auto& e : array)
			e *= 2;

	for (auto e : array)
		cout << e << " " ;

	cout << endl;

	string str("hello world");
	for (auto ch : str)
	{
		cout << ch << " ";
	} 
		cout << endl;

}

运行结果:

4.string类对象的修改操作 

函数名称功能说明
push_back在字符串后尾插字符c
append在字符串后追加一个字符串
operator+= (重点)在字符串后追加字符串str
c_str(重点)返回C格式字符串
find + npos(重点)从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
rfind从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
substr在str中从pos位置开始,截取n个字符,然后将其返回
void string4()
{
	string s1("hello world");

	
	s1.push_back('x');
	cout << "push_back后:";
	cout << s1 << endl;  //尾插一个字符c

	s1.append("abc");
	cout << "append后:";
	cout << s1 << endl;//尾插一个字符串

	s1.operator+=("hello");
	cout << "operator+=后:";
	cout << s1<<endl;//尾插一个字符串

	cout << "c_str:";
	const char* str = s1.c_str();
	cout << str << endl;//返回C格式字符串

	//c_str主要是用来将string对象转化为C风格的字符串指针,用于传给const char*类型参数的函数

	cout << "find:";
	//size_t find (char c, size_t pos = 0) const;
	int num1 = s1.find('e');
	cout << num1 << endl;//pos位置开始往后找字符c,返回该字符在字符串中的位置(正着找)

	cout << "rfind:";
	//ize_t rfind (char c, size_t pos = npos) const;
	//npos static const size_t npos = -1;
	//his constant is defined with a value of - 1, which because size_t is an unsigned integral type,
	// it is the largest possible representable value for this type.
	//总结:npos是一个很大数,该类型的最大值
	int num2 = s1.rfind('e');
	cout << num2 << endl;//pos位置开始往前找字符c,返回该字符在字符串中的位置(倒着找)

	cout << "s1:" << s1 << endl;
	cout << "substr:";
	//string substr (size_t pos = 0, size_t len = npos) const;
	string tmp = s1.substr(2, 5);//从pos位置开始,截取n和字符,然后返回
	cout << tmp << endl;


}

运行结果: 

注意:

1. 在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。

2. 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。

5.string类非成员函数

函数功能说明

operator+尽量少用,因为传值返回,导致深拷贝效率低

operator>> (重点)输入运算符重载

operator<< (重点)输出运算符重载

getline (重点)获取一行字符串

relational operators (重点)大小比较

void string5()
{
	string s1("hello world");
	string s2("xiaoxin");
	//string operator+ (const string & lhs, const string & rhs);
	cout << "operator+:";
	cout << operator+(s1, s2) << endl;//涉及深拷贝,效率低下,尽量少用

	cout << "operator+>>";//输入运算符重载
	string s3;
	operator>>(cin, s3);
	cout << s3 << endl;

	cout << "operator<<";
	operator<<(cout,s1) << endl;

	//getline 获取一行字符
	//getline与比如getchar,scanf之类的区别在于,后者的两个一般都是以空格,换行符分界
	//如果输入带空格的字符串,后者就会将其当成两个字符串,从而读不到空格
	//getline就能读到中间的空格,将其当成一个字符串
	//istream& getline(istream & is, string & str, char delim);
	// 第一种,delim默认是遇到换行符截止
	//istream& getline(istream & is, string & str);
	//这一种是遇到str截止

	//relational operators
	//这个函数库里包含了各种比较大小的函数,函数类型为bool类型
	//知道是这样的就可以
	std::string foo = "alpha";
	std::string bar = "beta";

	if (foo == bar) std::cout << "foo and bar are equal\n";
	if (foo != bar) std::cout << "foo and bar are not equal\n";
	if (foo < bar) std::cout << "foo is less than bar\n";
	if (foo > bar) std::cout << "foo is greater than bar\n";
	if (foo <= bar) std::cout << "foo is less than or equal to bar\n";
	if (foo >= bar) std::cout << "foo is greater than or equal to bar\n";
	
}

运行结果:

 

 3.总结

以上介绍的都是string类的主要接口,还有一些string的接口不常用,感兴趣的可以可以自己学一下,下面是我自己整理的,还比较全面,希望有所帮助。下一篇我们就来介绍string类的模拟实现。

感谢各位的观看~

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

//class string
//{
//private:
//	char _buff[16];
//	char* _str;
//	size_t size;
//	size_t capacity;
//
//};


//构造
void string1()
{
	string s1;
	string s2("hello world");
	string s3(s2);

	cout << s1 << endl;
	cout << s2 << endl;
	cout << s2 << endl;

	//string (const string& str, size_t pos, size_t len = npos);
	//有多少拷贝多少
	string s4(s2, 6, 15);
	cout << s4 << endl;

	//npos是有缺省值的,可以不传
	string s5(s2, 6);
	cout << s5 << endl;

	//拷贝前n个字符
	string s6("hello world", 5);
	cout << s6 << endl;

	string s7(10, 'x');
	cout << s7 << endl;
}

//三种遍历方式
void string2()
{
	string s1("hello world");

	//小标+[]
	for (size_t i = 0; i < s1.size(); i++)
	{
		cout << s1[i] << ' ';
	}

	cout << endl;

	//迭代器
	string::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << ' ';
		it++;
	}

	cout << endl;

	//范围for-自动赋值,自动迭代,自动判断结束
	//底层其实就是迭代器
	for (auto& ch : s1)
	{
		cout << ch << ' ';
	}

	cout << endl;

	//auto自动推断类型
	//map<string, string> dict;
	//map<string, string>::iterator mit = dict.begin();
	//auto mit = dict.begin();
	//使用起来更加便捷,但是代码的可读性会降低

}

//迭代器
void string3()
{
	//iterator begin();
	string s2("hello world");
	string::iterator it = s2.begin();
	while (it != s2.end())
	{
		*it += 2;
		cout << *it << ' ';
		it++;
	}
	cout << endl;

	string::reverse_iterator rit = s2.rbegin();
	while (rit != s2.rend())
	{
		cout << *rit << ' ';
		rit++;
	}
	cout << endl;

	//const_iterator begin() const;
	const string s3("hello world");
	string::const_iterator cit = s3.begin();
	while (cit != s3.end())
	{
		//*cit += 2;
		cout << *cit << " ";
		++cit;
	}
	cout << endl;

	string::const_reverse_iterator rcit= s3.rbegin();
	while (rcit != s3.rend())
	{
		// *rcit += 2;
		cout << *rcit << " ";
		++rcit;
	}
	cout << endl;
	 
	//只读不写
	//const_iterator cbegin() const noexcept;
	string::const_iterator csit = s3.cbegin();
	while (csit != s3.cend())
	{
		cout << *csit << " ";
		++csit;
	}
	cout << endl;

	
	string::const_reverse_iterator csrit = s3.crbegin();
	while (csrit != s3.crend())
	{
		cout << *csrit << " ";
		++csrit;
	}
	cout << endl;

	//begin()返回一个普通的迭代器,可读可写;cbegin()返回一个常量迭代器
	//只读不写
}

void TestPushBack()
{
	// reverse 反转  逆置
	// reserve 保留、预留
	string s;
	// 提前开空间,避免扩容,提高效率
	s.reserve(10);
	size_t sz = s.capacity();//15
	cout << "capacity changed: " << sz << '\n';

	cout << "making s grow:\n";
	for (int i = 0; i < 100; ++i)
	{
		s.push_back('c');
		if (sz != s.capacity())
		{
			sz = s.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}
	//31 47 70  105

	//刚开始是二倍扩,后面大概是1.5倍扩
	//因为刚开始是有个buff存在的,小于buff空间大小就存在buff里面
	//当大于buff的容量时,就会存到_str里面,地方发生转变的这次是2倍扩,后面在堆上的时候就
	//大概是1.5倍扩了
}

void string4()
{
	string s2("hello world");
	//size和length没有区别,只是size更具有通用性,更推荐使用
	cout << s2.size() << endl;
	cout << s2.length() << endl;
	//都不包含\0
	cout << s2.max_size() << endl;
	cout << s2.capacity() << endl;

	//resize:将字符串的长度调整为n个字符
	//void resize(size_t n);
	//void resize(size_t n, char c);
	s2.resize(5);
	//多的部分用X填充
	s2.resize(12, 'x');
	cout << s2 << endl;

	string s1("hello worldxxxxxxxxxxxxx");
	cout << s1.size() << endl;//24
	//不够会扩容,一般是以1.5倍进行扩容
	cout << s1.capacity() << endl << endl;//31


	//在VS下一般不会缩容,但是不同的平台不一样,例如g++就会缩容
	s1.reserve(20);
	cout << s1.size() << endl;//24
	cout << s1.capacity() << endl << endl;//31

	//这里就没有缩容
	//缩容也有规定,缩容不会缩的比size小
	s1.reserve(28);
	cout << s1.size() << endl;//24
	cout << s1.capacity() << endl << endl;//31

	//扩容
	s1.reserve(40);
	cout << s1.size() << endl;//24
	cout << s1.capacity() << endl << endl;//47

	s1.clear();//清空字符串,但是容量不变
	cout << s1.size() << endl;//0
	cout << s1.capacity() << endl << endl;//47

	//判断字符串是否为空
	std::string str1 = "";
	if (str1.empty()) {
		std::cout << "字符串为空" << std::endl;
	}
	else {
		std::cout << "字符串不为空" << std::endl;
	}
		
	//std::string::shrink_to_fit
	//与reserve相比,这个更有约束力一些,该函数会请求减少string占用的空间
	//以适用于当前的内容大小,但是也不一定

	string s4("hello");
	s4.shrink_to_fit();
	cout << s4.size() << endl;//5
	cout << s4.capacity() << endl << endl;//15
	//原本大小就小于15的,这里就没有缩容

	std::string str(100, 'x');
	std::cout << "1. capacity of str: " << str.capacity() << '\n';//111

	str.resize(10);
	std::cout << "2. capacity of str: " << str.capacity() << '\n';//111

	str.shrink_to_fit();
	std::cout << "3. capacity of str: " << str.capacity() << '\n';//15
	//这里就缩容了
}


//元素访问
void string5()
{
	//operator[]和at用法上没有区别
	//oparator[]里面是断言,越界会报错;但是at越界会抛异常,抛out_of_range的异常
	//back()函数用于获取字符串的最后一个字符
	//front用于获取字符串的第一个字符

}

//调节器modifier
void string6()
{
	//operator+=
	string s("hello world");
	s.operator+=('x');
	s.operator+=("hxxxxxxx");
	s.operator+=(s);

	s += 'y';
	s += "3333333";
	s += s;

	cout << s << endl;
	cout << endl << endl;

	//append
	//append除了和operator+=上面相同的用法外,还有下面的用法
	//1.string& append (const string& str, size_t subpos, size_t sublen);
	//用于将一个字符串str,从指定的subpos位置开始,长度为sublen追加到当前字符串的末尾
	string s1("hello world");
	s1.append(s1, 2, 4);
	cout << s1 << endl;
	
	//string& append (const char* s, size_t n);
	s1.append("xxxxx", 3);
	cout << s1 << endl;

	//string& append (size_t n, char c);
	s1.append(3,'h');
	cout << s1 << endl;

	//template <class InputIterator>
	//string& append(InputIterator first, InputIterator last);
	std::vector<char> vec = { 'w','r','o','l','d' };
	s1.append(vec.begin(), vec.end());
	cout << s1 << endl;
	//补充一点:first和last不一定就是起始位置和终止位置;也可以是自己指定位置
	//但是string类里只给了begin和end,这就需要自定义迭代器,现在我还不会

	//void push_back (char c);
	s1.push_back('l');

	//assign - 用来给字符串赋予新的值
	//string& assign(const string & str);
	string s3("hello world");
	s3.assign(s1);
	cout << s3 << endl;

	//string& assign(const string & str, size_t subpos, size_t sublen);
	s3.assign(s1, 5, 7);
	cout << s3 << endl;
	
	//string & assign(const char* s);
	s3.assign("xxxxx");
	cout << s3 << endl;//xxxxx
	
	//string& assign(const char* s, size_t n);
	s3.assign("hello world", 5);
	cout << s3 << endl;
	
	//string& assign(size_t n, char c);
	s3.assign(5, 's');
	cout << s3 << endl;
	
	//template <class InputIterator>
	//string& assign(InputIterator first, InputIterator last);
	std::vector<char> charvec = { 'h','e','l','l','o' };
	s3.assign(charvec.begin(), charvec.end());
	cout << s3 << endl;
	
	//insert
	//用法总结:在指定位置插入单个字符、字符串,另一个字符串的一部分
	//使用迭代器进行插入操作


	//replace
	//用于替换字符串里的一部分内容
	
	//erase
	//string& erase (size_t pos = 0, size_t len = npos);
	//有缺省值可以不给
	s3.erase(0, 3);//从第几个位置删除几个字符
	cout << s3 << endl;

	s3.erase(s3.begin());//删除第一个字符
	cout << s3 << endl;

	s3.erase(--s3.end());//尾删
	cout << s3 << endl;
	//end()并不是指向最后一个字符,而是最后一个字符的下一个位置
	
	//swap
	//void swap(string & str);
	s3.swap(s1);//交换s1与s3的内容
	cout << s3 << endl;
	cout << s1 << endl;

	//pop_back
	//删除最后一个字符

}


void string7()
{
	//c_str-返回字符串的指针
	//data也是返回一个字符串的指针
	//copy和substr都可用于拷贝字符或者字符串
	//size_t copy (char* s, size_t len, size_t pos = 0) const;
	//copy是将string里的内容拷贝到外部的字符串数组s中;
	// string substr (size_t pos = 0, size_t len = npos) const;
	//而substr是将string里提取子字符串返回一个新的string对象
	//find是找一个字符,字符串,string对象;rfind是倒着找
	// 找到返回索引;找不到返回string::npos
	//find_first_of
	std::string str("Please, replace the vowels in this sentence by asterisks.");
	std::cout << str << '\n';

	std::size_t found = str.find_first_of("abcdef");//找到任意一个都返回索引
	while (found != std::string::npos)
	{
		str[found] = '*';
		found = str.find_first_not_of("abcdef", found + 1);

	}
	//find_last_of是倒着找
	//find_first_not_of是找不到返回索引;find_last_not_of是倒着找,找不到返回索引
	//cpmpare不参与,用的比较多的运算符重载
	//get_allocator还不会


}

void string8()
{
	//oparator+  用于字符串的拼接
	// 可以连接两个string对象;string对象和字符串字面量;字符串字面量和string对象
	//这里解释一下要实现字符串字符串字面量+string对象的底层;该函数不是成员函数,或者将其设为全局函数
	//举个例子,双目操作符的左操作数默认为类对象,字符串字面量+string对象这个就行不通
	string s1("hello");

	string s2 = s1 + "world";
	cout << s2 << endl;

	string s3 = "world" + s1;
	cout << s3 << endl;

	//swap
	//这个和上面的一个的使用方式不同,两个参数
	//void swap (string& x, string& y);

	//getline
	//getline与比如getchar,scanf之类的区别在于,后者的两个一般都是以空格,换行符分界
	//如果输入带空格的字符串,后者就会将其当成两个字符串,从而读不到空格
	//getline就能读到中间的空格,将其当成一个字符串
	//istream& getline(istream & is, string & str, char delim);
	// 第一种,delim默认是遇到换行符截止
	//istream& getline(istream & is, string & str);
	//这一种是遇到str截止
}

int main()
{
	string8();
	//TestPushBack();
	
	return 0;
}
///

// 范围for和auto的扩展

//auto不能做参数,但是可以做返回值,不过不建议使用
//范围for适用于容器和数组

//int func1()
//{
//	return 10;
//}
//
 不能做参数
void func0(auto a = 0)
{}

//但是能做返回值,不过不建议使用
//auto func2()
//{
//	//...
//	return func1();
//}
//
//auto func3()
//{
//	//...
//	return func2();
//}

//int main()
//{
//	int a = 10;
//	auto b = a;
//	auto c = 'a';
//	auto d = func1();
//	// 编译报错:rror C3531: “e”: 类型包含“auto”的符号必须具有初始值设定项
//	//auto e;
//	cout << typeid(b).name() << endl;
//	cout << typeid(c).name() << endl;
//	cout << typeid(d).name() << endl;
//
// auto不能用于数组
//	//auto array[] = { 4, 5, 6 };
//
//	auto ret = func3();
//
//	int array[] = { 1, 2, 3, 4, 5 };
//	// C++98的遍历
//	for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
//	{
//		array[i] *= 2;
//	}
//	for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
//	{
//		cout << array[i] << endl;
//	}
//	
//	// yyds
//	// 范围for适用于容器 和 数组
//	// C++11的遍历
//	for (auto& e : array)
//		e *= 2;
//
//	for (auto e : array)
//		cout << e << " " << endl;
//
//	return 0;
//}

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

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

相关文章

Nodejs中使用Minio

Minio 安装Minio MinIO下载 下载完&#xff0c;服务端和客户端后&#xff0c;最好像我这样做&#xff0c;去分一下路径。 安装完后&#xff0c;进入bin目录输入以下指令&#xff1a; # 设置账户 setx MINIO_ROOT_USER admin# 设置密码 setx MINIO_ROOT_PASSWORD password# …

高效办公必备!图片转PDF功能,让工作更轻松

在数字化时代&#xff0c;将图片转换为PDF格式是一项非常实用的技能&#xff1b;无论是在工作、学习还是生活中&#xff0c;我们都可能遇到需要将图片转化为PDF格式的情况&#xff1b;今天通过这篇文章给大家分享四款好用的图片转pdf 的工具&#xff1a; 第一款&#xff1a;福…

flutter开发实战-flutter web加载html及HtmlElementView的使用

flutter开发实战-flutter web加载html及HtmlElementView的web控件 HtmlElementView 是 Flutter 中用于嵌入 HTML 内容的 widget。这个 widget 允许你将一个 HTML 元素嵌入到 Flutter 应用中。 一、HtmlElementView基本使用 在工程的pubspec.yaml中引入插件 HtmlElementView…

多波束EM2040D以及POSMV使用记录

多波束EM2040D采集软件SIS4.3升级到SIS5.11之后&#xff0c;我们碰到了很多问题&#xff0c;现在将问题和解决过程记录一下。 1、SIS5软件打不开 SIS5软件打不开&#xff0c;报KSlSMainApp has stopped working弹框。 ​ 判断是电脑问题&#xff0c;更新最新win10系统&#…

ue5 伤害插件

主角或敌人都能用的插件&#xff0c;复用性很高 首先创建以下插件、接口、类型文件 两个枚举中的参数名称&#xff0c;E_DamageResponse区分是各个伤害后的反应&#xff0c;比如不同伤害造成的动画或粒子特效等的不同&#xff0c;E_DamageType是伤害类型&#xff0c;有各种伤害…

【网络安全】空字节绕过:URL回调+XSS+SQL绕WAF

未经许可,不得转载。 文章目录 空字节URL回调XSSSQL空字节 \0,也称为null字节,是一个值为零的特殊字符。在编程中,通常用来表示字符串的结束。攻击者可以利用null字节注入来绕过一些验证或过滤机制。 以下三个漏洞,空字节功不可没。 URL回调 密码重置功能,发起请求后…

【牛站 / USACO2007】

题目 思路 离散化&#xff08;降低空间复杂度&#xff09; 点的编号 ∈ [ 1 , 1000 ] &#xff0c;但是点的个数最多为 2 ⋅ T ∈ [ 4 , 200 ] 点的编号 \in [1, 1000]&#xff0c;但是点的个数最多为 2 \cdot T \in[4, 200] 点的编号∈[1,1000]&#xff0c;但是点的个数最多为…

【NLP】大模型长文本处理技术与GLM-4-Plus评测

本文将介绍Transformer模型在处理长文本数据时所采用的关键技术&#xff0c;特别是旋转位置编码&#xff08;RoPE&#xff09;和Flash Attention机制。 此外&#xff0c;本文介绍GLM系列模型&#xff0c;特别是最新发布的GLM-4-Plus模型。我们将通过实际的评测方法和结果&…

管理学习(一)马云《赢在中国》创业演讲整理

目录 一、小公司也需要制度二、不要害怕冒险三、创业者要的不是技术&#xff0c;而是胆识四、不要惧怕和大企业竞争五、理念不一样&#xff0c;老板永远是对的六、要真实地为客户创造价值七、跟风险投资谈判&#xff0c;说到要做到八、风险投资&#xff0c;只能帮你不能救你九、…

24秋开学考

文件上传 上传一个.php的格式&#xff0c;上面说是非法的文件格式。 2.传了一个phpinfo.gif&#xff0c;说什么在目录里。 3.有两个页面一个labs1一个labs2 &#xff0c;当在第一个页面上传1.jpg&#xff0c;在第二个页面上传1.jpg时&#xff0c;给了我们一个目录,在测试其他时…

[图解]识别类和属性-投资少见效快产量高

1 00:00:00,530 --> 00:00:04,360 接下来&#xff0c;我们就要来识别实体类和属性了 2 00:00:05,670 --> 00:00:07,260 前面也讲了&#xff0c;从哪里识别 3 00:00:08,120 --> 00:00:11,470 从用例规约那里来识别 4 00:00:12,400 --> 00:00:15,770 在识别的时候…

气膜体育馆投资前景广阔:健康产业中的新兴机遇—轻空间

气膜体育馆作为一种新型的建筑形式&#xff0c;为投资者带来了丰富的商业机会。随着全民健身的理念普及&#xff0c;气膜体育馆在市场上逐渐展现出巨大潜力。 市场需求不断增长 随着健康意识提升&#xff0c;人们对运动场地的需求日益增加。气膜体育馆凭借其灵活的建筑形式&…

【线性代数】正定矩阵,二次型函数

本文主要介绍正定矩阵&#xff0c;二次型函数&#xff0c;及其相关的解析证明过程和各个过程的可视化几何解释&#xff08;深蓝色字体&#xff09;。 非常喜欢清华大学张颢老师说过的一段话&#xff1a;如果你不能用可视化的方式看到事情的结果&#xff0c;那么你就很难对这个…

select、poll、epoll的区别

select、poll、epoll均为linux中的多路复用技术。3种技术出现的顺序是select、poll、epoll&#xff0c;3个版本反应了多路复用技术的迭代过程。我们现在开发网络应用时&#xff0c; 一般都会使用多路复用&#xff0c;很少有用一个线程来监听一个fd的&#xff0c;其中epoll又是最…

鸿蒙开发5.0【Picker的受限权限适配方案】

Picker由系统独立进程实现&#xff0c;应用可以通过拉起Picker组件&#xff0c;用户在Picker上选择对应的资源&#xff08;如图片、文档等&#xff09;&#xff0c;应用可以获取Picker返回的结果。 类型受限权限使用的picker音频ohos.permission.READ_AUDIO&#xff0c;ohos.p…

【无人机设计与控制】 四轴飞行器的位移控制

摘要 本文介绍了一种四轴飞行器的位移控制方法&#xff0c;并通过Simulink模型进行仿真和验证。该方法通过PID控制器对飞行器的位移进行精确调节&#xff0c;以实现飞行器在三维空间中的稳定定位和路径跟踪。通过参数调节&#xff0c;能够适应不同的飞行任务需求&#xff0c;确…

UnLua环境搭建

一、环境搭建 1、下载UnLua工程&#xff1a;https://github.com/Tencent/UnLua 2、复制Plugins/UnLua目录下的插件到自己的项目中 3、重新生成自己的VS工程 4、打开VS工程的项目名.Build.cs文件&#xff0c;引用UnLua插件,重新编译工程 PublicDependencyModuleNames.AddRan…

【Nacos】Nacos快速上手使用(注册中心)【详解】

文章目录 1.基本介绍2. 使用Nacos服务注册中心2.1创建Nacos提供者集群 8001&#xff0c;80022.2创建Nacos消费者集群 8887 1.基本介绍 Nacos(Dynamic Naming and Configuration Service)是服务中心的另外一种实现。从注册中心的功能实现角度&#xff0c;与Eureka等价&#xff…

HumanNeRF:Free-viewpoint Rendering of Moving People from Monocular Video 翻译

HumanNeRF&#xff1a;单目视频中运动人物的自由视点绘制 引言。我们介绍了一种自由视点渲染方法- HumanNeRF -它适用于一个给定的单眼视频ofa人类执行复杂的身体运动&#xff0c;例如&#xff0c;从YouTube的视频。我们的方法可以在任何帧暂停视频&#xff0c;并从任意新的摄…

Python批量读取身份证信息录入系统和重命名

前言 大家好&#xff0c; 如果你对自动化处理身份证图片感兴趣&#xff0c;可以尝试以下操作&#xff1a;从身份证图片中快速提取信息&#xff0c;填入表格并提交到网页系统。如果你无法完成这个任务&#xff0c;我们将在“Python自动化办公2.0”课程中详细讲解实现整个过程。…