標(biāo)準(zhǔn)C語言段錯誤總結(jié)_第1頁
標(biāo)準(zhǔn)C語言段錯誤總結(jié)_第2頁
標(biāo)準(zhǔn)C語言段錯誤總結(jié)_第3頁
標(biāo)準(zhǔn)C語言段錯誤總結(jié)_第4頁
標(biāo)準(zhǔn)C語言段錯誤總結(jié)_第5頁
已閱讀5頁,還剩15頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

標(biāo)準(zhǔn)C語言段錯誤總結(jié)

C語言2009-02-1711:49:51閱讀21評論0字號:大中小訂閱

最近一段時間在linux下用C做一些學(xué)習(xí)和開發(fā),但是由于經(jīng)驗不足,問題多

多。而段錯誤就是讓我非常頭痛的一個問題。不過,目前寫幾百行的代碼,也很

少出現(xiàn)段錯誤,或者是即使出現(xiàn)了,也很容易找出來,并且處理掉。

那什么是段錯誤?段錯誤為什么是個麻煩事?以及怎么發(fā)現(xiàn)程序中的段

錯誤以及如何避免發(fā)生段錯誤呢?

一方面為了給自己的學(xué)習(xí)做個總結(jié),另一方面由于至今沒有找到一個比

較全面介紹這個雖然是“FREQUENTLYASKEDQUESTIONS”的問題,所以我來做個

拋磚引玉吧。下面就從上面的幾個問題出發(fā)來探討一下“Segmentationfaults”

吧。

目錄

lo什么是段錯誤?

2O為什么段錯誤這么“麻煩”?

3。編程中通常碰到段錯誤的地方有哪些?

4。如何發(fā)現(xiàn)程序中的段錯誤并處理掉?

正文

lo什么是段錯誤?

下面是來自Answers,com的定義:

Asegmentationfault(oftenshortenedtosegfault)isaparticularerror

conditionthatcanoccurduringtheoperationofcomputersoftware.In

short,asegmentationfaultoccurswhenaprogramattemptstoaccessa

memorylocationthatitisnotallowedtoaccess,orattemptstoaccess

amemorylocationinawaythatisnotallowed(e.g.,attemptstowrite

toaread-onlylocation,ortooverwritepartoftheoperating

system).SystemsbasedonprocessorsliketheMotorola68000tendtorefer

totheseeventsasAddressorBuserrors.

Segmentationisoneapproachtomemorymanagementandprotectioninthe

operatingsystem.Ithasbeensupersededbypagingformostpurposes,but

muchoftheterminologyofsegmentationisstillused,''segmentation

fault〃beinganexample.Someoperatingsystemsstillhavesegmentation

atsomelogicallevelalthoughpagingisusedasthemainmemorymanagement

policy.

OnUnix-likeoperatingsystems,aprocessthataccessesinvalidmemory

receivestheSIGSEGVsignal.OnMicrosoftWindows,aprocessthataccesses

invalidmemoryreceivestheSTATUSACCESSVIOLATIONexception.

Asegmentationfault(oftenshortenedtosegfault)isaparticularerror

conditionthatcanoccurduringtheoperationofcomputersoftware.In

short,asegmentationfaultoccurswhenaprogramattemptstoaccessa

memorylocationthatitisnotallowedtoaccess,orattemptstoaccess

amemorylocationinawaythatisnotallowed(e.g.,attemptstowrite

toaread-onlylocation,ortooverwritepartoftheoperatingsystem).

SystemsbasedonprocessorsliketheMotorola68000tendtorefertothese

eventsasAddressorBuserrors.

Segmentationisoneapproachtomemorymanagementandprotectioninthe

operatingsystem.Ithasbeensupersededbypagingformostpurposes,but

muchoftheterminologyofsegmentationisstillused,segmentation

fault"beinganexample.Someoperatingsystemsstillhavesegmentation

atsomelogicallevelalthoughpagingisusedasthemainmemorymanagement

policy.

OnUnix-likeoperatingsystems,aprocessthataccessesinvalidmemory

receivestheSIGSEGVsignal.OnMicrosoftWindows,aprocessthataccesses

invalidmemoryreceivestheSTATUS_ACCESS_V1OLAT1ONexception.

另外,這里有個基本上對照的中文解釋,來自

httpi/A^vw./html_sql/3/132559.htm

