C++ 标准库string类型


摘自 C++ Primer中文版(第4版) 3.2节

string类型收持长度可变的字符串,C++标准库负责管理存储字符的相闭内存,和提供各种有效的操作。标准库string类型的目的就是满足对字符串的一般应用。

    string s;             // empty string

#include <string>

using std::string;

3.2.1  定义和初始化String对象

string标准库收持几个构造函数(2.2.3节)。构造函数是一个特殊成员函数,定义如何初始化该类型的对象。表3-1列出了几个string类型常用的构造函数。当没有明确指定对象初始代式时,系统将使用默认构造函数(2.3.4节)。

3-1  几种初始化String对象的方式

本例开始的程序均假设程序中所有必须的#includeusing声明已给出。

       cout << word << endl;

string s2(s1);

s2初始化为s1的一个副本

如果c不是空格,但可输出,则为true

s3初始化为一个字符串字面值副本

string s4(n, 'c');

s4初始化为字符'c'n个副本

 

警告:标准库string类型和字符串字面值                                            

因为汗青原因和为了与C语言兼容,字符串字面值与标准库string类型不是同一种类型。这一点很容易引发紊乱,编程时一定要注意区分字符串字面值和string数据类型的使用,这很重要。

习题                                                           

如果c是控制字符,则为true

习题3.3  列举出三种初始化String对象的方法。

习题3.4  ss2的值分别是什么?

   string s;

   int main() {

     << " punctuation characters in " << s << endl;

   }

3.2.2  String的读写

v1 == v2

// Note: #include and using declarations must be added to compile this code

int main()

{

The size of The expense of spirit

    cin >> s;             // read whitespace-separated string into s

    cout << s << endl;  // write s to the output

    return 0;

}

以上程序首先定义命名为s的字符串,第二行代码:

cin >> s;        // read whitespace-separated string into s

从标准输入读取string,并将读入的串存储在s中。string类型的输入操作符:

l   读取并忽略开头所有的空白字符(如空格,换行符,制表符)。

l   读取字符直至再次遇到空白字符,读取终止。

因此,如果输入到程序的是“   Hello World!   ”(注意到开头和结尾的空格),则屏幕上将输出“Hello”,而不含任何空格。

    // read line at time until end-of-file

string s1, s2;

cin >> s1 >> s2; // read first input into s1, second into s2

另外还有一个有效的string IO操作:getline。这个函数接受两个参数:一个输入流对象和一个string对象。getline函数从输入流的下一行读取,并保存读取的内容到string中,但不包孕换行符。和输入操作符不一样的是,getline并不忽略行开头的换行符。只要getline遇到换行符,即使它是输入的第一个字符,getline也将休止读入并返回。如果第一个字符就是换行符,则string参数将被置为空string

如果给定和上一个程序同样的输入,则输出的结果将是:

HelloWorld!

对于上例编译时必须加上#include来标示iostreamstring标准库和给出用到的所有标准库中名字string,cin,cout,endlusing声明。

    s[index] = tolower(s[index]);

1. 读入未知数目的string对象

和内置类型的输入操作符一样,string输入操作符也会返回所读的数据流。因此,可以把输入操作作为判定条件,这与我们在1.4.4节读取整型数据的程序做法是一样的。下面的程序将从标准输入读取一组string对象,然后在标准输出上逐行输出:

int main()

{

    string word;

    // read until end-of-file, writing each word to a new line

    while (cin >> word)

默认构造函数,s1为空串

    return 0;

}

上例中,用输入操作符来读取string对象。该操作符返回所读的istream对象,并在读取结束后,作为while的判定条件。如果输入流是有效的,即还没到达文件尾且没遇到无效输入,则施行while循环体,并将读取到的字符串输出到标准输出。如果到达了文件尾,则跳出while循环。

2. getline读取整行文本

cout << s1 << s2 << endl; // write both strings

getline函数将istream参数作为返回值,和输入操作符一样也把它用作判定条件。例如,重写前面那段程序,把每行输出一个单词改为每次输出一行文本:

int main()

