strcpy 和 strncpy

來源:互聯網
上載者:User

 

 庫函數 extern char *strcpy(char *dest,char *src)

用法:#include <string.h>
 
  功能:把src所指由NULL結束的字串複製到dest所指的數組中。
 
  說明:src和dest所指記憶體地區不可以重疊且dest必須有足夠的空間來容納src的字串。
        返回指向dest的指標。

   注意:strcpy不是遇到/0就不複製了  ,複製完成後判斷最後的字元是否為'/0' ,如果是,則退出迴圈!

               也就是說,dest是有結束標誌'/0'的!


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

    解說:
    1.strcpy的實現代碼
 

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

       assert((dest!= NULL) && (src != NULL));

       char *tmp= dest;

       while ((*tmp++ = *src++) != ‘/0’)   

/*迴圈結束時 *dest為:'/0' ,不用手動加結束標誌*/

                    /*nothing*/;

return dest;

}

    錯誤的做法:
    [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)。 linux下卻正是如此實現的!!??
    (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;

/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++ 裡的其實是一樣的,除了異常處理哪裡稍不同而已。 

 

kernel linux-2.6.22 /lib/string.c 中 strncpy實現

 

char *strncpy(char *dest, const char *src, size_t count)
{
 char *tmp = dest;

 while (count) {
  if ((*tmp = *src) != 0)
   src++;
  tmp++;
  count--;
 }                                              /*Warning:!!!未設定dest結束:'/0'  !!!*/
 return dest;
}

注意比較linux下的strcpy與strncpy的不同:

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

/*運行結束時,*dest的值為:'/0' ,已經有了結束標誌。*/

strncpy: if ((*tmp = *src) != 0)         /*為什麼可以用0來判斷???*/

/*運行結束時,*tmp的值不確定 ,不一定有結束標誌(若參數count小於src字元個數),那樣tmp將一直讀取到記憶體中的'/0'為止。*/

 為什麼這段代碼的strlen(tmp) 返回6?

#include <stdio.h>
#include <stdio.h>
#include <string.h>

char *strncpy_1(char *dest,const char *src,size_t count)
{
 char *tmp = dest;

 while(count)
 {

  if((*tmp=*src)!='/0')
  {
  
   src++;
   tmp++;

  }

  count--;
  
 }

 if(*tmp!='/0')
  *++tmp='/0';
 
 return dest;
}

void print(char *ch)
{
 char *tmp ;

 for(tmp=ch;*tmp!='/0';tmp++)
  printf("%c",*tmp);
 printf("/n");
}

int main(void)
{
 char *tmp;
 char src[]="hello,world!";
 char dest[20];

 printf("The length of src is : %d/n",strlen(src));

 printf("The source string is :/t");
 print(src);
 
 tmp = strncpy_1(dest,src,5);

 printf("The destination string is :/t");
 print(tmp);

 printf("The length of dest is : %d/n",strlen(tmp));

 return 0;
 
}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.