C/C++之Memcpy and memmove

memcpy與memmove的目的都是將N個字節的源內存地址的內容拷貝到目標內存地址中。c++

但當源內存和目標內存存在重疊時,memcpy會出現錯誤,而memmove能正確地實施拷貝,但這也增長了一點點開銷。數組

memmove的處理措施:函數

(1)當源內存的首地址等於目標內存的首地址時,不進行任何拷貝spa

(2)當源內存的首地址大於目標內存的首地址時,實行正向拷貝指針

(3)當源內存的首地址小於目標內存的首地址時,實行反向拷貝code

-- memcpy實現ip

 
1 voidmemcpy(void* dest, const void* src, size_t n)
2 {
3 char* d = (char*) dest;
4 const char* s = (const char*) src;
5 while(n-–)
6 *d++ = *s++;
7 return dest;
8 }

 

Notes:內存

  • memcpy的參數指針類型是void*,具體賦值操做是以字節爲單位。
  • 必須進行類型轉換。
  • 返回的仍是void*型的dest。

 

-- memmove實現字符串

 
01 voidmemmove(void* dest, const void* src, size_t n)
02 {
03 char* d = (char*) dest;
04 const char* s = (const char*) src;
05  
06 if (s>d)
07 {
08 // start at beginning of s
09 while (n--)
10 *d++ = *s++;
11 }
12 else if (s<d)
13 {
14 // start at end of s
15 d = d+n-1;
16 s = s+n-1;
17  
18 while (n--)
19 *d-- = *s--;
20 }
21 return dest;
22 }

 示意圖:原型

(1)內存低端 <-----s-----> <-----d-----> 內存高端 start at end of s
(2)內存低端 <-----s--<==>--d-----> 內存高端 start at end of s
(3)內存低端 <-----sd-----> 內存高端 do nothing
(4)內存低端 <-----d--<==>--s-----> 內存高端 start at beginning of s
(5)內存低端 <-----d-----> <-----s-----> 內存高端 start at beginning of s

Notes:
  • s==d時,什麼都不作。
  • d在前,正向拷貝。
  • d在後,逆向拷貝。

 

 

 


 

 

 

1.memmove

函數原型:void *memmove(void *dest, const void *source, size_t count)

返回值說明:返回指向dest的void *指針

參數說明:dest,source分別爲目標串和源串的首地址。count爲要移動的字符的個數

函數說明:memmove用於從source拷貝count個字符到dest,若是目標區域和源區域有重疊的話,memmove可以保證源串在被覆蓋以前將重疊區域的字節拷貝到目標區域中。

2.memcpy

函數原型:void *memcpy(void *dest, const void *source, size_t count);

返回值說明:返回指向dest的void *指針

函數說明:memcpy功能和memmove相同,可是memcpy中dest和source中的區域不能重疊,不然會出現未知結果。
原型:extern char *strcpy(char *dest,char *src);  功能:把src所指由NULL結束的字符串複製到dest所指的數組中。  說明:src和dest所指內存區域不能夠重疊且dest必須有足夠的空間來容納src的字符串,返回指向dest的指針。

  其實在strcpy的實現比較多,但思想是一致的,通常用C來實現,可是memcpy和memmove這樣的函數多是用匯編實現的,而且充分利用塊拷貝的思想,不會單字節單字節的拷貝。因此效率strcpy<memcpy.

memmove通常因爲要判斷內存是否重合,效率也會較memcpy低些。

1 /***
2 * @brief 以字節的方式直接拷貝
3 * 庫中實現是以彙編實現,
4 * 其實能夠直接調用strncat函數
5 * **/
6 void *memcpy(void *dst,void *src,size_t n)
7 {
8 char *dp = (char *)dst;
9 char *sp = (char *)src;
10 assert((src!=0)&&(dst!=0)&&(n>0));//not null
11 while(n--)
12 *(dp++) = *(sp++);
13 /**!邊界*/
14 dp = '\0';
15 return dst;
16 }

 

 

 

 

Memcpy and memmove - 蘭花草 - 蘭花草的博客memmove
 1 void *memmove(void *dst,const void *src,int n)                                                
2 {
3 char *dp = (char *)dst;
4 char *sp = (char *)src;
5 assert((src!=0)&&(dst!=0)&&(n>0));//not null
6 //非重疊
7 //dp < sp
8 //dp > (sp+n)
9 if(dp<sp||(sp+n)>=dp)
10 {
11 while(n--)
12 *(dp++) = *(sp++);
13 *dp = '\0';
14 }else if(sp<dp)//重疊 (此時條件 sp<dp<(sp+n))若是sp==dp則快速的返回
15 {//反向拷貝
16 sp += n;
17 dp += n;
18 *dp = '\0';
19 while(n--)
20 *(--dp) = *(--sp);
21 }
22 return dst;
23 }

 注意對於重合的要反向拷貝

 

 

 

 

 


/*
 *Magicman
 *myMemcpy.c
 *不調用庫函數,實現內存拷貝
*/

 

 

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

void *myMemcpy(void *dest, const void *src, int len)
{
    assert((dest != NULL) && (src != NULL) && (len >= 0));

    if (dest == src)
    {
        return dest;
    }

    while (len-- > 0)
    {
        *(char *)dest++ = *(char *)src++;
    }

    return dest;
}

int main(int argc, char argv[])
{
    char str[20] = "Testing myMemory!";
    char pstr[20] = "";
    char *pp = str;
    int ia[10] = {1,2,3,4,5,6,7,8,9,10};
    int ib[10] = {};
    int *ip = NULL;

    myMemcpy((void *)pstr, (void *)str, sizeof(str));

    printf("%s/n", pstr);

    printf("%s/n", myMemcpy((void *)pp, (void *)str, 20));

    myMemcpy((void *)ib, (void *)ia, 5*sizeof(int));

    for (ip = ib; ip < ib + 10; ip++)
    {
        printf("%d  ", *ip);
    }

    printf("/n");
    
    return 0;
}

 


讓本身實現memcpy庫函數,要求考慮特殊狀況,兩段內存存在覆蓋,以及指針爲空的狀況。

幾點結論: 
1,memcpy實現從源source中拷貝n個字節到目標destin中,src源數據應該保留。
2,memmove實現移動一塊字節,src源數據能夠不保留。
3,memcpy沒有考慮內存覆蓋問題(由assert條件可知);而memmove考慮了內存覆蓋問題,並給出瞭解決辦法。4,memcpy和memmove中不須要考慮數組越界問題,dst的長度應該大於src的長度,這是調用者應該考慮的問題。

相關文章
相關標籤/搜索