{

    string line;

输入和输出操作的行为与内置类型操作符根本类似。尤其是,这些操作符返回左操作数作为运算结果。因此,我们可以把多个读操作或多个写操作放在一起:

  s1 += s2;      // equivalent to s1 = s1 + s2

string类型通过下标操作符([])来访问string对象中的单个字符。下标操作符需要取一个size_type类型的值,来标明要访问字符的位置。这个下标中的值通常被称为“下标”或“索引(index)”。

s.size()

isprint(c)

由于line不含换行符,若要逐行输出需要自行加加。照旧,我们用endl来输出一个换行符并刷新输出缓冲区。

注意由于getline函数返回时丢弃换行符,换行符将不会存储在string对象中。

习题                                美团网                           

习题3.5  编写程序实现从标准输入每次读入一行文本。然后改写程序,每次读入一个单词。

string s1 = big;     // s1 is a copy of big

习题                                                          

string str("some string");

3-2  string操作

s.empty()

    return 0;

s[n]

s1 + s2

s1 = s2

for (string::size_type ix = 0; ix != str.size(); ++ix)

!=, <, <=,

> >=

如果s为空串,则返回true,否则返回false

编译并运行这个程序,得到的结果为:

返回s中位置为n的字符,位置从0开始计数。

s1s2连接成一个新字符串,返回新天生的字符串。

s1内容交换为s2的副本。

比较v1v2的内容,相等则返回true,否则返回false

s5 = tmp + “world”;       // ok: + has a string operand

1. stringsizeempty操作

string s4 = "hello" + ", ";              // error: no string operand

int main()

{

    string st("The expense of spirit\n");

        << " characters, including the newline" << endl;

    cout << "The size of " << st << "is " << st.size()

    return 0;

}

string对象的下标从0开始。如果s是一个string对象且s不空s[0]就是字符串的第一个字符s[1]就表示第二个字符(如果有的话)s[s.size()-1]则表示s的最后一个字符。

可用下标操作符分别取出string对象的每个字符,分行输出:

is 22 characters, including the newline

相识string对象是不是为空是有效的。一种方法是将size0举行比较:

if (st.size() == 0)

援用下标超出下标作用范围就会引发溢出错误。

本例中,程序员并不需要知道string对象中有几许个字符,只想知道size是不是为0。用string的成员函数empty()可以更直接地回答这个问题:

S3s4的初始化只用了一个单独的操作。在这些例子中,很容易判定s3的初始化是合法的:把一个string对象和一个字符串字面值连接起来。而s4的初始化试图将两个字符串字面值相加,因此是非法的。

     // ok: empty

7. string对象获取字符

2. string::size_type类型

逻辑上来讲,size()成员函数似乎应该返回整型数值,或如2.2节“建议”中所述的无符号整数。但事实上,size操作返回的是string::size_type类型的值。我们需要对这类类型做一些解释。

string类类型和许多其他库类型都定义了一些伙伴类型companion types。这些伙伴类型使得库类型的使用是机器无闭的(machine-independent)size_type就是这些伙伴类型中的一种。它定义为与unsigned型(unsigned intunsigned long)具有相同的含义,而且可以保证足够大可存储任意string对象的长度。为了使用由string类型定义的size_type类型,程序员必须加上作用域操作符来说明所使用的size_type类型是由string类定义的。

任何存储stringsize操作结果的变量必须为string::size_type类型。特殊重要的是,不要把size的返回值赋给一个int变量。

虽然我们不知道string::size_type的确切类型,但可以知道它是unsigned型(2.1.1节)。对于任意一种给定的数据类型,它的unsigned型所能表示的最大正数值比对应的signed要大一倍。这个事实表明size_type存储的string长度是int所能存储的两倍。

使用int变量的另一个问题是,有些机器上int变量的表示范围太小,甚至无法存储实际并不长的string对象。如在有16int型的机器上,int类型变量最大只能表示32767个字符的string对象。而能包容一个文件内容的string对象轻易就会超过这个数字。因此,为了避免溢出,保存一个string对象size的最平安的方法就是使用标准库类型string:: size_type

3. string闭系操作符

string类定义了几种闭系操作符用来比较两个string值的大小。这些操作符实际上是比较每个string对象的字符。

string对象比较运算是区分大小写的,即同一个字符的大小写情势被认为是两个不同的字符。在多数计算机上,大写的字母位于小写字母之前:任何一个大写字母都小于任意的小写字母。

==操作符比较两个string对象,如果它们相等,则返回true。两个string对象相等是指它们的长度相同,且含有相同的字符。标准库还定义了!=操作符来测试两个string对象是不是不等。

闭系操作符<,<=,>,>=分别用于测试一个string对象是不是小于、小于或等于、大于、大于或等于另一个string对象:

string big = "big", small = "small";

习题3.6  解释string类型的输入操作符和getline函数分别如那边理空白字符。

if (big == small)    // false

如果c是小写字母,则返回其大写字母情势,否则直接返回c

tolower(c)

    // ...

闭系操作符比较两个string对象时采用了和(大小敏感的)字典排序相同的策略:

l   如果两个string对象长度不同,且短的string对象与长的string对象的前面部分相婚配,则短的string对象小于长的string对象。

l   如果两个string对象的字符不同,则比较第一个不婚配的字符。

举例来说,给定string对象:

string substr  = "Hello";

string phrase  = "Hello World";

string slang   = "Hiya";

substr小于phrase,而slang则大于substrphrase

4. string对象的赋值

整体上说,标准库类型尽量设计得和根本数据类型一样方便易用。因此,大多数库类型收持赋值操作。对string对象来说,可以把一个string对象赋值给另一个string对象:

// st1 is an empty string, st2 is a copy of the literal

string st1, st2 = "The expense of spirit";

st1 = st2; // replace st1 by a copy of st2

赋值操作后,st1就包含了st2串所有字符的一个副本。

大多数string库类型的赋值等操作的实现乡市遇到一些效率上的问题,但值得注意的是,从概念上讲,赋值操作确实需要的工作。它必须先把st1占用的相闭内存释放掉,然后再分配给st1足够存放st2副本的内存空间,最后把st2中的所有字符复制到新分配的内存空间。

得到的结果为:

习题3.7  编一程序读入两个string对象,测试它们是不是相等。若不相等,则指出两个中哪个较大。接着,改写程序测试它们的长度是不是相等,若不相等指出哪个较长。

string s1("hello, ");

string s2("world\n");

下面把两个string对象连接起来产生第三个string对象:

    string s3 = s1 + s2;      // s3 is hello, world\n

如果要把s2直接追加到s1的末尾,可使用+=操作符:

    while (getline(cin, line))

6. 和字符串字面值的连接

上面的字符串对象s1s2直接包含了标点符号。也可以通过将string对象和字符串字面值混合连接得到同样的结果:

string s1("hello");

string s3 = s1 + ", ";                // ok: adding a string and a literal

string s3 = s1 + ", " + s2 + "\n";

 

isxdigit(c)

string s2 = "world";

}

       cout << line << endl;

    // ...

