C程序設(shè)計(第四版)第11章 常見錯誤分析_第1頁
C程序設(shè)計(第四版)第11章 常見錯誤分析_第2頁
C程序設(shè)計(第四版)第11章 常見錯誤分析_第3頁
C程序設(shè)計(第四版)第11章 常見錯誤分析_第4頁
C程序設(shè)計(第四版)第11章 常見錯誤分析_第5頁
已閱讀5頁,還剩49頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

1、 要真正學(xué)好要真正學(xué)好C、用好、用好C并不容易,并不容易,“靈活靈活”固然是固然是好事,但也使人難以掌握,尤其是初學(xué)者往往出好事,但也使人難以掌握,尤其是初學(xué)者往往出了錯還不知怎么回事。了錯還不知怎么回事。C編譯程序?qū)φZ法的檢查編譯程序?qū)φZ法的檢查不如其他高級語言那樣嚴(yán)格不如其他高級語言那樣嚴(yán)格(這是為了給程序人員這是為了給程序人員留下留下“靈活靈活”的余地的余地)。因此,往往要由程序設(shè)計。因此,往往要由程序設(shè)計者自己設(shè)法保證程序的正確性。調(diào)試一個者自己設(shè)法保證程序的正確性。調(diào)試一個C程序程序要比調(diào)試一個要比調(diào)試一個PASCAL或或FORTRAN程序更困難程序更困難一些。需要不斷積累經(jīng)驗,提高

2、程序設(shè)計和調(diào)試一些。需要不斷積累經(jīng)驗,提高程序設(shè)計和調(diào)試程序的水平。程序的水平。 下面是常見的一些錯誤:下面是常見的一些錯誤:(1) 忘記定義變量。如:忘記定義變量。如:main()x=3; y=6; printf(%dn,x+y); C要求對程序中用到的每一個變量都必須定義其要求對程序中用到的每一個變量都必須定義其類型,上面程序中沒有對類型,上面程序中沒有對x、y進(jìn)行定義。應(yīng)在函進(jìn)行定義。應(yīng)在函數(shù)體的開頭加數(shù)體的開頭加intx,y;這是學(xué)過這是學(xué)過BASIC和和FORTRAN語言的讀者寫語言的讀者寫C程序時常見的一個錯誤。程序時常見的一個錯誤。在在BASIC語言中,可以不必先定義變量類型就可

3、語言中,可以不必先定義變量類型就可直接使用。在直接使用。在FORTRAN中,未經(jīng)定義類型的變中,未經(jīng)定義類型的變量按隱含的量按隱含的I-N規(guī)則決定其類型,而規(guī)則決定其類型,而C語言則要求語言則要求對用到的每一個變量都要在本函數(shù)中定義對用到的每一個變量都要在本函數(shù)中定義(除非已除非已定義為外部變量定義為外部變量)。(2) 輸入輸出的數(shù)據(jù)的類型與所用格式說明符不一致。輸入輸出的數(shù)據(jù)的類型與所用格式說明符不一致。例如,若例如,若a已定義為整型,已定義為整型,b已定義為實型。已定義為實型。a=3;b=45;printf(%f%dn,a,b);編譯時不給出出錯信息,但運(yùn)行結(jié)果將與原意不符,編譯時不給出出

4、錯信息,但運(yùn)行結(jié)果將與原意不符,輸出為輸出為0.00000016402它們并不是按照賦值的規(guī)則進(jìn)行轉(zhuǎn)換它們并不是按照賦值的規(guī)則進(jìn)行轉(zhuǎn)換(如把如把45轉(zhuǎn)換轉(zhuǎn)換成成4),而是將數(shù)據(jù)在存儲單元中的形式按格式符的,而是將數(shù)據(jù)在存儲單元中的形式按格式符的要求組織輸出要求組織輸出(如如b占占4個字節(jié),只把最后兩個字節(jié)中個字節(jié),只把最后兩個字節(jié)中的數(shù)據(jù)按的數(shù)據(jù)按%d,作為整數(shù)輸出,作為整數(shù)輸出)。(3) 未注意未注意int型數(shù)據(jù)的數(shù)值范圍。型數(shù)據(jù)的數(shù)值范圍。在在Turbo C編譯系統(tǒng),對一個編譯系統(tǒng),對一個int整型數(shù)據(jù)分配兩個整型數(shù)據(jù)分配兩個字節(jié)。因此一個整數(shù)的范圍為字節(jié)。因此一個整數(shù)的范圍為-21521

