C語(yǔ)言模擬實(shí)現(xiàn)memmove的示例代碼
前言
上一篇我們介紹了memcpy和strcpy的區(qū)別,以及memcpy模擬實(shí)現(xiàn),但這兩個(gè)庫(kù)函數(shù)都有一個(gè)缺點(diǎn),那就是不能自己復(fù)制自己的內(nèi)容
例子
這有一個(gè)數(shù)組arr,其元素分別為1、2、3、4、5、6、7、8、9、10,我們想將1、2、3、4復(fù)制到2的后面,從而將數(shù)組arr變成1、2、1、2、3、4、7、8、9、10
用memcpy嘗試

我們發(fā)現(xiàn),跟我們預(yù)期的 1、2、1、2、3、4、7、8、9、10有出入。
錯(cuò)誤原因
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
memcpy(arr + 2, arr, 16);memcpy實(shí)現(xiàn)過(guò)程
void* my_memcpy(void* dest, void* src, size_t count)
{
void* ret = dest;
while (count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
} 當(dāng)我們這樣操作時(shí),src一開(kāi)始指向1,1被復(fù)制到了3的位置上,后面指向2,2被復(fù)制到4的位置上,當(dāng)src指針指向原來(lái)的3時(shí),指向的內(nèi)容變成了1,又將1復(fù)制到了5的位置上,當(dāng)src指向原來(lái)的4時(shí),指向的內(nèi)容變成了2,又將2復(fù)制到了6的位置上。所以就出錯(cuò)了。
用memmove嘗試

我們發(fā)現(xiàn)目的達(dá)到了,說(shuō)明memmove適用于內(nèi)存發(fā)生重疊的情況。那么memmove是怎么實(shí)現(xiàn)的呢?
memmove的模擬實(shí)現(xiàn)
整段代碼
void* my_memmove(void* dest, void* src, size_t count)
{
void* ret = dest;
if (dest < src)
{
while (count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
while (count--)
{
*((char*)dest + count) = *((char*)src + count);
}
}
return ret;
}memmove的定義


由圖可知,memmove的返回值是目標(biāo)地址,形勢(shì)參數(shù)分別是(目標(biāo)地址,源頭地址,需要操作的字節(jié)數(shù))
具體實(shí)現(xiàn)步驟
第一種情況(dest在src后),采用由后向前復(fù)制

由上面的錯(cuò)誤分析,我們知道是因?yàn)楹竺嬉粡?fù)制過(guò)去的內(nèi)容被更改了,還是用上面的例子做示范,我們從1開(kāi)始復(fù)制的話,1會(huì)將3覆蓋掉,進(jìn)而導(dǎo)致想將3復(fù)制到到5的位置上時(shí),實(shí)際上是將1復(fù)制到5的位置上。
那么我們?nèi)绻麖?開(kāi)始復(fù)制呢?我們由后至前進(jìn)行復(fù)制,將4復(fù)制到6,再將3復(fù)制到5,這樣我們就不怕3、4被1、2覆蓋掉了。

我們要想先將4復(fù)制到6,先得將src指向4,dest指向6,然后再進(jìn)行交換。我們用加傳過(guò)去的字節(jié)數(shù)來(lái)實(shí)現(xiàn)。
*((char*)dest + count) = *((char*)src + count);

我們想將指針前移,直接count減一就行,又因?yàn)槲覀円貜?fù)這一行為,所以我們使用while循環(huán)來(lái)實(shí)現(xiàn)。
while (count--)
{
*((char*)dest + count) = *((char*)src + count);
}第二種情況(dest在src前),采用由前向后復(fù)制
如果dest在src前,我們還能用由后至前的方法復(fù)制嗎?
例如,我們將3、4、5、6向前移動(dòng)2次,也就是將1、2、3、4、5、6、7、8、9、10變成3、4、5、6、5、6、7、8、9、10

