看這樣一段程式碼:
#include <iostream>
using namespace std;
int main()
{
const char s[] = "hello";
cout << "Array content (s): " << s << endl; // 輸出字串內容
cout << "Address of s (&s): " << &s << endl; // 輸出整個陣列的地址
cout << "Address of s[0] (s): " << (void*)s << endl; // 強制轉換輸出地址
}
輸出如下:
輸出結果解釋
-
Array content (s): hello
s 被解釋為字串的首地址,因此輸出字串內容。
-
Address of s (&s): 0x70fe10
&s 是整個陣列的地址,和陣列首地址一致,但型別不同。
-
Address of s[0] (s): 0x70fe10
s 被轉換為 void*,明確輸出其地址。
著重解釋下為什麼s 被解釋為字串的首地址,因此輸出字串內容
詳細原因與機制
-
陣列名的退化
-
在 C 和 C++ 中,當陣列名 s 在需要指標的上下文中使用時,它會退化為一個指向陣列首元素的指標(即
&s[0]
)。這種退化適用於大多數場景,例如傳參或與指標運算。 -
但注意,此時陣列名 s 並不是一個指標,它是一個常量,表示陣列首元素的地址。
-
-
cout 的行為
-
cout 是一個流輸出物件,它對不同型別的輸入進行了過載:
-
如果輸入的是指向 char 的指標(即
const char*
或char*
),cout 會將其解釋為一個 C 風格字串,並輸出字串內容。 -
如果輸入的是其他型別的指標,例如
void*
或int*
,cout 會輸出這個指標的地址。
在該程式碼中,s 退化為
const char*
,因此 cout 將其解釋為 C 風格字串並輸出 "hello"。 -
-
字串的儲存
const char s[] = "hello";
實際上在記憶體中分配了一個 6 位元組的陣列:
地址 內容
0x70fe10 'h'
0x70fe11 'e'
0x70fe12 'l'
0x70fe13 'l'
0x70fe14 'o'
0x70fe15 '\0'
當 s 被用作 cout 的引數時,s 退化為 &s[0]
(即 0x70fe10),因此 cout 會從該地址開始,逐位元組讀取字元並輸出,直到遇到字串的終止符 \0。
著重解釋下s和&s
-
s 是什麼?
-
s 是一個字元陣列,
const char s[] = "hello";
定義了一個大小為 6(包括字串末尾的空字元 \0)的陣列。 -
s 的型別是 const char[6]。
-
-
&s 是什麼?
-
&s 是整個陣列 s 的地址,而不是陣列的第一個元素的地址(s 和 &s 在語義上不同)。
-
s 表示陣列首元素(s[0])的地址,型別是
const char*
。 -
&s 表示整個陣列的地址,型別是
const char (*)[6]
。
-
-
cout 如何處理 &s?
-
在 cout 中,標準輸出流沒有過載對
const char (*)[N]
型別的直接處理。 -
當傳遞 &s 時,它會退化為一個指向陣列的指標。
-
通常,C++ 的 cout 會將指標解釋為地址,並輸出地址值(例如 0x70fe10)。
-