5、5-1,即,即-3276832767。常見這樣的程序段:。常見這樣的程序段:int num;num=89101;printf(%d,num); 得到的卻是得到的卻是23565,原因是,原因是89101已超過已超過32767。兩。兩個字節(jié)容納不下個字節(jié)容納不下89101,則將高位截去。見圖,則將高位截去。見圖16.1。即將超過低即將超過低16位的數(shù)截去。即將位的數(shù)截去。即將89101減去減去216(即即16位二進(jìn)制所形成的模位二進(jìn)制所形成的模)。89101-65536=23565。有時還會出現(xiàn)負(fù)數(shù)。例如有時還會出現(xiàn)負(fù)數(shù)。例如num=196607; 輸出得輸出得-1。因為。因為196607的二進(jìn)制

6、形式為的二進(jìn)制形式為00 00 00 00 00 00 00 1011 11 11 11 11 11 11 11去掉高位去掉高位10,低,低16位的值是位的值是-1(-1的補(bǔ)碼是:的補(bǔ)碼是:1111111111111111)。對于超過整個范圍的數(shù),要用對于超過整個范圍的數(shù),要用long型,即改為型,即改為long intnum; num=89101;printf(%ld,num);請注意,如果只定義請注意,如果只定義num為為long型,而在輸出時仍用型,而在輸出時仍用“%d”說明符,仍會出現(xiàn)以上錯誤。說明符,仍會出現(xiàn)以上錯誤。(4) 輸入變量時忘記使用地址符。如:輸入變量時忘記使用地址符。如

7、:scanf(%d%d,a,b);這是許多初學(xué)者剛學(xué)習(xí)這是許多初學(xué)者剛學(xué)習(xí)C語言時一個常見的疏忽,語言時一個常見的疏忽,或者說是習(xí)慣性的錯誤,因為在其他語言中在輸入或者說是習(xí)慣性的錯誤,因為在其他語言中在輸入時只需寫出變量名即可,而時只需寫出變量名即可,而C語言要求指明語言要求指明“向哪向哪個地址標(biāo)識的單元送值個地址標(biāo)識的單元送值”。應(yīng)寫成。應(yīng)寫成scanf(%d%d,&a,&b);(5) 輸入時數(shù)據(jù)的輸入時數(shù)據(jù)的形式形式與要求不符。與要求不符。用用scanf函數(shù)輸入數(shù)據(jù),應(yīng)注意如何組織輸入函數(shù)輸入數(shù)據(jù),應(yīng)注意如何組織輸入數(shù)據(jù)。數(shù)據(jù)。假如有以下假如有以下scanf函數(shù):函數(shù):s

8、canf(%d%d,&a,&b);有人按下面的方法輸入數(shù)據(jù):有人按下面的方法輸入數(shù)據(jù):3,4這是錯的。數(shù)據(jù)間應(yīng)該用空格來分隔。應(yīng)該用以下方這是錯的。數(shù)據(jù)間應(yīng)該用空格來分隔。應(yīng)該用以下方法輸入:法輸入:3 4(中間有空格)(中間有空格)如果如果scanf函數(shù)為函數(shù)為scanf(%d,%d,&a,&b);對對scanf函數(shù)中格式字符串中除了格式說明符外,函數(shù)中格式字符串中除了格式說明符外,對其他字符必須按原樣輸入。因此,應(yīng)按以下方法對其他字符必須按原樣輸入。因此,應(yīng)按以下方法輸入:輸入:3,4此時如果用此時如果用“3 4”反而錯了。反而錯了。(6) 在用在用scan