建议:采用C标准库头文件的C++版本                                                    

如果c是小写字母,则为true

s5的初始化方法显得有点不可思议,但这类用法和标准输入输出的串联效果是一样的(1.2节)。本例中,string标准库定义加操作返回一个string对象。这样,在对s5举行初始化时,子表达式s1 + ", "将返回一个新string对象,后者再和字面值“world\n”连接。整个初始化过程可以改写为:

string tmp = s1 + “, ”;   // ok: + has a string operand

保持这些运算符惯有的含义。

string s2("world");

empty()成员函数将返回bool值(2.1节),如果string对象为空则返回true,否则返回false

string对象的长度指的是string对象中字符的个数,可以通过size操作获取:

如果c是字母或数字,则为true

string s6 = "hello" + ", " + s2;        // error: can't add string literals

       string s2;

3-2列出了常用的string操作。

for (string::size_type index = 0; index != s.size(); ++index)

    cout << str[ix] << endl;

每次通过循环,就从str对象中读取一个字符,输出该字符并换行。

8. 下标操作可用作左值

前面说过,变量是左值(2.3.1节),且赋值操作的左操作数必须是左值。和变量一样,string对象的下标操作返回值也是左值。因此,下标操作可以放于赋值操作符的左边或右边。通过下面循环把str对象的每一个字符置为’*’:

for (string::size_type ix = 0; ix != str.size(); ++ix)

     str[ix] = '*';

9. 计算下标值

任何可产生整型数值的表达式都可用作下标操作符的索引。例如,假设somevalsomeotherval是两个整型对象,可以这样写:

str[someotherval * someval] = someval;

虽然任何整型数值都可作为索引,但索引的实际数据类型却是unsigned类型string:: size_type

前面讲过,要string::size_type类型的变量接受size函数的返回值。在定义用作索引的变量时出于同样的道理string对象的索引变量最好也用string:: size_type类型。

在使用下标索引string对象时,必须保证索引值“在上下界范围内”。“在上下界范围内”就是指索引值是一个赋值为size_type类型的值,其取值范围在0string对象长度减1之间。使用string::size_type类型或其他unsigned类型作为索引,就可以保证索引值不小于0。只要索引值是unsigned类型,就只需要检测它是不是小于string对象的长度。

标准库不要求查抄索引值,所用索引的下标越界是没有定义的,这样往往会导致严峻的运行时错误。

