我們在寫程序時,一般講究見到變量的命名,就能讓別人基本知道該變量的含義。memcpy內存拷貝,沒有問題;memmove,內存移動?錯,如果這樣理解的話,那麼這篇文章你就必須要好好看看了,memmove還是內存拷貝。那麼既然memcpy和memmove二者都是內存拷貝,那二者究竟有什麼區別呢?
你有沒有好好的參加過一場C++筆試。讓你寫出memcpy的實現,這是多麼常見的筆試題啊。現在,拿起你的演算紙和筆;是的,是筆和紙,不是讓你在你的IDE上寫。寫不出來?看下面吧:
void *mymemcpy(void *dest, const void *src, size_t count){
assert(dest != NULL && src != NULL);
char *tmp = (char *)dest;
char *p = (char *)src;
while (count--)
{
*tmp++ = *p++;
}
return dest;}
memcpy的實現很簡單,一般在筆試時,出現寫源碼的題目,無非就是需要注意以下幾點:
當然了,我的這個沒有錯誤處理,也不需要錯誤處理。上面,我寫出了memcpy的實現源碼,實現原理如下圖所示:
這樣下去,上面的代碼會運行的很好,如果出現下面的情況呢?
i、n、k的內存和J、e、l的內存地址重合了,現在再使用上面的代碼進行copy時,會出現什麼問題呢?你有沒有想過這個問題。如果沒有,那就現在想想,不急著閱讀下面的內容。
然後,我再留一個問題,上面的代碼中,為什麼都需要將void *轉換成char *呢?比如:
char *tmp = (char *)dest;
可以留言回答哦。
memmove也是用來實現內存的直接拷貝的。說起這個命名,我個人覺的多少還是有點坑的。既然memmove也是用來內存數據移動的,那就先來看看memmove的實現源碼。
void *mymemmove(void *dest, const void *src, size_t count){
assert(dest != NULL && src != NULL)
if (dest < src)
{
char *p = (char *)dest;
char *q = (char *)src;
while (count--)
{
*p++ = *q++;
}
}
else
{
char *p = (char *)dest + count;
char *q = (char *)src + count;
while (count--)
{
*--p = *--q;
}
}
return dest;}
從源碼看,memmove的確比memcpy復雜一些;再仔細一看,多了些什麼?哦,多了一個else分支,而正是這個else分支,就處理了當src和dest的內存重合的問題。
從實現源碼中的確能看出一些貓膩,當出現了src和dest的內存有重合的時機時,memmove的處理規則是從後往前進行copy。當然了,重合的問題,需要考慮的以下兩種場合。
如圖所示,當出現(1)對應的情況時,就需要先從src的頭部開始復制;也就是memmove源碼中的if分支,這部分源碼和memcpy的實現是一致的;當出現(2)對應的情況時,就需要先從src的尾部開始復制,防止出現了覆蓋現象。這就是memmove比memcpy多的一個考慮點,所以說,在實際使用時,使用memmove是比memcpy更安全的。
總結到了這裡,我覺的我已經把問題說清楚了。你說呢?如果你還有什麼好的想法,歡迎你和我分享。