C語言內(nèi)存函數(shù)的使用及其模擬實(shí)現(xiàn)
前言
在C語言中,我們除了會(huì)經(jīng)常用到與字符相關(guān)的函數(shù),我們還會(huì)使用到與內(nèi)存相關(guān)的庫函數(shù)。今天我們就來學(xué)習(xí)幾個(gè)常見的內(nèi)存函數(shù)吧!
memcpy
void * memcpy ( void * destination, const void * source, size_t num );
這是一個(gè)內(nèi)存復(fù)制函數(shù),該函數(shù)會(huì)從source的位置開始向后復(fù)制num個(gè)字節(jié)的數(shù)據(jù)到destination的內(nèi)存位置。
這個(gè)函數(shù)在遇到 ‘\0' 的時(shí)候并不會(huì)停下來。
用法如下:
#include <stdio.h> #include <string.h> int main() { char arr1[] = "Pierre de Fermat"; char arr2[40]; memcpy(arr2, arr1, strlen(arr1) + 1); printf("%s\n", arr2); return 0; }
上述代碼的arr2的輸出結(jié)果為arr1中的內(nèi)容。
我們要注意,在目標(biāo)空間中,要保證有足夠的空間放得下要拷貝的內(nèi)容,以免造成越界。
模擬實(shí)現(xiàn)如下:
//memcpy的模擬實(shí)現(xiàn) #include<stdio.h> #include<string.h> #include<assert.h> //不會(huì)考慮內(nèi)存重疊的情況 void* my_memcpy(void* dest, const void* source, size_t nums) { //先記錄下dest的初始位置,便于后續(xù)返回 void* ret = dest; //判斷傳入的兩個(gè)指針是否為空 assert(dest, source); //利用循環(huán)來控制拷貝字節(jié)的個(gè)數(shù) while (nums--) { //由于傳入的是void*類型的指針,所以在使用前要強(qiáng)制轉(zhuǎn)換為char* *(char*)dest = *(char*)source; dest = ((char*)dest) + 1; source = ((char*)source) + 1; } return ret; }
memcmp
int memcmp ( const void * ptr1,const void * ptr2,size_t num );
這個(gè)函數(shù)是用來比較指定字節(jié)數(shù)的內(nèi)存空間是否相同。
返回值如下:
上圖來自于這里
當(dāng)ptr1的內(nèi)容小于ptr2的內(nèi)容,就返回一個(gè)小于零的數(shù),當(dāng)ptr1的內(nèi)容大于ptr2的內(nèi)容,就返回一個(gè)大于零的數(shù),相等則返回零。
由于用法比較簡(jiǎn)單,就不進(jìn)行演示啦!
模擬實(shí)現(xiàn)如下:
#include<stdio.h> #include<string.h> #include<assert.h> int my_memcmp(const void* p1, const void* p2, size_t num) { //判斷傳入的兩個(gè)指針是否為空 assert(p1 && p2); //利用循環(huán)依次比較 int i = 0; for (i = 0; i < num; i++) { if (*((char*)p1 + i) > (*(char*)p2 + i)) { return 1; } else if(*((char*)p1 + i) < (*(char*)p2 + i)){ return -1; } } return 0; }
memmove
void * memmove ( void * destination, const void * source, size_t num );
上面我們已經(jīng)學(xué)習(xí)過memcpy 函數(shù)的使用了,但是,如果我們的源空間和目標(biāo)空間有重復(fù)的部分,那么memcpy這個(gè)函數(shù)就會(huì)出現(xiàn)錯(cuò)誤,為了避免出錯(cuò),我們就來學(xué)習(xí)一下memmove這個(gè)函數(shù)吧!
int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; memmove(arr+2, arr, 16); printf("%s\n", arr); return 0; }
上面的代碼執(zhí)行后,arr會(huì)變成{3,4,5,6,5,6,7,8,9,10}
這個(gè)函數(shù)的模擬實(shí)現(xiàn)要分情況討論
1.如果dest在source前面,那么就有可能會(huì)出現(xiàn)有一部分內(nèi)存重疊的情況,我們就需要在source中,先拷貝前面的數(shù)據(jù)在拷貝后面的數(shù)據(jù),即從前往后拷貝。
2.如果dest在source后面,兩個(gè)指針相減的數(shù)值小于要移動(dòng)的字節(jié)數(shù),那么也會(huì)有內(nèi)存重疊的情況,那么此時(shí),我們就需要先拷貝后面的數(shù)據(jù),在拷貝前面的數(shù)據(jù),即從后向前拷貝。
3.如果dest與source之間的差值大于要拷貝的字節(jié)數(shù),那么此時(shí)就屬于是兩塊不重疊的內(nèi)存之間的拷貝,此時(shí)即使是用memcpy也不會(huì)有問題。
綜上,我們可以已dest在source前后作為分界線。
如果dest在source前面,那么我們就從前往后拷貝,如果dest在source后面,那么我們就從后往前拷貝。
具體代碼實(shí)現(xiàn)如下:
#include<stdio.h> #include<string.h> #include<assert.h> void* my_memmove(void* dest, void* source, size_t num) { assert(dest && source); //記錄初始dest的位置,方便后續(xù)返回 void* ret = dest; //如果dest在source的前面,那么我們可以從前往后拷貝,防止數(shù)據(jù)被覆蓋 if (dest < source) { while (num--) { *(char*)dest = *(char*)source; dest = (char*)dest + 1; source = (char*)source + 1; } } else { while (num--) { //下面的num在第一次進(jìn)入循環(huán)的時(shí)候已經(jīng)減過1了 *((char*)dest + num)= *((char*)source + num); } } return ret; }
memset
void * memset ( void * ptr, char value, size_t num );
這個(gè)函數(shù)一般用于初始化一段內(nèi)存。
我們只需要傳入內(nèi)存空間的地址,需要初始化的字符,還有需要初始化的字節(jié)數(shù)即可。
由于這個(gè)函數(shù)的用法也比較簡(jiǎn)單,所以我們也不進(jìn)行用法演示啦!
模擬實(shí)現(xiàn)如下:
#include<stdio.h> #include<string.h> #include<assert.h> void* my_memset(void* dest, char ch, size_t num) { void* ret = dest; assert(dest); while (num--) { *(char*)dest = ch; ((char*)dest)++; } return ret; }
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
- C語言的字符串函數(shù),內(nèi)存函數(shù)筆記詳解
- c語言重要的字符串與內(nèi)存函數(shù)
- C語言詳解如何應(yīng)用模擬字符串和內(nèi)存函數(shù)
- C語言超詳細(xì)講解字符串函數(shù)和內(nèi)存函數(shù)
- C語言深入詳解四大內(nèi)存函數(shù)的使用
- C語言字符串函數(shù),字符函數(shù),內(nèi)存函數(shù)使用及模擬實(shí)現(xiàn)
- 深入了解C語言中的字符串和內(nèi)存函數(shù)
- 深度解析三個(gè)常見的C語言內(nèi)存函數(shù)
- C語言內(nèi)存函數(shù)的實(shí)現(xiàn)示例
- C語言內(nèi)存函數(shù)的具體使用
- C語言實(shí)現(xiàn)內(nèi)存函數(shù)的示例代碼
相關(guān)文章
C語言實(shí)現(xiàn)酒店預(yù)訂管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)酒店預(yù)訂管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06深入理解:Java是類型安全的語言,而C++是非類型安全的語言
本篇文章是對(duì)Java是類型安全的語言,而C++是非類型安全的語言進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06C語言超詳細(xì)講解猜數(shù)字游戲的實(shí)現(xiàn)
現(xiàn)在很多游戲都有抽獎(jiǎng)抽卡的功能,其實(shí)這個(gè)就類似于猜數(shù)字,生成一個(gè)隨機(jī)數(shù),然后你去猜,猜對(duì)了就得獎(jiǎng)。猜到一定次數(shù)就會(huì)保底。要實(shí)現(xiàn)猜數(shù)字的小游戲,首先是要讓程序生成隨機(jī)數(shù),這就要用到rand、srand和time這三個(gè)函數(shù),其次要了解時(shí)間戳2022-07-07基于Matlab LBP實(shí)現(xiàn)植物葉片識(shí)別功能
局部二值模式(LBP)是由Ojala等人于2002年提出,它被用于特征提取,而且提取的特征是圖像的紋理特征。本文將利用Matlab和LBP實(shí)現(xiàn)植物葉片識(shí)別,需要的可以參考一下2022-02-02C++ 實(shí)現(xiàn)靜態(tài)鏈表的簡(jiǎn)單實(shí)例
這篇文章主要介紹了C++ 實(shí)現(xiàn)靜態(tài)鏈表的簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-06-06C++右值引用與移動(dòng)構(gòu)造函數(shù)基礎(chǔ)與應(yīng)用詳解
左值和右值都是針對(duì)表達(dá)式,左值是指表達(dá)式結(jié)束后依然存在的持久對(duì)象,右值是指表達(dá)式結(jié)束時(shí)就不再存在的臨時(shí)對(duì)象,下面這篇文章主要給大家介紹了關(guān)于C++11右值引用和移動(dòng)語義的相關(guān)資料,需要的朋友可以參考下2023-02-02C++ Qt開發(fā)之PushButton按鈕組件的使用詳解
Qt 是一個(gè)跨平臺(tái)C++圖形界面開發(fā)庫,利用Qt可以快速開發(fā)跨平臺(tái)窗體應(yīng)用程序,本文將重點(diǎn)介紹QPushButton按鈕組件的常用方法及靈活運(yùn)用,感興趣的小伙伴可以學(xué)習(xí)一下2023-12-12