我們發(fā)現(xiàn)并沒(méi)有成為我們想象當(dāng)中的樣子。
錯(cuò)誤原因
依然是要被復(fù)制的內(nèi)容在被復(fù)制之前就被更改了,這里先將6移動(dòng)到4,5移動(dòng)到3,想將4移動(dòng)到2時(shí),實(shí)際上復(fù)制過(guò)去的是6,以此類(lèi)推...
所以我們要采用由前向后復(fù)制的方法(【C語(yǔ)言】字符串拷貝函數(shù)(strcpy)與內(nèi)存拷貝函數(shù)的不同及內(nèi)存拷貝函數(shù)(memcpy)的模擬實(shí)現(xiàn)一文里有)
總結(jié)
memcpy不能實(shí)現(xiàn)自己拷貝自己,也就是不適用于內(nèi)存疊加的情況。我們用memmove便可以解決這個(gè)問(wèn)題。
對(duì)于memmove的模擬實(shí)現(xiàn),核心思想就是將會(huì)被覆蓋的、要被復(fù)制的內(nèi)容提前使用。這里分為兩種情況,一種是被復(fù)制的內(nèi)容地址在目標(biāo)內(nèi)容地址的前面,另一種就是被復(fù)制的內(nèi)容地址在目標(biāo)內(nèi)容地址的后面,對(duì)于前一種情況,我們使用由后至前進(jìn)行復(fù)制的方法,對(duì)于后一種情況,我們使用由前至后進(jìn)行復(fù)制的方法(dest在src后就由后向前。dest在src前,就由前向后)。
到此這篇關(guān)于C語(yǔ)言模擬實(shí)現(xiàn)memmove的示例代碼的文章就介紹到這了,更多相關(guān)C語(yǔ)言 memmove內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
利用簡(jiǎn)潔的C語(yǔ)言代碼解決跳臺(tái)階問(wèn)題與約瑟夫環(huán)問(wèn)題
這篇文章主要介紹了利用簡(jiǎn)潔的C語(yǔ)言代碼解決跳臺(tái)階問(wèn)題與約瑟夫環(huán)問(wèn)題的方法,跳臺(tái)階問(wèn)題與約瑟夫環(huán)問(wèn)題是常見(jiàn)的基礎(chǔ)算法題目,需要的朋友可以參考下2016-02-02
C語(yǔ)言入門(mén)篇--學(xué)習(xí)選擇,if,switch語(yǔ)句以及代碼塊
本篇文章是基礎(chǔ)篇,適合c語(yǔ)言剛?cè)腴T(mén)的朋友,本文主要帶大家學(xué)習(xí)一下C語(yǔ)言的選擇,if,switch語(yǔ)句及代碼塊,幫助大家快速入門(mén)c語(yǔ)言的世界,更好的理解c語(yǔ)言2021-08-08
C++從文本文件讀取數(shù)據(jù)到vector中的方法
這篇文章主要給大家介紹了利用C++如何從文本文件讀取數(shù)據(jù)到vector中,文章通過(guò)實(shí)例給出示例代碼,相信會(huì)對(duì)大家的理解和學(xué)習(xí)很有幫助,有需要的朋友們下面來(lái)一起看看吧。2016-10-10
C++語(yǔ)法中的函數(shù)重載和默認(rèn)參數(shù)
這篇文章主要介紹了C++語(yǔ)法中的函數(shù)重載和默認(rèn)參數(shù),本文從語(yǔ)法角度通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03
C語(yǔ)言對(duì)結(jié)構(gòu)體數(shù)組按照某項(xiàng)規(guī)則進(jìn)行排序的實(shí)現(xiàn)過(guò)程探究
這篇文章主要介紹了C語(yǔ)言對(duì)結(jié)構(gòu)體數(shù)組按照某項(xiàng)規(guī)則進(jìn)行排序的實(shí)現(xiàn)過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2023-02-02
VSCode Linux的C++代碼格式化配置的實(shí)現(xiàn)
動(dòng)格式化代碼容易出現(xiàn)錯(cuò)誤,特別是當(dāng)代碼量較大時(shí),使用自動(dòng)格式化可以減少這種錯(cuò)誤的風(fēng)險(xiǎn),本文主要介紹了VSCode Linux的C++代碼格式化配置的實(shí)現(xiàn),感興趣的可以了解一下2023-10-10

