String类型详解

一、定义和初始化string对象

这里写图片描述

直接初始化和拷贝初始化: 
如果使用等号(=)初始化一个变量,实际上执行的是拷贝初始化,编译器把把等号右侧的初始值拷贝到新创建的对象中去。与之相反,如果不等于等号,则执行的是直接初始化。

string s5 = "hiya";         //拷贝初始化  
string s6("hiya");          //直接初始化  
string s7(10, 'c');         //直接初始化,s7的内容是cccccccccc 
  • 1
  • 2
  • 3

、string对象上的操作

这里写图片描述

1. 读写string对象:

#include<iostream>
#include <string.h>

using namespace std;

int main()  
{  
    string s;               // 空字符串  
    cin >> s;               // 将string对象读入s,遇到空白停止  
    cout << s << endl;      // 输出s  
    return 0;  
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在执行读取操作时,string对象会自动忽略开头的空白(即空格符、换行符、制表符等)并从第一个真正的字符开始读起,直到遇见下一处空白为止。

如上所述,如果程序的输入是” Hello World! “(注意开头和结尾处的空格),则输出将是”Hello”,输出结果中没有任何空格。

2. 使用getline读取一整行

如果希望能在最终得到的字符串中保留输入时的空白符,这时应该用getline函数代替原来的>>运算符。getline函数的参数是一个输入流和一个string对象,函数从给定的输入流中读入内容,直到遇到换行符为止(注意换行符也被读进来了),然后把所读的内容存入到那个string对象中去(注意不存换行符)。getline只要一遇到换行符就结束读取操作并返回结果,哪怕输入的一开始就是换行符也是如此。如果输入真的一开始就是换行符,那么所得的结果是个空string。

和输入运算符一样,getline也会返回它的流参数。因此既然输入运算符能作为判断的条件,我们也能用getline的结果作为条件。例如,可以通过改写之前的程序让它一次输出一整行,而不再是每行输出一个词了:

扫描二维码关注公众号,回复: 3925500 查看本文章
#incude<iostream>
#include<string.h>

using namespace std;

int main()  
{  
    string word;  
    while (cin >> word)             // 反复读取,直至到达文件末尾  
        cout << word << endl;   // 逐个输出单词,每个单词后面紧跟一个换行  
    return 0;  
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

因为line中不包含换行符,所以我们手动地加上换行操作符。和往常一样,使用endl结束当前行并刷新显示缓冲区。

触发getline函数返回的那个换行符实际上被丢弃掉了,得到的string对象中并不包含该换行符。

3. string::size_type类型

string类及其他大多数标准库类型都定义了几种配套的类型。这些配套类型体现了标准库类型与机器无关的特性,类型size_type即是其中的一种。在具体使用的时候,通过作用域操作符来表明名字size_type是在类string中定义的。尽管我们不太清楚string::size_type类型的细节,但有一点是肯定的:它是一个无符号类型的值而且能足够存放下任何string对象的大小。所有用于存放string类的size函数返回值的变量,都应该是string::size_type类型的。

4. 比较string对象

string类定义了几种用于比较字符串的运算符。这些比较运算符逐一比较string对象中的字符,并且对大小写敏感,也就是说,在比较时同一个字母的大写形式和小写形式是不同的。

相等性运算符(==和!=)分别检验两个string对象相等或不相等,string对象相等意味着它们的长度相同而且所包含的字符也全都相同。关系运算符<、<=、>、>=分别检验一个string对象是否小于、小于等于、大于、大于等于另外一个string对象。上述这些运算符都依照(大小写敏感的)字典顺序:

(1)如果两个string对象的长度不同,而且较短string对象的每个字符都与较长string对象对应位置上的字符相同,就说较短string对象小于较长string对象。

(2)如果两个string对象在某些对应的位置上不一致,则string对象比较的结果其实是string对象中第一对相异字符比较的结果。

下面是string对象比较的一个示例:

string st1(10, 'c'), st2;  // st1的内容是 cccccccccc,st2是一个空字符串  
st1 = st2;      // 赋值:用st2的副本替换st1的内容,此时st1和st2都是空字符串 
  • 1
  • 2

5. 两个string对象相加

两个string对象相加得到一个新的string对象,其内容是把左侧的运算对象与右侧的运算对象串接而成。也就是说,对string对象使用加法运算符(+)的结果是一个新的string对象,它所包含的字符由两部分组成:前半部分是加号左侧string对象所含的字符、后半部分是加号右侧string对象所含的字符。另外,复合赋值运算符(+=)负责把右侧string对象的内容追加到左侧string对象的后面:

string s1 = "hello, ", s2 = "world\n";  
string s3 = s1 + s2;    // s3的内容是hello, world\n  
s1 += s2;               // 等价于s1s1 = s1 + s2
  • 1
  • 2
  • 3

因为标准库允许把字符字面值和字符串字面值转换成string对象,所以在需要string对象的地方就可以使用这两种字面值来替代。利用这一点将之前的程序改写为如下形式:

string s1 = "hello", s2 = "world"; // 在s1和s2中都没有标点符号  
string s3 = s1 + ", " + s2 + '\n';
  • 1
  • 2

当把string对象和字符字面值及字符串字面值混在一条语句中使用时,必须确保每个加法运算符(+)的两侧的运算对象至少有一个是string:

string s4 = s1 + ", ";   // 正确:把一个string对象和一个字面值相加  
string s5 = "hello" + ", ";     // 错误:两个运算对象都不是string  
string s6 = s1 + ", " + "world";  
    // 正确:每个加法运算符都有一个运算对象是string  
string s7 = "hello" + ", " + s2; // 错误:不能把字面值直接相加
  • 1
  • 2
  • 3
  • 4
  • 5

6. 处理string对象中的字符

这里写图片描述

如果想对string对象中的每个字符做点儿什么操作,目前最好的办法是使用C++11新标准提供的一种语句:范围for(range for)语句。这种语句遍历给定序列中的每个元素并对序列中的每个值执行某种操作,其语法形式是:

for (declaration : expression)  
    statement 
  • 1
  • 2

其中,expression部分是一个对象,用于表示一个序列。declaration部分负责定义一个变量,该变量将被用于访问序列中的基础元素。每次迭代,declaration部分的变量会被初始化为expression部分的下一个元素值。

一个string对象表示一个字符的序列,因此string对象可以作为范围for语句中的expression部分。举一个简单的例子,我们可以使用范围for语句把string对象中的字符每行一个输出出来:

string str("some string");  // 每行输出str中的一个字符。 
for (auto c : str)          // 对于str中的每个字符  
     cout << c << endl;         // 输出当前字符,后面紧跟一个换行符 
  • 1
  • 2
  • 3

for循环把变量c和str联系了起来,其中我们定义循环控制变量的方式与定义任意一个普通变量是一样的。 
此例中,通过使用auto关键字让编译器来决定变量c的类型,这里c的类型是char。每次迭代,str的下一个字符被拷贝给c,因此该循环可以读作”对于字符串str中的每个字符c,”执行某某操作。此例中的”某某操作”即输出一个字符,然后换行。

使用范围for语句改变字符串中的字符

如果想要改变string对象中字符的值,必须把循环变量定义成引用类型。记住,所谓引用只是给定对象的一个别名,因此当使用引用作为循环控制变量时,这个变量实际上被依次绑定到了序列的每个元素上。使用这个引用,我们就能改变它绑定的字符。

新的例子不再是统计标点符号的个数了,假设我们想要把字符串改写为大写字母的形式。为了做到这一点可以使用标准库函数toupper,该函数接收一个字符,然后输出其对应的大写形式。这样,为了把整个string对象转换成大写,只要对其中的每个字符调用toupper函数并将结果再赋给原字符就可以了:

string s("Hello World!!!");  
// 转换成大写形式。  
for (auto &c : s)       // 对于s中的每个字符(注意:c是引用)  
    c = toupper(c);   // c是一个引用,因此赋值语句将改变s中字符的值  
cout << s << endl; 
  • 1
  • 2
  • 3
  • 4
  • 5

7.只处理一部分字符

如果要处理string对象中的每一个字符,使用范围for语句是个好主意。如果需要访问的只是其中一个字符,或者访问多个字符但遇到某个条件就要停下来。例如,同样是将字符改为大写形式,不过新的要求不再是对整个字符串都这样做,而仅仅把string对象中的第一个字母或第一个单词大写化。

要想访问string对象中的单个字符有两种方式:一种是使用下标,另外一种是使用迭代器。

下标运算符([ ])接收的输入参数是string::size_type类型的值,这个参数表示要访问的字符的位置;返回值是该位置上字符的引用。

string对象的下标从0计起。如果string对象s至少包含两个字符,则s[0]是第1个字符、s[1]是第2个字符、s[s.size()-1]是最后一个字符。

string对象的下标必须大于等于0而小于s.size()。

一、定义和初始化string对象

这里写图片描述

直接初始化和拷贝初始化: 
如果使用等号(=)初始化一个变量,实际上执行的是拷贝初始化,编译器把把等号右侧的初始值拷贝到新创建的对象中去。与之相反,如果不等于等号,则执行的是直接初始化。

string s5 = "hiya";         //拷贝初始化  
string s6("hiya");          //直接初始化  
string s7(10, 'c');         //直接初始化,s7的内容是cccccccccc 
  • 1
  • 2
  • 3

、string对象上的操作

这里写图片描述

1. 读写string对象:

#include<iostream>
#include <string.h>

using namespace std;

int main()  
{  
    string s;               // 空字符串  
    cin >> s;               // 将string对象读入s,遇到空白停止  
    cout << s << endl;      // 输出s  
    return 0;  
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在执行读取操作时,string对象会自动忽略开头的空白(即空格符、换行符、制表符等)并从第一个真正的字符开始读起,直到遇见下一处空白为止。

如上所述,如果程序的输入是” Hello World! “(注意开头和结尾处的空格),则输出将是”Hello”,输出结果中没有任何空格。

2. 使用getline读取一整行

如果希望能在最终得到的字符串中保留输入时的空白符,这时应该用getline函数代替原来的>>运算符。getline函数的参数是一个输入流和一个string对象,函数从给定的输入流中读入内容,直到遇到换行符为止(注意换行符也被读进来了),然后把所读的内容存入到那个string对象中去(注意不存换行符)。getline只要一遇到换行符就结束读取操作并返回结果,哪怕输入的一开始就是换行符也是如此。如果输入真的一开始就是换行符,那么所得的结果是个空string。

和输入运算符一样,getline也会返回它的流参数。因此既然输入运算符能作为判断的条件,我们也能用getline的结果作为条件。例如,可以通过改写之前的程序让它一次输出一整行,而不再是每行输出一个词了:

#incude<iostream>
#include<string.h>

using namespace std;

int main()  
{  
    string word;  
    while (cin >> word)             // 反复读取,直至到达文件末尾  
        cout << word << endl;   // 逐个输出单词,每个单词后面紧跟一个换行  
    return 0;  
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

因为line中不包含换行符,所以我们手动地加上换行操作符。和往常一样,使用endl结束当前行并刷新显示缓冲区。

触发getline函数返回的那个换行符实际上被丢弃掉了,得到的string对象中并不包含该换行符。

3. string::size_type类型

string类及其他大多数标准库类型都定义了几种配套的类型。这些配套类型体现了标准库类型与机器无关的特性,类型size_type即是其中的一种。在具体使用的时候,通过作用域操作符来表明名字size_type是在类string中定义的。尽管我们不太清楚string::size_type类型的细节,但有一点是肯定的:它是一个无符号类型的值而且能足够存放下任何string对象的大小。所有用于存放string类的size函数返回值的变量,都应该是string::size_type类型的。

4. 比较string对象

string类定义了几种用于比较字符串的运算符。这些比较运算符逐一比较string对象中的字符,并且对大小写敏感,也就是说,在比较时同一个字母的大写形式和小写形式是不同的。

相等性运算符(==和!=)分别检验两个string对象相等或不相等,string对象相等意味着它们的长度相同而且所包含的字符也全都相同。关系运算符<、<=、>、>=分别检验一个string对象是否小于、小于等于、大于、大于等于另外一个string对象。上述这些运算符都依照(大小写敏感的)字典顺序:

(1)如果两个string对象的长度不同,而且较短string对象的每个字符都与较长string对象对应位置上的字符相同,就说较短string对象小于较长string对象。

(2)如果两个string对象在某些对应的位置上不一致,则string对象比较的结果其实是string对象中第一对相异字符比较的结果。

下面是string对象比较的一个示例:

string st1(10, 'c'), st2;  // st1的内容是 cccccccccc,st2是一个空字符串  
st1 = st2;      // 赋值:用st2的副本替换st1的内容,此时st1和st2都是空字符串 
  • 1
  • 2

5. 两个string对象相加

两个string对象相加得到一个新的string对象,其内容是把左侧的运算对象与右侧的运算对象串接而成。也就是说,对string对象使用加法运算符(+)的结果是一个新的string对象,它所包含的字符由两部分组成:前半部分是加号左侧string对象所含的字符、后半部分是加号右侧string对象所含的字符。另外,复合赋值运算符(+=)负责把右侧string对象的内容追加到左侧string对象的后面:

string s1 = "hello, ", s2 = "world\n";  
string s3 = s1 + s2;    // s3的内容是hello, world\n  
s1 += s2;               // 等价于s1s1 = s1 + s2
  • 1
  • 2
  • 3

因为标准库允许把字符字面值和字符串字面值转换成string对象,所以在需要string对象的地方就可以使用这两种字面值来替代。利用这一点将之前的程序改写为如下形式:

string s1 = "hello", s2 = "world"; // 在s1和s2中都没有标点符号  
string s3 = s1 + ", " + s2 + '\n';
  • 1
  • 2

当把string对象和字符字面值及字符串字面值混在一条语句中使用时,必须确保每个加法运算符(+)的两侧的运算对象至少有一个是string:

string s4 = s1 + ", ";   // 正确:把一个string对象和一个字面值相加  
string s5 = "hello" + ", ";     // 错误:两个运算对象都不是string  
string s6 = s1 + ", " + "world";  
    // 正确:每个加法运算符都有一个运算对象是string  
string s7 = "hello" + ", " + s2; // 错误:不能把字面值直接相加
  • 1
  • 2
  • 3
  • 4
  • 5

6. 处理string对象中的字符

这里写图片描述

如果想对string对象中的每个字符做点儿什么操作,目前最好的办法是使用C++11新标准提供的一种语句:范围for(range for)语句。这种语句遍历给定序列中的每个元素并对序列中的每个值执行某种操作,其语法形式是:

for (declaration : expression)  
    statement 
  • 1
  • 2

其中,expression部分是一个对象,用于表示一个序列。declaration部分负责定义一个变量,该变量将被用于访问序列中的基础元素。每次迭代,declaration部分的变量会被初始化为expression部分的下一个元素值。

一个string对象表示一个字符的序列,因此string对象可以作为范围for语句中的expression部分。举一个简单的例子,我们可以使用范围for语句把string对象中的字符每行一个输出出来:

string str("some string");  // 每行输出str中的一个字符。 
for (auto c : str)          // 对于str中的每个字符  
     cout << c << endl;         // 输出当前字符,后面紧跟一个换行符 
  • 1
  • 2
  • 3

for循环把变量c和str联系了起来,其中我们定义循环控制变量的方式与定义任意一个普通变量是一样的。 
此例中,通过使用auto关键字让编译器来决定变量c的类型,这里c的类型是char。每次迭代,str的下一个字符被拷贝给c,因此该循环可以读作”对于字符串str中的每个字符c,”执行某某操作。此例中的”某某操作”即输出一个字符,然后换行。

使用范围for语句改变字符串中的字符

如果想要改变string对象中字符的值,必须把循环变量定义成引用类型。记住,所谓引用只是给定对象的一个别名,因此当使用引用作为循环控制变量时,这个变量实际上被依次绑定到了序列的每个元素上。使用这个引用,我们就能改变它绑定的字符。

新的例子不再是统计标点符号的个数了,假设我们想要把字符串改写为大写字母的形式。为了做到这一点可以使用标准库函数toupper,该函数接收一个字符,然后输出其对应的大写形式。这样,为了把整个string对象转换成大写,只要对其中的每个字符调用toupper函数并将结果再赋给原字符就可以了:

string s("Hello World!!!");  
// 转换成大写形式。  
for (auto &c : s)       // 对于s中的每个字符(注意:c是引用)  
    c = toupper(c);   // c是一个引用,因此赋值语句将改变s中字符的值  
cout << s << endl; 
  • 1
  • 2
  • 3
  • 4
  • 5

7.只处理一部分字符

如果要处理string对象中的每一个字符,使用范围for语句是个好主意。如果需要访问的只是其中一个字符,或者访问多个字符但遇到某个条件就要停下来。例如,同样是将字符改为大写形式,不过新的要求不再是对整个字符串都这样做,而仅仅把string对象中的第一个字母或第一个单词大写化。

要想访问string对象中的单个字符有两种方式:一种是使用下标,另外一种是使用迭代器。

下标运算符([ ])接收的输入参数是string::size_type类型的值,这个参数表示要访问的字符的位置;返回值是该位置上字符的引用。

string对象的下标从0计起。如果string对象s至少包含两个字符,则s[0]是第1个字符、s[1]是第2个字符、s[s.size()-1]是最后一个字符。

string对象的下标必须大于等于0而小于s.size()。

猜你喜欢

转载自blog.csdn.net/qq_36621927/article/details/79221106