C語(yǔ)言全部?jī)?nèi)存操作函數(shù)的實(shí)現(xiàn)詳細(xì)講解
memcpy內(nèi)存拷貝函數(shù)
void* memcpy(void* destination, const void* source, size_t num);
- memcpy函數(shù)從source的位置開(kāi)始向后拷貝num個(gè)字節(jié)的數(shù)據(jù)到destination的內(nèi)存位置
- 這個(gè)函數(shù)在遇到
\0
的時(shí)候并不會(huì)停下來(lái) - 如果source和destination有任何的重疊,復(fù)制的結(jié)果都是未定義的
使用方法:
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> int main() { char arr1[20] = { 0 }; char arr2[] = "hello world!"; int arr3[10] = { 0 }; int arr4[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int i = 0; memcpy(arr1, arr2, 12); memcpy(arr3, arr4, 16); printf("%s\n", arr1); for (i = 0; i < 10; i++) { printf("%d ", arr3[i]); } return 0; }
輸出結(jié)果:
如果源頭和目的地是同一塊內(nèi)存它進(jìn)行拷貝的時(shí)候會(huì)出現(xiàn)覆蓋的情況。
如:
#include <stdio.h> #include <string.h> int main() { int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int i = 0; memcpy(arr + 2, arr, 16); for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } return 0; }
可以看到它并沒(méi)有如我們預(yù)期的輸出來(lái)輸出結(jié)果,我們預(yù)期的結(jié)果應(yīng)該是:1 2 1 2 3 4 7 8 9 10
可是memcpy拷貝的時(shí)候會(huì)覆蓋,而C語(yǔ)言對(duì)memcpy的標(biāo)準(zhǔn)是只要能實(shí)現(xiàn)拷貝即可,不考慮同一塊內(nèi)存拷貝會(huì)覆蓋的情況,這種情況是由另一個(gè)函數(shù)來(lái)處理。
當(dāng)然有些編譯器對(duì)memcpy函數(shù)的實(shí)現(xiàn)是有優(yōu)化過(guò)的,目前我個(gè)人知道的編譯器是VS它是對(duì)memcpy有優(yōu)化的,如果拷貝的是同一塊內(nèi)存它不會(huì)覆蓋,而是如預(yù)期的那樣進(jìn)行拷貝。
memcpy函數(shù)的實(shí)現(xiàn)
#include <assert.h> void* my_memcpy(void* dest, const void* src, unsigned int count) { assert(dest && src);//斷言 void* temp = dest;//temp保存dest的起始地址 while (count--) { *(char*)dest = *(char*)src;//復(fù)制src的內(nèi)容到dest ++(char*)dest;//下一個(gè)字節(jié)的拷貝 ++(char*)src; } return temp;//返回dest起始地址 }
void* my_memcpy(void* dest, const void* src, unsigned int count);
參數(shù)一:void* dest
- dest設(shè)置成空類型,因?yàn)榭疹愋涂梢越邮杖魏未笮〉臄?shù)據(jù),但是有一個(gè)缺陷它不能自增或者自減,也不能直接解引用因給它空類型是一個(gè)沒(méi)有具體類型,它不知道它能訪問(wèn)多少個(gè)字節(jié),所以使用空類型的時(shí)候我們需要強(qiáng)制類型轉(zhuǎn)換。
- dest是緩沖區(qū)
參數(shù)二:void* src
- 它的類型和dest一樣不過(guò),它和參數(shù)一不同的是它被const保護(hù)起來(lái)了,因?yàn)樗皇潜粡?fù)制也就是說(shuō)我們只是訪問(wèn)它里面的內(nèi)容并不需要修改它,所以我們就加一個(gè)const把它保護(hù)起來(lái),防止我們不小心對(duì)它進(jìn)行修改
參數(shù)三:unsigned int counst
- counst是我們要修改多少字節(jié)的參數(shù),修改是以字節(jié)為單位的,它的類型是unsigned int (無(wú)符號(hào)整整形)也就是說(shuō)不能出現(xiàn)負(fù)數(shù)
返回類型:void*
- 返回dest的首地址
assert(dest && src)
這個(gè)是用來(lái)保證代碼的健壯性,assert()
函數(shù)是斷言,如果傳過(guò)來(lái)的是空指針,那么就是假因?yàn)镹ULL的值是0,只有兩邊都為真才不會(huì)有提示。
*(char*)dest = *(char*)src
因?yàn)槭?code>void* 類型所以我們要強(qiáng)制轉(zhuǎn)換才能解引用進(jìn)行拷貝操作,而我們要操作的是一個(gè)字節(jié)所以轉(zhuǎn)為字符型指針最合適。
++(char*)dest;
和上面的同理,要強(qiáng)制類型轉(zhuǎn)換才能進(jìn)行++和–操作。
memmvoe函數(shù)
void* memmove(void* destination, const void* source, size_t num);
- 和memcpy的差別就是memmove函數(shù)處理的源內(nèi)存塊和目標(biāo)內(nèi)存塊是可以重疊的。
- 如果源空間和目標(biāo)空間出現(xiàn)重疊,就得使用memmove函數(shù)處理
使用方法:
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> #include <assert.h> int main() { int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int i = 0; memmove(arr + 2, arr, 16); for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } return 0; }
memmove
和memcpy
的使用方法一樣,沒(méi)什么大區(qū)別。
memmove函數(shù)的實(shí)現(xiàn)
#include <assert.h> void* my_memmove(void* dest, const void* src, unsigned int count) { assert(dest && src);//斷言 void* temp = dest; if (dest < src)//小于src從前向后 { while (count--) { *(char*)dest = *(char*)src; ++(char*)dest; ++(char*)src; } } else//大于從后向前 { while (count--) { *((char*)dest + count) = *((char*)src + count); } } return temp; }
為了處理同塊內(nèi)存的拷貝,這里我們分為了兩種方法。
- 從前向后拷貝
- 從后向后拷貝
memcpy用的是從前向后拷貝,所以會(huì)出現(xiàn)被覆蓋的情況。
那么問(wèn)題來(lái)了,我們什么情況才從前向后拷貝和從后向前拷貝呢?
我們可以以src為分界線,如果dest小于src我們就從前向后,這樣就避免了src的內(nèi)容被覆蓋之后被拷貝到dest里面去,如果dest大于src,我們就從后向前。
那有人問(wèn)如果等于呢?等于的話你從前向后還是從后向前不都一樣?
所以按照這個(gè)思路我們寫成兩個(gè)拷貝順序,從后向前我們不用思考了,想在我們只需要思考從后向前拷貝。
while (count--) { *((char*)dest + count) = *((char*)src + count); }
從后向前我們只需要先得到dest和src末尾的地址就能進(jìn)行從后向前操作了,count + dest
不就得到了末尾了嗎?counst + dest
得到末尾的\0
的地址,但是我們不需要修改\0
所以count + dest
之前我們對(duì)count
自減。
后面就不需要dest自減的操作了,因?yàn)?code>count每次減一我們就得到前面一個(gè)的地址,當(dāng)count
減完了,我們也拷貝完了。
memcmp內(nèi)存塊比較函數(shù)
int memcmp(const void* ptr1, const void* ptr2, size_t num);
- 比較從ptr1和ptr2指針開(kāi)始的num個(gè)字節(jié)
- 返回值,當(dāng)ptr1大于ptr2就返回大于1的值,當(dāng)ptr1小于ptr2就返回小于0的值,當(dāng)?shù)扔诘臅r(shí)候返回0
使用案列:
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> #include <assert.h> int main() { char arr1[] = "abcz"; char arr2[] = "abcd"; if ( 0 < memcmp(arr1, arr2, 4)) { printf("大于\n"); } else if(0 > memcmp(arr1, arr2, 4)) { printf("小于\n"); } else { printf("等于\n"); } return 0; }
memcpy函數(shù)的實(shí)現(xiàn)
#include <assert.h> int my_memcmp(void* dest, const void* src, unsigned int count) { assert(dest && src);//斷言 if (!count) { return 0; } while (--count && *(char*)dest == *(char*)src) { ++(char*)dest; ++(char*)src; } return *(char*)dest - *(char*)src; }
if (!count) { return 0; }
如果count
是0的話就直接返回0
while (count-- && *(char*)dest == *(char*)src) { ++(char*)dest; ++(char*)src; }
當(dāng)count
個(gè)數(shù)比較完或者dest不等于src,我們就停止循環(huán)。
return *(char*)dest - *(char*)src;
直接返回dest - src,如果它們兩相等一定返回0,dest小于src返回的是小于0的值,大于則返回大于0的值。
memset修改內(nèi)存塊
void *memset( void *dest, int c, size_t count )
- dest是目的
- 地第二個(gè)修改成什么?
- 第三個(gè)修改內(nèi)存的個(gè)數(shù)
memset是以1字節(jié)為單位來(lái)修改,第二個(gè)參數(shù)是要修改成什么字符,第三個(gè)參數(shù)是修改內(nèi)存?zhèn)€數(shù)以1字節(jié)為單位
使用案列:
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> int main() { char arr[10] = { 0 }; int i = 0; memset(arr, '6', 10); for (i = 0; i < 10; i++) { printf("arr[%d]=%c\n", i, arr[i]); } return 0; }
memset函數(shù)實(shí)現(xiàn)
#include <assert.h> void* my_memset(void* dest, int a, unsigned int count) { assert(dest);//斷言 void* temp = dest;//記錄dest的首地址 while (count--) { *(char*)dest = a; ++(char*)dest; } return temp;//返回dest的首地址 }
while (count--) { *(char*)dest = a; ++(char*)dest; }
把a(bǔ)的值給dest,來(lái)進(jìn)行修改,每次修改一個(gè)字節(jié)就自增一修改下個(gè)字節(jié)。
到此這篇關(guān)于C語(yǔ)言全部?jī)?nèi)存操作函數(shù)的實(shí)現(xiàn)詳細(xì)講解的文章就介紹到這了,更多相關(guān)C語(yǔ)言內(nèi)存操作函數(shù)的實(shí)現(xiàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C語(yǔ)言深入講解動(dòng)態(tài)內(nèi)存分配函數(shù)的使用
- c語(yǔ)言詳解動(dòng)態(tài)內(nèi)存分配及常見(jiàn)錯(cuò)誤的解決
- C語(yǔ)言深入探索動(dòng)態(tài)內(nèi)存分配的使用
- C語(yǔ)言的動(dòng)態(tài)內(nèi)存分配及動(dòng)態(tài)內(nèi)存分配函數(shù)詳解
- C語(yǔ)言編程動(dòng)態(tài)內(nèi)存分配常見(jiàn)錯(cuò)誤全面分析
- C語(yǔ)言內(nèi)存操作函數(shù)使用示例梳理講解
- C語(yǔ)言內(nèi)存操作函數(shù)詳解
- C語(yǔ)言動(dòng)態(tài)內(nèi)存分配和內(nèi)存操作函數(shù)使用詳解
相關(guān)文章
VC創(chuàng)建DLL動(dòng)態(tài)鏈接庫(kù)的方法
這篇文章主要介紹了VC創(chuàng)建DLL動(dòng)態(tài)鏈接庫(kù)的方法,實(shí)例分析VC創(chuàng)建動(dòng)態(tài)鏈接庫(kù)的完整步驟,需要的朋友可以參考下2015-05-05C語(yǔ)言超詳細(xì)講解結(jié)構(gòu)體與聯(lián)合體的使用
結(jié)構(gòu)體和聯(lián)合體用于描述事物的屬性,如一只鳥的信息,可能包括它的品種,體重,顏色,年齡等,接下來(lái)大家一起來(lái)詳細(xì)看看吧2022-05-05新手向超詳細(xì)的C語(yǔ)言實(shí)現(xiàn)動(dòng)態(tài)順序表
本文主要介紹了C語(yǔ)言實(shí)現(xiàn)動(dòng)態(tài)順序表,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09C++插件化 NDD源碼的插件機(jī)制實(shí)現(xiàn)解析
這篇文章主要介紹了C++插件化 NDD源碼的插件機(jī)制實(shí)現(xiàn)解析,這里再介紹推薦下優(yōu)秀的國(guó)產(chǎn)軟件開(kāi)源項(xiàng)目?NDD(notepad--),一個(gè)支持windows/linux/mac的文本編輯器,目標(biāo)是要國(guó)產(chǎn)替換同類軟件,需要的朋友可以參考下2023-03-03C++中的三種繼承public,protected,private詳細(xì)解析
我們已經(jīng)知道,在基類以private方式被繼承時(shí),其public和protected成員在子類中變?yōu)閜rivate成員。然而某些情況下,需要在子類中將一個(gè)或多個(gè)繼承的成員恢復(fù)其在基類中的訪問(wèn)權(quán)限2013-09-09C++實(shí)現(xiàn)LeetCode(48.旋轉(zhuǎn)圖像)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(48.旋轉(zhuǎn)圖像),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07Qt+OpenCV實(shí)現(xiàn)目標(biāo)檢測(cè)詳解
這篇文章主要介紹了如何利用Qt和OpenCV中自帶xml文件實(shí)現(xiàn)目標(biāo)檢測(cè),文中的實(shí)現(xiàn)過(guò)程講解詳細(xì),感興趣的小伙伴可以動(dòng)手試一試2022-03-03