memmove 和 memcpy的區別以及處理內存重疊問題

區別:

memcpy和memmove()都是C語言中的庫函數,在頭文件string.h中,作用是拷貝一定長度的內存的內容,原型分別如下:

void *memcpy(void *dst, const void *src, size_t count);
void *memmove(void *dst, const void *src, size_t count);
他們的作用是一樣的,唯一的區別是,當內存發生局部重疊的時候,memmove保證拷貝的結果是正確的,memcpy不保證拷貝的結果的正確。

一、memcpy函數

Memcpy原型:     

void *memcpy(void *dest, const void *src, size_t n);
描述:
        memcpy()函數從src內存中拷貝n個字節到dest內存區域,但是源和目的的內存區域不能重疊。
返回值:
        memcpy()函數返回指向dest的指針。
二、memmove函數

memmovey原型:

void *memmove(void *dest, const void *src, size_t n);
描述:
       memmove() 函數從src內存中拷貝n個字節到dest內存區域,但是源和目的的內存可以重疊。
返回值:
        memmove函數返回一個指向dest的指針。

從上面的描述中可以看出兩者的唯一區別就是在對待重疊區域的時候,memmove可以正確的完成對應的拷貝,而memcpy不能。

內存覆蓋的情形有以下兩種,

先看memcpy()和memmove()這兩個函數的實現:

void* my_memcpy(void* dst, const void* src, size_t n)
{
    char *tmp = (char*)dst;
    char *s_src = (char*)src;

    while(n--) {
        *tmp++ = *s_src++;
    }
    return dst;
}
從實現中可以看出memcpy()是從內存左側一個字節一個字節地將src中的內容拷貝到dest的內存中,這種實現方式導致了對於圖中第二種內存重疊情形下,最後兩個字節的拷貝值明顯不是原先的值了,新的值是變成了src的最開始的2個字節了。

而對於第一種內存覆蓋情況,memcpy的這種拷貝方式是可以的。

而memmove就是針對第二種內存覆蓋情形,對memcpy進行了改進,改進代碼如下:

void* my_memmove(void* dst, const void* src, size_t n)
{
    char* s_dst;
    char* s_src;
    s_dst = (char*)dst;
    s_src = (char*)src;
    if(s_dst>s_src && (s_src+n>s_dst)) {      //-------------------------第二種內存覆蓋的情形。
        s_dst = s_dst+n-1;
        s_src = s_src+n-1;
        while(n--) {
            *s_dst-- = *s_src--;
        }
    }else {
        while(n--) {
            *s_dst++ = *s_src++;
        }
    }
    return dst;
}

在第二種內存覆蓋的情形下面,memcpy會出錯,但是memmove是能正常工作的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章