标准库类型string
零.前言
终于到了一个C++里比较重要的一个玩意儿了,string
。因为C语言对字符串非常不友好,所以有必要熟练掌握C++里的string
类。
本文会讲最常用的string
操作,后面的第九节也会讲述其他的string
操作。
嗷,对了,string
是std里的类型,所以我们除了#include<string>
,还需要using std::string;
一.定义和初始化string对象
1.初始化例子
最常用几个初始化string的例子:
string s1;
string s2 = s1;
string s3 = "kanna";
string s4(5,'c'); // s4是ccccc
如果默认初始化一个string对象,则会得到一个没有任何字符的string对象。如果提供了一个字符串字面值,则该字面值中除了最后一个空字符外其他所有的字符都会被拷贝到新创建的string对象中。
2.直接初始化和拷贝初始化
如果使用等号=
就是执行的拷贝初始化
,如果不使用等号,就是直接初始化
。
string s3 = "kanna"; //直接初始化
string s4(5,'c'); //拷贝初始化
当然,也可以这样拷贝初始化:
string s3 = string(5,'c');
二.string对象上的操作
用后面的知识说,就是对已知方法的重写,就是让 +-*/==
这些符号也支持这个类型。
1.读写string对象
读:
string s;
cin >> s;
string
对象会忽略开头的空白(空格符、换行符、制表符等),从第一个真正的字符开始读起,直到遇到下一处空白。
string s;
cin >> s; //输入“ Hello World ”
cout << s; //输出“Hello”
当然,你也可以连续输入与输出:
string s1, s2;
cin >> s1 >> s2; //输入“ Hello World ”
cout << s1 << s2; //输出“HelloWorld”
2.读一整行
如果我们想保留字符串中的空白符,我们除了可以通过循环读取,保存为多个string
对象这种方法,我们可以通过内置函数getline
读取一整行。他会一直读取流中的数据,直到遇见一个换行符
,然后保存之前读到的内容,并舍弃掉换行符,就如同这个代码,可以把多行输入换成一行输出:
string line;
while(getline(cin, line))
cout << line;
return 0;
3.empty和size操作
empty
顾名思义,结果根据对象是否为空,返回一个对应的布尔值,比如上文中,我们可以尝试用line.empty()
来查看line是否为空。
size
会返回string
对象的长度,你可以理解为调用size
可以返回string
里有多少个char
。
4.string::size_type
对于这个类,你可以理解为string
类为了统一在不同编译器下,string
长度能够合理表示,它创建了一个临时变量
,它的内存占用空间可能等同于int
或者unsigned int
,.size()
函数就是返回的这个类型。具体使用的时候,可以通过auto
或者decltype
去声明它,亦或者使用字面值让编译器自动转换成它。
5.比较string对象
> <
这几个符号都遵守以下规律
- 如果两个
string
长度不同,较短的string
对象的每个字符都与长的string
对象一样,就说明这个短的小于长的 - 如果某些位置上不一致,那么就是比较第一个不相同的ascii码的大小值。
eg: abcdefg < abcdefgh
、abcd < d
6.赋值
如果两个变量都为string
对象,那么直接用赋值符号=
就可以了
7.相加
这里的相加是追加
,就如同
string a = "123", b = "456";
a += b;
//此时 a = "123456"
8.字面值和string对象相加
C/C++中,字面值都不是标准的string
变量,所以无法让两个字面值相加,但是在string
对象的加法中,字面值会变成一个strting
类参与运算,所以我们可以通过string
对象来使得字面值相加
仔细理解这段话后,写出以下代码
#include<iostream>
#include<string>
using namespace std;
int main()
{
string temp = "123";
temp = temp + "456";
cout << temp << endl; //123456
temp = "000" + temp;
cout << temp << endl; //000123456
temp = "000" + "111" + temp;
cout << temp << endl; //error: invalid operands of types 'const char [4]' and 'const char [4]' to binary 'operator+'
return 0;
}
所以,我们只要记住,要想最后结果为string
,+
两侧一定要有一个string
类
三.处理string对象中的字符
1.C++中的C语言头文件
为了使得C++
兼容C
,C++
对其“老版本”的库,进行了兼容性移植,现在可以把C语言的库xxx.h
换成cxxx
,并在c++
中使用。比如使用cctype
库对string
中的每个字符进行操作。
2.处理每个字符?使用基于范围的for语句
来了,新for语句来了!
for (declaration : expression)
statement
其中declaration
负责定义一个变量,用于访问序列中的基础元素,expression
是一个对象,用于表示一个序列。每次迭代,declaration
部分的变量会被初始化为expression
部分的下一个元素值。
就类似于python
中的“”:for x in xxxx:
比如这个代码,可以把"123"变成"234"
string temp = "123";
for (auto c : temp){
cout << char(c + 1);// 编译器把c+1会当成整型,并输出505152,所以强制转换一下
}
3.使用范围for,改变字符串中的值
还是上面的例子,我们试试:
string temp = "123";
for (auto c : temp){
c += 1;
}
cout << temp; //123
啊这,好像并没有改变到temp的值。因为前面说过:declaration
部分的变量会被初始化为expression
部分的下一个元素值。所以这里的c,其实是一个新对象,所以为了修改temp的值,我们应该把它设置为引用
:
string temp = "123";
for (auto &c : temp){
c += 1;
}
cout << temp; //234
4.只处理一部分字符
要想访问中的某一个字符,一是使用下标,二就是使用迭代器。迭代器后面会讲,这里就讲讲下标运算符[ ]
string
对象位置从0开始计数,最后一个是.size() - 1
。
比如sting a = "123"
,那么:a[0] = '1'
,a[1] = '2'
,a[2] = '3'
, a[a.size() - 1] = '3'
。
而[]
接收的参数是string::size_type
,当然你用0这些整型字面值代替就可以了。
但一定要记住:0<= 下标 < .size(),否则会出现奇怪的错误
5.使用下标执行随机访问
也就是说[]
里的值,不一定是连续的,只要是在0<= 下标 < .size()
就都可以,官方给了个哈希表的程序,我就不展示了,懒得敲。以前博客《C语言中的数组用法》里简单说过。