[轉載]strcpy實現

題目:
     已知strcpy函數的原型是:
         char * strcpy(char * strDest,const char * strSrc);
     1.不調用庫函數,實現strcpy函數。
     2.解釋爲什麼要返回char *。

     解說:
     1.strcpy的實現代碼

         char * strcpy(char * strDest,const char * strSrc)
        {                
             if ((strDest==NULL)||(strSrc==NULL)) //[1]  
             throw "Invalid argument(s)"; //[2]
             char * strDestCopy=strDest;   //[3]
             while ((*strDest++=*strSrc++)!='/0'); //[4]
             return strDestCopy;      
         }

     錯誤的做法:
     [1]
     (A)不檢查指針的有效性,說明答題者不注重代碼的健壯性。
     (B)檢查指針的有效性時使用((!strDest)||(!strSrc))或(!(strDest&& strSrc)),說明答題者對C語言中類型的隱式轉換沒有深刻認識。在本例中char *轉換爲bool即是類型隱式轉換,這種功能雖然靈活,但更多的 是導致出錯概率增大和維護成本升高。所以C++專門增加了bool、true、false三個關鍵字以提供更安全的條件表達式。
     (C)檢查指針的有效性時使用((strDest==0)||(strSrc==0)),說明答題者不知道使用常量的好處。直接使用字 面常量(如本例中的0)會減少程序的可維護性。0雖然簡單,但程序中可能出現很多處對指針的檢查,萬一出現筆誤,編譯器不能發現,生成的程序內含邏輯錯 誤,很難排除。而使用NULL代替0,如果出現拼寫錯誤,編譯器就會檢查出來。
     [2]
     (A)return new string("Invalid argument(s)");,說明答題者根本不知道返回值的用途,並且 他對內存泄漏也沒有警惕心。從函數中返回函數體內分配的內存是十分危險的做法,他把釋放內存的義務拋給不知情的調用者,絕大多數情況下,調用者不會釋放內 存,這導致內存泄漏。
     (B)return 0;,說明答題者沒有掌握異常機制。調用者有可能忘記檢查返回值,調用者還可能無法檢查返回值(見後面的鏈式表達 式)。妄想讓返回值肩負返回正確值和異常值的雙重功能,其結果往往是兩種功能都失效。應該以拋出異常來代替返回值,這樣可以減輕調用者的負擔、使錯誤不會 被忽略、增強程序的可維護性。
     [3]
     (A)忘記保存原始的strDest值,說明答題者邏輯思維不嚴密。
     [4]
     (A)循環寫成while (*strDest++=*strSrc++);,同[1](B)。
     (B)循環寫成while (*strSrc!='/0') *strDest++=*strSrc++;,說明答題者對邊界條件的檢查不力。循環體結束後,strDest字符串的末尾沒有正確地加上'/0'。

     2.返回strDest的原始值使函數能夠支持鏈式表達式,增加了函數的“附加值”。同樣功能的函數,如果能合理地提高的可用性,自然就更加理想。
     鏈式表達式的形式如:
         int iLength=strlen(strcpy(strA,strB));
     又如:
         char * strA=strcpy(new char[10],strB);
     返回strSrc的原始值是錯誤的。其一,源字符串肯定是已知的,返回它沒有意義。其二,不能支持形如第二例的表達式。其三,爲了保護源字符串,形參用const限定strSrc所指的內容,把const char *作爲char *返回,類型不符,編譯報錯。

Linux 下的定義是這樣的:
/usr/lib/string.h

string.h:char *strcpy (char *__restrict __dest, __const char *__restrict __src)      __THROW __nonnull ((1, 2));

/usr/src/linux-2.6.0-test3/lib/string.c

/** * strcpy - Copy a %NUL terminated string * @dest: Where to copy the string to * @src: Where to copy the string from */

char * strcpy(char * dest,const char *src){ 

        char *tmp = dest; 

        while ((*dest++ = *src++) != '/0')

                 /* nothing */;

         return tmp;

}

在 string.h 中有 __THROW 這個宏,我們來查看一下在哪裏定義的:
$ grep __THROW /usr/include/*.h |grep define

...usr/include/malloc.h:#   define __THROW throw ()...

而且幾乎每個預處理指令都由 __THROW 來處理,可以這樣查看:
$ grep -R __THROW /usr/include/* | grep "#"

linux 裏的和高質量C/C++ 裏的其實是一樣的,除了異常處理哪裏稍不同而已。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章