網站首頁 編程語言 正文
前言
上一篇我們介紹了memcpy和strcpy的區別,以及memcpy模擬實現,但這兩個庫函數都有一個缺點,那就是不能自己復制自己的內容
例子
這有一個數組arr,其元素分別為1、2、3、4、5、6、7、8、9、10,我們想將1、2、3、4復制到2的后面,從而將數組arr變成1、2、1、2、3、4、7、8、9、10
用memcpy嘗試
我們發現,跟我們預期的?1、2、1、2、3、4、7、8、9、10有出入。
錯誤原因
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
memcpy(arr + 2, arr, 16);
memcpy實現過程
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;
}
當我們這樣操作時,src一開始指向1,1被復制到了3的位置上,后面指向2,2被復制到4的位置上,當src指針指向原來的3時,指向的內容變成了1,又將1復制到了5的位置上,當src指向原來的4時,指向的內容變成了2,又將2復制到了6的位置上。所以就出錯了。
用memmove嘗試
我們發現目的達到了,說明memmove適用于內存發生重疊的情況。那么memmove是怎么實現的呢?
memmove的模擬實現
整段代碼
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的返回值是目標地址,形勢參數分別是(目標地址,源頭地址,需要操作的字節數)
具體實現步驟
第一種情況(dest在src后),采用由后向前復制
由上面的錯誤分析,我們知道是因為后面要被復制過去的內容被更改了,還是用上面的例子做示范,我們從1開始復制的話,1會將3覆蓋掉,進而導致想將3復制到到5的位置上時,實際上是將1復制到5的位置上。
那么我們如果從4開始復制呢?我們由后至前進行復制,將4復制到6,再將3復制到5,這樣我們就不怕3、4被1、2覆蓋掉了。
我們要想先將4復制到6,先得將src指向4,dest指向6,然后再進行交換。我們用加傳過去的字節數來實現。
*((char*)dest + count) = *((char*)src + count);
我們想將指針前移,直接count減一就行,又因為我們要重復這一行為,所以我們使用while循環來實現。
while (count--)
{
*((char*)dest + count) = *((char*)src + count);
}
第二種情況(dest在src前),采用由前向后復制
如果dest在src前,我們還能用由后至前的方法復制嗎?
例如,我們將3、4、5、6向前移動2次,也就是將1、2、3、4、5、6、7、8、9、10變成3、4、5、6、5、6、7、8、9、10
我們發現并沒有成為我們想象當中的樣子。
錯誤原因
依然是要被復制的內容在被復制之前就被更改了,這里先將6移動到4,5移動到3,想將4移動到2時,實際上復制過去的是6,以此類推...
所以我們要采用由前向后復制的方法(【C語言】字符串拷貝函數(strcpy)與內存拷貝函數的不同及內存拷貝函數(memcpy)的模擬實現一文里有)
總結
memcpy不能實現自己拷貝自己,也就是不適用于內存疊加的情況。我們用memmove便可以解決這個問題。
對于memmove的模擬實現,核心思想就是將會被覆蓋的、要被復制的內容提前使用。這里分為兩種情況,一種是被復制的內容地址在目標內容地址的前面,另一種就是被復制的內容地址在目標內容地址的后面,對于前一種情況,我們使用由后至前進行復制的方法,對于后一種情況,我們使用由前至后進行復制的方法(dest在src后就由后向前。dest在src前,就由前向后)。
原文鏈接:https://blog.csdn.net/ZHENGZJM/article/details/128471331
相關推薦
- 2022-04-21 提升Python編碼能力的3個重要概念_python
- 2022-10-21 K8s解決主機重啟后kubelet無法自動啟動問題(推薦)_云其它
- 2022-12-23 C語言中scanf的用法舉例_C 語言
- 2022-07-02 Python遠程SSH庫Paramiko詳細操作_python
- 2022-10-06 zabbix如何添加監控主機和自定義監控項_zabbix
- 2024-07-15 項目開發中使用Date和LocalDateTime處理日期
- 2024-03-03 layuiadmin新建tabs標簽頁,點擊保存,打開新的標簽頁并刷新
- 2022-10-16 Python?讀取?Word?文檔操作_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支