天天看點

strcpy函數、memcpy函數、strncpy函數的實作

Strcpy函數

1.strcpy聲明

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

功能:把 src 所指由NULL結束的字元串複制到 dest 所指的數組中。
說明:src 和 dest 所指記憶體區域不可以重疊且 dest 必須有足夠的空間來容納 src 的字元串。傳回指向 dest 結尾處字元(NULL)的指針。
           

2. strcpy的實作:

實作要求:

1,檢查指針有效性;

2,傳回目的指針ret;

3,源字元串的末尾 ‘\0’ 需要拷貝。

4, 考慮記憶體重疊情況

char *my_strcpy(char *dst,const char *src)
{
    assert(dst != NULL);
    assert(src != NULL);
    char *ret = dst;
    memcpy(dst,src,strlen(src)+);
    return ret;
}
           

由于這裡的實作基于memcpy函數,下面我們也介紹memcpy函數的實作。

錯誤例子:(未考慮記憶體重疊現象)

char *my_strcpy(char *dst,const char *src)
{
    assert(dst != NULL);
    assert(src != NULL);
    char *ret = dst;
    while((* dst++ = * src++) != '\0') 
        ;
    return ret;
}
           

memcpy函數

1.memcpy函數的聲明

函數原型: void *memcpy(void*dest, const void *src, size_t n);

功能:從源src所指的記憶體位址的起始位置開始,拷貝n個位元組的資料到目标dest所指的記憶體位址的起始位置中。

說明:

1)src和dest所指記憶體區域不能重疊,函數傳回指向dest的指針。如果src和dest以任何形式出現了重疊,它的結果是未定義的。

2)與strcpy相比,memcpy遇到’\0’不結束,而且一定會複制完n個位元組。隻要保證src開始有n位元組的有效資料,dest開始有n位元組記憶體空間就行。

3)如果目标數組本身已有資料,執行memcpy之後,将覆寫原有資料(最多覆寫n個)。 如果要追加資料,則每次執行memcpy()後,要将目标位址增加到要追加資料的位址。

4)source和destin都不一定是數組,任意的可讀寫的空間均可.

2.memcpy函數的實作

這裡我們memcpy函數實作時考慮到了記憶體重疊的情況,可以完成指定大小的記憶體拷貝,memcpy的實作:

void * my_memcpy(void *dst,const void *src,unsigned int count)
{
     assert(dst);
     assert(src);
     void * ret = dst;
     if (dst <= src || (char *)dst >= ((char *)src + count))//源位址和目的位址不重疊,低位元組向高位元組拷貝
     {
         while(count--)
         {
             *(char *)dst = *(char *)src;
             dst = (char *)dst + ;
             src = (char *)src + ;
         }
     }
     else                       //源位址和目的位址重疊,高位元組向低位元組拷貝
     { 
         dst = (char *)dst + count - ;
         src = (char *)src + count - ; 
         while(count--) 
         {
             *(char *)dst = *(char *)src;
             dst = (char *)dst - ;
             src = (char *)src - ;
         }
    }
    return ret;
}
           

兩種不會出現記憶體重疊的圖形化解釋:

1,dst <= src

strcpy函數、memcpy函數、strncpy函數的實作

2, (char *)dst >= ((char *)src + count)

strcpy函數、memcpy函數、strncpy函數的實作

3. memcpy函數的優化(參見部落格:http://blog.csdn.net/xiaobo620/article/details/7488827)

改進思想:

大部分認為memcpy是一個char到char的拷貝的循環,擔心它的效率。實際上,memcpy是一個效率最高的記憶體拷貝函數,他不會那麼傻,來做一個一個位元組的記憶體拷貝,在位址不對齊的情況下,他是一個位元組一個位元組的拷,位址對齊以後,就會使用CPU字長來拷(和dma類似),32bit或64bit,還會根據cpu的類型來選擇一些優化的指令來進行拷貝。總的來說,memcpy的實作是和CPU類型、作業系統、cLib相關的。毫無疑問,它是記憶體拷貝裡效率最高的,請放心使用。(這是我從連結中的部落格拷貝過來的,請看原部落格,尊重原著)

void *mymemcpy(void *dst,const void *src,size_t num)
{
    assert((dst!=NULL)&&(src!=NULL));
    int wordnum = num/;//計算有多少個32位,按4位元組拷貝
    int slice = num%;//剩餘的按位元組拷貝
    int * pintsrc = (int *)src;
    int * pintdst = (int *)dst;
    while(wordnum--)*pintdst++ = *pintsrc++;
    while (slice--)*((char *)pintdst++) =*((char *)pintsrc++);
    return dst;
}
           

參考部落格:http://blog.csdn.net/gpengtao/article/details/7464061/

圖檔位址:https://www.processon.com/diagraming/595e38b7e4b0c2773f85b5e1

strncpy函數

1. strncpy函數的聲明

char * strncpy( char * dest, const char * src, size_t num );

功能:将字元串src中最多n個字元複制到字元數組dest中(它并不像strcpy一樣隻有遇到NULL才停止複制,而是多了一個條件停止,就是說如果複制到第n個字元還未遇到NULL,也一樣停止),傳回指向dest的指針。

2. strncpy函數的實作

/*
1.當要拷貝的字元個數(size_t n)小于或等于Src長度, Dest的最後不會加\0
2.當要拷貝的字元個數(size_t n)大于Src長度,Dest最後會自動追加一個\0
*/
char *mystrncpy(char *dest,const char *src,int n)
{
    char *strDest=dest;
    assert((dest!=NULL)&&(src!=NULL));
    while( n &&(*dest++=*src++)!='\0')
    {
        n--;
    }
    if (n)
    {
        while(--n)
        {
            *dest++='\0';
        }
    }
    return strDest;
}
           

2種不同情況的圖形化解釋:

1.

strcpy函數、memcpy函數、strncpy函數的實作

2.

strcpy函數、memcpy函數、strncpy函數的實作

參考部落格:http://blog.csdn.net/hgj125073/article/details/8464375

圖檔位址:https://www.processon.com/diagraming/595e3fbae4b0c5e101f306fa

繼續閱讀