常見錯誤和程序調試_第1頁
已閱讀1頁,還剩59頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、第16章 常見錯誤和程序調試,16.1 常見錯誤分析16.2 程序調試,要真正學好C、用好C并不容易,“靈活”固然是好事,但也使人難以掌握,尤其是初學者往往出了錯還不知怎么回事。C編譯程序對語法的檢查不如其他高級語言那樣嚴格(這是為了給程序人員留下“靈活”的余地)。因此,往往要由程序設計者自己設法保證程序的正確性。調試一個C程序要比調試一個PASCAL或FORTRAN程序更困難一些。需要不斷積累經驗,提高程序設計和調試程序的水平。

2、C語言有些語法規(guī)定和其他高級語言不同,學習過其他高級語言的讀者往往按照使用其他高級語言的習慣來寫C程序,這也是出錯的一個原因。,16.1 常見錯誤分析下面將初學者在學習和使用C語言(不包括C++)時容易犯的錯誤列舉出來,以起提醒的作用。這些內容在以前各章中大多已談到,為便于查閱,在本章中集中列舉,供初學者參考,以此為鑒。(1) 忘記定義變量。如:main( )  {x=3; y=6; printf(&qu

3、ot;%d\n ",x+y); },C要求對程序中用到的每一個變量都必須定義其類型,上面程序中沒有對x、y進行定義。應在函數體的開頭加int x,y;這是學過BASIC和FORTRAN語言的讀者寫C程序時常見的一個錯誤。在BASIC語言中,可以不必先定義變量類型就可直接使用。在FORTRAN中,未經定義類型的變量按隱含的I-N規(guī)則決定其類型,而C語言則要求對用到的每一個變量都要在本函數中定義(除非已定義為外部變量)。

4、(2) 輸入輸出的數據的類型與所用格式說明符不一致。例如,若a已定義為整型,b已定義為實型。,a=3;b=4.5;printf("%f %d\n",a,b);編譯時不給出出錯信息,但運行結果將與原意不符,輸出為0.000000 16402它們并不是按照賦值的規(guī)則進行轉換(如把4.5轉換成4),而是將數據在存儲單元中的形式按格式符的要求組織輸出(如b占4個字節(jié),只把最后兩個字節(jié)中的數據按%d,作為整數輸出)

5、。(3) 未注意int型數據的數值范圍。一般微型計算機上使用的C編譯系統(tǒng),對一個整型數據分配兩個字節(jié)。因此一個整數的范圍為,-215~215-1,即-32768~32767。常見這樣的程序段:int num; num=89101;  printf("%d",num);得到的卻是23565,原因是89101已超過32767。兩個字節(jié)容納不下89101,則將高位截去。見圖16.1。即將超過低16位的數截去。即

6、將89101減去216(即16位二進制所形成的模)。89101-65536=23565。,圖16.1有時還會出現(xiàn)負數。例如num=196607;輸出得-1。因為196607的二進制形式為00 00 00 00 00 00 00 1011 11 11 11 11 11 11 11去掉高位10,低16位的值是-1(-1的補碼是:1111111111111111)?! τ诔^整個范圍的數,要用long型,即改為long int

7、 num;num=89101;,printf("%ld",num);請注意,如果只定義num為long型,而在輸出時仍用“%d”說明符,仍會出現(xiàn)以上錯誤。(4) 輸入變量時忘記使用地址符。如:scanf("%d%d",a,b);這是許多初學者剛學習C語言時一個常見的疏忽,或者說是習慣性的錯誤,因為在其他語言中在輸入時只需寫出變量名即可,而C語言要求指明“向哪個地址標識的單元送值”。應寫成

8、scanf("%d%d",&a,&b);(5) 輸入時數據的組織與要求不符。用scanf函數輸入數據,應注意如何組織輸入,數據。假如有以下scanf函數:scanf("%d%d",&a,&b);有人按下面的方法輸入數據:3,4這是錯的。數據間應該用空格來分隔。讀者可以用printf("%d%d",a,b);來驗證一下。應該用以下

9、方法輸入:34如果scanf函數為scanf("%d,%d",&a,&b);對scanf函數中格式字符串中除了格式說明符外,,對其他字符必須按原樣輸入。因此,應按以下方法輸入:3,4此時如果用“34”反而錯了。還應注意,不能企圖用scanf("input a & b:%d,%d",&a,&b);想在屏幕上顯示一行信息:input a &

10、amp; b:然后在其后輸入a和b的值,這是不行的。這是由于有的讀者以為scanf具有BASIC語言中的INPUT語句的功能(先輸出一個字符串,再輸入變量的值)。如果想在屏幕上得到所需的提示信息,可以另加一個printf函數語句:printf("input a & b:");,scanf("%d,%d",&a,&b);(6) 誤把“=”作為“等于”比較符。在許多高級語

11、言中,用“=”符號作為關系運算符“等于”。例如,在BASIC或PASCAL程序中都可以寫if(a=b) then…但在C語言中,“=”是賦值運算符,“==”才是關系運算符“等于”。如果寫成if(a=b) printf("a equal to b");C編譯系統(tǒng)將(a=b)作為賦值表達式處理,將b的值賦給a,然后判斷a的值是否零,若為非零,則作為“真”;若為零作為假。如果a的值為3,b的值為4,,a≠b,按原意

12、不應輸出“ae q u a lt ob”。而現(xiàn)在先將b的值賦給a,a也為4,賦值表達式的值為4。if語句中的表達式值為真(非零),因此輸出“ae q u a lt o b”。這種錯誤在編譯時是檢查不出來的,但運行結果往往是錯的。而且由于習慣的影響,程序設計者自己往往也不易發(fā)覺。(7) 語句后面漏分號。C語言規(guī)定語句末尾必須有分號。分號是C語句不可缺少的一部分。這也是和其他語言不同的。有的初學者往往忘記寫這一分號。如:,a=3b=

13、4編譯時,編譯程序在“a=3”后面未發(fā)現(xiàn)分號,就把下一行“b=4”也作為上一行的語句的一部分,這就出現(xiàn)語法錯誤。有時編譯時指出某行有錯,但在該行上并未發(fā)現(xiàn)錯誤,應該檢查上一行是否漏了分號。如果用復合語句,有的學過PASCAL語言的讀者往往漏寫最后一個語句的分號,如:{t=a; a=b; b=t   },在PASCAL中分號是兩個語句間的分隔符而不是語句的一部分,而在C中,沒有分號的就不是語句。(8) 在

14、不該加分號的地方加了分號。例如:if(a>b);   printf("a is larger than b\n");本意為當a>b時輸出“a is larger than b”的信息。但由于在if(a>b)后加了分號,因此if語句到此結束。即當(a>b)為真時,執(zhí)行一個空語句。本來想a≤b時不輸出上述信息,但現(xiàn)在printf函數語句并不從屬于if語句,而是與if語句平行的語句。不論,a>b還是a≤b,都輸出

15、“a is larger than b”?! ∮秩纾骸 or(i=0;i<10;i++); {scanf("%d",&x); printf("%d\n",x*x); }本意為先后輸入10個數,每輸入一個數后輸出它的平方值。由于在for( )后加了一個分號,使循環(huán)體變成了空語句。只能輸入一個整數并輸出它的平方值??傊?,在if、for、while語

16、句中,不要畫蛇添足多加分號。,(9) 對應該有花括弧的復合語句,忘記加花括弧。如:sum=0;  i=1;  while(i<=100) sum=sum+i; i++;本意是實現(xiàn)1+2+…+100,即∑i。但上面的語句只是重復了sum+1的操作,而且循環(huán)永不終止。因為i的值始終沒有改變。錯誤在于沒有寫成復合語句形式。因此while語句的范圍到其后第一個分號為止。語句“i++;”不屬于循環(huán)體范圍之內。

17、應改,100i=0,為while(i<=100) {sum=sum+i; i++; }(10) 括弧不配對?! ‘斠粋€語句中使用多層括弧時常出現(xiàn)這類錯誤,純屬粗心所致。如:while((c=getchar( )!='#')putchar(c);少了一個右括弧。,(11) 在用標識符時,忘記了大寫字母和小寫字母的區(qū)別?! ±纾簃ain( )  {int a,b,c;

18、 a=2;b=3; C=A+B; printf("%d+%d=%",A,B,C);  ?。幾g時出錯。編譯程序把a和A認作是兩個不同的變量名處理,同樣b和B,c和C都分別代表兩個不同的變量。,(12) 引用數組元素時誤用了圓括弧。如:main( )  {int i,a(10); for(i=0;i<10;i++) scanf("%d&quo

19、t;,&a(i)); }C語言中對數組的定義或引用數組元素時必須用方括弧。(13) 在定義數組時,將定義的“元素個數”誤認為是“可使用的最大下標值”。,main( ) ?。鹖nt a[10]={1,2,3,4,5,6,7,8,9,10}; int i; for(i=1;i<=10;i++)printf("%d",a[i]); }想輸出a[1]到a[10]。但一些初

20、學者常犯的錯誤。C語言規(guī)定定義時用a[10],表示a數組有10個元素,而不是可以用的最大下標值為10。數組只包括a[0]到a[9]10個元素,因此用a[10]就超出a數組的范圍了。,(14) 對二維或多維數組的定義和引用的方法不對。main( ) ?。鹖nt a[5,4];… printf("%d",a[1+2,2+2]);… ?。龑ΧS數組和多維數組在定義和引用時必須將每一維的數據分別用方括

21、弧括起來。上面a[5,4]應改為a[5][4],a[1+2,2+2]應改為a[1+2][2+2]。根據C的語法規(guī)則,在一個方括弧中的是一個維的下標表達式,a[1+2,2+2]中方括弧中的“1+2,2+2”,是一個逗號表達式,它的值是第二個數值表達式的值,即2+2的值為4。所以a[1+2,2+2]相當于a[4]。而a[4]是a數組的第4行的首地址。因此執(zhí)行printf函數輸出的結果并不是a[3][4]的值,而是a數組第4行的首地址。(1

22、5) 誤以為數組名代表數組中全部元素。例如:main( ) ?。鹖nt a[4]={1,3,5,7}; printf("%d%d%d%d\n",a); ?。?企圖用數組名代表全部元素。在C語言中,數組名代表數組首地址,不能通過數組名輸出4個整數。(16) 混淆字符數組與字符指針的區(qū)別。main( ) ?。鹀har str[4]; str="Computer and c&

23、quot;; printf("%s\n",str);   }編譯出錯。str是數組名,代表數組首地址。在編譯時對str數組分配了一段內存單元,因此在程序運行期間str是一個常量,不能再被賦值。因此,,str=“Computer and c”是錯誤的。如果把“char str[4];”改成“charstr;”,則程序正確。此時str是指向字符數據的指針變量,str=“Computer and c”是合

24、法的,它將字符串的首地址賦給指針變量str,然后在printf函數語句中輸出字符串“Computer and c”。因此應當弄清楚字符數組與字符指針變量用法的區(qū)別。(17) 在引用指針變量之前沒有對它賦予確定的值。main( ) ?。鹀har*p; scanf("%s",p);,…   }沒有給指針變量p賦值就引用它,編譯時給出警告信息。應當改為charp,c[20];  p=c; 

25、 scanf("%s",p);即先根據需要定義一個大小合適的字符數組c,然后將c數組的首地址賦給指針變量p,此時p有確定的值,指向數組c。再執(zhí)行scanf函數就沒有問題了,把從鍵盤輸入的字符串存放到字符數組c中。(18) switch語句的各分支中漏寫break語句。,例如:switch(score) ?。鹀ase 5:printf("Very good!"); case 4:

26、printf("Good!"); case 3:printf("Pass!"); case 2:printf("Fail!"); defult:printf("data error!"); ?。鲜鰏witch語句的作用是希望根據score(成績)打印出評語。但當score的值為5時,輸出為Very Good!Goo

27、d!Pass!Fail!data error!,原因是漏寫了break語句。case只起標號的作用,而不起判斷作用,因此在執(zhí)行完第一個printf函數語句后接著執(zhí)行第2、3、4、5個printf函數語句。應改為switch(score) ?。鹀ase 5:printf("Verygood!");break; case 4:printf("Good!");   break;

28、 case 3:printf("Pass!");  break; case 2:print("Fail!");   break; defult:print("data error!");,}(19) 混淆字符和字符串的表示形式。char sex;  sex="M";…sex是字符變量,只能存放一個字符。而字符

