strcpy與strcpy_s的問題



一下是使用strcpy_s與strcpy的安全性比較

 char szBuf[2] = {0};

 strcpy_s(szBuf, 2, "12131");  //新的CRT函數
 strcpy(szBuf,  "12131");    //老的CRT函數

上述代碼,明顯有緩衝區溢出的問題。 使用strcpy_s函數則會拋出一個異常。而使用strcpy函數的結果則未定,因爲它錯誤地改變了程序中其他部分的內存的數據,可能不會拋出異常但導致程序數據錯誤,也可能由於非法內存訪問拋出異常。

使用新的增強安全的CRT函數有什麼好處呢?簡單地說,新的函數加強了對參數合法性的檢查以及緩衝區邊界的檢查,如果發現錯誤,會返回errno或拋出異常。老版本的這些CRT函數則沒有那麼嚴格的檢查與校驗,如果錯誤地傳輸了參數或者緩衝區溢出,那麼錯誤並不能被立刻發現,對於定位程序錯誤也帶來更大困難。


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 *返回,類型不符,編譯報錯。


strcpy_s源代碼


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