??個人主頁:修修修也
??所屬專欄:C語言
??操作環(huán)境:Visual Studio 2022
目錄
?一.memmove()函數(shù)簡介
1.函數(shù)功能
2.函數(shù)參數(shù)
1>.void * destination
2>.onst void * source
3>.size_t num
3.函數(shù)返回值
4.函數(shù)頭文件
二.memmove()函數(shù)的具體使用
1.使用memmove()函數(shù)完成拷貝整型數(shù)組數(shù)據(jù)(目的地與源重疊)
2.使用memmove()函數(shù)完成拷貝字符數(shù)組數(shù)據(jù)(目的地與源重疊)
三.模擬實現(xiàn)memmove()函數(shù)功能
??實現(xiàn)思路
1.函數(shù)參數(shù)及返回值設(shè)定邏輯
??函數(shù)參數(shù):
??函數(shù)返回值:
2.函數(shù)功能實現(xiàn)邏輯
1.情況一(兩個內(nèi)存塊不重疊)
2.情況二(兩個內(nèi)存塊有重疊)
??代碼編寫
??運行測試
1.測試my_memmove()函數(shù)的逆序拷貝
2.測試my_memmove()函數(shù)的順序拷貝
結(jié)語
?一.memmove()函數(shù)簡介
我們先來看一下cplusplus.com - The C++ Resources Network網(wǎng)站上memmove()函數(shù)的基本信息:
1.函數(shù)功能
可以看到,memmove()函數(shù)的功能是:
從源頭指向的內(nèi)存塊拷貝固定字節(jié)數(shù)的數(shù)據(jù)到目標指向的內(nèi)存塊,并且源頭的內(nèi)存塊與目標內(nèi)存塊可以重疊.(最后一點是memmove()與memcpy最大的區(qū)別)
2.函數(shù)參數(shù)
該函數(shù)一共有三個參數(shù),分別是:
void * memmove ( void * destination, const void * source, size_t num );
1>.void * destination
第一個參數(shù)的類型是無類型指針(void*),它指向拷貝的目的地內(nèi)存塊,它的作用是為函數(shù)提供目的地的內(nèi)存塊起始地址,以便函數(shù)能夠準確地將內(nèi)容拷貝到我們需要的內(nèi)存空間.
2>.onst void * source
第二個參數(shù)的類型是被const修飾(const修飾的指針,const在*左邊表示指針指向的內(nèi)容不可修改,const在*右邊表示指針的指向不可修改)的無類型指針(void*),它指向拷貝數(shù)據(jù)的來源內(nèi)存塊,它的作用是為函數(shù)提供拷貝源頭內(nèi)存塊起始地址,以便函數(shù)能夠準確找到拷貝的源頭進行拷貝.
3>.size_t num
第三個參數(shù)的類型是size_t(無符號整形),它表示要拷貝數(shù)據(jù)的字節(jié)數(shù),它的作用是告訴函數(shù)需要拷貝的字節(jié)數(shù)是多少,以便函數(shù)精準的拷貝該數(shù)目字節(jié)數(shù)空間的內(nèi)容到目的地.
3.函數(shù)返回值
函數(shù)的返回值類型是無類型指針(void*),它的作用是在函數(shù)運行結(jié)束后返回拷貝后的目的地內(nèi)存塊的起始地址.
4.函數(shù)頭文件
該函數(shù)包含在頭文件<string.h>中.
二.memmove()函數(shù)的具體使用
memmove()函數(shù)的使用場景是:
當我們想拷貝一個整型數(shù)組/結(jié)構(gòu)體/枚舉常量等strcpy()函數(shù)無法拷貝的數(shù)據(jù),并且目的地內(nèi)存塊和源頭內(nèi)存塊可能會有重疊的時候,我們可以考慮使用memmove()函數(shù)來完實現(xiàn)這一訴求,當然,想要使用memmove()函數(shù)拷貝字符串數(shù)據(jù)或者拷貝目的地內(nèi)存塊和源頭內(nèi)存塊不重疊也是可以的.(但是會有些殺雞用牛刀的感覺哈哈哈)
下面是拷貝時源內(nèi)存塊與目標內(nèi)存塊重疊的情況示意圖:
1.使用memmove()函數(shù)完成拷貝整型數(shù)組數(shù)據(jù)(目的地與源重疊)
因為拷貝目的地內(nèi)存塊與源內(nèi)存塊不重疊的情況我們已經(jīng)在memcpy()函數(shù)部分詳細展示過了,因此在memmove()函數(shù)部分我們將著重展示它的內(nèi)存塊重疊時的使用情況.
如下,我們使用memmove()函數(shù)將arr數(shù)組中的1,2,3,4,5拷貝到3,4,5,6,7的位置上去:
分別給memmove()函數(shù)傳入三個參數(shù):
拷貝目的地地址(即arr+2),拷貝來源地址(即arr),拷貝字節(jié)數(shù)(即sizeof(arr[0])*5).
/* memmove 使用測試 */
#include <stdio.h>
#include <string.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr+2, arr, sizeof(arr[0])*5);
//sizeof(arr[0])計算的結(jié)果是arr數(shù)組中一個元素的字節(jié)大小,乘5代表5個
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
在vs編譯器中運行查看結(jié)果:
可以看到memmove()函數(shù)成功的將arr數(shù)組中的1,2,3,4,5拷貝到了3,4,5,6,7的位置上.
2.使用memmove()函數(shù)完成拷貝字符數(shù)組數(shù)據(jù)(目的地與源重疊)
如下,我們使用memmove()函數(shù)將str數(shù)組的" very useful"拷貝到" useful......"的位置上去:
分別給memmove()函數(shù)傳入三個參數(shù):
拷貝目的地地址(即str+20),拷貝來源地址(即str+15),拷貝字節(jié)數(shù)(即11).
/* memmove 使用測試 */
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "memmove can be very useful......";
memmove(str + 20, str + 15, 11);
//使用memmove()函數(shù)拷貝內(nèi)存塊重疊字符串
printf("%s\n", str);
return 0;
}
在vs編譯器中運行查看結(jié)果:
?可以看到memmove()函數(shù)成功的將str數(shù)組的" very useful"拷貝到了" useful......"的位置上.
三.模擬實現(xiàn)memmove()函數(shù)功能
??實現(xiàn)思路
1.函數(shù)參數(shù)及返回值設(shè)定邏輯
??函數(shù)參數(shù):
void * destination
因為memmove()函數(shù)要實現(xiàn)的是內(nèi)存空間的拷貝,所以在使用memmove()函數(shù)時我們難免會遇到拷貝不同類型數(shù)據(jù)的可能,因此在這里我們需要將目的地的地址類型設(shè)置為無類型指針(void*),以便函數(shù)后續(xù)可以處理任意類型的數(shù)據(jù).
const void * source
將來源地址的類型設(shè)置為無類型指針(void*)的原因與目的地的原因相同,都是便于函數(shù)可以處理任意類型的數(shù)據(jù).
而給來源的地址指針加上const的原因是防止拷貝的過程中將來源的內(nèi)容不慎修改,在*指針左側(cè)加上const就可以使const修飾的指針指向的內(nèi)容變成常量.
size_t num
?因為要拷貝的字節(jié)數(shù)恒為非負數(shù),因此字節(jié)數(shù)的類型是無符號整形(size_t).
??函數(shù)返回值:
void*
函數(shù)返回值設(shè)置為void*的原因同目的地及來源地相同,都是便于函數(shù)可以在處理完任意類型的數(shù)據(jù)后可以返回目的地的地址.
2.函數(shù)功能實現(xiàn)邏輯
在講實現(xiàn)邏輯之前,我們先分情況討論一下在拷貝數(shù)據(jù)時,我們可能遇到的幾種情況:
注:以下演示中,*src指針指向源頭起始內(nèi)存塊,*dest指針指向目標起始內(nèi)存塊.
1.情況一(兩個內(nèi)存塊不重疊)
這種情況下內(nèi)存空間的拷貝邏輯是較為簡單的,不論是數(shù)據(jù)從前向后拷貝還是從后向前拷貝,結(jié)果都是正確的.
例如這種情況:
?或是這種情況:
2.情況二(兩個內(nèi)存塊有重疊)
這種情況就比較復(fù)雜了,同樣分兩種情況,如圖:
當源頭指針在前時,只能從源頭內(nèi)存塊的后端向前端移動拷貝:
?
拷貝邏輯示意圖(序號代表拷貝次序):
當目的地指針在前時,只能從源頭內(nèi)存塊的前端向后端移動拷貝:
拷貝邏輯示意圖(序號代表拷貝次序):
分析清楚上面四種不同的情況,我們就可以在代碼的編寫中對不同情況進行分情況討論了.
當然這里的分情況是十分靈活的,你可以四種情況各分一種,也可以按拷貝模式來分,從前向后拷的算一種,從后向前拷的算另一種.
除了兩個必須按固定方式拷貝的情況之外,剩下兩種情況無論按哪種方式拷貝都行.
那么我們在這里就選擇一種最簡單也最容易理解的方式來模擬實現(xiàn)memmove()函數(shù)吧.
即如果源頭指針在前(小),從后向前拷貝;目的地指針在前(小),從前向后拷貝
數(shù)據(jù)在內(nèi)存中的存儲示意圖:
?
??代碼編寫
清楚了不同情況的拷貝邏輯后,代碼的編寫就只需要按上面說的分兩種情況就好了,以及,函數(shù)在實現(xiàn)時的其他需要注意的點我都標注在注釋中了.
綜上,my_memmove()函數(shù)的完整實現(xiàn)代碼如下:
//模擬實現(xiàn)my_memmove()函數(shù)
void* my_memmove(void* destination, const void* source, size_t num)
{
assert(destination); //防止源頭或目的地指針為NULL
assert(source);
void* ret = destination;
if (source < destination) //內(nèi)存中數(shù)據(jù)的存儲是由低地址到高地址的
{
//從后向前拷貝
while (num--) //以num為20為例,在num進入while循環(huán)之后,就立刻--,變成19了
{
*((char*)destination + num ) = *((char*)source + num );
//這時source+num剛好指向的是源頭內(nèi)存塊的最后一個字節(jié)
}
}
else
{
while (num--)
{
//從前向后拷貝
*((char*)destination) = *((char*)source);
++((char*)destination);
++((char*)source);
//這里使用后置++的話一定要給(char*)destination整體帶上括號
//否則后置++的優(yōu)先級比(char*)的強制類型轉(zhuǎn)換的優(yōu)先級高,
//導(dǎo)致指針類型還是void*時就進行++操作,這是在C標準中是不允許的
}
}
return ret;
}
??運行測試
1.測試my_memmove()函數(shù)的逆序拷貝
如下,我們使用my_memmove()函數(shù)將arr數(shù)組的1,2,3,4,5拷貝到3,4,5,6,7的位置上去:
即按照前面提到的這種情況進行拷貝:
vs2022測試運行結(jié)果:
可以看到my_memmove()函數(shù)成功的將arr數(shù)組中的1,2,3,4,5拷貝到了3,4,5,6,7的位置上.
2.測試my_memmove()函數(shù)的順序拷貝
如下,我們使用my_memmove()函數(shù)將arr數(shù)組的3,4,5,6,7拷貝到1,2,3,4,5的位置上去:
即按照前面提到的這種情況拷貝:
vs2022中測試運行結(jié)果:
可以看到my_memmove()函數(shù)成功的將arr數(shù)組中的3,4,5,6,7拷貝到了1,2,3,4,5的位置上.
結(jié)語
希望這篇memmove()函數(shù)的介紹到能對大家有所幫助,歡迎大佬們留言或私信與我交流.
最后的最后,感謝這位大佬指出了我在memcpy()函數(shù)階段模擬實現(xiàn)的不足,因為和他的交流,才促成了這篇博客的產(chǎn)生:
學(xué)海漫浩浩,我亦苦作舟!關(guān)注我,大家一起學(xué)習(xí),一起進步!
相關(guān)文章推薦
【C語言】memcpy()函數(shù)
【C語言】memset()函數(shù)
【C語言】strcpy()函數(shù)
【C語言】strlen()函數(shù)
【C語言】rand()函數(shù)(如何生成指定范圍隨機數(shù))
【實用調(diào)試技巧】總是找不到Bug?手把手教你在vs2022中調(diào)試程序
C語言內(nèi)存相關(guān)庫函數(shù)思維導(dǎo)圖:文章來源:http://www.zghlxwxcb.cn/news/detail-738446.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-738446.html
到了這里,關(guān)于【C語言】memmove()函數(shù)(拷貝重疊內(nèi)存塊函數(shù)詳解)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!