9、f函數(shù)向字符數(shù)組輸入數(shù)據(jù)時,在數(shù)組函數(shù)向字符數(shù)組輸入數(shù)據(jù)時,在數(shù)組名前面多加了名前面多加了&,例如:,例如:char a20;scanf(“%s”, &a);在對變量輸入數(shù)據(jù)時應(yīng)當(dāng)加在對變量輸入數(shù)據(jù)時應(yīng)當(dāng)加&,例如,例如&a,但是數(shù)組,但是數(shù)組名本身已經(jīng)表示地址,不需要再加名本身已經(jīng)表示地址,不需要再加&,應(yīng)當(dāng)寫成:,應(yīng)當(dāng)寫成:scanf(“%s”, a);(7) 在用在用scanf函數(shù)向數(shù)值型數(shù)組輸入數(shù)據(jù)時,直接函數(shù)向數(shù)值型數(shù)組輸入數(shù)據(jù)時,直接用數(shù)組名,例如:用數(shù)組名,例如:int a20;scanf(“%d”, a);這是錯誤的。數(shù)值型的數(shù)組不能一次

10、性整體輸入,這是錯誤的。數(shù)值型的數(shù)組不能一次性整體輸入,只能一個個元素單獨輸入,應(yīng)當(dāng)寫成:只能一個個元素單獨輸入,應(yīng)當(dāng)寫成:int a20;int i;for(i=0;i20;i+) scanf(“%d”, &ai);(8) 語句后面漏分號,例如:語句后面漏分號,例如:a=3b=4;(9) 在預(yù)處理指令后面加分號,例如:在預(yù)處理指令后面加分號,例如:#include ;注意預(yù)處理不是語句,是指令,所以不需要分號。注意預(yù)處理不是語句,是指令,所以不需要分號。(10) 在不該加分號的地方加分號,例如:在不該加分號的地方加分號,例如:if (ab); printf(“a is larger

11、than bn”);這個寫法相當(dāng)于這個寫法相當(dāng)于if的條件成立時,執(zhí)行空語句(就的條件成立時,執(zhí)行空語句(就是那個分號);而無論條件是否成立,是那個分號);而無論條件是否成立,printf都需要都需要執(zhí)行。顯然這不是程序的本意。再例如:執(zhí)行。顯然這不是程序的本意。再例如:int a20;int i;for(i=0;i20;i+); scanf(“%d”, &ai);for后面的那個分號,直接導(dǎo)致后面的那個分號,直接導(dǎo)致scanf不屬于循環(huán)體。不屬于循環(huán)體。(11) 對于應(yīng)該有花括號的復(fù)合語句,忘記加花括號,對于應(yīng)該有花括號的復(fù)合語句,忘記加花括號,例如:例如:sum=0;i=1;whi

12、le (iy?x:y; 改法改法1,在,在main中增加中增加max函數(shù)聲明:函數(shù)聲明:int main() float max(float x, float y); float a,b,c; a=3.5; b=-7.6; c=max(a,b); printf(“%f”, c); return 0;改法改法2,將,將max函數(shù)定義提到函數(shù)定義提到main之前,如:之前,如:float max(float x, float y) return xy?x:y; int main() float a,b,c; a=3.5; b=-7.6; c=max(a,b); printf(“%f”, c); r

13、eturn 0;(25) 對函數(shù)聲明與函數(shù)定義不匹配,如對函數(shù)聲明與函數(shù)定義不匹配,如fun定義為:定義為:int fun(int x, float y, long z) 則正確的聲明寫法只有三種:則正確的聲明寫法只有三種:int fun(int x, float y, long z);int fun(int, float, long); /可以不寫變量名可以不寫變量名int fun(int a, float b, long c); /可以亂寫變量名可以亂寫變量名其余寫法都是錯誤的。其余寫法都是錯誤的。(26) 在需要頭文件的地方?jīng)]有用在需要頭文件的地方?jīng)]有用#include指令包含頭指令包含