所謂的段錯誤就是指訪問的內(nèi)存超出了系統(tǒng)所給這個程序的內(nèi)存空間,通常這

個值是由gdtr來保存的,他是一個48位的寄存器,其中的32位是保存由它指

向的gdl表,后13位保存相應(yīng)于gdl的下標(biāo),最后3位包括了程序是否在內(nèi)存

中以及程序的在epu中的運行級別,指向的gdt是由以64位為一個單位的表,在

這張表中就保存著程序運行的代碼段以及數(shù)據(jù)段的起始地址以及與此相應(yīng)的段

限和頁面交換還有程序運行級別還有內(nèi)存粒度等等的信息。?旦?個程序發(fā)生了

越界訪問,epu就會產(chǎn)生相應(yīng)的異常保護(hù),于是segmentationfault就出現(xiàn)了

所謂的段錯誤就是指訪問的內(nèi)存超出了系統(tǒng)所給這個程序的內(nèi)存空間,通常這個

值是由gdtr來保存的,他是一個48位的寄存器,其中的32位是保存由它指向

的gdt表,后13位保存相應(yīng)于gdt的下標(biāo),最后3位包括了程序是否在內(nèi)存中

以及程序的在epu中的運行級別,指向的gdt是由以64位為一個單位的表,在這

張表中就保存著程序運行的代碼段以及數(shù)據(jù)段的起始地址以及與此相應(yīng)的段限

和頁面交換還有程序運行級別還有內(nèi)存粒度等等的信息。一日.一個程序發(fā)牛了越

界訪問,cpu就會產(chǎn)生相應(yīng)的異常保護(hù),于是segmentationfault就出現(xiàn)了

通過上面的解釋,段錯誤應(yīng)該就是訪問了不可訪問的內(nèi)存,這個內(nèi)存區(qū)要么是

不存在的,要么是受到系統(tǒng)保護(hù)的。

2o為什么段錯誤這么麻煩?

中國linux論壇有一篇精華帖子《Segmentfault之永遠(yuǎn)的痛》

(http:〃www.linuxforum.net/forum/gshowflat.php?Cat=&Board=program&Num

bcr=193239&pagc=2&vicw=collapsed&sb=5&o=all&fpart=l&vc=l)

在主題帖子里頭,作者這么寫道:

寫程序好多年了,Segnentfault是許多C程序員頭疼的提不。指針是好東西,

但是隨著指針的使用卻誕生了這個同樣威力巨大的惡魔。

Segmentfault之所以能夠流行于世,是與Glibc庫中基本所有的函數(shù)都默認(rèn)型

參指針為非空有著密切關(guān)系的。

不知道什么時候才可以有能夠處理NULL的glibc庫誕生啊!

不得已,我現(xiàn)在為好多的函數(shù)做了衣服,避免glibc的函數(shù)被NULL給感染,導(dǎo)

致我的Mem訪問錯誤,而我還不知道NULL這個病毒已經(jīng)在侵蝕我的身體了。

Segmentfault永遠(yuǎn)的痛

寫程序好多年了,Segnentfault是許多C程序員頭疼的提示“指針是好東西,

但是隨著指針的使用卻誕生了這個同樣威力巨大的惡魔。

Segmentfault之所以能夠流行于世,是與G1ibc庫中基本所有的函數(shù)都默認(rèn)型

參指針為非空有著密切關(guān)系的。

不知道什么時候才可以有能夠處理NULL的glibc庫誕生啊!

不得已,我現(xiàn)在為好多的函數(shù)做了衣服,避免glibc的函數(shù)被NULL給感染,導(dǎo)

致我的Mem訪問錯誤,而我還不知道NULL這個病毒已經(jīng)在侵蝕我的身體了。

Segmentfault永遠(yuǎn)的痛

寫程序好多年了,Segnentfault是許多C程序員頭疼的提示。指針是好東西,

但是隨著指針的使用卻誕生了這個同樣威力巨大的惡魔。

Segmentfault之所以能夠流行于世,是與Glibc庫中基本所有的函數(shù)都默認(rèn)型

參指針為非空有著密切關(guān)系的。

不知道什么時候才可以有能夠處理NULL的glibc庫誕生?。?/p>

不得已,我現(xiàn)在為好多的函數(shù)做了衣服,避免glibc的函數(shù)被NULL給感染,導(dǎo)

