C語言中所謂的字符串不過是字符數組,后跟一個0x00字符標識結尾,所以反轉起來很容易,只要一個循環依次將第一個字符和最后一個字符交換,第二個字符和倒數第二個字符交換……如果最中間有兩個字符(即需要反轉的字符串長度為偶數),那就交換,如果最中間有一個字符(即需要反轉的字符串長度為奇數),那就不需要碰它。還有就是最后一個用來標識字符串結尾的0x00字符不用動它。
這道題目通常是考察三個方面,一是對指針和字符串的理解,二是是否進行合法性檢查,例如輸入參數為空指針時是否進行檢查,三是返回值是否是恰當,即使你通過參數返回了反轉后的字符串指針,也建議在返回值里再返回一下,就像strcpy函數實現的那樣。其實還有第四點往往是大家都忽略了的,那就是Unicode問題,如果傳入的字符串指針指向的是Unicode字符串,那么反轉的時候就不能一個字符一個字符的處理了,不過似乎大多數面試官都沒對這一點有過要求,如果你在筆試或面試中遇到這個問題,我建議你想監考或面試官詢問一下是否需要考慮Unicode。我面試的時候因為被面試官弄的很緊張,也忘記了這點,寫完后檢查代碼准備交過去時才想起來,索性就當不知道這回事……呵呵。
有了上面這幾點,我們就可以很容易地用C語言寫出這個函數了。
1 char *revstr(char *str, size_t len) 2 { 3 4 char *start = str; 5 char *end = str + len - 1; 6 char ch; 7 8 if (str != NULL) 9 { 10 while (start < end) 11 { 12 ch = *start; 13 *start++ = *end; 14 *end-- = ch; 15 } 16 } 17 return str; 18 }
代碼很簡單,就不多介紹了,只是為什么我給這個函數叫revstr而不是strrev呢?我開始時也是給它叫strrev,只是鏈接時卻出錯了,這時我才發現VS2005的C++編譯器已經在string.h中中提供了一個strrev函數(這看起來並不是C標准庫函數,我不知道還有哪些編譯器提供了這個函數),如果你安裝了crt代碼包的話可以找到這個函數的實現。我們來看一下它是如何實現的吧。
1 char * __cdecl _strrev ( 2 char * string 3 ) 4 { 5 char *start = string; 6 char *left = string; 7 char ch; 8 9 while (*string++) /* find end of string */ 10 ; 11 string -= 2; 12 13 while (left < string) 14 { 15 ch = *left; 16 *left++ = *string; 17 *string-- = ch; 18 } 19 20 return(start); 21 }
這與我上面給出的函數並沒有什么本質的不同,只是只傳入了一個參數,並沒有傳入字符串長度,但是我覺得還是傳入這個長度比較好,因為有可能我們並不想反轉整個字符串,如果采用我給出的那種實現,一個長度為10的字符串,我們只想反轉前7個字符也是可以的。還有就是微軟給出的這個實現並沒有判斷是否傳入空指針,不過我覺得這並不是個大問題,這要取決於你的具體期望,就像我在啟明星辰的筆試中遇到了一道題目,要求我實現一個函數將傳入的字符串中的小寫字母轉換成大寫字母,那么如果傳入的字符串是小寫字母和數字混合的呢?函數應該出錯還是應該跳過數字繼續處理?兩種方式都沒錯,怎么選擇要取決於你或者閱卷人對這個函數的期望,在筆試或面試中你可以詢問監考活面試官,如果沒有得到准確的描述,你怎么實現都是正確的。
