标准库string、vector都是对内置数组类型的抽象,string支持变长的字符串,vector表示可变长的集合。迭代器是string和vector的配套类型,常用于访问string或者vector中的元素。
string作为标准库的一部分,定义在命名空间std中。
#include <string>
using namespace std::string;
1、定义和初始化string对象
string实际上是一个类,类对象的初始化都是由类中的构造函数决定的。string具有很多种初始化方式。默认初始化为空字符串。
带等号的是拷贝初始化,其他的是直接初始化
string s1; //默认初始化,s1是一个空字符串
string s2(s1); //s2是s1的副本 直接初始化
string s2=s1; //等价于s2(s1) 拷贝初始化
string s3("value"); //s3是字面值"value"的副本,除了字面值最后的那个空字符‘\0’外 直接初始化
string s3="value"; //等价于s3("value") 拷贝初始化
string s4(n,'c'); //把s4初始化为由连续n个字符c组成的字符串
2、string对象上的操作
2.1 读写string对象-标准输入输出 >> <<
string s; //空字符串
cin>>s; //将string对象读入s,遇到空白位置
cout<<s<<endl; //输出s
使用cin输入string的时候,从第一个字符到第一个空白(包括空格、换行、制表符等)为止。
如果上程序输入“ hello word! ”
输出的将是 “hello”
可以连续输入
string s1,s2;
cin>>s1>>s2;
cout<<s1<<s2<<endl;
如果上程序输入“ hello word! ”
输出的将是 “helloword!”
2.2 使用getline读取一整行
getline输入string对象,可保留空白符,遇到换行符为止(换行符也读进去了,但是不保存到string对象中)
string line;
while(getline(cin,line)){ //遇到换行符,则输入一次string对象
cout<<line<<enld
}
getline第一个参数是输入流。使用该参数之前,如果该参数做过输入的操作则会影响getline的输入,因此需要清除cin的缓冲区。
如下述代码所示:
如果输入的type是2,则getline获取的内容就是换行符,最终输出的是字符串。
原因分析:cin的时候会产生一个缓冲区,执行cin>>type时输入2和换行符,缓冲区中有:2和换行符,此时2写入到type中,cin缓冲区中还有换行符,使用geiline(cin,line)的时候,cin中遇到换行符结束输入,将空字符串写入到line中。
解决这个问题的方法是,getline使用cin之前情况cin的缓冲区
cin.clear();
cin.sync();
string word,line;
cout<<"请选择读取字符串的方式,1是逐词读取;2是按行读取."<<endl;
char type;
cin>>type;
if(type=='1'){
cout<<"请输入字符串: Welcome to c++ family! "<<endl;
cin>>word;
cout<<word<<endl;
}
//清空输入缓冲区
//cin.clear();
//cin.sync();
if(type=='2'){
cout<<"请输入字符串: Welcome to c++ family! "<<endl;
getline(cin,line);
cout<<line<<endl;
}
cout<<"输入有误!"<<endl;
system("pause");
为什么输入1的时候,不会出现这个问题呢?
因为cin方式输入字符串的时候是从第一个字符到第一个空白结束。当输入1和换行符时,cin缓冲区中有1和换行符,然后将1写入到type中,cin缓冲区中还剩下换行符,但是因为继续cin输入时是从遇到的第一个字符开始算到所以可以继续输入
2.3 string的empty和size操作
empty()判断字符串是否为空,为空则但会true 不为空则返回false.
while(getline(cin,line)){
if(!line.empty()){
cout<<line<<endl;
}
}
size()函数返回string对象的长度(即字符个数),返回值类型是无符号整数,最好不要与有符号数混用!!!!
size()函数返回值的类型是string::size_type类型,该类型实际就是与机器无关的无符号整形,可以放下任何string对象的大小。所以使用该函数返回值的时候要注意,不能跟带符号混用,可能会产生意想不到的错误。
假设n为负数,则s.size()<n 永远是true,因为负数n会自动转换成为一个比较大的无符号值。
2.4 string对象比较
可使用==、!==、 <、 <=、 >、 >= 对string对象进行比较
==意味着string对象长度相等且每个字符也相等
string对象比较,先比较长度 在逐个比较字符
2.5 string对象相加
两个string对象相加,并没有什么特别的,就是字符串拼接在一起。如下述代码所示
string s1="hello,",s2="world\n";
string s3=s1+s2;
cout<<s3<<endl; //s3的内容是“hello,world\n”
s1+=s2; //等价于 s1=s1+s2
如果是字面值跟string对象相加,则需要注意:
string对象一定要在前面且至少要有一个string对象
字符串字面值并不是string对象!
string s4=s1+"primer"; //正确
string s5="hello,"+"world\n";//错误。因为两个对象都不是string对象
string s5="hello,"+s1;//错误。string对象跟字面值相加,string对象要放在前面
string s5=s1+"world\n";//正确
3、处理字符串中的字符
处理string对象中每个字符,c++标准库中提供了cctype,用于对字符的属性进行处理或者判断。
但需要注意的是,cctype中提供的函数都没有判断字符的合法性,如果传入的字符是中文或者不在-1和255之间,则会报错。
- isalnum(c) 当c是字母或者数字时为真 isalpha( c ) 当c是字母时为真
- iscntrl(c)当c是控制字符时为真
- isdigit(c) 当c是数字时为真
- isgraph(c) 当c不是空格但可打印时为真
- islower(c)当c是小写字母时为真
- isprint(c) 当c是可打印字符时为真(即c是空格或者c具有可视形式)
- ispunct(c) 当c是标点符号时为真(即c不是控制字符、数字、字母、可打印空白中的一种)
- isspace(c) 当c是空白时为真(即c是空格、横向制表符、纵向制表符、回车符、换行符、进纸符中的一种)
- isupper(c) 当c是大写字母时为真
- isxdigit(c) 当c是十六进制数字时为真
- tolower(c) 如果c是大写字母。则将字符c转换成小写字母。否则原样输出
- toupper(c) 如果c是小写字母,则将字符c转换成大写字母,否则原样输出
ps:在ASCII码中,第0~31号及第127号(共33个)是控制字符或通讯专用字符,如控制符:LF(换行)、CR(回车)、FF(换页)、DEL(删除)、BS(退格)、BEL(振铃)等;通讯专用字符:SOH(文头)、EOT(文尾)、ACK(确认)等。
遍历string对象中的字符
string str="hello";
for(auto ch:str){
cout<<ch<<endl;
}
string str="hello";
auto size = str.size();
for(decltype(str.size()) i =0 ; i<size; i++){
cout<<str[i] <<endl;
}
string str = "hello";
auto begin = str.begin();
auto end = str.end();
while (begin != end) {
cout << *begin << endl;
begin++;
};
改变string中字符的值
要改变string对象中字符的值,必须使用引用(下标取值返回的也是引用)或者迭代器
//使用引用
string str="hello";
for(auto &ch:str){
ch='w';
}
//使用下标
string str="hello";
auto size = str.size();
for(decltype(str.size()) i =0 ; i<size; i++){
str[i] = 'w';
}
//使用迭代器
string str = "hello";
auto begin = str.begin();
auto end = str.end();
while (begin != end) {
*begin ='w';
begin++;
};
cout << str << endl;
使用下标访问时尤其要注意不要越界了!!