29、常量的形式是用單引號括起來的,應改為sex='M';“M”是用雙引號括起來的字符串,它包括兩個字符:‘M’和‘\0’,無法存放到字符變量sex中。,(20) 使用自加(++)和自減(--)運算符時出的錯誤?! ±纾簃ain( ) ?。鹖ntp,a[5]={1,3,5,7,9}; p=a; printf("%d",*p++); ?。簧偃苏J為“*p++”的作用是

30、先使p加1,即指向第1個元素a[1]處,然后輸出第一個元素a[1]的值3。其實應該是先執(zhí)行p++,而p++的作用是先用p的原值,用完后使p加1。p的原值指向數組a的第0個元素a[0],,因此*p就是第0個元素a[0]的值1。結論是先輸出a[0]的值,然后再使p加1。如果是*(++p),則先使p指向a[1],然后輸出a[1]的值。(21) 有人習慣用傳統(tǒng)的方式對函數形參進行聲明,但卻把對函數的形參和函數中的局部變量混在一起定義。如:m

31、ax(x,y)  int x,y,z;  {z=x>y?x,y; return(z);  ?。?應改為max(x,y) int x,y; {int z; z=x>y?x:y; return(z); }(22) 所調用的函數在調用語句之后才定義,而又在調用前未加說明。main( ) ?。鹒loat x,y,z;,x=3.5;y=-7.6; z=max(x,y);

32、 printf("%f\n",z);   } float max(float x,float y)   {return(z=x>y?x:y);}這個程序乍看起來沒有什么問題,但在編譯時有出錯信息。原因是max函數是實型的,而且在main函數之后才定義,也就是max函數的定義位置在main函數中的調用max函數之后。改錯的方法可以用以下二者之一:,① 在main函數中增加一個對max函數的聲明,即

