C語言中的內存函數有如下這些
- memcpy
- memmove
- memcmp
- memset
下面看看memmove函數
memmove
為什么會需要memmove函數?
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
// 想把12345 拷貝到 34567上去
// 應該打印 1 2 1 2 3 4 5 8 9 10
my_memcpy(arr + 2, arr, 20);
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
// 但是輸出 1 2 1 2 1 2 1 8 9 10
return 0;
}
上面會輸出 1 2 1 2 1 2 1 8 9 10,我們來看看為什么會出現這樣的結果。
我這里畫了張圖,方便理解。
因為拷貝的地方重疊了,使原來的數據(3 4 5)被覆蓋了,導致最后出來的結果不是我們想要的。
也就是說,如果拷貝的地方重疊了,那么就會出現這種情況。
那么如何解決呢?答案就是從后往前拷貝,指針從最后的地方開始操作。
還是上一張圖
這樣,就得出了我們想要的結果。
但是呢,也不能一概而論,就全部都是從后往前拷貝,還是得分情況的,具體就是看destination
和source
的位置關系。
回到最開始的問題,為什么會需要memmove函數?,因為memmove這個函數可以處理這種重疊拷貝。
老規矩,我們還是看看文檔是怎樣說的,如下
void * memmove ( void * destination, const void * source, size_t num );
Move block of memory
移動內存塊(移動內存數據)
Copies the values of num bytes from the location pointed by source to the memory block pointed by destination. Copying takes place as if an intermediate buffer were used, allowing the destination and source to overlap.
從source(源內存塊位置)直接指向的地方開始復制num個字節的數據到destination指向的內存塊位置。然后復制就像使用了中間緩沖區一樣,允許destination和source重疊。
The underlying type of the objects pointed by both the source and destination pointers are irrelevant for this function; The result is a binary copy of the data.
這句話沒看懂,不影響我們學這個。
The function does not check for any terminating null character in source - it always copies exactly num bytes.
這個函數不會檢查'\0',不會遇到'\0'就停下來,它就只認識要復制的num個字節數據。
To avoid overflows, the size of the arrays pointed by both the destination and source parameters, shall be at least num bytes.
為了避免溢出,這兩個數組的大小至少為num個字節。
可以看出,memmove和memcpy的唯一區別就是,memmove函數處理的源內存塊和目標內存塊是可以重疊的。
也就是說,如果源空間和目標空間出現重疊,就得使用memmove函數處理。
實現
斷言指針不為空是個好習慣~
void* my_memmove(void* dest, void* src, size_t num)
{
//dest落在了src的左邊,從前往后拷貝
//dest落在了src的右邊,同時沒有超過那個重疊的邊界的時候,從后往前拷貝
assert(dest != NULL);
assert(src != NULL);
void* rest = dest;
// void* 不能直接解引用,那么如何復制呢?
// 給了num個字節,也就是需要復制num個字節
// 那就轉換成char*,一個一個字節的復制過去
if (dest < src)
//if (dest < src || dest > (char*)src + num)
{
//dest落在了src的左邊,從前往后拷
while (num--)
{
*(char*)dest = *(char*)src;
//++(char*)dest;
//++(char*)src;
((char*)dest)++;
((char*)src)++;
}
}
else
{
// 從后往前拷
// 找到最后一個字節
while (num--)
{
*((char*)dest + num) = *((char*)src + num);
}
}
return rest;
}
最后,謝謝你看到這里,謝謝你認真對待我的努力,希望這篇博客有幫到你
你輕輕一個贊,就是我世界里的一顆星
還有因本人水平有限,如有錯誤以及不足之處,歡迎靚仔靚女們
指出。