Re: [問題] 二維陣列的陣列名稱
看板C_and_CPP (C/C++)作者Favonia (小西風最乖了*^^*)時間13年前 (2011/07/24 20:34)推噓4(4推 0噓 15→)留言19則, 6人參與討論串5/7 (看更多)
想要補充三點 LPH66 大沒有提到的東西(但我寫的可能不適合初學者讀 orz)
第一個,printf 的 %p 只能用來印 void* 不能用來印其他種指標!(感覺可以
寫一篇「如何印指標」到 FAQ 裡面了...)編譯器沒辦法幫你轉型成 void*.
註:我覺得標準「希望」char* 也可以用,但是把標準翻遍還是覺得沒有寫得非
常清楚。
※ 引述《LPH66 (-858993460)》之銘言:
: 是的 這個某處並不是紀錄在某個變數裡
: 以我以前回過的一篇文的講法就是「它是綁在 a 這個符號上」
: 因此當有和它相關的位移運算時它就會把這個某處給代進去去運算
: 因此最後編譯出來的程式中 這個值將會直接出現在指令上而不是存在某個變數裡
第二個我想講一個經典例子:萬一有人寫了兩個檔案,一個有
| int a[100];
另一個檔案有
| extern int *a;
在很多實作中會死很慘。原因是指標和陣列是不一樣的東西。
: ---
: 我們將這個由陣列意義轉變成指標意義的概念稱做 decay
: 說成 "陣列 decay 成指標"
(以下講 C)第三個就是我用很囉唆的方法講一下指標和陣列的錯覺好了。我個人
覺得最好先把指標和陣列當成完全不同的東西,然後另外記得這個自動轉換規則就好:
| Except when it is the operand of the sizeof operator or the unary & operator,
| or is a string literal used to initialize an array, an expression that has
| type "array of *type*" is converted to an expression with type "pointer to
| *type*" that points to the initial element of the array object and is not
| an lvalue. If the array object has register storage class, the behavior is
| undefined.
複製全文是給想知道所有規則的人看的。以下以慢速度解析到底發生什麼事情:
| int a[2][3] = {1,2,3,4,5,6};
a[0] 會被翻譯成 *(a+0), 然後(精神上)執行下列的運算:
(1) a 算出一個型態 int[2][3], 代表那個陣列的 lvalue.
(2) 按照上述規則先被轉型為型態 int(*)[3], 指向 a 第一個元素的指標,然後
(3) a+0 還是得到一個型態為 int(*)[3], 指向 a 第一個元素的指標;最後
(4) *(a+0) 得到型態為 int[3], 代表 a 第一個元素的 lvalue.
(a[0])[3] 則會被翻譯成 *(*(a+0)+3) 就從上面的部份繼續吧 xD
(5) *(a+0) 先被轉型為型態 int*, 指向 a[0] 第一個元素的指標,然後
(6) *(a+0)+3 得到一個型態為 int*, 指向 a[0] 第四個元素的指標;最後
(7) *(*(a+0)+3) 得到型態為 int, 代表 a[0] 第四個元素的 lvalue.
C 語言讓人產生錯覺的地方就是步驟 (2) 和 (5). 然後...
| int (*b)[3];
| b = a;
(1-1) b 算出一個型態 int (*)[3], 代表那個指標的 lvalue.
(2-1) a 算出一個型態 int [2][3], 代表那個陣列的 lvalue.
(2-2) a 根據上面規則轉型為型態 int (*)[3], 指向 a 第一個元素的指標
(3) b = a 算出的值型態為 int (*)[3] 但不是 lvalue. 副作用是把左邊代表的
物件的內容,更新為右邊算出來的值。兩邊型態一樣所以不太需要管轉型。
(註:步驟 (1-1) 可能實際上在步驟 (2-1) 甚至步驟 (2-2) 之後。)
個人覺得先把陣列和指標當成完全不同的東西,然後再去記 C 語言很多地方會自
動轉型(也就是所謂的 "decay")觀念會比較清楚一點點。
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 140.112.30.39
※ 編輯: Favonia 來自: 140.112.30.39 (07/24 20:36)
推
07/24 20:53, , 1F
07/24 20:53, 1F
→
07/24 20:53, , 2F
07/24 20:53, 2F
嗯 a=b 是一個 expression (但這跟 int a=b; 的等號不同)
→
07/24 20:56, , 3F
07/24 20:56, 3F
→
07/24 20:56, , 4F
07/24 20:56, 4F
這裡的副作用就是賦值這件事情沒錯!
※ 編輯: Favonia 來自: 140.112.30.39 (07/24 20:57)
推
07/24 21:20, , 5F
07/24 21:20, 5F
※ 編輯: Favonia 來自: 140.112.30.39 (07/24 21:25)
→
07/24 22:17, , 6F
07/24 22:17, 6F
→
07/24 22:25, , 7F
07/24 22:25, 7F
→
07/24 22:26, , 8F
07/24 22:26, 8F
→
07/24 22:29, , 9F
07/24 22:29, 9F
→
07/24 22:29, , 10F
07/24 22:29, 10F
因為不同型態的指標的表示法和對齊要求可能會不一樣。我現在用的電腦,根據
別的標準,剛好都一樣(連函數指標都一樣),所以很難給一個會壞掉的例子...
以下兩部份給有興趣看 C99 標準的人:
| A pointer to void shall have the same representation and alignment
| requirements as a pointer to a character type. 39) Similarly, pointers
| to qualified or unqualified versions of compatible types shall have
| the same representation and alignment requirements. All pointers to
| structure types shall have the same representation and alignment
| requirements as each other. All pointers to union types shall have
| the same representation and alignment requirements as each other.
| Pointers to other types need not have the same representation or
| alignment requirements.
@ C99 6.2.5/27
| 39) The same representation and alignment requirements are meant to
| imply interchangeability as arguments to functions, return values
| from functions, and members of unions.
@ C99 註腳 39(沒有任何約束力)
推
07/24 22:32, , 11F
07/24 22:32, 11F
→
07/24 22:33, , 12F
07/24 22:33, 12F
編輯:補上一個附註(跟上面註腳 39 有關)。
※ 編輯: Favonia 來自: 140.112.30.39 (07/25 04:01)
→
07/25 10:08, , 13F
07/25 10:08, 13F
→
07/25 10:09, , 14F
07/25 10:09, 14F
→
07/25 10:17, , 15F
07/25 10:17, 15F
Wikipedia 這段討論的是 6.3.2.3(跟「指向的型態」的對齊要求有關),但我
引用的是 6.2.5(跟「自己的型態」的對齊要求有關)。這裡 printf 想要印出指標
自己,沒有要印出指標指到的內容,所以我想參考 6.2.5 是對的。
※ 編輯: Favonia 來自: 140.112.30.39 (07/25 15:08)
→
07/25 18:31, , 16F
07/25 18:31, 16F
不太懂你的意思 @@ 它只有說
(1) 指向 void 和指向 char 表示法和對齊要求一樣
(2) 指向 T 和指向 xxx T 一樣的表示法和對齊要求一樣
(3) 指向結構的指標表示法和對齊要求一樣
(4) 指向 union 的指標表示法和對齊要求一樣
其他沒講的指標可以長得很不一樣 <-- 我 highlight 這句
※ 編輯: Favonia 來自: 140.112.30.39 (07/25 21:43)
→
07/25 21:47, , 17F
07/25 21:47, 17F
「不需要一樣」這句話是講給實作聽的。也就是實作可以在標準給的限制下隨便挑
自己喜歡的表示法;程式設計師不能假設表示法一樣。這句話不是對程式設計師說「不
一樣也可以交叉使用」。除了特別規定的例外外,程式設計師都不能假設交叉使用一定
會成功(如果只有參考語言標準)。
※ 編輯: Favonia 來自: 140.112.30.39 (07/25 23:00)
推
07/26 16:06, , 18F
07/26 16:06, 18F
→
07/26 16:06, , 19F
07/26 16:06, 19F
討論串 (同標題文章)
C_and_CPP 近期熱門文章
PTT數位生活區 即時熱門文章