strcpy函数实现的几种方式
C/C++——strcpy函數的實現?和解析
題目:?
????已知strcpy函數的原型是:?
????????char?*?strcpy(char?*?strDest,const?char?*?strSrc);?
????1.不調用庫函數,實現strcpy函數。?
????2.解釋為什么要返回char?*。
(一)高質量c++編程上的答案
五、編寫strcpy函數(10分)
已知strcpy函數的原型是
???????char *strcpy(char *strDest, const char *strSrc);
???????其中strDest是目的字符串,strSrc是源字符串。
(1)不調用C++/C的字符串庫函數,請編寫函數?strcpy
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”) );
?
【規則6-2-3】不要將正常值和錯誤標志混在一起返回。正常值用輸出參數獲得,而錯誤標志用return語句返回。錯誤信息可以用throw拋出。
?
2????????建議6-2-1】有時候函數原本不需要返回值,但為了增加靈活性如支持鏈式表達,可以附加返回值。
例如字符串拷貝函數strcpy的原型:
char *strcpy(char *strDest,const char *strSrc);
strcpy函數將strSrc拷貝至輸出參數strDest中,同時函數的返回值又是strDest。這樣做并非多此一舉,可以獲得如下靈活性:
????char str[20];
????int??length = strlen( strcpy(str, “Hello World”) );
()
?
?(二)程序員面試寶典中的答案
char* strcpy1(char?*strDest,?const?char*?strSrc)
{
???????assert(strSrc?!=?NULL?);
???????assert(strDest?!=?NULL);
???????int?i;
???????char?*address?=?strDest;
?
????for(i?= 0;?strSrc[i] !=?'\0';?i++)
??????????????strDest[i] =?strSrc[i];
???????strDest[i] =?'\0';
?
???????return?address;
}
(三)帶有異常拋出的答案和解析
????解說:?
????1.strcpy的實現代碼?
?
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]:???規則6-1-3】如果參數是指針,且僅作輸入用,則應在類型前加const,以防止該指針在函數體內被意外修改。
????錯誤的做法:?
????//[1]
????(A)如果不檢查指針的有效性,說明答題者不注重代碼的健壯性。?
????(B)如果檢查指針的有效性時使用((!strDest)||(!strSrc))或(!(strDest&&strSrc)),說明答題者對C語言中類型的隱式轉換沒有深刻認識。在本例中((!strDest)是將char?*轉換為bool即是類型隱式轉換,這種功能雖然靈活,但更多的是導致出錯概率增大和維護成本升高。所以C++專門增加了bool、true、false三個關鍵字以提供更安全的條件表達式。?
????(C)如果檢查指針的有效性時使用((strDest==0)||(strSrc==0)),說明答題者不知道使用常量的好處。直接使用字面常量(如本例中的0)會減少程序的可維護性。0雖然簡單,但程序中可能出現很多處對指針的檢查,萬一出現筆誤,編譯器不能發現,生成的程序內含邏輯錯誤,很難排除。而使用NULL代替0,如果出現拼寫錯誤,編譯器就會檢查出來。
(D)NULL?==?strDest是將?常量寫在表達式的左邊,如果將表達式寫錯了,寫成了賦值,則馬上報錯;如果?將表達式改成?strDest??==NULL,在寫的過程中?漏寫了?一個=,變成了?strDest?=?NULL,則檢查不出錯誤來,可能會出現意想不到的錯誤
????//[2]
????(A)return?new?string("Invalid?argument(s)");,說明答題者根本不知道返回值的用途,并且他對內存泄漏也沒有警惕心。從函數中返回函數體內分配的內存是十分危險的做法,他把釋放內存的義務拋給不知情的調用者,絕大多數情況下,調用者不會釋放內存,這導致內存泄漏。?
????(B)return?0;,說明答題者沒有掌握異常機制。調用者有可能忘記檢查返回值,調用者還可能無法檢查返回值(見后面的鏈式表達式)。妄想讓返回值肩負返回正確值和異常值的雙重功能,其結果往往是兩種功能都失效。應該以拋出異常來代替返回值,這樣可以減輕調用者的負擔、使錯誤不會被忽略、增強程序的可維護性。?
???//[3]
????(A)如果忘記保存原始的strDest值(即忘記?保留strDest的頭指針),說明答題者邏輯思維不嚴密。?
????//[4]?
????(A)循環寫成while?(*strDest++=*strSrc++);,同[1](B)。?
????(B)如果循環寫成while?(*strSrc!='\0')?*strDest++=*strSrc++;,說明答題者對邊界條件的檢查不力。這樣的話,就是先判斷是否為零,然后再賦值,肯定是不會把結尾零賦給strDest的,而[4]中的循環是先賦值,再判斷是否為零,是會給strDest賦上結尾零的,如此這樣,這個形式循環體結束后,strDest字符串的末尾沒有正確地加上'\0'。
要正常的話應該寫成:
while?(*strSrc!='/0')?*strDest++=*strSrc++;
strDest[i] =?'\0';//?strDest字符串的末尾加上'\0'
這里還有說一句:?=?和?*?和?right ++?這三個符號中,*?和??右++的優先級都是2級,是對等的,其次是?=?,?由于?右++的特點:是滯后使用,?造成?會先賦值,再指針++
也就是說:*strDest++=*strSrc++;
??????*strDest++:會拆成?*strDest?和?strDest++兩個對等的部分
其讓人感覺到的執行順序
l???????*strDest = *strSrc;
l???????然后才能是?strDest++,strSrc++
?
舉個例子如下:
#define?product(x) (x * x)
?int?i = 3, j, k;
j = product(i++);
k = product(++i);
cout << j <<?" "?<< k << endl;//輸出為9和49
即使定義為#define product(x) ((x) * (x))得到的結果還是一樣
????2.返回strDest的原始值使函數能夠支持鏈式表達式,增加了函數的“附加值”。同樣功能的函數,如果能合理地提高的可用性,自然就更加理想。?
????鏈式表達式的形式如:?
????????int?iLength=strlen(strcpy(strA,strB));?
????又如:?
????????char?*?strA=strcpy(new?char[10],strB);?
????返回strSrc的原始值是錯誤的。其一,源字符串肯定是已知的,返回它沒有意義。其二,不能支持形如第二例的表達式。其三,為了保護源字符串,形參用const限定strSrc所指的內容,把const?char?*作為char?*返回,類型不符,編譯報錯。
關于鏈式表達式
已知strcpy函數的原型是 char *strcpy(char *strDest, const char *strSrc);
其中strDest是目的字符串,strSrc是源字符串。
(1)不調用C++/C的字符串庫函數,請編寫函數
strcpy 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”) );
?--------------------------------------------------------------------------------------------------------------------------------
看到了這個詞:鏈式表達式,之前沒有聽過,所以去百度了一下,發現有人解釋的還算明白:
-------------------------------------------------------------------------------------------------------------------------------- http://topic.csdn.net/t/20061123/21/5180993.html 1,
就是方便一些,否則就要這樣寫:
char strDest[12];
strcpy( strDest, “hello world”);
int length = strlen(strDest);
什么鏈式就是一連串寫下來的意思。。。
?--------------------------------------------------------------------------------------------------------------------------------
?其實,說白了,就是如果上面的字符串拷貝函數strcopy的返回值是void,那么,上面那句:
?int length = strlen( strcpy( strDest, “hello world”) );
?就要像上面那位的回答,寫成好幾句了:
char strDest[12];
?strcpy( strDest, “hello world”);
int length = strlen(strDest);
而這種直接返回char *的手段,就是為了后來函數調用者方便而設計的.不用你這么麻煩用上述方法去使用了,而直接可以使用拷貝后的dest字符串了.這種方便的實現方法,看起來就是鏈子鏈在一起的,所以稱為 鏈式表達式
如此而已.呵呵.
關于鏈式表達式
已知strcpy函數的原型是 char *strcpy(char *strDest, const char *strSrc);
其中strDest是目的字符串,strSrc是源字符串。
(1)不調用C++/C的字符串庫函數,請編寫函數
strcpy 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”) );
?--------------------------------------------------------------------------------------------------------------------------------
看到了這個詞:鏈式表達式,之前沒有聽過,所以去百度了一下,發現有人解釋的還算明白:
-------------------------------------------------------------------------------------------------------------------------------- http://topic.csdn.net/t/20061123/21/5180993.html 1,
就是方便一些,否則就要這樣寫:
char strDest[12];
strcpy( strDest, “hello world”);
int length = strlen(strDest);
什么鏈式就是一連串寫下來的意思。。。
?--------------------------------------------------------------------------------------------------------------------------------
?其實,說白了,就是如果上面的字符串拷貝函數strcopy的返回值是void,那么,上面那句:
?int length = strlen( strcpy( strDest, “hello world”) );
?就要像上面那位的回答,寫成好幾句了:
char strDest[12];
?strcpy( strDest, “hello world”);
int length = strlen(strDest);
而這種直接返回char *的手段,就是為了后來函數調用者方便而設計的.不用你這么麻煩用上述方法去使用了,而直接可以使用拷貝后的dest字符串了.這種方便的實現方法,看起來就是鏈子鏈在一起的,所以稱為 鏈式表達式
如此而已.呵呵.
總結
以上是生活随笔為你收集整理的strcpy函数实现的几种方式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C/C++ struct 区别
- 下一篇: 测试分类与测试用例