memcpy函數的作用:
将由src指向位址為起始位址的連續n個位元組的資料複制到以dest指向位址為起始位址的空間内,函數傳回一個指向dest的指針。
想必大多數人在面試時被要求寫 memcpy的實作,很不幸,我也吃過這個虧(這種題要是寫的一塌糊塗後面完全沒戲),是以還是得提前準備一下,不然就隻能呵呵了。
先來看看一段錯誤的示範: 找茬
void * memcpy(void *dest, const void *src, unsigned int count);
{
if ((src == NULL) || (dest == NULL))
return;
while (count--) *dest++ = *src++;
return dest;
}
特别說明:
1、與strcpy相比,memcpy遇到'\0'不會結束,而是一定要拷貝完n個位元組,是以要指定拷貝的資料長度
2、memcpy可以拷貝任何資料類型的對象,如果dest和src的指針類型不一樣,也需要處理,不能直接++使位址自增(例如: int* p和 char*q, p++指針的值是4個4個加(0,4,8),q++是1個1個加(0,1,2,3,4))
3、如果dest本身就有資料,執行memcpy()之後會覆寫原有的資料,是以src和dest所指向的記憶體區域不能有重疊
4、不能改變形參的值,定義新的臨時變量來操作
5、參數提供的位址可能為空
完善後的代碼:
void *memcpy(void *dest, const void *src, size_t count)
{
if (dest == NULL || src == NULL )
{
return NULL;
}
char *tmp_dest = dest;
const char *tmp_src = src;
while (count--) *tmp_dest++ = *tmp_src++ ;
return dest;
}
這樣寫的代碼文法上看起來沒什麼問題了,但是不要忘記 src和dest所指向的記憶體區域不能有重疊,是以上面這段代碼還是有bug。這個算是不容易看出來的bug,如果這樣寫了以後代碼出現問題就很難排除了,這也就是為什麼寫不好這個函數指定會被淘汰的原因了。
dest和src所指向的位址有重疊的情況
記憶體位址重疊的情況分為兩種,第一種是dest的位址在src位址的後面,另一種則是dest位址在src位址的前面。
這兩種情況在memcpy中都是不允許出現的,需要在代碼中處理以避免。
為了處理上面這兩種情況,後來又提供了另一個函數memmove,在不需要保留原來記憶體區域的資料的時候可以使用memmove。
最終的正确的版本:
void *memcpy(void *dest, const void *src, size_t count)
{
if (dest == NULL || src == NULL || dest <= src+count)
{
return NULL;
}
char *tmp_dest = dest;
const char *tmp_src = src;
while (count--) *tmp_dest++ = *tmp_src++ ;
return dest;
}
上面就是正确的版本了,我所能考慮到的問題都處理了。
另外,這段代碼還可以優化,比如根據CPU的位元組長度,把原來一個一個位元組拷貝轉換為按CPU的長度拷貝,等等。
感興趣的話自己研究一下吧,這裡就不介紹了。