标准库类型string是可变长的字符序列,如果使用该类型,必须包括string,同时,string是std空间中的名字,因此,使用前需要:
#include <string>
using std::string
一、string的定义和初始化
string的初始化方式如下:
string s1; //默认初始化,s1为空串
string s2 = s1; //使用来为s2初始化,是赋值初始化
string s2(s1); //使用来为s2初始化,是直接初始化
string s3 = "value"; //使用字面值"value"来为s2初始化,是赋值初始化
string s3("value"); //使用字面值"value"来为s2初始化,是直接初始化
string s4(n,'c'); //s4初始化为n个c组成的字符串
- 使用等号的是拷贝初始化,不使用等号的是直接初始化
- 在使用字符串初始化的时候string会丢弃字符串最后面的换行符
二、string对象的操作
string的读写操作
使用cin和cout进行string读写
string s;
cin >> s; //读取输入到字符串
cout << s << endl; //写出字符串到输出
- 读取字符串会忽略开头的空白(包括空格,换行符,制表符),遇见下一个空白停止。如读取" abc “,最后只读取"abc”
- 可以多个输入一起读取,输入时中间留空白就可以 cin >> s1 >> s2;
- 当使用cin >> s 作为判断条件时候,正常读取为真;非法输入或者读取到文件结尾符号为假,使用该条件可以逐个单词读取整个文件
- 但是直接使用字符串字面值给string赋值的时候可以包含空格和制表符,不能包括换行符,如string a = “HELLO WORD”,则a是会包括中间的空格的
使用getline进行string读取
string s1;
getline(is,s); //从文件is中读取一整行给s
getline(cin,s); //从标准输入中读取一整行给s
- getline读取时候遇见空格和制表符不跳过,只有遇见换行的时候停止读取
- getline会读取换行,但在给字符串赋值的之后会丢弃换行
- 使用getline()作为判定条件,当读取到非法数据或者文件末尾的时候为假,使用该条件可以逐行读取整个文件
string的empty和size
string s;
s.empty(); s为空返回true,s为非空返回false
s.size(); 返回s中字符个数
-s.size()函数返回的是string::size_type类型的值,他是一个无符号的值,因此他和int类型的值在一起就相当于无符号和有符号一起混用,这样会导致int转换成unsigned,当int为负数的时候就会出问题。因此我们在写程序的时候必须保证和.size()返回值在一起的值是无符号的。
- 因此我们在要与string的size()进行交互的时候,应这样安全的定义数字变量
string s = "dfgasdfsa";
decltype(s.size()) n = 0;
//这样也保持了n与.size()类型一致,不会出现类型转换
if (n < s.size())
比较string对象
- 当两个string长度一致,且对应位置的字符均一致的时候,string1==string2
- 当string1和string2对应位置字符不一致的时候,两个字符串的大小取决于第一个不一致位置对应的字符大小
- 大写字母小于小写字母,a<b,A<B
- 当string1和string2对应位置字符均一致,但是长度不同的时候(也就是一个string是另外一个的子集),长的string大
相加操作
两个string对象相加
s3 = s1 + s2; //相加等效与拼接,s3是s1在前s2在后拼接而成
s1 += s2; //相当于s1 = s1 + s2;
string对象和字符串字面值相加
- 为了兼容C,字符串字面值并不是string类型,在两者相加过程中实际发生了字符串字面值向string对象的类型转换。
- string对象可以加字符串字面值,但两个字符串字面值不能直接相加
string s1;
string s2 = s1 + "hell"; //合法
string s3 = "helll" + "asasdf" //非法
- 同时,在连续加的时候,加法是从左到右结合的,因此在连续加的时候我们必须保证每一个加号两边至少有一个string对象
string s1;
string s2 = s1 + "sdafasd" + "sdfas";
//合法,第一个s1保证了加号左边一直是string对象
stsring s3 = "sdfad" + "sdf" + s1;
//非法,第一个+两边均为字符串字面值
三、string对象中的字符
通过继承C语言中的ctype标准库,可以对字符有一系列的处理,引用该库的方式如下:
#include <cctype>
- C语言中,标准库名字为name.h,当C++继承后,则改为cname,但两种标准库名字的引用在C++中均合法
- 在C++中,尽量使用cname,因为cname中的名字都在std空间下,而name.h则不再std空间下
cctype中常用函数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ut8Bkcnp-1621249932744)(FF42ABB490B4497EACCA1A5976D35B6E)]
- 这里需要注意的是,表中说的为真,其返回值其实不是true,而是一个非零数,因此isalnum()和true是永远不相等的
- 保险起见,使用该类真假函数的时候,加上一个bool()进行以下类型转换,使其从数字变成ture或者false
- 同时注意toupper©和tolower©只是返回c的对应大写或者小写字母,本身c不改变
使用下标访问字符串中的字符
使用如下标运算符[]可以访问字符串s中指定位置的字符
string s = "sdfadfas";
decltype(s.size()) n = 0;
for (; n<s.size() && !isspace(s[n]); n++)
s[n] = toupper(s[n]);
- 当n和s.size()交互的时候,使用decltype将n定义成和s.size()相同的类型,防止出错
- 在使用[]访问字符时,必须先用n<s.size()保证没有超出范围,因为超出范围的下标会出发不可知结果,但不会报错
- 对于&&,只有左面条件为真才会判断右边条件,因此将n<s.size()写在左面保证了先判定下标没越界再使用下标进行!isspace(s[n])判定
- 禁止使用下标为string添加新的字符串,这在操作时会发生下标越界,可以使用+拼接字符串的形式向已有字符串中添加新的内容
使用for(range for)访问字符串中的字符
C++11提供了类似于python中迭代器的使用方法,称作范围for循环,格式如下
for(auto declaration : expression){
...
}
- 其中expression是可迭代对象,declaration每次返回expression中的一个值
- 一般用auto推断declaration的类型,根据网上说这样是为了减小代码量
- 范围for循环不应该改变遍历对象的长度
该语句在访问string中字符的具体应用:
string s = "dsaf sdafsd";
for (auto a : s){
a = toupper(a); //实际上没有改变s
}
for (auto &b : s){
b = toupper(b); //s变成了大写
}
- 这里需要注意auto a :s实际上相当于a = s[n],所以改变a没有 改变s
- 而auto &a :s 相当于&a = s[n],a是s[n]的引用,所以当s不是常量字符串的时候改变a可以改变s