3.2.4  string对象中字符的处理

我们常常要对string对象中的单个字符举行处理,例如,通常需要知道某个特殊字符是不是为空白字符、字母或数字。表3-3列出了各种字符操作函数,适用于string对象的字符(或其他任何char值)。这些函数都在cctype头文件中定义。

3-3  cctype定义的函数

isalnum(c)

如果c是数字,则为true

isalpha(c)

如果c是字母,则为true

iscntrl(c)

习题3.2  什么是默认构造函数?

isdigit(c)

返回s中字符的个数。

isgraph(c)

string s3("value");

islower(c)

if (st.empty())

s6的初始化是非法的。依次来看每个子表达式,则第一个子表达式试图把两个字符串字面值连接起来。这是不允许的,因此这个语句是错误的。

isspace(c)

ispunct(c)

如果c是标点符号,则为true

如果c是可输出的字符,则为true

如果c是空白字符,则为true

isupper(c)

如果c是大写字母,则为true

string s1 = "hello";   // no punctuation

表中的这些函数,可输出的字符是指那些可以显式表示的字符。空白字符则是空格、制表符、垂直制表符、回车符、换行符和进纸符中的任意一种;标点符号则是除了数字、字母或(可输出的)空白字符(如空格)以外的其他字符。

if (big <= s1)       // true, they're equal, so big is less than or equal to s1

如果c是大写字母,则返回其小写字母情势,否则直接返回c

toupper(c)

string s5 = s1 + ", " + "world";        // ok: each + has string operand

当举行string对象和字符串字面值混合连接操作时,+操作符的左右操作数必须至少有一个是string类型的:

3-3中的大部分函数是测试一个给定的字符是不是符合条件,并返回一个int值作为真值。如果测试失败,则该函数返回0,否则返回一个(无意义的)0值,表示被拆字符符合条件

如果c是十六进制数,则为true

这里给出一个例子,运用这些函数输出一给定string对象中标点符号的个数:

string s("Hello World!!!");

string::size_type punct_cnt = 0;

// count number of punctuation characters in s

习题3.10  编一程序,从string对象中去掉标点符号。要求输入到程序的字符串必须含有标点符号,输出结果则是去掉标点符号后的string对象。

    if (ispunct(s[index]))

       ++punct_cnt;

string s1;

与其它的标准库类型一样,用户程序要使用string类型对象,必须包含相闭头文件。如果程序员提供合适的using声明,那么编写出来的程序将会变得简短一些:

这个程序的输出结果是:

3 punctuation characters in Hello World!!!

和返回真值的函数不同的是,tolowertoupper函数返回的是字符,返回实参字符本身或返回该字符相应的大小写字符。我们可以用tolower函数把string对象s中的字母改为小写字母,程序如下:

// convert s to lowercase

for (string::size_type index = 0; index != s.size(); ++index)

cout << punct_cnt

cout << s << endl;

5. 两个string对象相加

hello world!!!

     // ok: empty

C++标准库除了定义了一些特定于C++的设施外,还包孕C标准库。C++中的头文件cctype其实就是利用了C标准库函数,这些库函数就定义在C标准库的ctype.h头文件中。

C标准库头文件命名情势为name.h,而C++版本则命名为cname,少了后缀.h而在头文件名前加了cc表示这个头文件源自C标准库。因此,cctypectype.h文件的内容是一样的,只是采用了更适合C++程序的情势。特殊地,cname头文件中定义的名字都定义在命名空间std内,而.h版本中的名字却不是这样。

通常,C++程序中应采用cname这类头文件的版本,而不采用name.h版本,这样,标准库中的名字在命名空间std中保持一致。使用.h版本会给程序员带来负担,因为他们必须记得哪些标准库名字是从C继承来的,而哪些是C++所特有的。

3.2.3  string对象的操作

string对象的加法被定义为连接(concatenation)。也就是说,两个(或多个)string对象可以通过使用加操作符+或者复合赋值操作符+=1.4.1节)连接起来。给定两个string对象:

习题3.8  编一程序,从标准输入读取多个string对象,把它们连接起来存放到一个更大的string对象中。并输出连接后string对象。接着,改写程序,将连接后相邻string对象以空格隔开。

习题3.9  下列程序实现什么功能?实现合法吗?如果不合法,说明理由。

   string s;

   cout << s[0] << endl;  

我们已在第1章学习了用iostream标准库来读写内置类型的值,如int,double等。同样地,也可以用iostreamstring标准库,使用标准输入输出操作符来读写string对象


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值