為什麼這篇c語言指標題目鄉民發文收入到精華區:因為在c語言指標題目這個討論話題中,有許多相關的文章在討論,這篇最有參考價值!作者EdisonX (閉上眼的魚)看板C_and_CPP標題Re: [問題] 指標和雙重指標考題時間...
以下是昨天晚上作夢夢到的,夢到某位學生對這題有興趣,
< 小弟講指標的講義有講到類似的東西 >
所以大致講一下這是什麼情形。
這題寫法我不知到底合不合標準(是有幾個不完成合標準沒錯,只是一般人這麼用),
所以有幾個 基本假設 先講清楚。
(1) CHAR_BITS = 8
(2) sizeof(char) = 1 < 這不是基本假設了, 是規定 >
(3) sizeof(int) = 4
(4) machine memory platfrom is "little endia"
(5) Project using Release Mode, not Debug Mode.<depends on compiler>
(6) 二補數系統
若這是練習題的話,上面五個假設應是基本要有的。
最後如果你「運氣不好」跑得出結果,請別認為是好事,
該想一下有沒有辦法讓編譯器處理這種壞習慣,
這題目只存在於面試考觀念而已。
: 我最近寫題目 寫到一題
: 不知道答案是什麼 自己用 VC跑 竟然跑不出來
你原本的程式碼有一處是筆誤的,在 VC 下不是「跑不出來」,
而是「無法編譯」、「編譯錯誤」,下次直接把錯誤敘述清楚。
※ 引述《SNSDpk5566 (5566 超強)》之銘言:
: char d[3] = {100,200,300};
: int *p = &d;
: int **pn = &p;
假設前三行記憶體內容如下,記憶體編碼應用 8 碼較合適,唯說明以四碼。
┌────┬────┬────┬────┬──┬───┬───┐
Addr│0x1200 │0x1201 │0x1202 │0x1203 │... │0x1300│0x1304│
├────┼────┼────┼────┼──┼───┼───┤
Var │ d[0] │ d[1] │ d[2] │ ???? │... │*p │**pn │
├────┼────┼────┼────┼──┼───┼───┤
內容│ 100 │ 200 │ 300 │ ???? │... │0x1200│0x1300│
└────┴────┴────┴────┴──┴───┴───┘
hex 0x64 0xc8 0x2c 0xbf
< 這個 byte 數值是假設的 >
上面張圖可以講很久了,
(1) d[2] = 300, 一個 signed-byte 最多只能存 -128~+127,這已經溢位了,
實際上存多少?不知道,但一種「可能」的數值是 (300-256 = 44),
但無論如何,它不會把溢位多出的部份存到 0x1203。
(2) d[1] = 200, 這也溢位了, 範圍不在 -128~+127,實際上「可能」的數值是
(200-256 = -56)。
(3) 不論 d[1], d[2] 問題,我們都以 16 進位示之,原因是存在 memory 都是二進位,
無關正負號。
(4) 當寫下 *p = &d , 或 *p=(int*)d 的時候,由於 *p 本身是「整數」指標,所以
p 指向記憶體範圍是從 0x1200~0x1203,也就是說,它會用到第 4 個 unknow byte,
上面假設,在記憶體裡面是 0xbf,那問題來了,
printf("%08x\n", *p);
答案是多少?
它不是 0x 64 c8 2c bf, 由於是 little-endian 的關係,所以 *p 會被解讀成
0x bf 2c c8 64
: *p-=1;
所以 *p-=1, 會變成 0xbf 2c c8 63,以這例子而言,
實際上就是將 d[0] 扣 1 ,記憶體如下
┌────┬────┬────┬────┬──┬───┬───┐
Addr│0x1200 │0x1201 │0x1202 │0x1203 │... │0x1300│0x1304│
├────┼────┼────┼────┼──┼───┼───┤
Var │ d[0] │ d[1] │ d[2] │ ???? │... │*p │**pn │
├────┼────┼────┼────┼──┼───┼───┤
內容│ 99 │ 200 │ 300 │ ???? │... │0x1200│0x1300│
└────┴────┴────┴────┴──┴───┴───┘
hex 0x63 0xc8 0x2c 0xbf
上述可知,其實完全動不到未知的第 4 個 byte, (Address 0x1203),
所以印出 printf("%d", *p); 的時候會是未知的, 關鍵在於 0x1203 多少不確定,
但前 3 bytes 變化是可以「粗略估計」的,就像上面流程所述。
故這時候如果要問我 *p 是多少,我的回答是 0x??2cc863
至於到目前為止,compiler 真的可以那麼順利讓它轉過去嗎?
oh, 不一定。已知一些 compiler 在 debug 時會用 hex speaker,
去檢查使用者寫的程式碼有沒有用到非法空間,如果有做這層檢查的話,
上述在做 int *p = (int*)&d ; 轉型的時候就會失敗了。
然而開啟 release mode (-o2) 時,這個不會再自己去檢查是不是寫到非法空間,
所以 "有機會" 可以轉型成功,反正最後 "以這個例子" ,並不會影響到第 4 個 byte,
會影響到第4個 byte 的情況有兩種:
<a> 電腦為 little-endian (一般假設),且 d[0]~d[2] 全都是 0,
所以減法造成了減法上的借位,這時才動用了 0x1203 之內容。
<b> 電腦為 big-endian 時就一定會動到 0x1203 這個 value。至於 Mixed-Endian、
Middle-Endian 小弟沒研究,就不多贅述了。
: p = &d[1];
這行改變了 p 的內容值,記憶體內容變如下。
┌────┬────┬────┬────┬──┬───┬───┐
Addr│0x1200 │0x1201 │0x1202 │0x1203 │... │0x1300│0x1304│
├────┼────┼────┼────┼──┼───┼───┤
Var │ d[0] │ d[1] │ d[2] │ ???? │... │*p │**pn │
├────┼────┼────┼────┼──┼───┼───┤
內容│ 99 │ 200 │ 300 │ ???? │... │0x1201│0x1300│
└────┴────┴────┴────┴──┴───┴───┘
hex 0x63 0xc8 0x2c 0xbf 0xcc
: **p+=1; **pn+=1;
這行我認為是筆誤寫錯,應該是要寫 **pn+=1 才對,
不然會造成編譯錯誤。分解步驟:
pn --> 取到 pn 的內容,0x1300。
*pn --> 取到 (0x1300) 的內容,0x1201。
**pn --> 取到 (0x1201) 的內容,。
至此,**pn 得到是一個 int, 所以從 0x1201 往後提出 4 bytes 出來,
也就是 0x1201~0x1204 的值,以 little-endian 去解讀,
無奈 0x1204 我們也不知道,只好暫時先假設成 0xcc 了,
little-endian 解讀出來後就變成 0xccbf2cc8 ,最後一步..
**pn+=1 --> 將 (0x1201) 的內容 0xccbf2cc8 取出來,做+1動作得 0xccbf2cc9,
再以 little-endian 方式放回到 (0x1201) 裡面去。
┌────┬────┬────┬────┬──┬───┬───┐
Addr│0x1200 │0x1201 │0x1202 │0x1203 │... │0x1300│0x1304│
├────┼────┼────┼────┼──┼───┼───┤
Var │ d[0] │ d[1] │ d[2] │ ???? │... │*p │**pn │
├────┼────┼────┼────┼──┼───┼───┤
內容│ 99 │ 201 │ 300 │ ???? │... │0x1201│0x1300│
└────┴────┴────┴────┴──┴───┴───┘
hex 0x63 0xc9 0x2c 0xbf 0xcc
一樣,這個時候如果問我 *p , **pn 是多少的話,
我的回答是 0x????2cc9,變前 2 bytes 不確定。
: p--;
: 求 *p , **p, d[0] d[1]
最後的解讀就看 printf 輸出格式怎麼處理,就算知道記憶體長怎樣,
輸出格式亂搞還是會得到不同結果,故認為題目就只有寫
求 *p , **p, d[0] d[1]
個人認為是不夠的,printf 格式寫出來才有繼續討論的必要。
----------------------------
以上敘述若有誤、或不盡理想的部份,歡迎指正,感謝收聽。
--
「自從我學了 C# , 人都變聰明 , 考試都考一百分」
「自從我學了 VB , 皮膚都變好 , 人也變漂亮了 」
「自從我學了 Java , 明顯變壯 , 個子也變高了 」
「自從我學了 C++ , 內分泌失調 , 頭都禿了... 」
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 180.177.76.161
※ 編輯: EdisonX 來自: 180.177.76.161 (09/14 22:43)