致我的Mem訪問錯誤,而我還不知道NULL這個病毒已經(jīng)在侵蝕我的身體了。

Segmentfault永遠(yuǎn)的痛

后面有好多網(wǎng)友都跟帖了,討論了Segmentationfaults為什么這么

“痛”,尤其是對于服務(wù)器程序來說,是非常頭痛的,為了提高效率,要盡量減

少一些不必要的段錯誤的“判斷和處理”,但是不檢查又可能會存在段錯誤的隱

患。

那么如何處理這個“麻煩”呢?

就像人不可能“完美”一樣,由人創(chuàng)造的“計算機(jī)語言“同樣沒有“完美”

的解決辦法。

我們更好的解決辦法也許是:

通過學(xué)習(xí)前人的經(jīng)驗和開發(fā)的工具,不斷的嘗試和研究,找出更恰當(dāng)?shù)?/p>

方法來避免、發(fā)現(xiàn)并處理它。對于一些常見的地方,我們可以避免,對于一些“隱

藏”的地方,我們要發(fā)現(xiàn)它,發(fā)現(xiàn)以后就要及時處理,避免留下隱患。

下面我們可以通過具體的實驗來舉出一些經(jīng)常出現(xiàn)段錯誤的地方,然后

再舉例子來發(fā)現(xiàn)和找出這類錯誤藏身之處,最后處理掉。

3。編程中通常碰到段錯誤的地方有哪些?

為了進(jìn)行下面的實驗,我們需要準(zhǔn)備兩個工具,一個是g",一個是gdb

我是在ubuntu下做的實驗,安裝這兩個東西是比較簡單的

sudoapt-getinstallgcc-4.0libc6-dev

sudoapt-getinstallgdb

好了,開始進(jìn)入我們的實驗,我們粗略的分一下類

1)往受到系統(tǒng)保護(hù)的內(nèi)存地址寫數(shù)據(jù)

有些內(nèi)存是內(nèi)核占用的或者是其他程序正在使用,為了保證系統(tǒng)正常工

作,所以會受到系統(tǒng)的保護(hù),而不能任意訪問。

例子1:

Code:

#include<stdio.h>

intmainO

(

inti=0;

scanfi);/*shouldhaveused&i*/

printf(〃%d\rT,i);

return0;

)

[Ctrl+ASelectAll]

編譯和執(zhí)行一下

$gcc-osegerrsegerr.c

$./segerr

10

段錯誤

咋一看,好像沒有問題哦,不就是讀取一個數(shù)據(jù)然后給輸出來嗎?

下面我們來調(diào)試一下,看看是什么原因?

$gcc-g-osegerrsegerr.c-加-g選項杳看調(diào)試信息

$gdb./segerr

(gdb)1-用1(list)顯示我們的源代碼

1ttinclude<stdio.h>

2

3int

4mainC

5(

6inti=0;

7

8scanf(〃%d〃,i);/*shouldhaveused&i

*/

9printf(〃%d\n〃,i);

10return0;

(gdb)b8一用b(break)設(shè)置斷點

Breakpoint1at0x80483b7:filesegerr.c,line8.

(gdb)pi-用p(print)打印變量i的值[看到

沒,這里i的值是0哦]

$1=0

(gdb)r一用r(run)運行,直到斷點處

Startingprogram:/home/falcon/temp/segerr

Breakpoint1,main;)atsegerr.c:8

8scanf(〃%d〃,i);/*shouldhaveused&i

*/一[試圖往地址0處寫進(jìn)一個值]

(gdb)n一用n(next)執(zhí)行下一步

10

ProgramreceivedsignalSIGSEGV,Segmentationfault.

0xb7e9alcain_I0_vfscanf()from/lib/tls/i686/cmov/libc.so.6

(gdb)c一在上面我們接收到了SIGSEGV,然后用

c(continue)繼續(xù)執(zhí)行

Continuing.

ProgramterminatedwithsignalSTGSEGV,Segmentationfault.

Theprogramnolongerexists.

(gdb)quit一退出gdb

$gcc-g-osegerrsegerr.c-加-g選項查看調(diào)試信息

$gdb./segerr

(gdb)1-用1(list)顯示我們的源代碼

1#include<stdio.h>

2

3int

4main(}

5(

6inti=0:

7

8scanfi);/*shouldhaveused&i

*/

9printf(〃%d\n〃,i);

10return0;