33、函數的原型:main( )   {float max(float,float);/*聲明將要用到的max函數為實型*/ float x,y,z; x=3.5;y=-7.6; z=max(x,y); printf("%f\n",z);  ?。?將max函數的定義位置調到main函數之前。即:,float max(float x,float y) {re

34、turn(z=x>y?x:y);}   main() ?。鹒loat x,y,z; x=3.5;y=-7.6; z=max(x,y); printf("%f\n",z); ?。@樣,編譯時不會出錯,程序運行結果是正確的。,(23) 誤認為形參值的改變會影響實參的值。main( ) ?。鹖nta,b; a=3;b=4; swap(a,b);

35、 printf("%d,%d\n",a,b);  }  swap(int x,int y) ?。鹖nt t; t=x;x=y;y=t; },原意是通過調用swap函數使a和b的值對換,然后在main函數中輸出已對換了值的a和b。但是這樣的程序是達不到目的的,因為x和y的值的變化是不傳送回實參a和b的,main函數中的a和b的值并未改變。如果想從函數得到一個以上的變化了的值,應該用指針

36、變量。用指針變量作函數參數,使指針變量所指向的變量的值發(fā)生變化。此時變量的值改變了,主調函數中可以利用這些已改變的值。如:main( )  {int a,b,*p1,*p2; a=3;b=4;,p1=&a;p2=&b; swap(p1,p2); printf("%d,%d\n",a,b); /a和b的值已對換/   }  swap(int *pt1, int

37、 *pt2) ?。鹖nt t; t=*pt1;*pt1=*pt2;*pt2=t;   }(24) 函數的實參和形參類型不一致。main( ),{int a=3,b=4; c=fun(a,b);… } fun(float x,float y) {… }實參a、b為整型,形參x、y為實型。a和b的值傳遞給x和y時,x和y的值并非3和4。C要求實參與形參的類型一致。如