14、頭文件,例如程序中使用了文件,例如程序中使用了fabs函數(shù),忘記包含函數(shù),忘記包含math.h文件。文件。至于程序中使用的函數(shù)在哪一個頭文件中,可以通至于程序中使用的函數(shù)在哪一個頭文件中,可以通過查幫助文檔獲得,例如微軟的過查幫助文檔獲得,例如微軟的MSDN。再不行的。再不行的話,還可以上網(wǎng)去搜。話,還可以上網(wǎng)去搜。 (27) 誤認(rèn)為形參值的改變會影響實參的值。誤認(rèn)為形參值的改變會影響實參的值。int main( ) int a, b; a=3;b=4; swap(a,b); printf(%d,%dn,a,b); return 0;void swap(int x,int y) int t;

15、t=x;x=y;y=t; 原意是通過調(diào)用原意是通過調(diào)用swap函數(shù)使函數(shù)使a和和b的值對換,然后的值對換,然后在在main函數(shù)中輸出已對換了值的函數(shù)中輸出已對換了值的a和和b。但是這樣。但是這樣的程序是達(dá)不到目的的,因為的程序是達(dá)不到目的的,因為x和和y的值的變化是的值的變化是不傳送回實參不傳送回實參a和和b的,的,main函數(shù)中的函數(shù)中的a和和b的值并的值并未改變。未改變。 如果想從函數(shù)得到一個以上的變化了的值,應(yīng)該如果想從函數(shù)得到一個以上的變化了的值,應(yīng)該用指針變量。用指針變量作函數(shù)參數(shù),使指針變用指針變量。用指針變量作函數(shù)參數(shù),使指針變量所指向的變量的值發(fā)生變化。此時變量的值改量所指向的

16、變量的值發(fā)生變化。此時變量的值改變了,主調(diào)函數(shù)中可以利用這些已改變的值。如:變了,主調(diào)函數(shù)中可以利用這些已改變的值。如:int main( )int a,b,*p1,*p2; a=3;b=4; p1=&a;p2=&b; swap(p1,p2); printf(%d,%dn,a,b);/a和和b的值已對換的值已對換 swap(int *pt1, int *pt2)int t; t=*pt1;*pt1=*pt2;*pt2=t; /借助指針間接修改借助指針間接修改a,b 事實上,變量的指針和變量的地址是一樣的,所以事實上,變量的指針和變量的地址是一樣的,所以swap函數(shù)的調(diào)用可以不借

17、助指針,直接使用地址:函數(shù)的調(diào)用可以不借助指針,直接使用地址:swap(&a, &b); /直接將直接將a,b的地址傳入的地址傳入(28) 函數(shù)的實參和形參類型不一致。函數(shù)的實參和形參類型不一致。int main() int fun(int x, int y); float a=3.5, b=4.6, c; c=fun(a, b); / 這行有警告,因為數(shù)值的精度受損這行有警告,因為數(shù)值的精度受損printf(“%f”, c); int fun(int x,int y) return x+y; 實參實參a、b為整型,形參為整型,形參x、y為實型。為實型。a和和b的值傳遞的值傳遞

18、給給x和和y時,時,x和和y的值并非的值并非3和和4。C要求實參與形參要求實參與形參的類型一致。如果在的類型一致。如果在main函數(shù)中對函數(shù)中對fun作原型作原型聲明:聲明:float fun (float, float);程序可以正常運(yùn)行。程序可以正常運(yùn)行。(29) 不同類型的指針混用。不同類型的指針混用。int main( )int i=3,*p1; float a=1.5,*p2; p1=&i;p2=&a;p2=p1; printf(%d,%dn,*p1,*p2); 企圖使企圖使p2也指向也指向i,但,但p2是指向?qū)嵭妥兞康闹羔?,不是指向?qū)嵭妥兞康闹羔槪荒苤赶蛘妥兞俊?/p>