(gdb)b8一用b(break)設(shè)置斷點

Breakpoint1at0x80483b7:filesegerr.c,line8.

(gdb)pi一用p(print)打印變量i的值[看到

沒,這里i的值是。哦]

$1=0

(gdb)r一用r(run)運行,直到斷點處

Startingprogram:/home/falcon/temp/segerr

Breakpoint1,main:)atsegerr.c:8

8scanf(〃%d",i);/*shouldhaveused&i

*/~[試圖往地址0處寫進(jìn)一個值]

(gdb)n一用n(next)執(zhí)行下?步

10

ProgramreceivedsignalSIGSEGV,Segmentationfault.

0xb7e9alcain_I0vfscanf()from/lib/tls/i686/cmov/libc.so.6

(gdb)c一在上面我們接收到了SIGSEGV,然后用

c(coniinue)繼續(xù)執(zhí)行

Continuing.

ProgramterminatedwithsignalSICSECV,Segmentationfault.

Theprogramnolongerexists.

(gdb)quit-退出gdb

果然

我們“不小心”把&i寫成了i

而我們剛開始初始化了i為0,這樣我們不是試圖向內(nèi)存地址0存放一個值嗎?

實際上很多情況下,你即使沒有初始化為零,默認(rèn)也可能是0,所以要特別注

-ZdKa

,導(dǎo)、O

補(bǔ)充:

可以通過man7signal查看SIGSEGV的信息。

$man7signal|grepSEGV

Reformattingsignal;7),pleasewait...

SIGSEGV11CoreInvalid

memoryreference

例子2:

Code:

#include<stdio.h>

intmain()

(

char*p;

p=NULL;

*P二'x';

printfC%c/z,*p);

return0;

)

[Ctrl+ASelectAll]

很容易發(fā)現(xiàn),這個例子也是試圖往內(nèi)存地址0處寫東西。

這里我們通過gdb來查看段錯誤所在的行

$gcc-g-osegerrsegerr.c

$gdb./segerr

(gdb)r一直接運行,我們看到拋出段錯誤以后,自動顯示出了

出現(xiàn)段錯誤的行,這就是一個找出段錯誤的方法

Startingprogram:/home/falcon/temp/segerr

ProgramreceivedsignalS1GSEGV,Segmentationfault.

0x08048516inmain:)atsegerr.c:10

10*p='x';

(gdb)

$gcc-g-osegerrsegerr.c

$gdb./segerr

(gdb)r一直接運行,我們看到拋出段錯誤以后,自動顯示出了

出現(xiàn)段錯誤的行,這就是一個找出段錯誤的方法

Startingprogram:/home/falcon/temp/segerr

ProgramreceivedsignalSIGSEGV,Segmentationfault.

0x08048516inmain;)atsegerr.c:10

10*p='x';

(gdb)

2

)內(nèi)存越界(數(shù)組越界,變量類型不?致等)

例子3:

Code:

tfinclude<stdio.h>

intmain()

(

chartest[1];

printf(z/%cz/,test[1000000000]);

return0;

)

[Ctrl+ASelectAll]

這里是比較極端的例子,但是有時候可能是會出現(xiàn)的,是個明顯的數(shù)組越界的

問題

或者是這個地址是根本就不存在的

例子4:

Code:

#include<stdio.h>

intmain()

(

intb=10;

printf(〃%s\n〃,b);

return0;

}

[Ctrl+ASelectAll]

我們試圖把一個整數(shù)按照字符串的方式輸出出去,這是什么問題呢?

由于還不熟悉調(diào)試動態(tài)鏈接庫,所以

我只是找到了printf的源代碼的這里

聲明部分:

intpos=0,cnt_printed_chars=0,i;

unsignedchar*chptr;

va_listap;

%$格式控制部分:

case's':

chptr=va_arg(ap,unsignedchar*);

i=0;

while(chptr[i])

{...

cnt_printed_chars++;

putchar(chptr[i++]);

}

聲明部分:

intpos=0,cnt_printed_chars=0,i;

unsignedchar*chptr;

valistap;

如格式控制部分:

case's':

chptr=va_arg(ap,unsignedchar*);

i=0;

while(chptr[i])