38、果在main函數中對fun作原型,聲明:fun (float, float);程序可以正常運行,此時,按不同類型間的賦值的規(guī)則處理,在虛實結合后x=3.0, y=4.0。也可以將fun函數的位置調到main函數之前,也可獲正確結果。(25) 不同類型的指針混用。main( ) ?。鹖nt i=3,*p1; float a=1.5,*p2; p1=&i; p2=&a;,p2=p1;

39、 printf("%d,%d\n",*p1,*p2);  ?。髨D使p2也指向i,但p2是指向實型變量的指針,不能指向整型變量。指向不同類型的指針間的賦值必須進行強制類型轉換。如:p2=(float*)p1;作用是先將p1的值轉換成指向實型的指針,然后再賦給p2。這種情況在C程序中是常見的。例如,用malloc函數開辟內存單元,函數返回的是指向被分配內存空間的void *類型的指針。而人們希望開辟的是,

40、存放一個結構體變量值的存儲單元,要求得到指向該結構體變量的指針,可以進行如下的類型轉換。struct student ?。鹖nt num; char name[20]; float score; };  struct student student1,*p;…  p=(struct student *)malloc(LEN);,p是指向struct student結構體類型數據的指針,將mal

41、loc函數返回的void *類型指針轉換成指向struct student類型變量的指針。(26) 沒有注意函數參數的求值順序。例如有以下語句:i=3;printf("%d,%d,%d\n",i,++i,++i);  許多人認為輸出必然是3,4,5實際不盡然。在Turbo C和其他一些C系統(tǒng)中輸出是5,5,4,因為這些系統(tǒng)是采取自右至左的順序求函數參數的值。先求出最右面一個參數(++i)的值為4,再求出第