19、能指向整型變量。指向不同類型的指針間的賦值必須進(jìn)行強(qiáng)制類型轉(zhuǎn)指向不同類型的指針間的賦值必須進(jìn)行強(qiáng)制類型轉(zhuǎn)換。如:換。如:p2=(float*)p1;作用是先將作用是先將p1的值轉(zhuǎn)換成指向?qū)嵭偷闹羔?,然后再的值轉(zhuǎn)換成指向?qū)嵭偷闹羔?,然后再賦給賦給p2。這種情況在這種情況在C程序中是常見的。例如,用程序中是常見的。例如,用malloc函函數(shù)開辟內(nèi)存單元,函數(shù)返回的是指向被分配內(nèi)存空數(shù)開辟內(nèi)存單元,函數(shù)返回的是指向被分配內(nèi)存空間的間的void *類型的指針。而人們希望開辟的是存放類型的指針。而人們希望開辟的是存放一個結(jié)構(gòu)體變量值的存儲單元,要求得到指向該結(jié)一個結(jié)構(gòu)體變量值的存儲單元,要求得到指向該結(jié)

20、構(gòu)體變量的指針,可以進(jìn)行如下的類型轉(zhuǎn)換構(gòu)體變量的指針,可以進(jìn)行如下的類型轉(zhuǎn)換:struct studentint num; char name20; float score; ;struct studentstudent1,*p;p=(struct student *)malloc(LEN);p是指向是指向struct student結(jié)構(gòu)體類型數(shù)據(jù)的指針,將結(jié)構(gòu)體類型數(shù)據(jù)的指針,將malloc函數(shù)返回的函數(shù)返回的void *類型指針轉(zhuǎn)換成指向類型指針轉(zhuǎn)換成指向struct student類型變量的指針。類型變量的指針。(30) 沒有注意函數(shù)參數(shù)的求值順序。例如有以下語沒有注意函數(shù)參數(shù)的求值順序

21、。例如有以下語句:句:i=3;printf(%d,%d,%dn,i,+i,+i);許多許多人認(rèn)為輸出必然是人認(rèn)為輸出必然是3,4,5實際不盡然。在實際不盡然。在Turbo C和其他一些和其他一些C系統(tǒng)中輸出是系統(tǒng)中輸出是5,5,4因為這些系統(tǒng)是采取自右至左的順序求函數(shù)參數(shù)的因為這些系統(tǒng)是采取自右至左的順序求函數(shù)參數(shù)的值。先求出最右面一個參數(shù)值。先求出最右面一個參數(shù)(+i)的值為的值為4,再求出,再求出第第2個參數(shù)個參數(shù)(+i)的值為的值為5,最后求出最左面的參數(shù),最后求出最左面的參數(shù)(i)的值的值5。C標(biāo)準(zhǔn)沒有具體規(guī)定函數(shù)參數(shù)求值的順序是自左而右標(biāo)準(zhǔn)沒有具體規(guī)定函數(shù)參數(shù)求值的順序是自左而右還是

22、自右而左。但每個還是自右而左。但每個C編譯程序都有自己的順序,編譯程序都有自己的順序,在有些情況下,從左到右求解和從右到左求解的結(jié)果在有些情況下,從左到右求解和從右到左求解的結(jié)果是相同的。例如是相同的。例如fun1(a+b,b+c,c+a);fun1是一個函數(shù)名。是一個函數(shù)名。3個實參表達(dá)式個實參表達(dá)式a+b、b+c、c+a。在一般情況下,自左至右地求這在一般情況下,自左至右地求這3個表達(dá)式的值和自個表達(dá)式的值和自右至左地求它們的值是一樣的,但在前面舉的例子右至左地求它們的值是一樣的,但在前面舉的例子是不相同的。因此,建議最好不用會引起二義性的是不相同的。因此,建議最好不用會引起二義性的用法。