{...

entprintedchars++;

putchar(chptr[i++]);

仔細(xì)看看,發(fā)現(xiàn)了這樣一個問題,在打印字符串的時候,實際上是打印某個地

址開始的所有字符,但是當(dāng)你想把整數(shù)當(dāng)字符串打印的時候,這個整數(shù)被當(dāng)成

了一個地址,然后printf從這個地址開始去打印字符,直到某個位置上的值為

\0。所以,如果這個整數(shù)代表的地址不存在或者不可訪問,自然也是訪問了不該

訪問的內(nèi)存segmentationfault。

類似的,還有諸如:sprintf等的格式控制問題

比如,試圖把char型或者是int的按照版輸出或存放起來,如:

Code:

#include<stdio.h>

ttinclude<string.h>

charc-c;

inti=10;

charbuf[100];

printfCW;c);〃試圖把char型按照字符串格式輸出,這里

的字符會解釋成整數(shù),再解釋成地址,所以原因同上面那個例子

printf(〃%s〃,i);〃試圖把int型按照字符串輸出

mcmset(buf,0,100):

sprintf(buf,z/%s\c);〃試圖把char型按照字符串格式轉(zhuǎn)換

memset(buf,0,100):

sprintf(buf,i);〃試圖把int型按照字符串轉(zhuǎn)換

[Ctrl+ASelectAll]

3)其他

其實大概的原因都是一樣的,就是段錯誤的定義。但是更多的容易出錯的地方就

要自己不斷積累,不段發(fā)現(xiàn),或者吸納前人已經(jīng)積累的經(jīng)驗,并且注意避免再

次發(fā)生。

例如:

<1>定義了指針后記得初始化,在使用的時候記得判斷是否為NULL

<2>在使用數(shù)組的時候是否被初始化,數(shù)組下標(biāo)是否越界,數(shù)組元素是否存在等

<3>在變量處理的時候變量的格式控制是否合理等

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

我在進(jìn)行一個多線程編程的例子里頭,定義了一個線程數(shù)組

ftdefineTHREAD_MAX_NUM

pthread_tthread[THREAD_MAX_NUM];

用pthread_create創(chuàng)建了各個線程,然后用pthread_join來等待線程的結(jié)束

剛開始我就直接等待,在創(chuàng)建線程都成功的時候,pthreadjoin能夠順利等待

各個線程結(jié)束,但是一旦創(chuàng)建線程失敗,那用pthread.join來等待那個本不存

在的線程時自然會存在訪問不能訪問的內(nèi)存的情況,從而導(dǎo)致段錯誤的發(fā)生,

后來,通過不斷調(diào)試和思考,并且得到網(wǎng)絡(luò)上資料的幫助,找到了上面的原因

和解決辦法:

在創(chuàng)建線程之前,先初始化我們的線程數(shù)組,在等待線程的結(jié)束的時候,判斷

線程是否為我們的初始值

如果是的話,說明我們的線程并沒有創(chuàng)建成功,所以就不能等拉。否則就會存在

釋放那些并不存在或者不可訪問的內(nèi)存空間。

上面給出了很常見的幾種出現(xiàn)段錯誤的地方,這樣在遇到它們的時候就容易避

免拉。但是人有時候肯定也會有疏忽的,甚至可能還是會經(jīng)常出現(xiàn)上面的問題或

者其他常見的問題,所以對于一些大型一點的程序,如何跟蹤并找到程序中的

段錯誤位置就是需要掌握的一門技巧拉。

4。如何發(fā)現(xiàn)程序中的段錯誤?

有個網(wǎng)友對這個做了比較全面的總結(jié),除了感謝他外,我把地址弄了過來。文章

名字叫《段錯誤bug的調(diào)試》

(http:〃www.cublog.cn/u/5251/showart.php?id=173718),應(yīng)該說是很全面的。

而我常用的調(diào)試方法有:

1)在程序內(nèi)部的關(guān)鍵部位輸出(printf)信息,那樣可以跟蹤段錯誤在代碼中

可能的位置

為了方便使用這種調(diào)試方法,可以用條件編譯指令#ifdefDEBUG和#0。近£毛

printf函數(shù)給包含起天,編譯的時候加上-DDEBUG參數(shù)就可以查看調(diào)試信息。反

之,不加上該參數(shù)進(jìn)行調(diào)試就可以。

2)用gdb來調(diào)試,在運行到段錯誤的地方,會自動停下來并顯示出錯的行和行

這個應(yīng)該是很常用的,如果需要用gdb調(diào)試,記得在編譯的時候加上-g參數(shù),

