昨天遇到一個很奇怪的問題,如下:
按照理論,最后*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.(知道原因了)
修改后:
這里終於正確了。
PS:前面一種情況,棧被系統回收,但是仍能輸出一次99,我猜可能是系統還沒來的及回收。。。
PSS:指針太容易出錯了。。