重要的事情说三遍:
string
类在前面的章节中已经简要介绍过。它是一个非常强大的类,用于处理和操作字符字符串。然而,由于字符串实际上是字符序列,我们也可以将它们表示为字符类型元素的普通数组。
例如,以下数组:
char foo [20];
是一个可以存储最多 20 个 char
类型元素的数组。它可以表示为:
因此,该数组具有存储最多 20 个字符序列的容量。但这种容量不需要完全用尽:数组也可以容纳较短的序列。例如,在程序中的某个时刻,可以在 foo
中存储 "Hello"
或 "Merry Christmas"
序列,因为这两个都可以适应容量为 20 个字符的序列。
按照惯例,字符序列中字符串的结束由一个特殊字符标志:空字符(null character),其字面值可以写为 '\0'
(反斜杠,零)。
在这种情况下,名为 foo
的 20 个 char
元素的数组可以表示存储字符序列 "Hello"
和 "Merry Christmas"
为:
请注意,在字符串本身的内容之后,添加了一个空字符 '\0'
以指示序列的结束。灰色面板代表具有不确定值的 char
元素。
初始化以空字符结尾的字符序列
由于字符数组是普通数组,它们遵循相同的规则。例如,要用一些预定的字符序列初始化一个字符数组,可以像初始化其他数组一样进行:
char myword[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
上述声明了一个 6 个元素的 char
类型数组,用于初始化形成单词 "Hello"
的字符加上一个空字符 '\0'
。
但字符元素数组有另一种初始化方式:直接使用字符串字面量。
在前几章的一些示例中已经多次出现了字符串字面量。它们通过将文本用双引号("
)括起来来指定。例如:
"the result is: "
这是一个字符串字面量,可能在早期的示例中使用过。
用双引号("
)括起来的字符序列是字面常量。它们的类型实际上是以空字符结尾的字符数组。这意味着字符串字面量总是自动在末尾附加一个空字符 '\0'
。
因此,名为 myword
的 char
元素数组可以通过以下两种语句之一用以空字符结尾的字符序列初始化:
char myword[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
char myword[] = "Hello";
在这两种情况下,字符数组 myword
都被声明为具有 6 个 char
元素的数组:组成单词 "Hello"
的 5 个字符,加上一个指定序列结束的最后一个空字符 '\0'
,在第二种情况中,当使用双引号("
) 时,它会自动附加。
请注意,这里我们讨论的是在声明时初始化字符数组,而不是稍后分配值(声明后)。实际上,由于字符串字面量是普通数组,它们具有相同的限制,不能分配值。
表达式(如上所述已经声明 myword
)如下:
myword = "Bye";
myword[] = "Bye";
无效,就像以下表达式也无效:
myword = { 'B', 'y', 'e', '\0' };
这是因为数组不能被分配值。不过,可以单独为每个元素分配值。例如,这将是正确的:
myword[0] = 'B';
myword[1] = 'y';
myword[2] = 'e';
myword[3] = '\0';
字符串和以空字符结尾的字符序列
普通数组中包含以空字符结尾的字符序列是 C 语言中表示字符串的典型类型(这就是它们也被称为 C 字符串的原因)。在 C++ 中,即使标准库定义了一个特定的字符串类型(类 string
),普通数组中包含以空字符结尾的字符序列(C 字符串)仍然是表示字符串的自然方式;实际上,字符串字面量仍然总是产生以空字符结尾的字符序列,而不是 string
对象。
在标准库中,字符串的两种表示方式(C 字符串和库字符串)共存,并且大多数需要字符串的函数都支持两种方式。
例如,cin
和 cout
直接支持以空字符结尾的序列,允许它们像字符串一样直接从 cin
中提取或插入到 cout
中。例如:
// 字符串和 NTCS
#include <iostream>
#include <string>
using namespace std;
int main ()
{
char question1[] = "What is your name? ";
string question2 = "Where do you live? ";
char answer1 [80];
string answer2;
cout << question1;
cin >> answer1;
cout << question2;
cin >> answer2;
cout << "Hello, " << answer1;
cout << " from " << answer2 << "!\n";
return 0;
}
在这个示例中,同时使用了使用以空字符结尾的字符序列的字符数组和字符串。它们在与 cin
和 cout
一起使用时相当可互换,但它们的声明有显著差异:数组具有固定大小,需要在声明时隐式或显式指定;question1
的大小恰好为 20 个字符(包括终止的空字符),而 answer1
的大小为 80 个字符;而字符串只是字符串,没有指定大小。这是因为字符串在运行时具有动态大小,而数组的大小在编译时确定,在程序运行之前。
无论如何,以空字符结尾的字符序列和字符串可以很容易地相互转换:
以空字符结尾的字符序列可以隐式转换为字符串,字符串可以通过使用 string
的成员函数 c_str
或 data
转换为以空字符结尾的字符序列:
char myntcs[] = "some text";
string mystring = myntcs; // 将 C 字符串转换为字符串
cout << mystring; // 以库字符串形式打印
cout << mystring.c_str(); // 以 C 字符串形式打印
(注意:string
的 c_str
和 data
成员是等效的)