用來顯示調(diào)試信息,對于這個,網(wǎng)友在《段錯誤bug的調(diào)試》文章里創(chuàng)造性的使

用這樣的方法,使得我們在執(zhí)行程序的時候就可以動態(tài)撲獲段錯誤可能出現(xiàn)的

位置:通過撲獲SIGSEGV信號來觸發(fā)系統(tǒng)調(diào)用gdb來輸出調(diào)試信息。如果加上上

面提到的條件編譯,那我們就可以非常方便的進(jìn)行段錯誤的調(diào)試?yán)?/p>

3)還有—?個catchscgv命令

通過查看幫助信息,可以看到

Catchsegmentationfaultsinprograms

這個東西就是用來撲獲段錯誤的,它通過動態(tài)加載器(Id-linux.so)的預(yù)加載

機(jī)制(PRELOAD)把一個事先寫好的庫(/lib/libSegFault.so)加載上,用于捕

捉斷錯誤的出錯信息。

到這里,“初級總結(jié)篇”算是差不多完成拉。歡迎指出其中表達(dá)不當(dāng)甚至錯誤的

地方,先謝過!

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

lo段錯誤的定義

Anscrs.com

http:〃www.answers,com

Definitionof"Segmentationfault"

http:〃www.faqs.org/qa/qa-673.html

2o《什么是段錯誤》

http://www.Iinux999.org/html_sql/3/132559.htm

3。《Segmentfault之永遠(yuǎn)的痛》

http:〃www.linuxforum.net/forum/gshowflat.php?Cat=&Board=program&Numb

er=193239&page=2&view=collapsed&sb=5&o=all&fpart=

4?!抖五e誤bug的調(diào)試》

http:〃www.cublog.cn/u/5251/showart.php?id=173718

后記

雖然感覺沒有寫什么東西,但是包括查找資料和打字,也花了好些幾個小時,不

過總結(jié)一下也是值得的,歡迎和我一起交流和討論,也歡迎對文章中表達(dá)不當(dāng)

甚至是錯誤的地方指正一下

段錯誤(Segmentalionfault)

原文出處:/blog/article.php7tid_700.html

我只是把排版弄舒服一點,很好的文章,雖然說是初級篇,但幫助確實很大。

I)往受到系統(tǒng)保護(hù)的內(nèi)存地址寫數(shù)據(jù)

有些內(nèi)存定內(nèi)核占用的或者是其他程序正在使用,為了保證系統(tǒng)正常工作,所以會受到系統(tǒng)的保護(hù),而不

能任意訪問.

#include<stdio.h>

int

main()

(

inti=0;

scanf("%d",i);/*shouldhaveused&i*/

printf("%d\n",i);

return0:

)

編譯和執(zhí)行一下,咋一看,好像沒有問題哦,不就是讀取一個數(shù)據(jù)然后給輸出來嗎?

falcon@falcon:-/ieinpSgcc-g-osegerrsegerr.c-力口-g選項查看調(diào)試信息

falcon@falcon:~/tempSgdb./segerr

GNUgdb6.4-dcbian

Copyright2005FreeSoftwareFoundation,Inc.

GDBisfreesoftware,coveredbytheGNUGeneralPublicLicense,andyouare

welcometochangeitand/ordistributecopiesofitundercertainconditions.

Type“showcopying“toseetheconditions.

ThereisabsolutelynowarrantyforGDB.Type44showwananty"tordetails.

ThisGDBwasconfiguredas44i486-linux-gnu"…Usinghostlibthrcad_dblibrary"/

lib/tls/i686/cmov/libthread_db.so.1".

(gdb)1-用l(lisl)顯示我們的源代碼

1#include<stdio.h>

2

3int

4main()

5(

6inti=0;

7

8scanfi);/*shouldhaveused&i*/

9printf(”\心i);

10return0;

(gdb)b8-用b(break)設(shè)置斷點

Breakpoint1at0x80483b7:filesegerr.c,line8.

(gdb)pi-用p(print)打印變量i的值[看到?jīng)].這里i的值是0哦]

$1=0

(gdb)1?-用r(run)運行,直到斷點處

Starlingprogram:/homc/falcon/temp/segcrr

Breakpoint1.main()atsegen.c:8

