你的兩個例子沒有可比性。
在你的第二個例子,你有
char a[] = "abcdefg";
char *p = a;
所以a
是一個數組,並p
是一個指針。畫在圖片中,它看起來像
+---+---+---+---+---+---+---+---+
a: | a | b | c | d | e | f | g | \0|
+---+---+---+---+---+---+---+---+
^
|
+----|----+
p: | * |
+---------+
而且這一切都很好;該代碼沒有問題。
但在你的第一個例子中,在文件1.c
你定義一個名爲p
數組:
+---+---+---+---+---+---+---+---+
p: | a | b | c | d | e | f | g | \0|
+---+---+---+---+---+---+---+---+
可以命名的數組「p
」如果你想(編譯當然不關心),但隨後,在文件0.c
中,您改變主意並聲明p
是一個指針。您還聲明(使用「extern
」關鍵字)p
是在其他地方定義的。所以編譯器會根據你的要求編寫代碼併發送到位置p
,並期望在那裏找到一個指針 - 或者在圖片中,它希望找到一個包含指向其他地方的箭頭的框。但它實際上發現的是你的字符串"abcdefg"
,只是它沒有意識到它。它可能最終試圖將字節0x61 0x62 0x63 0x64
(即,構成字符串"abcdefg"
的第一部分的字節)解釋爲指針。顯然這是行不通的。
你可以清楚地看到這一點,如果你改變0.c
的printf
調用
printf("%p\n", p);
這將輸出指針p
爲指針的價值。 (當然,p
並不是一個真正的指針,但是你對編譯器說謊,並且告訴它它是,所以你會看到的是編譯器把它當作指針的結果,再試圖瞭解這裏。)在我的系統這種打印
0x67666564636261
這是所有8個字節的字符串"abcdefg\0"
的,按相反的順序。 (由此我們可以推斷,我這(一)使用64位指針和(b)的機器上是小端)。所以,如果我試圖打印
printf("%c\n", p[3]);
它會嘗試獲取來自0x67666564636264
(即,0x67666564636261
+ 3)的字符並打印出來。現在,我的機器具有相當數量的內存,但它沒有那麼多,所以位置0x67666564636264
不存在,因此當它試圖從那裏獲取時程序崩潰。
還有兩件事。
如果數組是不一樣的指針,你怎麼會在你的第二個例子說
char *p = a;
脫身,一個我說的是「所有的罰款;沒有問題」? 如何將右側的數組分配給左側的指針? 答案是著名的「C數組和指針的等價」(臭名昭著的?):實際發生的事情是一樣,如果你說的
char *p = &a[0];
每當您在表達式中使用數組,你得到的是實際上是一個指向數組第一個元素的指針,就像我在這個答案中的第一張圖片中展示的一樣。
當你問到「爲什麼它不工作,而它在這裏工作?」時,還有兩種其他的方式可以問你。 假設我們有兩個功能
void print_char_pointer(char *p)
{
printf("%s\n", p);
}
void print_char_array(char a[])
{
printf("%s\n", a);
}
然後假設我們回到你的第二個例子,有
char a[] = "abcdefg";
char *p = a;
和假設,我們稱之爲
print_char_pointer(a);
或
print_char_array(p);
如果你嘗試它,你會發現它們都沒有問題。 但是,這怎麼可能呢?當我們調用print_char_pointer(a)
時,如何將數組傳遞給 需要指針的函數? 當我們調用print_char_array(p)
時,我們如何將指針傳遞給需要數組的一個 函數?
嗯,請記住,只要我們在表達式中提到一個數組, 我們得到的是一個指向數組第一個元素的指針。所以,當 我們稱之爲
print_char_pointer(a);
我們得到的是就像我們寫了
print_char_pointer(&a[0]);
什麼是真正被傳遞給函數是一個指針,這是 函數需要什麼,所以我們很好。
但是另一種情況下,我們將指針傳遞給聲明爲接受數組的函數?那麼,「C中數組和指針之間的等價」實際上是另一個原則。 當我們寫
void print_char_array(char a[])
編譯對待它就像我們寫了
void print_char_array(char *a)
爲什麼會編譯器做這樣的事情?爲什麼呢,因爲它知道 沒有數組會被傳遞給一個函數,所以它知道沒有 函數實際上會收到一個數組,所以它知道 函數會接收一個指針。所以這就是編譯器對待它的方式。
(而且,很清楚,當我們談到「在C數組和指針的等價 」,我們不是說 指針和數組是等價的,只是有這個 特殊等價我已經提到了 這兩個等價原則已經在這裏,其中三個都是 ,僅供參考:(1)當你在表達式中提到一個數組的名字時,你自動獲得的數組的名字是 是一個指向數組的第一個元素的指針 (2)每當你聲明一個似乎接受一個 數組的函數時,它實際接受的是一個指針。 (3)無論何時您在 p[i]
的指針上使用「數組」下標運算符[]
,您實際得到的結果與您寫入*(p + i)
的結果一樣。事實上,如果仔細考慮一下,由於 原則(1),即使當您在 上使用數組下標運算符時,您實際上在 指針上使用它。但這是一個非常奇怪的概念,如果你不想, 不必擔心,因爲它只是起作用。)
因此,你已經聲明瞭一個具有兩個衝突類型的變量,並詢問它爲什麼不是加工? –
在彙編程序文件('gcc -S -fverbose-asm -O')中的循環k在'1.c''p'中爲 –
是*數組*,在'0.c'中是*指針*。 –