qileilove

          blog已經(jīng)轉(zhuǎn)移至github,大家請(qǐng)?jiān)L問(wèn) http://qaseven.github.io/

          邊界測(cè)試——讓BUG現(xiàn)形

            題目:寫(xiě)一個(gè)函數(shù),輸入一行字符,將此字符串中最長(zhǎng)的單詞輸出。

          #include <stdio.h>

          #include <string.h>

          int main()

          {int alphabetic(char);

          int longest(char []);

          int i;

          char line[100];

          printf("input one line:\n");

          gets(line);

          printf("The longest word is:");

          for(i=longest(line);alphabetic(line[i]);i++)

          printf("%c",line[i]);

          printf("\n");

          return 0;

          }



          int alphabetic(char c)

          {

          if((c>='a'&&c<='z')||(c>='A'&&c<='z'))

          return(1);

          else

          return(0);

          }



          int longest(char string[])

          {int len=0,i,length=0,flag=1,place=0,point;

          for(i=0;i<=strlen(string);i++)

          if(alphabetic(string[i]))

          if(flag)

          {point=i;

          flag=0;

          }

          else

          len++;

          else

          {flag=1;

          if(len>=length)

          {length=len;

          place=point;

          len=0;

          }

          }

          return(place);

          }

            運(yùn)行結(jié)果:

            input a line:             
            I am a student.           
            The longest word is : student

            題目要求“寫(xiě)一個(gè)函數(shù),輸入一行字符,將此字符串中最長(zhǎng)的單詞輸出”,可是無(wú)論alphabetic()還是longest()函數(shù)都沒(méi)有實(shí)現(xiàn)“輸入一行字符,將此字符串中最長(zhǎng)的單詞輸出”這個(gè)功能要求。疑惑很久,發(fā)現(xiàn)實(shí)現(xiàn)這個(gè)功能的函數(shù)居然是main()。這就難免讓人貽笑大方了。因?yàn)榘凑粘R?guī)的慣例,要求寫(xiě)一個(gè)函數(shù)實(shí)現(xiàn)某個(gè)功能,從來(lái)不是要求寫(xiě)main(),盡管不能說(shuō)main()不是“一個(gè)函數(shù)”。然而如果是要求main()完成的事情,通常是作為一個(gè)完整的問(wèn)題提出的,不會(huì)提出“寫(xiě)一個(gè)函數(shù)”這樣的要求。如果硬要狡辯“寫(xiě)一個(gè)函數(shù)”也不排除是寫(xiě)main(),就牽強(qiáng)的近乎強(qiáng)詞奪理了。不過(guò)設(shè)若真的有人如此嘴硬,你還真拿他沒(méi)什么辦法。

            既然是不見(jiàn)棺材不掉淚,那就不妨繼續(xù)往下看。

            在代碼中一眼瞄見(jiàn)了flag這個(gè)變量。經(jīng)驗(yàn)表明,凡是有這個(gè)flag變量的代碼,80%以上都是垃圾代碼。道理很簡(jiǎn)單:首先,多數(shù)問(wèn)題根本不需要設(shè)置這個(gè)別別扭扭標(biāo)志變量,只有那些善于把自己的思維扭曲得如同爛麻花一樣的人才喜歡時(shí)不時(shí)地祭出flag這個(gè)破爛的法寶。其次,即使需要設(shè)置標(biāo)準(zhǔn)變量,優(yōu)秀的代碼作者也不會(huì)使用這個(gè)含義模糊不清的名字作為標(biāo)志變量名,而會(huì)用一個(gè)更貼切、意義更明確恰當(dāng)更適合描述問(wèn)題的名字。所以,一般來(lái)說(shuō),flag往往反映了代碼的垃圾度。


            對(duì)于垃圾代碼,沒(méi)必要進(jìn)行過(guò)于細(xì)致的分析,只要指出錯(cuò)誤即可。不要試圖了解這種代碼的思路,因?yàn)檫@種代碼的思路本來(lái)就是錯(cuò)亂不堪的,就如同不要試圖理解瘋子的胡言亂語(yǔ)一樣。不要試圖修繕一座胡亂搭建起來(lái)的破爛不堪的危房,推倒重來(lái)才是明智的選擇。

            然而,找出程序的漏洞或錯(cuò)誤,往往比完成程序要難得多。而且越是垃圾的代碼越難查錯(cuò),因?yàn)槔a往往也不具備良好的可測(cè)試性。

            但是對(duì)付這種可測(cè)試性極差的垃圾代碼,有一些簡(jiǎn)單的辦法往往非常容易奏效,比如邊界檢查。訓(xùn)練有素的程序員通常都特別注意邊界,無(wú)論是寫(xiě)代碼時(shí)還是檢查代碼時(shí)。因?yàn)樗麄冎肋@里非常容易出錯(cuò),而且往往失之毫厘謬之千里。但垃圾代碼的作者,由于代碼是東拼西補(bǔ)、胡亂拼湊而成的,所以往往顧不上或考慮不到這些,因此垃圾代碼很容易被“邊界檢查”這把小刀輕而易舉地戳破。以alphabetic()函數(shù)為例,只要簡(jiǎn)單地考察一下其中if語(yǔ)句所要求的表達(dá)式——(c>='a'&&c<='z')||(c>='A'&&c<='z'),就不難發(fā)現(xiàn)c<='z'這個(gè)子表達(dá)式是c<='Z'之誤。這樣就充分說(shuō)明原代碼中存在著B(niǎo)UG。

            順便說(shuō)一下,alphabetic()函數(shù)中的if-else語(yǔ)句用得非常愚蠢,因?yàn)?c>='a'&&c<='z') || (c>='A'&&c<='Z')這個(gè)表達(dá)式的值本身就只能為0或1,所以直接返回這個(gè)表達(dá)式的值就可以了。壓根用不著脫褲子放屁地寫(xiě)一個(gè)if-else語(yǔ)句。

          int alphabetic(char c)
          {
             return   (c>='a'&&c<='z'
                  ||  (c>='A'&&c<='Z');
          }

            或許,有人會(huì)認(rèn)為這是一個(gè)簡(jiǎn)單的筆誤或印刷錯(cuò)誤,修正了這個(gè)錯(cuò)誤原來(lái)的代碼是正確的。那么好吧,下面改正這個(gè)錯(cuò)誤后再來(lái)運(yùn)用一次簡(jiǎn)單的邊界測(cè)試。

            由于問(wèn)題要求輸出一行字符中最長(zhǎng)的單詞,而一行字符中可能有0個(gè)單詞、1個(gè)單詞、2個(gè)單詞……。注意,這里0個(gè)單詞的情況就是一種邊界情況,運(yùn)行這個(gè)程序并輸入0個(gè)單詞(輸入一行不含任何字母的字符,因?yàn)榇a作者把連續(xù)的若干字母字符作為一個(gè)單詞),后果居然是——運(yùn)行時(shí)程序崩潰了。這個(gè)結(jié)果絕對(duì)可以充分說(shuō)明原來(lái)的代碼是錯(cuò)誤的。

            這個(gè)結(jié)果是如何產(chǎn)生的呢?只要在紙上走查一遍,就不難發(fā)現(xiàn),輸入一行不含任何字母的字符時(shí),longest()函數(shù)中嵌套在for語(yǔ)句內(nèi)部的if語(yǔ)句將毫無(wú)意義地反復(fù)執(zhí)行

              {flag=1;
          if(len>=length)
          {length=len;
          place=point;
          len=0;
          }
          }

            部分,而其中的賦值給place的point卻居然是一個(gè)不確定的垃圾值。

            應(yīng)該如何正確地給出這個(gè)問(wèn)題的代碼呢?正確解決問(wèn)題的前提是正確地提出問(wèn)題。原來(lái)問(wèn)題的提法本身就有很多不正確或不嚴(yán)謹(jǐn)?shù)牡胤健@纾?#8220;將此字符串中最長(zhǎng)的單詞輸出”,這個(gè)要求本身就是似是而非很不明確的。比如,字符串中有兩個(gè)單詞長(zhǎng)度相同且都長(zhǎng)于其他單詞,究竟應(yīng)該輸出這兩個(gè)單詞中的任何一個(gè)還是需要同時(shí)輸出這兩個(gè)單詞?再有,要求函數(shù)“輸入一行字符”也非常無(wú)聊。為了能正確地解決問(wèn)題,有必要對(duì)原問(wèn)題的錯(cuò)誤要求進(jìn)行如下更正:

            寫(xiě)一個(gè)函數(shù),輸出字符串中的任一長(zhǎng)度最長(zhǎng)的單詞。這里所謂的單詞,是指不含空白字符的連續(xù)字符序列。

          #include <stdio.h>  
             
          void print_a_longestword ( const char [] ) ;  
          int  be_white  ( const char )  ;  
          int  find_begin( char const [] , unsigned ) ;  
          int  find_end  ( char const [] , unsigned ) ;  
          void output    ( char const [] , unsigned , unsigned ) ;  
             
          int main( void )  
          {  
             printf("%s中一最長(zhǎng)單詞為:","");            //測(cè)試""   
             print_a_longestword("");  
                
             printf("%s中一最長(zhǎng)單詞為:"," \n\t ");      //測(cè)試" \n\t "  
             print_a_longestword(" \n\t ");  
             
             printf("%s中一最長(zhǎng)單詞為:"," abc ");       //測(cè)試" abc "  
             print_a_longestword(" abc ");  
             
             printf("%s中一最長(zhǎng)單詞為:"," abc \tabcd  "); //測(cè)試" abc \tabcd  "  
             print_a_longestword(" abc \tabcd  ");  
                   
             return 0;  
          }  
             
          void output( char const str[] , unsigned from , unsigned to )  
          {  
             while(from < to)  
                putchar(str[from ++]);  
             putchar('\n');     
          }  
             
          int find_end (  const char str[] , unsigned from )  
          {  
                while( str[from]!='\0' && ! be_white( str[from] ) )  
                   from ++ ;  
                return from ;     
          }  
             
          int find_begin (  const char str[] , unsigned from )  
          {  
                while( be_white( str[from] ) )  
                   from ++ ;  
                return from ;     
          }  
             
          int be_white( const char c )  
          {  
             return       c == ' '    ||  
                       c == '\t'  ||  
                       c == '\n'  ;  
          }  
             
          void print_a_longestword ( char const line[] )  
          {  
             unsigned site = 0U ;     
             unsigned begin_longest , end_longest ;  
             begin_longest = end_longest = site    ;  
                
             do{  
                int this_begin , this_end  ;  
                   
                site = this_begin = find_begin ( line , site )    ;//單詞開(kāi)頭   
                site = this_end  = find_end   ( line , site )     ;//單詞結(jié)尾        
             
                if(   ( this_end    - this_begin )   
                    > ( end_longest - begin_longest ) ){  
                   begin_longest = this_begin ;  
                   end_longest   = this_end   ;       
                }       
             
             }while( line[ site ] != '\0') ;     
             
             output( line , begin_longest , end_longest );  
          }

          posted on 2011-12-05 09:38 順其自然EVO 閱讀(138) 評(píng)論(0)  編輯  收藏


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          <2011年12月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(55)

          隨筆分類(lèi)

          隨筆檔案

          文章分類(lèi)

          文章檔案

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 报价| 同仁县| 吉木萨尔县| 林州市| 天门市| 双辽市| 如东县| 准格尔旗| 丁青县| 农安县| 彭阳县| 常熟市| 凤凰县| 逊克县| 靖江市| 宜昌市| 衡东县| 大关县| 高州市| 铜梁县| 社旗县| 凤台县| 页游| 云龙县| 兴山县| 祁门县| 仲巴县| 安阳县| 延川县| 庆元县| 神木县| 云和县| 中山市| 芷江| 习水县| 山阴县| 怀远县| 苍南县| 孟州市| 岑溪市| 贞丰县|