8scanf("%d”,i);/*shouldhaveused&i*/■[試圖往地址0處寫進(jìn)一個值]

(gdb)n-用n(nexl)執(zhí)行下一步

10

ProgramreceivedsignalSIGSEGV.Segmentationfault.

0xb7e9alcain_10_vfscanf()from/Iib/tis/i686/cmov/libc.so.6

(gdb)c-在上面我們接收到了SIGSEGV,然后用c(continue)繼續(xù)執(zhí)行

Continuing.

ProgramterminatedwithsignalSIGSEGV.Segmentationfault.

Theprogramnolongerexists.

(gdb)quit-退出gdb

果然

我們“不小心”把&i寫成了i

而我們剛開始初始化了i為0,這樣我們不是試圖向內(nèi)存地址0存放一個值嗎?

[補(bǔ)充:

可以通過man7signal查看SIGSEGV的信息。

falcon@falcon:~/tempSman7signal|grepSEGV

Reformattingsignal(7),pleasev/ait...

SIGSEGV11CoreInvalidmemoryreference

例子2:

#include<stdio.h>

int

main()

1

char*p;

p=NULL;

*p='x';

printf(',%c,\*p);

return0:

}

很容易發(fā)現(xiàn),這個例子也是試圖往內(nèi)存地址0處寫東西。

這里我們通過gdb來查看段錯誤所在的行

falcon@falcon>/tempSgcc-g-osegerrsegerr.c

falcon@falcon:~/tenipSgdb./s3geiT

GNUgdb6.4-dcbian

Copyright2005FreeSoftwareFoundation,Inc.

GDBisfreesoftware,coveredbytheGNUGeneralPublicLicense,andyouare

welcometochangeitand/ordistributecopiesofitundercertainconditions.

Type“showcopying''toseetheconditions.

ThereisabsolutelynowarrantyforGDB.Type44showwarranty"fordetails.

ThisGDBwasconfiguredasUi486-linux-gnu",,,Usinghostlibthread_dblibrary

<</lib/tls/i686/cmo\7libthread_dbso.r,.

(gdb)r-直接運行,我們看到拋出段錯誤以后,自動顯示出了出現(xiàn)段錯誤的行,這就是一個找出段錯誤的

方法

Startingprogram:/home/falcon/temp/segerr

ProgramreceivedsignalSIGSEGV,Segmentationfault.

0x08048516inmain()atseger.c:10

10*p=&';

(gdb)

2)內(nèi)存越界(數(shù)組越界,變量類型不?致等)

#include<stdio.h>

int

main()

(

chartest[l];

prinlf('%c'',test[1000000000));

return0;

}

這里是比較極端的例子,但是有時候可能是會出現(xiàn)的.是個明顯的數(shù)組越界的問題

或者是這個地址是根本就不存在的

例子4:

#include<stdio.h>

int

niain()

{

intb=10;

printff*%s\n”,b);

return0;

}

我們試圖把一個整數(shù)按照字符串的方式輸出出去,這是什么問題呢?

由于還不熟悉調(diào)試動態(tài)鏈接庫.所以

我只是找到了printf的源代碼的這里

聲明部分:

intpos=0,cnt_printed_chars=0.i;

unsignedchar*chplr;

va_listap;

/*%s格式控制部分:*/

ease's':

chpir=va_arg(apunsignedchar*);

i=0;

while(chptr|iJ)

{???

cnt_printed_chars++;

putchar(chptr[i++]);

}

由于我沒有仔細(xì)分析代碼,大致的原因也可能是地址越界的原因?不過我可不確定哦。

如果大家知道怎么調(diào)試printf函數(shù),麻煩幫忙找出越界的真正原因吧,這個段錯誤也可能是

處在va_slart和va_arg等函數(shù)里頭?或者直接看看這個這里的prinlf源代碼的分析,看看是否

可以找出出錯的地方:

/bbsdetail_47325.htrnl

類似的,還有諸如:sprintf等的格式控制問題

比如,試圖把char型或者是ini的按照%s輸出或存放起來,如:

#include<stdio.h>

#include<string.h>

charc='c';

inti=10;

charbuf]IOO];

printf("%s",c);〃試圖把char型按照字符串格式輸出

printf("%s",i);〃試圖把int型按照字符串輸出

memset(buf,0,100);

叩rinlf(buf,"%s”,c);〃試圖把char型按照字符串格式轉(zhuǎn)換

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論