C語(yǔ)言內(nèi)存函數(shù)的使用及其模擬實(shí)現(xiàn)
前言
在C語(yǔ)言中,我們除了會(huì)經(jīng)常用到與字符相關(guān)的函數(shù),我們還會(huì)使用到與內(nèi)存相關(guān)的庫(kù)函數(shù)。今天我們就來(lái)學(xué)習(xí)幾個(gè)常見(jiàn)的內(nèi)存函數(shù)吧!

memcpy
void * memcpy ( void * destination, const void * source, size_t num );
這是一個(gè)內(nèi)存復(fù)制函數(shù),該函數(shù)會(huì)從source的位置開(kāi)始向后復(fù)制num個(gè)字節(jié)的數(shù)據(jù)到destination的內(nèi)存位置。
這個(gè)函數(shù)在遇到 ‘\0' 的時(shí)候并不會(huì)停下來(lái)。
用法如下:
#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)來(lái)控制拷貝字節(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ù)是用來(lái)比較指定字節(jié)數(shù)的內(nèi)存空間是否相同。
返回值如下:

上圖來(lá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í)過(guò)memcpy 函數(shù)的使用了,但是,如果我們的源空間和目標(biāo)空間有重復(fù)的部分,那么memcpy這個(gè)函數(shù)就會(huì)出現(xiàn)錯(cuò)誤,為了避免出錯(cuò),我們就來(lái)學(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ì)有問(wèn)題。
綜上,我們可以已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)減過(guò)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é)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
- C語(yǔ)言的字符串函數(shù),內(nèi)存函數(shù)筆記詳解
- c語(yǔ)言重要的字符串與內(nèi)存函數(shù)
- C語(yǔ)言詳解如何應(yīng)用模擬字符串和內(nèi)存函數(shù)
- C語(yǔ)言超詳細(xì)講解字符串函數(shù)和內(nèi)存函數(shù)
- C語(yǔ)言深入詳解四大內(nèi)存函數(shù)的使用
- C語(yǔ)言字符串函數(shù),字符函數(shù),內(nèi)存函數(shù)使用及模擬實(shí)現(xiàn)
- 深入了解C語(yǔ)言中的字符串和內(nèi)存函數(shù)
- 深度解析三個(gè)常見(jiàn)的C語(yǔ)言內(nèi)存函數(shù)
- C語(yǔ)言內(nèi)存函數(shù)的實(shí)現(xiàn)示例
- C語(yǔ)言內(nèi)存函數(shù)的具體使用
- C語(yǔ)言實(shí)現(xiàn)內(nèi)存函數(shù)的示例代碼
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)linux網(wǎng)卡連接檢測(cè)的方法
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)linux網(wǎng)卡連接檢測(cè)的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06
C++初階之list的模擬實(shí)現(xiàn)過(guò)程詳解
在C++中我們經(jīng)常使用STL,那個(gè)在那些我們常用的數(shù)據(jù)結(jié)構(gòu)vector,list的背后,又是如何實(shí)現(xiàn)的呢?這篇文章主要給大家介紹了關(guān)于C++初階之list的模擬實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2021-08-08
C++實(shí)現(xiàn)小型圖書(shū)管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)小型圖書(shū)管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
C++ STL入門(mén)教程(3) deque雙向隊(duì)列使用方法
這篇文章主要為大家詳細(xì)介紹了C++ STL入門(mén)教程第三篇,deque雙向隊(duì)列的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
簡(jiǎn)單實(shí)現(xiàn)C語(yǔ)言2048游戲
這篇文章主要為大家詳細(xì)介紹了簡(jiǎn)單實(shí)現(xiàn)C語(yǔ)言2048游戲,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05
C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單學(xué)生選課管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單學(xué)生選課管理系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-02-02
基于linux下C開(kāi)發(fā)中的幾點(diǎn)技術(shù)經(jīng)驗(yàn)總結(jié)
本篇文章是對(duì)linux下C開(kāi)發(fā)中的幾點(diǎn)技術(shù)經(jīng)驗(yàn)總結(jié)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
C++實(shí)現(xiàn)教職工信息管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)教職工信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
C++中引用的相關(guān)知識(shí)點(diǎn)小結(jié)
引用是C++一個(gè)很重要的特性,顧名思義是某一個(gè)變量或?qū)ο蟮膭e名,對(duì)引用的操作與對(duì)其所綁定的變量或?qū)ο蟮牟僮魍耆葍r(jià),這篇文章主要給大家總結(jié)介紹了C++中引用的相關(guān)知識(shí)點(diǎn),需要的朋友可以參考下2022-03-03

