字元序列

在之前的章節中,我們已經簡要介紹過 string 類。它是一個非常強大的類,用於處理和操作字串。然而,因為字串實際上是字元序列,我們也可以用普通字元型別的陣列來表示它們。

例如,下面的陣列:

1
char foo [20];

是一個可以儲存最多 20 個 char 型別元素的陣列。它可以表示為:


因此,這個陣列有能力儲存最多 20 個字元的序列。但這個容量不必完全用盡:該陣列也可以容納較短的序列。例如,在程式的某個時刻,序列 "Hello" 或序列 "Merry Christmas" 都可以儲存在 foo 中,因為它們都適合容量為 20 個字元的序列。

按照約定,用字元序列表示的字串的末尾由一個特殊字元來標記:空字元 (null character),其字面值可以寫作 '\0'(反斜槓,零)。

在這種情況下,這個名為 foo 的、包含 20 個 char 型別元素的陣列,可以表示為儲存了 "Hello""Merry Christmas" 字元序列的樣子:


請注意,在字串內容本身之後,如何新增一個空字元 ('\0') 來表示序列的結束。灰色面板代表值不確定的 char 元素。

以空字元結尾的字元序列的初始化

因為字元陣列是普通陣列,所以它們遵循與普通陣列相同的規則。例如,要用某個預定的字元序列來初始化一個字元陣列,我們可以像處理任何其他陣列一樣:

1
char myword[] = { 'H', 'e', 'l', 'l', 'o', '\0' };

上述程式碼聲明瞭一個包含 6 個 char 型別元素的陣列,並用構成單詞 "Hello" 的字元以及末尾的一個空字元 '\0' 來初始化它。

但是,字元元素陣列還有另一種初始化方式:直接使用字串字面量

在前面章節的一些示例所使用的表示式中,字串字面量已經出現過好幾次了。它們透過將文字括在雙引號 (") 中來指定。例如:

1
"the result is: "

這是一個字串字面量,可能在之前的某個示例中使用過。

用雙引號 (") 括起來的字元序列是字面常量。它們的型別實際上就是以空字元結尾的字元陣列。這意味著字串字面量的末尾總是會自動附加一個空字元 ('\0')。

因此,名為 myword 的 char 元素陣列可以透過以下兩種語句中的任意一種來初始化為一個以空字元結尾的字元序列:

1
2
char myword[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
char myword[] = "Hello";

在這兩種情況下,字元陣列 myword 都被宣告為大小為 6 個 char 元素的陣列:構成單詞 "Hello" 的 5 個字元,外加一個最後的空字元 ('\0')。這個空字元指定了序列的結束,在第二種使用雙引號 (") 的情況下,它是自動附加的。

請注意,我們這裡談論的是在宣告字元陣列時進行初始化,而不是在它們被宣告之後再給它們賦值。事實上,因為字串字面量是常規陣列,它們具有與常規陣列相同的限制,不能被賦值。

(在 myword 已經被如上宣告之後)像下面這樣的表示式:

1
2
myword = "Bye";
myword[] = "Bye";

無效的,就像下面這個表示式也無效一樣:

1
myword = { 'B', 'y', 'e', '\0' };

這是因為陣列不能被賦值。但請注意,它的每個元素可以被單獨賦值。例如,下面這樣是正確的:

1
2
3
4
myword[0] = 'B';
myword[1] = 'y';
myword[2] = 'e';
myword[3] = '\0';

字串和以空字元結尾的字元序列

以空字元結尾的普通字元序列陣列是 C 語言中用來表示字串的典型型別(因此它們也被稱為 C-風格字串)。在 C++ 中,儘管標準庫為字串定義了一個特定的型別(string 類),但以空字元結尾的普通字元序列陣列(C-風格字串)仍然是該語言中表示字串的一種自然方式;事實上,字串字面量仍然總是生成以空字元結尾的字元序列,而不是 string 物件。

在標準庫中,兩種表示字串的方式(C-風格字串和庫字串)共存,並且大多數需要字串的函式都被過載以支援這兩種方式。

例如,cincout 直接支援以空字元結尾的序列,允許它們像字串一樣直接從 cin 中提取或插入到 cout 中。例如:

// strings and 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;
}
What is your name? Homer
Where do you live? Greece
Hello, Homer from Greece!

在這個例子中,同時使用了以空字元結尾序列的字元陣列和字串。它們在與 cincout 結合使用時幾乎可以互換,但它們的宣告有一個顯著的區別:陣列具有固定大小,需要在宣告時顯式或隱式地指定;question1 的大小正好是 20 個字元(包括結尾的空字元),answer1 的大小是 80 個字元;而字串就是字串,沒有指定大小。這是因為字串具有在執行時確定的動態大小,而陣列的大小在編譯時、程式執行之前就已經確定了。

無論如何,以空字元結尾的字元序列和字串可以很容易地相互轉換:

以空字元結尾的字元序列可以隱式地轉換為字串,而字串可以透過使用 string 的成員函式 c_strdata 轉換為以空字元結尾的字元序列:

1
2
3
4
char myntcs[] = "some text";
string mystring = myntcs;  // convert c-string to string
cout << mystring;          // printed as a library string
cout << mystring.c_str();  // printed as a c-string 

(注意:stringc_strdata 成員函式是等效的)
Index
目錄