教育行業(yè)A股IPO第一股(股票代碼 003032)

全國咨詢/投訴熱線:400-618-4000

c/c++培訓之Strcpy函數的實現

更新時間:2016年10月21日16時13分 來源:傳智播客C++培訓學院 瀏覽次數:

Strcpy函數的實現
在C/C++程序員的面試中,你會遇到很多題目,但總會存在一些經典的題目,今天我們就來分析一下C/C++經典面試題目之strcpy函數的實現。
在筆試題中大多數都會存在這樣的一道題目:
已知strcpy函數的原型是: (10分)
char * strcpy(char * strDest,const char * strSrc);
    1.不調用庫函數,實現strcpy函數。
    2.解釋為什么要返回char *。
這道題目看似不難,但想要達到滿分還是不容易的。下面我們來看一個版本的答案:(1)
char *strcpy(char *strDest, const char *strSrc)      
{
    assert((strDest!=NULL) && (strSrc !=NULL));    // 2分
 
    char *address = strDest;                    // 2分
    while( (*strDest++ = * strSrc++) != '\0' )       // 2分
              NULL ;
    return address ;                          // 2分
}
(2) strcpy函數能把strSrc 的內容復制到strDest中,返回char * 的目的是為了實現鏈式表達式。   // 2分
如:  int length = strlen(strcpy(strDest, “hello world”));
下面在看一下C++中不適用庫函數,帶異常版本的答案:
char * strcpy3(char * strDest,const char * strSrc /*[0]*/)
{    
       if ((NULL == strDest)||(NULL == strSrc)) //[1]
              throw "Invalid argument(s)"; //[2]
 
       char * strDestCopy=strDest;  //[3]
 
       while ((*strDest++=*strSrc++)!='\0'); //[4]
 
       return strDestCopy;    
}
以上兩個版本的答案,僅供參考,下面我們來分析一下,此題目的考察點,即扣分點和知識點。
【0】如果參數是指針,并且作為輸入參數,應該適應const 修飾,防止該指針在函數體內 被意外修改。
錯誤的做法:
【1】
(A)不檢查指針(即參數)的有效性,說明答題者不注重代碼的健壯性。
(B)如果檢查指針的有效性時使用((!strDest)||(!strSrc))或(!(strDest&&strSrc)),說明答題者對C語言中類型的隱式轉換沒有深刻認識。在本例中((!strDest)是將char*轉換為bool即是類型隱式轉換,這種功能雖然靈活,但更多的是導致出錯概率增大和維護成本升高。所以C++專門增加了bool、true、false三個關鍵字以提供更安全的條件表達式。
(C)如果檢查指針的有效性時使用((strDest==0)||(strSrc==0)),說明答題者不知道使用常量的好處。直接使用字面常量(如本例中的0)會減少程序的可維護性。0雖然簡單,但程序中可能出現很多處對指針的檢查,萬一出現筆誤,編譯器不能發(fā)現,生成的程序內含邏輯錯誤,很難排除。而使用NULL代替0,如果出現拼寫錯誤,編譯器就會檢查出來。
(D)NULL == strDest是將 常量寫在表達式的左邊,如果將表達式寫錯了,寫成了賦值,則馬上報錯;如果 將表達式改成 strDest  ==NULL,在寫的過程中 漏寫了 一個=,變成了 strDest = NULL,則檢查不出錯誤來,可能會出現意想不到的錯誤。
【2】
(A)return new string("Invalid argument(s)");,說明答題者根本不知道返回值的用途,并且他對內存泄漏也沒有警惕心。從函數中返回函數體內分配的內存是十分危險的做法,他把釋放內存的義務拋給不知情的調用者,絕大多數情況下,調用者不會釋放內存,這導致內存泄漏。
(2)return 0;,說明答題者沒有掌握異常機制。調用者有可能忘記檢查返回值,調用者還可能無法檢查返回值(見后面的鏈式表達式)。妄想讓返回值肩負返回正確值和異常值的雙重功能,其結果往往是兩種功能都失效。應該以拋出異常來代替返回值,這樣可以減輕調用者的負擔、使錯誤不會被忽略、增強程序的可維護性。
【3】
(A)如果忘記保存原始的strDest值(即忘記 保留strDest的頭指針),說明答題者邏輯思維不嚴密。
【4】
(A)循環(huán)寫成while (*strDest++=*strSrc++);,同【1】(B)。
(B)如果循環(huán)寫成while (*strSrc!='\0')  *strDest++=*strSrc++;,說明答題者對邊界條件的檢查不力。這樣的話,就是先判斷是否為零,然后再賦值,肯定是不會把結尾零賦給strDest的,而[4]中的循環(huán)是先賦值,再判斷是否為零,是會給strDest賦上結尾零的,如此這樣,這個形式循環(huán)體結束后,strDest字符串的末尾沒有正確地加上'\0'。
要正常的話應該寫成:
while (*strSrc!='/0')   *strDest++=*strSrc++;
strDest[i] = '\0';   // strDest字符串的末尾加上'\0'
 
本文版權歸傳智播客C++培訓學院所有,歡迎轉載,轉載請注明作者出處。謝謝!
作者:傳智播客C/C++培訓學院
首發(fā):http://fskzgqt.cn/c/ 
0 分享到:
和我們在線交談!