42、2個參數(++i)的值為5,最后求出最左面的參數(i)的值5。C標準沒有具體規(guī)定函數參數求值的順序是自左而右還是自右而左。但每個C編譯程序都有自己的順序,在有些情況下,從左到右求解和從右到左求解的結果是相同的。例如fun1(a+b,b+c,c+a);fun1是一個函數名。3個實參表達式a+b、b+c、c+a。在一般情況下,自左至右地求這3個表達式的值和自右至左地求它們的值是一樣的,但在前面舉的例子,是不相同的。因此,建議最好不用會

43、引起二義性的用法。如果在上例中,希望輸出“3,4,5”時,可以改用i=3; j=i+1; k=j+1;printf("%d,%d,%d\n",i,j,k);(27) 混淆數組名與指針變量的區(qū)別。main( )  {int i,a[5]; for(i=0;i<5;i++)scanf("%d",a++);…,}企圖通過a的改變使指針下移,每次指向欲輸入數據的數組元素。它的錯

44、誤在于不了解數組名代表數組首地址,它的值是不能改變的,用a++是錯誤的,應當用指針變量來指向各數組元素。即:int i,a[5],*p;p=a;for(i=0;i<5;i++)scanf("%d",p++);  或int a[5],*p;for(p=a;p<a+5;p++),scanf("%d",p);  (28) 混淆結構體類型與結構體變量的區(qū)別,對一個結構體類型賦值。struc

45、t worker   {long int num; char name[20]; char sex; int age;    };   worker.num=187045;,strcpy(worker.name,"ZhangFun");   worker.sex='M';   worker.age=18;  這是錯誤的,只能對變量賦值而不能對

