[爆卦]指標與陣列的差別是什麼?優點缺點精華區懶人包

為什麼這篇指標與陣列的差別鄉民發文收入到精華區:因為在指標與陣列的差別這個討論話題中,有許多相關的文章在討論,這篇最有參考價值!作者Hazukashiine (恥ずかしい ね...(>///<))看板C_and_CP...

※ 引述《lalaboom (lalaboom)》之銘言:
: 標題: [問題] 對陣列名稱取址
: 時間: Tue May 12 19:54:31 2015
: 
: 之前我的認知陣列名稱是一個常數指標,非指標常數喔,
:  
: 1. 請問這個敘述對嗎?
:  
: 現在有陣列 int b[2]; int a[2][3];
:  
: 2. 請問為什麼 b 跟 &b 兩個address會一樣呢?
: 我可以理解 a, a[0], &a[0][0] 這3個一樣,
: 但是type不同,還是說這個認知也是錯的XD
:  
: 3. 陣列在記憶體裏面除了宣告出來的連續空間,
: 陣列名稱是否會有另外像宣告指標一樣有一個變數空間嗎?
:  
: 關於2之前好像有看到說&b = b 是定義好的 (compiler ? )

這些問題好像有許多的初學者都很困惑,
雖然明天我要考可怕的偏微分段考已經自顧不暇了,不過還是想回答一下。(笑

站在C語言本身的角度,陣列本身不是一個指標,它就是一個單單純純的陣列。
站在機器的角度,陣列佔據了記憶體一段連續的空閒,並且有個變數記錄了它的位置。
但是這個變數不是程式設計師可以直接獲得的,它需要進行轉換才能獲得。

先說說第二個好了:
b 跟 &b 的地址不一樣,簡單地說, &b 的地址並不存在,而且對編譯器來說是非法的。
因為當你在寫單獨一個 b 的時候, b 已經被隱式轉換成指標型態,而且這是被強制的。
在且 b 是一個右值(r-value),意思是你不能對此作取址的動作。

根據 ISO 文件 §4.2.1 Standard Conversions: Array-to-pointer conversion

An lvalue or rvalue of type "array of N T" or "array of unknown bound of T"
can be converted to an rvalue of type "pointer to T." The result is a pointer
to the first element of the array.

接下來的第三個也是一樣,
陣列名稱有佔空間嗎?結果呼之欲出,當然不佔。因為陣列名稱(b)是右值,並不佔空間。

可是你一定會很好奇不佔空間的話你的程式要如何知道陣列在哪?
這件事很妙,站在C語言的角度並不佔空間,但是實作上辦不到,所以當然要佔空間。
只是這個變數不是你的程式可以 access 的,它被編譯器巧妙地包裝了。
這樣很矛盾嗎?

其實,不。
因為程式語言本身定義的是語法結構,並不是實作的內容。
因此一個程式語言可以有很多種編譯器,像是 GCC C Compiler, MSVC etc.

如有錯誤歡迎指正。

( ̄▽ ̄#)=﹏﹏ 飄走=

--

當教授在講臺上C++的時候,我的臉比佳佳還要沮喪...
講正經的... C++是一個被過度設計的程式語言,完全遭透了!

--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 140.113.91.124
※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1431438143.A.864.html
※ 編輯: Hazukashiine (140.113.91.124), 05/12/2015 21:49:51
Feis: &b 存在且合法. b 不佔空間的話, 試解釋 sizeof(b) 05/12 21:54

&b 當然存在且合法。不存在的是 &b 的地址。
請您再仔細地看上文「&b 的地址(即&&b)並不存在,而且對編譯器來說是非法」

根據 ISO/IEC 9899:TC3 Committee Draft — Septermber 7, 2007 WG14/N1256

§6.5.3.4

3. ... When applied to an operand that has array type,
the result is the total number of bytes in the array.

這項目特別被舉出來是為了避免 sizeof(b) 中的 b 被 implicitly convert.
所以說,sizeof(b) 仍然是 int b[2] 這個陣列的位元組大小。

Feis: b 是個陣列. 但是不占空間嗎? 蠻有趣的 05/12 22:43

b 是陣列名稱, b[] 才是是陣列,該陣列的型態是 int[2]。
b 不佔空間,只有 b[] 佔空間,但是實作上需要使用一個空間來儲存 b[2] 的地址。
而且這個空間也一樣是放在 stack 中,會隨函式的增長或消滅來生成與毀滅。

CaptainH: b 是 lvalue 05/12 22:53
AstralBrain: b[2]不是陣列, b[2]是陣列的第3個element 05/12 22:57

已修正,感謝提出錯誤。

AstralBrain: b 是 lvalue (這很重要) http://ideone.com/mKCvI2 05/12 22:58

這是邏輯謬誤,使用C++來檢視C?
在C語言中,不實際擁有在記憶體中一塊物理位置的稱之為右值。
b 是陣列名稱(並非陣列本身),當然在記憶體中不擁有物理位置。

CaptainH: 那你怎麼解釋An lvalue or rvalue of type "array of N 05/12 22:58
CaptainH: T"這個東西? 05/12 22:58

Feis: 放在 stack 中? 這也蠻有趣的 05/12 23:15
CaptainH: 修正後仍是錯,b[]不是正確的語法,更別說他代表什麼了 05/12 23:15

不然大大覺得應該要如何準確地表示陣列?
陣列一語本來就不是正確的語法,最正確的用法是:

It has type `int[2]`.

Feis: 推一下右值的定義. 蠻有趣的 05/12 23:17

L-values have storage addresses that are programmatically accessible to the
running program, meaning that they are variables or dereferenced references to
a certain memory location.

Does b have its own storage address? Only b[0] and b[1] does!

Feis: 對了. 忘了問 4.2.1 的那節是 ISO C 哪個版本? 05/12 23:21
Feis: 我建議你可以去 C 標準找一下 rvalue (如果你在說 C 的話) 05/12 23:22
Feis: 所以你的 compiler 印不出 &b ? 05/12 23:24

`b` has type `int[2]`, and `&b` has type `int(*)[2]`.
Type `int(*)[2]` will decay to `int*` while the array length is useless.

Feis: 此外你可以想想 struct 變數~ 比對一下跟 array 的差別 05/12 23:26
Feis: 還有你的 sizeof 的說明不是已經說了 b 是 array type ? 05/12 23:27
Feis: 如果 b 不是 array type, 那 sizeof(b) 到底是甚麼.. 頭痛 05/12 23:27

我承認我真的不知道 b 是不是 array type,
但是 b 肯定是 int[2],只是在程式碼中會被轉型成 int(*)[2]。

Feis: b 會被轉成 &b[0] 喔~ 所以是 int * 而不是 int(*)[2] 05/12 23:41

絕不是 int*

http://stackoverflow.com/questions/2893911/
address-of-an-array-address-of-being-ignored-be-gcc

int(*)[2] 會 decay 成 int* 當陣列長度無用的時候,

Feis: 恩.. 我們看的是同一篇嗎 XDDDDD 05/12 23:45
Feis: 我需要一點時間理解. 晚安 : ) 05/12 23:46

A pointer that points to an array of 50 ints has type int (*)[50] - that's
the type of &test.

Feis: 是阿. 那不就是 &b 嗎 xD 05/12 23:48

是呀~所以 &b has type `int(*)[2]` not type `int*`.

Feis: 但是你說的不是 b 在程式碼中會被轉 int (*)[2] 嗎? 05/12 23:49
Feis: 我說的是 b 會轉為 int * 不是 &b 阿 QQ 05/12 23:50

喔喔喔~我錯亂惹~
整理一下:
b: int[2] -> int* (implicit conversion: array-to-pointer conversion)
&b: int(*)[2] (address-of operator)

Feis: 用編輯文章好難回阿 xD 原文 &b 的 address 應該不是 &&b 的 05/12 23:57
Feis: 意思. 或者我以為他不是 xD 05/12 23:58

搞不好真的不是,中文有時候會怪怪der.

bibo9901: 你是跟葉孤紅一樣有人專門寫一本錯誤的書給你看嗎 XD 05/13 00:00

XDDD
錯亂惹啦~先去準備偏微分啦!!!

這篇的重點是:
1. Implicit type conversion: array-to-pointer conversion
2. b has type int[2], and &b has type int(*)[], and &&b is invalid.

bibo9901: 既然 b 是一個 rvalue 那你怎麼能用 address-of 呢? 05/13 00:03

暈~
b 在 code 中被轉換的才是 rvalue,
在 sizeof operator 中不用被轉換,是 lvalue!!!

Feis: 提醒一下... standard conversion 是 C++ 的... 05/13 00:06

喔喔喔~是 Implicit type conversion
改了改了

bibo9901: 我說的是 address-of "&" 不是 sizeof 05/13 00:10

眼殘XD
compiler 很聰明吧~
也許看到前方有&就不會作 implicit conversion 吧?阿災?

bibo9901: 如果 b 不佔空間的 rvalue, 那你寫下 &b 就是非法的 05/13 00:11
Feis: 其實我不知道 rvalue 不占空間這樣的說法到底該怎麼解釋 xD 05/13 00:12
Feis: 我是覺得 rvalue 很玄阿~ 大家晚安~ 05/13 00:14
bibo9901: 的確很怪, 但暫且假設如他所說的那樣, 對 b 取址更怪 05/13 00:14

我翻遍標準文檔就還是覺得怪怪的
可能就真的不隱式轉換了吧~
※ 編輯: Hazukashiine (140.113.91.124), 05/13/2015 00:18:09
Feis: 對轉換有興趣請參閱 C89 標準 3.2.2.1 05/13 00:25
yvb: 94行說 "使用C++來檢視C?" 05/13 14:57
yvb: 但 35行 "ISO 文件 §4.2.1" 似乎引自 C++ ?? 05/13 14:57
yvb: 另外, 原原PO問 "為什麼 b 跟 &b 兩個address會一樣" 05/13 15:02
yvb: 然後 30行那邊回 "b 跟 &b 的地址不一樣" ... 05/13 15:02
yvb: 感覺答非所問? 還是 "地址不一樣" 似乎不是唯一解?? 05/13 15:03
yvb: 上面 F大的 3.2.2.1 其實是指 6.3.2.1 ? 05/13 17:09
Feis: yvb: 好像是版本差異 XD 那是 C89 Draft 05/13 17:20
yvb: soga... C89 3.2.2.1 => C90 6.2.2.1 => C99~C11 6.3.2.1 05/13 17:57
yvb: c89 要 google ansi.c.txt 才找得到 :P (好像沒 pdf 的?) 05/13 17:59

你可能也想看看

搜尋相關網站