笔记会持续更新,有错误的地方欢迎指正,谢谢!
前言:这一章我们主要介绍两种十分常用的标准库类型:string表示可变长字符串,vector表示可变长的容器。还会介绍迭代器,它是string和vector的配套类型,用于访问string中的字符或vector中的元素。
在开始介绍标准库类型之前,先简单学习一下命名空间的using声明:
我们用到的库函数基本都属于命名空间std,
using namespace std;
//这样就可以访问std中所有的名字,但是很多用不到,程序开销会变大。头文件不应包含using声明
因为头文件的内容在编译时会被拷贝到所有引用它的文件中去,如果头文件中有某个using声明,那么每个使用了该头文件的文件就都会有这个声明,很有可能产生一些名字冲突。
using声明的总结:每个using声明引入命名空间的一个成员,头文件中的代码一般不应使用using声明。
string定义
string表示可变长的字符序列,使用string必须包含下述代码:
#include <string> //要使用string类型,必须要包含string头文件。
using std::string; //string作为标准库的一部分,它定义在命名空间std中。
定义和初始化string对象
string s1; //s1
默认初始化,是一个空字符串
string s2 = s1;
等价于 string s2(s1);
//s2是s1的副本
string s3 = "hello";
等价于 string s3("hello");
//字符串字面值赋值
string s4(3, 'c');
//s4 = “ccc”;
对s1有个小问题,s1和”“相等吗?相等!
直接初始化和拷贝初始化
-拷贝初始化:使用等号初始化一个变量,编译器把等号右边的值拷贝到左边新建的对象中;
-直接初始化:不使用等号。
例子:
string s6 = "world";
//拷贝初始化
string s7("heihei");
//直接初始化
当初始值只有一个时,两种初始方法都行,但初始值有多个(如下),则最好使用直接初始化。
string s8(3, 'c');
//直接初始化
string对象上的操作
读写string
可使用IO操作读写string对象
int main()
{
string s;
cin >> s;//读取操作,从标准输入的内容读取到s中。
cout << s << endl;//输出s
return 0;
}
在执行读取操作时,string对象会自动忽略开头的空白(空格,换行,制表)并从第一个真正的字符开始读起,直到遇见下一处空白为止。 例子:如果输入” Bill Chen “,输出一定是”Bill”。 string对象也支持连续输入输出:
例子:
string s1, s2;
cin >> s1 >> s2; //第一个输入到s1,第二个输入到s2
cout << s1 << s2 << endl; //输出两个string对象
这段程序如果输入” Bill Chen “,输出是”BillChen” 。
只有这样的一种输入方式肯定不够,因为它只能读取数量确定的一个一个的单词,太复杂啦!救世主在下方!
读取未知数量的string
代码如下:
int main()
{
string word;
while(cin >> word)
{
cout << word << endl;
}
return 0;
}
使用getline读取一整行
有时候,我们还希望能在最终得到的字符串中保留输入的空白符,这时可用getline函数代替>>运算符。
int main()
{
string line;
while(getline(cin, line))//从输入流中读入内容直到读入换行符,保留空白符,但换行符不存入string对象中。
{
cout << line << endl;//一次输出一整行后再换行,再循环。
}
return 0;
}
strng的size函数和empty函数
empty()返回的是布尔类型;
size()返回string对象中字符的个数。
string::size_type类型
size()返回一个string::size_type类型的数,该类型是无符号类型,当表达式中存在有符号类型和无符号类型时,所有的操作数都转换为无符号类型。例子:假设n是一个负整型数,s.size()<n;
的判断结果一定为true,因为n自动转换为了比较大的无符号数。但int n=s.size();
和s.size()<80;
都是对的,因为未出现负数。
比较string对象
直接贴代码,读者就知道了啊。
string s0 = "Hello";
string s1 = "Hello";
string s2 = "Hello Bill";
string s3 = "Hi";
string s4 = "hi";
//大小结果:s0=s1<s2<s3<s4
**总结:**1.前面相同的话,长度长的则大;2.两个string对象在对应位置上不同,则比较第一对相异的两个字符;3.依照大小写敏感的字典顺序(大写 排在 小写 前)。
为string对象赋值
string类 允许把一个对象的值赋给另一个对象。
例子:
string str = "Hello";
string str1 = str;
两个string对象相加
string s1 = "Hello", s2 = " Bill";
s1 += s2; //s1 = s1 + s2,s1的内容变为Hello Bill
字面值和string对象相加
准则:字符字面值和字符串字面值都可转化为string对象,相加时加号两侧的运算对象至少有一个是string型:
原因:由于历史原因,也为了和C兼容,所以C++中的 字符串字面值 和 标准库类型string的对象 并不是同类型!
string s1 = "hello", s2 = "bill";
string s3 = s1 + ", " + s2; //正确
string s4 = "hello" + "bill"; //错误:两个运算对象都不是string
string s5 = s1 + ", " + "bill"; //正确:第一个加号的结果就是string
string s6 = "hello" + ", " + s2; //错误
处理string对象中的字符
题型: 比如检查一个string对象是否包含空白,或者把大写改为小写,或者查看某个特定字符是否出现等。
解答:如何获取字符本身并改变之?用cctype头文件中的标准库函数。
补充:C++标准库不仅自定义了C++特有的功能外,还兼容了C语言的标准库。所以,在C语言中的头文件name.h,C++将它命名为cname。这里的c表示这是一个属于C语言标准库的头文件。
使用 范围for语句 遍历处理每个字符
范围for语句:c是由str中的字符一个个地拷贝过去的,处理c即可。
简单的例子:每行输出str中的单个字符
string str("hey bill");
for(auto c : str)
cout << c << endl;
这里用auto来决定c的类型,这里c是char,每次迭代,str的下一个字符被拷贝给c。
复杂点的例子:统计一个string对象中标点符号的个数
string s("Hello World!!!??");
int punct_cnt = 0;
for(auto c : s)
{
if(ispunct(c))
{
++punct_cnt ;
}
}
punct_cnt 为5,不用解释啦。另外,[ ]符号中的数是什么类型的呢?s.size()返回值的类型?punct_cnt原本应该是什么类型呢?都是string的size_type,即无符号数。无符号数可默认转为有符号数;有符号数转无符号数看正负。
使用 范围for语句 遍历改变字符
如果我想把一个string对象中的小写字母都改成大写呢?
先看看下面的代码对不对?
string s("hello");
for(auto c : s)
{
c = toupper(c);//若c是小写则输出大写,否则原样输出。tolower则相反。
}
cout << s << endl;
SORRY!是错的,因为c是由s中的字符拷贝过去的,跟s没啥关系。 其实只需要改一个地方就好:
string s("hello");
for(auto &c : s)
{
c = toupper(c);
}
cout << s << endl;
以上是我们在处理string中所有字符的情况,只处理一部分字符呢?
只处理一部分字符呢?
当然是选择用 下标运算符[ ] 咯!
例子:我们只想把字符串中第一个字符改为大写,其他不变:
string s("some thing");
if(!s.empty()) //别忘了这个条件,提升代码的鲁棒性!
{
s[0] = toupper(s[0]);
}
使用下标执行迭代
例子:把s的第一个单词变成大写,其他不变:
string s("some thing");
for(int i=0;i<s.size()&&s[i]!='';++i)
s[i]=toupper(s[i]);
使用下标执行随机访问
例子:编写一个程序把0-15之间的十进制数转换成对应的十六进制数:
const string str= "0123456789ABCDEF";
string result;
int n;
while(cin >> n)//有效输入则进入循环,将标准输入赋给n。
{
if(n < 16)
{
result+= str[n]; //根据n获取到字符数组元素呗!
}
cout << result<< endl;
}