23、如果在上例中,希望輸出用法。如果在上例中,希望輸出“3,4,5”時,可時,可以改用以改用i=3;j=i+1;k=j+1;printf(%d,%d,%dn,i,j,k);(31) 混淆數(shù)組名與指針變量的區(qū)別。混淆數(shù)組名與指針變量的區(qū)別。int main( ) int i,a5; for(i=0;i5;i+) scanf(%d,a+);企圖通過企圖通過a的改變使指針下移,每次指向欲輸入數(shù)據(jù)的改變使指針下移,每次指向欲輸入數(shù)據(jù)的數(shù)組元素。它的錯誤在于不了解數(shù)組名代表數(shù)的數(shù)組元素。它的錯誤在于不了解數(shù)組名代表數(shù)組首地址,它的值是不能改變的,用組首地址,它的值是不能改變的,用a+是錯誤的,是錯誤的,應(yīng)當(dāng)

24、用指針變量來指向各數(shù)組元素。應(yīng)當(dāng)用指針變量來指向各數(shù)組元素。可以改成下面的寫法:可以改成下面的寫法:int i,a5,*p;p=a;for(i=0;i5;i+) scanf(%d,p+); 或者:或者:int a5,*p;for(p=a;pa+5;p+) scanf(%d,p);(32) 混淆結(jié)構(gòu)體類型與結(jié)構(gòu)體變量的區(qū)別,對一個混淆結(jié)構(gòu)體類型與結(jié)構(gòu)體變量的區(qū)別,對一個結(jié)構(gòu)體類型賦值。結(jié)構(gòu)體類型賦值。struct workerlong int num; char name20; char sex; int age; ;worker.num=187045; strcpy(,Z

25、hangFun);worker.sex=M;worker.age=18;這是錯誤的,只能對變量賦值而不能對類型賦值。這是錯誤的,只能對變量賦值而不能對類型賦值。上面只定義了上面只定義了struct worker類型而未定義變量。應(yīng)類型而未定義變量。應(yīng)改為改為struct worker worker_1;worker_1.num=187045;strcpy(worker_1.name,Zhang Fun);worker_1.sex=M;worker_1.age=18; 今定義了結(jié)構(gòu)體變量今定義了結(jié)構(gòu)體變量worker_1,并對其中的各成,并對其中的各成員賦值。員賦值。 (33) 使用文件時忘記打

26、開,或打開方式與使用情況使用文件時忘記打開,或打開方式與使用情況不匹配。不匹配。例如,對文件的讀寫,用只讀方式打開,卻企圖向例如,對文件的讀寫,用只讀方式打開,卻企圖向該文件輸出數(shù)據(jù),例如:該文件輸出數(shù)據(jù),例如:if(fp=fopen(test,r)=NULL) printf(cannot open this filen); exit(0); ch=fgetc(fp);while(ch!=#) ch=ch+4; fputc(ch,fp); /此語句有錯此語句有錯 ch=fget(fp); (34) 在打開文件時,指定的文件名找不到。例如:在打開文件時,指定的文件名找不到。例如:if (fp=fopen(“test”, “r”)=NULL) printf(“cannot open this filen”); exit(0);試圖打開一個已存在的文件試圖打開一個已存在的文件test,但是這個文件不存,但是這個文件不存在。一般出現(xiàn)這個問題的原因,是在。一般出現(xiàn)這個問題的原因,是test文件不在當(dāng)前文件不在當(dāng)前目錄下,所以把目錄下,所以把test的路徑寫全了就行了,如:的路徑寫全了就行了,如:if (fp=fopen(“d:temptest”, “r”)=NULL)注意路徑要用注意路徑要用分隔,因為單個分隔,因為單個是轉(zhuǎn)義字符的前綴。是轉(zhuǎn)義字符的前綴。(35) 忘記關(guā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

提交評論