Re: [問題] 二維陣列的陣列名稱

看板C_and_CPP (C/C++)作者 (小西風最乖了*^^*)時間13年前 (2011/07/24 20:34), 編輯推噓4(4015)
留言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
問一下 (3) b = a 是個 expression, 傳回 b 的值, 所以 F
07/24 20:53, 1F

07/24 20:53, , 2F
大才說 "算出的值型態為 int (*)[3] 但不是 lvalue." 嗎?
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
多謝 L 與 F 大!
07/24 21:20, 5F
※ 編輯: Favonia 來自: 140.112.30.39 (07/24 21:25)

07/24 22:17, , 6F
正常人不會去寫那種東西....extern int *a;...
07/24 22:17, 6F

07/24 22:25, , 7F
另外也不要去擔心%p 與void*的事了...
07/24 22:25, 7F

07/24 22:26, , 8F
我好奇的是,真的有程式碼release後還會輸出address嗎?
07/24 22:26, 8F

07/24 22:29, , 9F
第一個我很意外... void *與int *我以為都只是一個'值'
07/24 22:29, 9F

07/24 22:29, , 10F
對於 %p 來說,void *與int *會有什麼差別呢?
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
extern int *a; 就是誤以為指標跟陣列是一樣的
07/24 22:32, 11F

07/24 22:33, , 12F
debug的東西是不太會出現在release code裡...
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
我覺得你highlight的那段好像是不需要做轉型耶...
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
你highlight的那句不是說 不需要"一樣"嗎?
07/25 21:47, 17F
「不需要一樣」這句話是講給實作聽的。也就是實作可以在標準給的限制下隨便挑 自己喜歡的表示法;程式設計師不能假設表示法一樣。這句話不是對程式設計師說「不 一樣也可以交叉使用」。除了特別規定的例外外,程式設計師都不能假設交叉使用一定 會成功(如果只有參考語言標準)。 ※ 編輯: Favonia 來自: 140.112.30.39 (07/25 23:00)

07/26 16:06, , 18F
C FAQ 5.17 或許可以做個參考:
07/26 16:06, 18F

07/26 16:06, , 19F
文章代碼(AID): #1EB157xt (C_and_CPP)
討論串 (同標題文章)
文章代碼(AID): #1EB157xt (C_and_CPP)