昨天遇到一個很奇怪的問題,如下:
按照理論,最後*p的值應該是99,不知為什麼是15了,是以今天記錄用gdb調試的過程,并熟悉gdb的使用。
(調試過程參考:http://www.cnblogs.com/hankers/archive/2012/12/07/2806836.html)
開始:
1.
2.(用list從第1行開始列出源碼)
3.(一次隻列10行,如果要從第11行開始繼續列源代碼可以輸入list)
4.(也可以什麼都不輸直接敲回車,
gdb
提供了一個很友善的功能,在提示符下直接敲回車表示重複上一條指令。)
5.(
gdb
的很多常用指令有簡寫形式,例如
list
指令可以寫成
l
,要列一個函數的源代碼也可以用函數名做參數:)
6.(退出gdb環境)
7.(現在将niuke.cpp改名,然後gdb就列不出源碼了)
說明:
gcc
的
-g
選項并不是把源代碼嵌入到可執行檔案中的,在調試時也需要源檔案。
8.(源碼檔案恢複,重新開始)
gdb
停在
main
函數中變量定義之後的第一條語句處等待我們發指令,
gdb
列出的這條語句是即将執行的下一條語句。
9.(我們可以用
next
指令(簡寫為
n
)控制這些語句一條一條地執行)
說明:用n函數f()中的結果一下就列印出來了
10.(現在用start重新開始,用step指令(簡寫s)進入f()中去跟蹤執行)
現在進入了f()函數。
11.(在函數中有幾種檢視狀态的辦法,
backtrace
指令(簡寫為
bt
)可以檢視函數調用的棧幀)
可見目前f()是被main()調用的,傳入指針p傳給ret=0xbfffee94
12.(檢視目前f()函數内局部變量的值i locals 或者info locals)
13.(如果想檢視
main
函數目前局部變量的值也可以做到,先用
frame
指令(簡寫為
f
)選擇1号棧幀然後再檢視局部變量,i locals, info locals)
14.(繼續運作,然後用p+變量名檢視變量的值)
這裡......$5,$6,$7,$8......分别儲存了檢視的中間值:
未執行*ret = &a時:
ret: 0xbfffee94(為&p) *ret:0xbfffef54(p) **ret:-1073745577
執行*ret = &a後:
ret: 0xbfffee94 *ret:0xbfffee68 = &a:0xbfffee68(值為99) **ret:99(等于a)
15.(finish指令讓程式一直運作到目前函數結束)
傳回值是ret=0xbfffee94(&p)
16.(現在繼續運作)
注意:A &p address : 0xbfffee94(&p未改變) A p address : 0xbfffee68(與&a相同) A *p value : 15(奇怪的地方,為什麼不是99)
17.(換一種思路:在執行 cout << "A &p address : " << &p << endl; 之前直接檢視*p)
這裡可以看到*p=99,是正确的,位址也與上面相同
18.(繼續調試)
這裡發現*p=15,被改變了。
也就是說:在執行cout << "A &p address : " << &p << endl;後, *p的值被改變了,從99變為15了。
19.(連續輸出兩次*p)
這次發現第一次輸出結果正常,第二次輸出結果出錯,那為什麼呢?為什麼呢?????
20.(知道原因了)
說明:a是一個局部變量,&a在f()執行完後就被系統回收了。f()中ret = &a 這一步,使得p=&a,是以最後p輸出不對。
修改後:
這裡終于正确了。
PS:前面一種情況,棧被系統回收,但是仍能輸出一次99,我猜可能是系統還沒來的及回收。。。
PSS:指針太容易出錯了。。