作者tropical72 (藍影)
看板C_and_CPP
標題Re: [問題] 指標的指標問題
時間Sun Aug 28 01:52:24 2011
別再寄私信給我了,我已建議一些書,
找不到相關說明,或沒畫圖的,該再找一些書,
再不然,請善用你手邊 VS 逐步偵錯功能,
或發表出來讓其他版友有機會為你服務,
BBS 畫記憶體配置圖真不是件容易的事..
※ 引述《kswiss11 (kswiss)》之銘言:
: {
: *p1=(char*)malloc(16);
: strcpy(*p1, "Hello");
: }
: void main()
: {
: char*p=NULL;
Var. p
┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
Addr │0x12│ │ │ │ │ │ │ │ │ │ │
┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
Value │ 0 │ │ │ │ │ │ │ │ │ │ │
└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴
: printf("%p\n", &p);
0x12 (address of pointer)
: test(&p);
呼叫時,記憶體再配一個新的 p1,裡面存 p 之位址值,開始進入副函式
void test(char**
p1)
Var. p
p1
┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
Addr │
0x12│... │ │?? │ │ │ │ │ │ │ │
┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
Value │ 0 │... │ │
0x12│ │ │ │ │ │ │ │
└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴
{
*p1=(char*)malloc(16); /* equ. below lines. */
char * t = (char*)malloc(16); /* (1) */
* p1 = t; /* (2) */
(1) char* t = (char*)malloc(16);
t 指向新配置 16 個空間之開頭
Var. p
p1 t t+1 t+2 ... t+15
┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
Addr │
0x12│... │ │?? │... │
0x80│0x81│0x82│... │0x8f│ │
┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
Value │ 0 │... │ │
0x12│... │
??? │?? │ ?? │... │ ?? │ │
└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴
(2) *p1 = t;
將 t 之位址,設給 (p1 指向記憶體位址) 之內容
Var. p
p1 t t+1 t+2 ... t+15
┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
Addr │
0x12│... │ │?? │... │
0x80│0x81│0x82│... │0x8f│ │
┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
Value │
0x80│... │ │
0x12│... │
????│?? │ ?? │... │ ?? │ │
└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴
strcpy(*p1, "Hello");
將 (p1 指向位置) 指向位置,設成 'H' 'E' 'L' 'L' 'O' '\0'
Var. p p1 t t+1 t+2 ... t+16
┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
Addr │
0x12│... │ │?? │... │
0x80│0x81│0x82│... │0x8f│ │
┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
Value │
0x80│... │ │
0x12│... │'H' │'E' │ 'L'│... │ ?? │ │
└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴
0x80 'H' , 0x81 'E', 0x82 'L', 0x83 'L', 0x84 'O', 0x85 '\0'
0x86~0x8f ????
}
回到主程式後
Var. p
┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
Addr │
0x12│... │ │ │... │
0x80│0x81│0x82│... │0x8f│ │
┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
Value │
0x80│... │ │
│... │'H' │'E' │ 'L'│... │ ?? │ │
└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴
: printf("%s\n", p);
輸出 p 所指向位置之字串
從 0x80 開始輸出 'H', 一直輸出到 '\0',便輸出 "HELLO"
: }
最後加上
free(p);
p 內容雖仍不變,但其指向記憶體已不可使用
Var. p
┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
Addr │
0x12│... │ │ │... │
0x80│0x81│0x82│... │0x8f│ │
┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
Value │
0x80│... │ │
│... │??? │??? │ ???│... │ ?? │ │
└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴
字串 / 陣列 / 指標 本身便不好理解,
加上 sub_function 實際傳遞機制使得問題更加混亂,
此處確實不好第一次學習就理解,你的書沒有,才跟你說多找幾本書。
----
補原 po 於推文中的問題,
*p=(char*)malloc(16);不就等於p=(char**)malloc(16);嗎??
如果改成p=(char**)malloc(16);
然後strcpy(*p, "Hello");
執行後會出現異常,為什麼???
那兩行並不相等。
char **p;
p = (char**)malloc(16);
這段寫法很危險,想想 malloc 較為一般性的寫法為何
資料型態 *p;
p = (
資料態型 *)malloc(sizeof(
資料型態) * 配置個數)
malloc 裡面實際要放的是,「總共記憶體需求量」。
----
以
char *p1 而言,
char *p1;
p1 = (
char*)malloc(sizeof(
char) * 16);
這裡是配置一個「一維字元陣列,陣列大小有 16 個元素」
也因為每個字元所佔記憶體大小為 1 ,
所以 sizeof(char) 都不寫。
----
再看 char* *p1,
char* *p1;
p1 = (
char* *)malloc(sizeof(
char*) * 16);
這和推文問得一樣,只是把 * 分開一點,所以看起來怪怪的。再看一次公式
資料型態 *p;
p = (
資料態型 *)malloc(sizeof(
資料型態) * 配置個數)
現在資料型態是 char*, pointer to char,
配置出來的是 「一維指標陣列」,p 本身是陣列,
陣列元素裡面放的是一堆「位址值」,因為資料型態是 pointer to char,
那 sizeof(char *) 多大?
這是另一個討論很久的問題,但你現在可不用知道,只需要知道,
1. sizeof(...) 不要省
2. char** p = (char**)malloc(...) 出來的是指標陣列
3. char* p = (char*)malloc(...) 出來的是字元陣列
4. char*** p = (char***)malloc(...) 出來的還是指標陣列
其他的,不要再讚牛角下去了。
--
YouLoveMe() ? LetItBe() : LetMeFree();
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 180.177.78.41
推 ericinttu:打這一篇應該至少花了一小時. 08/28 01:55
推 james732:看到圖文並茂就要推了 08/28 01:56
推 purpose:原PO人好到讓我想哭了,應該也取個外號,冠上好人兩字... 08/28 01:58
→ james732:那我改成壞人,好人交給原po好了 XD 08/28 02:03
推 ericinttu:心得感想: 有時候要懂程式需要到刻骨銘心的地步才會真的 08/28 02:05
→ ericinttu: 懂. 至少我是經歷過無數次的這種才走到這裡08/28 02:06
→ ericinttu: 但看到現在的自己, 再比對一些強者, 又笑了. 08/28 02:07
→ ericinttu: 於是, 現在的我, 比較喜歡用功有傻勁的人 XD 08/28 02:08
→ tropical72:我打到嘴都歪、臉都綠、手都黑了。 08/28 02:05
推 tonyhsie:推好人 08/28 02:06
推 purpose:之前在版上衝動想要回篇 NTFS 的問題,打了一兩天差不多八 08/28 02:10
→ purpose:成內容,用 PCMan ANSI 編輯器存檔再開,發現很多內容被吃 08/28 02:11
→ purpose:掉,才發覺在BBS打長文章還真他媽有夠不方便 08/28 02:11
→ tropical72:..我一直在Ctrl+C/Ctrl+V自行編色碼,表格還是用無蝦米 08/28 02:12
→ tropical72:加上 Insert 切換畫出來的。 XD 08/28 02:12
→ james732:這一篇文章值 794 Ptt幣 (敬禮) 08/28 02:14
→ tropical72:寫到一半時,其實很想問大家都怎麼查 malloc/new 出來 08/28 02:15
→ tropical72:的內容?我是用 偵錯->視窗->記憶體 慢慢 trace.. 08/28 02:16
推 purpose:怎麼查,就變數監看 + 記憶體視窗 08/28 02:18
→ tropical72:嗯,看來似乎大多也都這樣,謝謝 p 大回覆。 *^_^* 08/28 02:19
推 ericinttu:覺得IDE工具不方便的話, 可以自己再寫輸出訊息的工具. 08/28 02:20
→ ericinttu:我當初學指標, 算是邊trace邊硬記下電腦處理的程序, 然 08/28 02:22
→ ericinttu:後再經過一段時間, 才真的懂 指,被指,記憶體位址 的東西 08/28 02:23
→ tropical72:e大聰明多了,我是不斷 printf address 觀察學習的. 08/28 02:25
→ james732:我是在寫linked-list的時候用監看式拉來拉去突然頓悟XDD 08/28 02:26
推 purpose:其實這個程式碼的偵錯算可以有技巧,把中斷點設在 test 裡 08/28 02:31
→ purpose:然後 VC 的監看式,你可以加 p1 &p1 去觀察,重點是開啟 08/28 02:32
→ purpose:「呼叫堆疊」視窗,用滑鼠輕輕的點 main 兩下,會跳到上個 08/28 02:32
→ purpose:函數,此時監看式又可以輸入 p 跟 &p 來監看了... 08/28 02:33
→ purpose:對了,還有監看式 p1,16 直接把 p1 轉成陣列也是有用 08/28 02:34
推 VictorTom:推好人:) 08/28 02:34
→ tropical72:p 大方法太好了,省去一堆記憶體trace麻煩.. 08/28 02:41
→ purpose:最近覺得用 WinAPIOverride32 來監看 API,神器,推薦大家 08/28 02:45
→ purpose:Linux 上應該沒像這套那麼方便的軟體 08/28 02:45
→ angleevil:厄...會寄信給別人的,真的算傻勁嗎? 有時候先問一下對方 08/28 07:56
→ angleevil:比較好吧. 08/28 07:57
→ angleevil:james732加油,請當一生一世的好人 08/28 07:58
推 bill42362:佛! 08/28 10:25
推 kswiss11:真的很感謝你 08/28 11:05
→ final01:linux沒神器 ... 08/28 12:13
推 littleshan:valgrind 就是神器啊,雖然功能不太一樣 08/28 14:13
→ james732:我最近都忙著在電影板嘴炮,沒空在這邊當好人 XDDD 08/28 14:48
推 johnhmj:強推免費的C/C++教學軟體「tropical72 (藍影)」 (∩_∩) 08/28 16:20
推 james732:推樓上,再推一次這篇 08/28 16:30
→ purpose:原PO上新聞版面了 08/28 17:50
→ kswiss11:*p1=(char*)malloc(6)是配置6個指標陣列 08/28 19:21
→ kswiss11:那每個陣列元素所指向的記憶體總共有多少個byte??? 08/28 19:22
你只知道用動態配置,但卻不知道配置出來的是什麼東西。
上面有給你一個公式了,
資料型態 *p;
p = (
資料態型 *)malloc(sizeof(
資料型態) * 配置個數)
所以
*p1=(
char*)malloc(6);
配出來的不是指標陣列,而是字元陣列。
另上面提到了, 全部要寫 *p1 = (char*)malloc(sizeof(char) * 6);
sizeof(char) 是「單一元素大小」,6 指的是「元素個數」,
之所以把 sizeof(char) 拿掉 (我認為
對初學者不是好作法),
是因為 sizeof(char) 剛好等於 1,也就是單一元素大小。
※ 編輯: tropical72 來自: 180.177.78.41 (08/28 19:42)
→ tropical72:!! purpose 大沒提醒我都沒注意到。 08/28 19:43
→ tropical72:話說補問的問題,不是連記憶體配置圖都畫出來了嗎 = = 08/28 19:50
推 alongalone:你應該回他..RTFM 跟 STFW... 08/28 23:18
推 Gilbert0:不推不行了~ 08/29 00:23
推 ayumiayayaai:太威猛了... kswiss11根本就沒好好看書= = 08/29 03:16
推 james732:發現板標換了耶,推一下 XDDD 08/29 03:55
推 myIDis7:推大好人 08/29 04:32
推 cobrasgo:你人真好(遞卡) 08/29 12:21
推 cobrasgo:linux的神器就gdb啦… 08/29 12:23
→ angleevil:我記得james732有兩次上版標 08/29 12:47
推 james732:一次而已吧! 08/29 13:13
→ angleevil:鳥哥那次也算 08/29 13:31
→ james732:那次我不承認 XD 08/29 14:30
推 sawang:太帥了 XD 08/29 19:32
推 xatier:t大好人! 08/30 16:37
※ azter:轉錄至看板 THUMath95 11/28 07:37