1. 程式人生 > >C/C++中的段錯誤(Segmentation fault)

C/C++中的段錯誤(Segmentation fault)

}
3)其他

其實大概的原因都是一樣的,就是段錯誤的定義。但是更多的容易出錯的地方就要自己不斷積累,不段發現,或者吸納前人已經積累的經驗,並且注意避免再次發生。

例如:

<1>定義了指標後記得初始化,在使用的時候記得判斷是否為NULL
<2>在使用陣列的時候是否被初始化,陣列下標是否越界,陣列元素是否存在等
<3>在變數處理的時候變數的格式控制是否合理等

再舉一個比較不錯的例子:

我在進行一個多執行緒程式設計的例子裡頭,定義了一個執行緒陣列
#define THREAD_MAX_NUM
pthread_t thread[THREAD_MAX_NUM];
用pthread_create建立了各個執行緒,然後用pthread_join來等待執行緒的結束


剛 開始我就直接等待,在建立執行緒都成功的時候,pthread_join能夠順利等待各個執行緒結束,但是一旦建立執行緒失敗,那用pthread_join來 等待那個本不存在的執行緒時自然會存在訪問不能訪問的記憶體的情況,從而導致段錯誤的發生,後來,通過不斷除錯和思考,並且得到網路上資料的幫助,找到了上面 的原因和解決辦法:

在建立執行緒之前,先初始化我們的執行緒陣列,在等待執行緒的結束的時候,判斷執行緒是否為我們的初始值
如果是的話,說明我們的執行緒並沒有建立成功,所以就不能等拉。否則就會存在釋放那些並不存在或者不可訪問的記憶體空間。

上面給出了很常見的幾種出現段錯誤的地方,這樣在遇到它們的時候就容易避免拉。但是人有時候肯定也會有疏忽的,甚至可能還是會經常出現上面的問題或者其他常見的問題,所以對於一些大型一點的程式,如何跟蹤並找到程式中的段錯誤位置就是需要掌握的一門技巧拉。


4。如何發現程式中的段錯誤?



而我常用的除錯方法有:

1)在程式內部的關鍵部位輸出(printf)資訊,那樣可以跟蹤 段錯誤 在程式碼中可能的位置

為了方便使用這種除錯方法,可以用條件編譯指令#ifdef DEBUG和#endif把printf函式給包含起來,編譯的時候加上-DDEBUG引數就可以檢視除錯資訊。反之,不加上該引數進行除錯就可以。

2)用gdb來除錯,在執行到段錯誤的地方,會自動停下來並顯示出錯的行和行號

這 個應該是很常用的,如果需要用gdb除錯,記得在編譯的時候加上-g引數,用來顯示除錯資訊,對於這個,網友在《段錯誤bug的除錯》文章裡創造性的使用 這樣的方法,使得我們在執行程式的時候就可以動態撲獲段錯誤可能出現的位置:通過撲獲SIGSEGV訊號來觸發系統呼叫gdb來輸出除錯資訊。如果加上上 面提到的條件編譯,那我們就可以非常方便的進行段錯誤的除錯拉。


3)還有一個catchsegv命令
通過檢視幫助資訊,可以看到

Catch segmentation faults in programs


這個東西就是用來撲獲段錯誤的,它通過動態載入器(ld-linux.so)的預載入機制(PRELOAD)把一個事先寫好的庫(/lib/libSegFault.so)載入上,用於捕捉斷錯誤的出錯資訊。

到這裡,“初級總結篇”算是差不多完成拉。歡迎指出其中表達不當甚至錯誤的地方,先謝過!


參考資料[具體地址在上面的文章中都已經給出拉]:

1。段錯誤的定義
Ansers.com

Definition of “Segmentation fault”

2。《什麼是段錯誤》

3。《Segment fault 之永遠的痛》

4。《段錯誤bug的除錯》


後記

雖然感覺沒有寫什麼東西,但是包括查詢資料和打字,也花了好些幾個小時,不過總結一下也是值得的,歡迎和我一起交流和討論,也歡迎對文章中表達不當甚至是錯誤的地方指正一下。