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

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

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

所属专栏: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类对象的常见构造

cpp 复制代码
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填充 |

cpp 复制代码
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+ end | begin获取一个字符的迭代器 + end获取最后一个字符下一个位 置的迭代器 |
| rbegin + rend | rbegin获取容器最后一个字符 + rend指向容器"反向的开头",在实际的容器范围之外,它在第一个元素之前。 |
| 范围for | C++11支持更简洁的范围for的新遍历方式 |

cpp 复制代码
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*没有任何区别,但用a**uto声明引用类型时则必须加&,**当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

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

auto不能直接用来声明数组

cpp 复制代码
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的底层很简单,容器遍历实际就是替换为迭代器,这个从汇编层也可以看到。

cpp 复制代码
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个字符,然后将其返回 |

cpp 复制代码
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 (重点) | 大小比较 |

cpp 复制代码
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类的模拟实现。

感谢各位的观看~

cpp 复制代码
#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;
//}
相关推荐
一棵开花的树,枝芽无限靠近你21 分钟前
【PPTist】添加PPT模版
前端·学习·编辑器·html
做人不要太理性24 分钟前
【C++】深入哈希表核心:从改造到封装,解锁 unordered_set 与 unordered_map 的终极奥义!
c++·哈希算法·散列表·unordered_map·unordered_set
程序员-King.33 分钟前
2、桥接模式
c++·桥接模式
chnming198737 分钟前
STL关联式容器之map
开发语言·c++
VertexGeek40 分钟前
Rust学习(八):异常处理和宏编程:
学习·算法·rust
程序伍六七1 小时前
day16
开发语言·c++
小陈phd1 小时前
Vscode LinuxC++环境配置
linux·c++·vscode
二进制_博客1 小时前
Flink学习连载文章4-flink中的各种转换操作
大数据·学习·flink
火山口车神丶1 小时前
某车企ASW面试笔试题
c++·matlab
codebolt2 小时前
ADS学习记录
学习