8.8.2 连接字符串
字符串最常见的运算可能要数连接两个字符串形成一个新的字符串了。我们可以用+运算符连接两个字符串对象或者一个字符串对象和一个字符串字面值。下面是一些示例:
- string sentence1("This sentence is false.");
- string sentence2("Therefore the sentence above must be true!");
- string combined; // Create an empty string
- sentence1sentence1 = sentence1 + "\n";
// Append string containing newline - combined = sentence1 + sentence2; // Join two strings
- cout << combined << endl; // Output the result
执行这些语句将导致下面的输出:
- This sentence is false.
- Therefore the sentence above must be true!
前3个语句创建字符串对象。下一个语句将字符串字面值"\n"附加到sentence1后面,并将结果存储在sentence1中。再下一个语句连接sentence1和sentence2,并将结果存储在combined中。最后一个语句输出字符串combined。
字符串可以用+运算符连接,是因为string类实现了operator+()。这暗示了操作数之一必须为string对象,因此我们不能用+运算符连接两个字符串字面值。记住,每次用+运算符连接两个字符串时,我们都是在创建一个新的string对象,这会引起一定数量的开销。下一节将介绍如何修改和扩展现有的string对象,在有些情况下这可能是一种更有效的方法,因为它不涉及创建新对象。
我们也可以用+运算符将一个字符连接到一个字符串对象上,因此前面的代码片段中的第三个语句可以写成:
- sentence1sentence1 = sentence1 + '\n';
// Append newline character to string
string类也可以实现operator+=(),因此右操作数可以是一个字符串字面值、一个字符串对象或者一个字符。前面的语句可以写成:
- sentence1 += '\n';
或者写成:
- sentence1 += "\n";
使用+=运算符与使用+运算符有一个区别。正如本书所指出的,+运算符创建一个包含合并后的字符串的新字符串对象。+=运算符将作为右操作数的字符串或字符附加到作为左操作数的string对象后面,因此直接修改string 对象,而不创建新的对象。
下面我们用一个示例来练习上面描述的概念。
试一试:创建与连接字符串
这是一个通过键盘输入姓名和年龄然后列出输入内容的简单示例。代码如下:
- // Ex8_09.cpp
- // Creating and joining string objects
- #include <iostream>
- #include <string>
- using std::cin;
- using std::cout;
- using std::endl;
- using std::string;
- using std::getline;
-
- // List names and ages
- void listnames(string names[], string ages[], size_t count)
- {
- size_t i = 0;
- cout << endl << "The names you entered are: " << endl;
- while(i<count && !names[i].empty()){
- cout << names[i] + " aged " + ages[i] + '.' << endl;
- i++
- }
-
- int main()
- {
- const size_t count = 100;
- string names[count];
- string ages[count];
- string firstname;
- string secondname;
-
- for(size_t i = 0 ; i<count ; i++)
- {
- cout << endl << "Enter a first name or press Enter to end: ";
- getline(cin, firstname, '\n');
- if(firstname.empty())
- {
- listnames(names, ages, i);
- cout << "Done!!" << endl;
- return 0;
- }
-
- cout << "Enter a second name: ";
- getline(cin, secondname, '\n');
-
- names[i] = firstname + ' ' + secondname;
- cout << "Enter " + firstname + "'s age: ";
- getline(cin, ages[i], '\n');
- }
- cout << "No space for more names." << endl;
- listnames(names, ages, count);
- return 0;
- }
这个示例产生类似下面的输出:
- Enter a first name or press Enter to end: Marilyn
- Enter a second name: Munroe
- Enter Marilyn's age: 26
- Enter a first name or press Enter to end: Tom
- Enter a second name: Crews
- Enter Tom's age: 45
- Enter a first name or press Enter to end: Arnold
- Enter a second name: Weisseneggar
- Enter Arnold's age: 52
- Enter a first name or press Enter to end:
- The names you entered are:
- Marilyn Munroe aged 26.
- Tom Crews aged 45.
- Arnold Weisseneggar aged 52.
- Done!!
示例说明
listnames函数列出存储在数组中的姓名和年龄(它们作为前两个实参传递)。第三个实参是数组中元素个数的计数。数据的清单出现在一个循环中:
- while(i<count && !names[i].empty())
- cout << names[i] + " aged " + ages[i++] + '.' << endl;
循环条件是双重保险(belt and brace)控制机制,它不仅检查索引i是否小于作为第三个实参传递的count的值,而且还调用当前元素的empty()函数来确认它不是空字符串。循环体中的那个语句用+运算符连接names[i]中的当前字符串与字面值"aged"、ages[i]字符串及字符'.',并将结果产生的字符串写到cout中。这个连接字符串的表达式等价于:
- ((names[i].operator+(" aged ")).operator+(ages[i++])).operator+('.')
每次调用operator+()函数都会返回一个从该运算得到的string对象,因此在计算这个表达式时创建了3个临时string对象。所以此表达式演示了将一个string对象与一个字符串字面值合并,将一个string对象与另一个string对象合并,以及将一个string对象与一个字符字面值合并。
在main()中,首先用下面的语句创建两个string对象的数组,长度为count:
- const size_t count = 100;
- string names[count];
- string ages[count];
names和ages数组将存储从键盘上输入的姓名和相应的年龄值。
在main()的for循环内,我们分别用在<string>头文件中定义的getline()函数模板来读取姓和名:
- cout << endl << "Enter a first name or press Enter to end: ";
- getline(cin, firstname, '\n');
- if(firstname.empty())
- {
- listnames(names, ages, i);
- cout << "Done!!" << endl;
- return 0;
- }
-
- cout << "Enter a second name: ";
- getline(cin, secondname, '\n');
getline()函数允许读空字符串,而用cin的>>运算符不能读空字符串。getline()的第一个实参是作为输入源的流,第二个实参是输入的目的地,第三个实参是标志输入操作结束的字符。如果我们省略第三个实参,输入'\n'将终止输入过程,因此我们在这里可以省略第三个实参。这里我们用读空字符串的能力来测试firstname中的空字符串(通过调用它的empty()函数)。由于空字符串是输入结束的信号,因此我们调用listnames()来输出数据并结束程序的执行。
当firstname不为空时,我们继续用getline()模板函数将姓读入sencondname中。我们用+运算符连接firstname和secondname,并将结果存储在names[i]中,它是names数组中当前未使用的元素。
在循环中最后读入年龄字符串,并将结果存储在ages[i]中。for循环将条目数限制为count,它对应于数组中的元素个数。如果我们没能成功地结束循环,那么数组在显示一条消息(表明已经输出了所输入的数据)后就满了。