46、類型賦值。上面只定義了struct worker類型而未定義變量。應改為struct worker  ?。鹟ong int num; char name[20]; char sex; int age;,};  struct worker worker-1;  worker-1.num=187045;  strcpy(worker-1.name,"Zhang Fun&q

47、uot;);  worker-1.sex='M';  worker-1.age=18;  今定義了結構體變量worker-1,并對其中的各成員賦值。(29) 使用文件時忘記打開,或打開方式與使用情況不匹配。例如,對文件的讀寫,用只讀方式打開,卻企圖向,該文件輸出數據,例如:if((fp=fopen("test","r"))==NULL) {printf(&q

48、uot;cannot open this file\n"); exit(0); }  ch=fgetc(fp);  while(ch!='#') {ch=ch+4; fputc(ch,fp); ch=fget(fp); },對以“r”方式(只讀方式)打開的文件,進行既讀又寫的操作,顯然是不行的。此外,有的程序常

49、忘記關閉文件,雖然系統(tǒng)會自動關閉所用文件,但可能會丟失數據。因此必須在用完文件后關閉它。以上只是列舉了一些初學者常出現(xiàn)的錯誤,這些錯誤大多是對于C語法不熟悉之故。對C語言使用多了,比較熟練了,犯這些錯誤自然就會減少了。在深入使用C語言后,還會出現(xiàn)其他一些更深入、更隱蔽的錯誤。,程序出錯有三種情況:① 語法錯誤。指違背了C語法的規(guī)定,對這類錯誤,編譯程序一般能給出“出錯信息”,并且告訴你在哪一行出錯。只要細心,是可以很快發(fā)現(xiàn)并排除的。

50、② 邏輯錯誤。程序并無違背語法規(guī)則,但程序執(zhí)行結果與原意不符。這是由于程序設計人員設計的算法有錯或編寫程序有錯,通知給系統(tǒng)的指令與解題的原意不相同,即出現(xiàn)了邏輯上的混亂。例如:前面第9條錯誤:sum=0;i=1;  while(i<=100) sum=sum+i;,i++;語法并無錯誤。但while語句通知給系統(tǒng)的信息是當i≤100時,執(zhí)行“sum=sum+i;”。C系統(tǒng)無法辨別程序中這個語句是否符合作者的原意,而

51、只能忠實地執(zhí)行這一指令。這種錯誤比語法錯誤更難檢查。要求程序員有較豐富的經驗。③ 運行錯誤。程序既無語法錯誤,也無邏輯錯誤,但在運行時出現(xiàn)錯誤甚至停止運行。例如:int a ,b ,c;scanf("%d %d",&a,&b);c=b/a;printf("c=%d\n",c);,輸入a和b的值, 輸出b/a的值, 程序沒有錯。 但是如果輸入a的值為0, 就會出現(xiàn)錯誤。 因

52、此程序應能適應不同的數據, 或者說能經受各種數據的“考驗” , 具有“健壯性”。寫完一個程序只能說完成任務的一半(甚至不到一半)。調試程序往往比寫程序更難,更需要精力、時間和經驗。常常有這樣的情況:程序花一天就寫完了,而調試程序二三天也未能完。有時一個小小的程序會出錯五六處,而發(fā)現(xiàn)和排除一個錯誤,有時竟需要半天,甚至更多。希望讀者通過實踐掌握調試程序的方法和技術。,16.2 程 序 調 試所謂程序調試是指對程序的查錯和排錯。調試程

53、序一般應經過以下幾個步驟:(1) 先進行人工檢查,即靜態(tài)檢查。在寫好一個程序以后,不要匆匆忙忙上機,而應對紙面上的程序進行人工檢查。這一步是十分重要的,它能發(fā)現(xiàn)程序設計人員由于疏忽而造成的多數錯誤。而這一步驟往往容易被人忽視。有人總希望把一切推給計算機系統(tǒng)去做,但這樣就會多占用機器時間。而且,作為一個程序人員應當養(yǎng)成嚴謹的科學作風,每一步都要嚴格把關,不把問題留給后面的工序?! 榱烁行У剡M行人工檢查,所編的程序應注意力,求做到以下

54、幾點:①應當采用結構化程序方法編程,以增加可讀性;②盡可能多加注釋,以幫助理解每段程序的作用;③在編寫復雜的程序時,不要將全部語句都寫在main函數中,而要多利用函數,用一個函數來實現(xiàn)一個單獨的功能。這樣既易于閱讀也便于調試,各函數之間除用參數傳遞數據這一渠道以外,數據間盡量少出現(xiàn)耦合關系,便于分別檢查和處理。(2) 在人工(靜態(tài))檢查無誤后,才可以上機調試。通過上機發(fā)現(xiàn)錯誤稱動態(tài)檢查。在編譯時給出語法錯誤的信息(包括哪一行有錯以及錯

55、誤類型),可以根據提示的信息具體找出程序中出錯之處并改正之。應當注意的是:有時提示的出錯行并不是真正出錯,的行,如果在提示出錯的行上找不到錯誤的話應當到上一行再找。另外,有時提示出錯的類型并非絕對準確,由于出錯的情況繁多而且各種錯誤互有關聯(lián),因此要善于分析,找出真正的錯誤,而不要只從字面意義上死摳出錯信息,鉆牛角尖。如果系統(tǒng)提示的出錯信息多,應當從上到下逐一改正。有時顯示出一大片出錯信息往往使人感到問題嚴重,無從下手。其實可能只有一二

56、個錯誤。例如,對所用的變量未定義,編譯時就會對所有含該變量的語句發(fā)出出錯信息。只要加上一個變量定義,所有錯誤都消除了。(3) 在改正語法錯誤(包括“錯誤”(error)和“警告”(warning))后,程序經過連接(link)就得到可,執(zhí)行的目標程序。運行程序,輸入程序所需數據,就可得到運行結果。應當對運行結果作分析,看它是否符合要求。有的初學者看到輸出運行結果就認為沒問題了,不作認真分析,這是危險的。有時,數據比較復雜,難以立即判

57、斷結果是否正確??梢允孪瓤紤]好一批“試驗數據”,輸入這些數據可以得出容易判斷正確與否的結果。例如解方程ax2+bx+c=0,輸入a、b、c的值分別為1、-2、1時,根x的值是1。這是容易判斷的,若根不等于1,程序顯然有錯。但是,用“試驗數據”時,程序運行結果正確,還不能保證程序完全正確。因為有可能輸入另一組數據時運行結果不對。例如,用x=-b±b2-4ac2a公式,求根x的值,當a≠0和b2-4ac>0時,能得出正確結果,當

58、a=0或b2-4ac<0時,就得不到正確結果(假設程序中未對a=0作防御處理以及未作復數處理)。因此應當把程序可能遇到的多種方案都一一試到。例如,if語句有兩個分支,有可能在流程經過其中一個分支時結果正確,而經過另一個分支時結果不對。必須考慮周全。事實上,當程序復雜時很難把所有的可能方案全部都試到,選擇典型的情況作試驗即可。(4) 運行結果不對,大多屬于邏輯錯誤。對這類錯誤往往需要仔細檢查和分析才能發(fā)現(xiàn)??梢圆捎靡韵罗k法:,① 將程

59、序與流程圖(或偽代碼)仔細對照,如果流程圖是正確的話,程序寫錯了,是很容易發(fā)現(xiàn)的。例如,復合語句忘記寫花括弧,只要一對照流程圖就能很快發(fā)現(xiàn)。② 如果實在找不到錯誤,可以采取“分段檢查”的方法。在程序不同位置設幾個printf函數語句,輸出有關變量的值,逐段往下檢查。直到找到在某一段中數據不對為止。這時就已經把錯誤局限在這一段中了。不斷縮小“查錯區(qū)”,就可能發(fā)現(xiàn)錯誤所在。③ 也可以用第9章介紹過的“條件編譯”命令進行程序調試(在程序調

60、試階段,若干printf函數語句要進行編譯并執(zhí)行。當調試完畢,這些語句不要再,編譯了,也不再被執(zhí)行了)。這種方法可以不必一一刪去printf函數語句,以提高效率。④ 如果在程序中沒有發(fā)現(xiàn)問題,就要檢查流程圖有無錯誤,即算法有無問題,如有則改正之,接著修改程序。⑤ 有的系統(tǒng)還提供debug(調試)工具,跟蹤流程并給出相應信息,使用更為方便,請查閱有關手冊。總之,程序調試是一項細致深入的工作,需要下功夫、動腦子、善于累積經驗。在程序調

溫馨提示

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

評論

0/150

提交評論