柚子快報(bào)激活碼778899分享:開發(fā)語言 C語言內(nèi)存函數(shù)
柚子快報(bào)激活碼778899分享:開發(fā)語言 C語言內(nèi)存函數(shù)
1.memcpy使用和模擬實(shí)現(xiàn)
在前面我們學(xué)了字符串的拷貝函數(shù)strcpy但是我們不能只是拷貝字符串我們?nèi)绻胍截惼渌脑趺崔k呢?下面就來教學(xué)一個(gè)函數(shù)memcpy這個(gè)函數(shù)是針對內(nèi)存塊進(jìn)行拷貝。
? memcpy ? 函數(shù)是一個(gè)標(biāo)準(zhǔn)的 C 語言庫函數(shù),用于從源地址復(fù)制一定數(shù)量的字節(jié)到目標(biāo)地址。這個(gè)函數(shù)通常用于內(nèi)存操作,比如復(fù)制數(shù)組、結(jié)構(gòu)體或其他數(shù)據(jù)塊。
函數(shù)的原型是:
void * memcpy ( void * destination, const void * source, size_t num );
??destination?:指向目標(biāo)內(nèi)存區(qū)域的指針,復(fù)制的數(shù)據(jù)將被寫入這里。 ??source? :指向源內(nèi)存區(qū)域的指針,數(shù)據(jù)將從這里復(fù)制。 ??num? :要復(fù)制的字節(jié)數(shù)。 ? ??memcpy?? 函數(shù)返回一個(gè)指向目標(biāo)內(nèi)存區(qū)域的指針,即 ???destination??。
在使用這個(gè)函數(shù)的時(shí)候有注意事項(xiàng):
下面還是老樣子,如果不能理解也沒有關(guān)系我會(huì)給一串代碼,在里面進(jìn)行解釋:
#include
#include
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
memcpy(arr2, arr1, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
下面在進(jìn)行這個(gè)函數(shù)的模擬實(shí)現(xiàn):?
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
//memcpy函數(shù)拷貝結(jié)束后,會(huì)返回目標(biāo)空間的起始地址
void* my_memcpy(void* dst, const void* src, size_t num)
//實(shí)參都是int*但是這里的形參為什么是void*類型的指針?因?yàn)槲覀儾恢皇窍胍獋髡皖愋偷?,恰好void*類型的可以接受更多
{
void* ret = dst;//這里為什么要把dst的地址存起來?因?yàn)閐st在下面要進(jìn)行解引用然后不斷地+1早已經(jīng)改變原先的地址了,返回就不準(zhǔn)確
assert(dst);
assert(src);
while (num--)//我們傳入了20個(gè)字節(jié),要一個(gè)字節(jié)一個(gè)字節(jié)的進(jìn)行打印,所以我們要進(jìn)行20次循環(huán),
{
*(char*)dst = *(char*)src;//這里為什么要進(jìn)行強(qiáng)制類型轉(zhuǎn)換成char*類型的,在進(jìn)行解引用呢?
//因?yàn)関oid*類型不能解引用而且只有char*類型可以一次訪問一個(gè)字節(jié)
dst = (char*)dst + 1;
src = (char*)src + 1;
}
return(ret);//memcpy函數(shù)拷貝結(jié)束后,會(huì)返回目標(biāo)空間的起始地址
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
my_memcpy(arr2, arr1, 20);//這里給的是20個(gè)字節(jié)一個(gè)整型占4個(gè)字節(jié)所以只能復(fù)制5個(gè)數(shù)字
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
這就是函數(shù)的模擬實(shí)現(xiàn),我已經(jīng)在里面進(jìn)行詳細(xì)的講解。?
但是下面的這句話是什么意思?
下面我再給串代碼講解一下:?這就是重合的情況。
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };//如果我們想把12345拷貝放到34567中怎么進(jìn)行?
//就是這樣arr1+2但是這樣我們認(rèn)為打印出來是這樣的,下面這樣。
// 1 2 1 2 3 4 5 8 9 10
//但是結(jié)果可不是這樣的。
my_memcpy(arr1+2, arr1, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
我們可以看出來我們想的和打印出來的就是不同,但是為什么呢?聽我講解:?
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
//當(dāng)你打算把12345放大34567中的時(shí)候你先把1 2放到了3 4所在的地方,接下來會(huì)把3 4放到5 6上,但是這時(shí)3 4已經(jīng)是1 2了,所以最終還是把1 2放到5 6中,7也是這個(gè)道理。
my_memcpy(arr1+2, arr1, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
但是這里還是有個(gè)小細(xì)節(jié)的?,因?yàn)檫@是我們定義的my_memcpy函數(shù)如果使用memcpy函數(shù)是不是就不會(huì)有這種情況了?對的:
但是這串代碼是對的,還是不能說明我們memcpy這個(gè)函數(shù)就是可以拷貝重疊情況,C語言標(biāo)準(zhǔn)庫是規(guī)定不可以到但是這個(gè)函數(shù)還是做到了。并不沖突。
memcpy函數(shù)只用拷貝不重疊的情況,那重疊的情況怎么辦?這就要用到memmove函數(shù)了。
2.memmove函數(shù)的使用和模擬實(shí)現(xiàn)
還是老樣子我們來介紹一下什么是memmove函數(shù)
? memmove ? 函數(shù)是 C 語言標(biāo)準(zhǔn)庫中的一個(gè)函數(shù),用于在內(nèi)存中復(fù)制一塊數(shù)據(jù)。它與 ? memcpy ? 函數(shù)類似,但 ? memmove ? 能夠處理源和目標(biāo)內(nèi)存區(qū)域重疊的情況。當(dāng)源和目標(biāo)內(nèi)存區(qū)域重疊時(shí), memcpy ? 可能無法正確復(fù)制數(shù)據(jù),而 ? memmove ? 能夠確保數(shù)據(jù)的正確復(fù)制。
我們從這個(gè)定義中可以看出來這個(gè)函數(shù)的獨(dú)特的地方。,可以處理重疊的情況。
下面我們來說一下這個(gè)函數(shù)的原型:
void * memmove ( void * destination, const void * source, size_t num );
??dest??:指向目標(biāo)內(nèi)存區(qū)域的指針。 ??src??:指向源內(nèi)存區(qū)域的指針。 ??n??:要復(fù)制的字節(jié)數(shù)。 ??memmove?? 函數(shù)返回一個(gè)指向目標(biāo)內(nèi)存區(qū)域的指針。
原型其實(shí)是和memcopy函數(shù)大差不差的。那下面我們來看一下這個(gè)函數(shù)怎么處理重疊的情況
這里給出的還是上面的代碼:
#include
#include
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr1+2, arr1, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
就是這樣,但是光看這個(gè)函數(shù)是不會(huì)了解本質(zhì)的,我們可以進(jìn)行模擬實(shí)現(xiàn):
但是我們需要考慮一個(gè)問題我們怎么拷貝這個(gè)數(shù)字才能達(dá)到不會(huì)重疊拷貝的情況:
src 但是呢還是有一種情況我們還需要注意:如果我們想要把3 4 5 6?7拷貝到1 2 3 4 5這時(shí)候怎么辦呢? dest 重要:對于這兩種情況我們可以進(jìn)行總結(jié):如果我想拷貝的一串?dāng)?shù)字在目標(biāo)數(shù)字前(src 那接下來我們把函數(shù)模擬實(shí)現(xiàn)出來:那么這里我先給一個(gè)大體的框架: #define _CRT_SECURE_NO_WARNINGS #include #include void* my_memmove(void* dest, const void* src, size_t num) { if (dest < src) { //前—>后 } else { //后-->前 } return ret; } int main() { int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; my_memmove(arr1 + 2, arr1, 20); int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr1[i]); } return 0; } 就是這樣在接下來就開始進(jìn)行細(xì)致的講解: #define _CRT_SECURE_NO_WARNINGS #include #include void* my_memmove(void* dest, const void* src, size_t num) { assert(dest && src); void* ret = dest; if (dest < src) { //前—>后 while (num--)//從后往前拷貝的還是和之前一樣。 { *(char*)dest = *(char*)src; dest = (char*)dest + 1; src = (char*)src + 1; } } else { //后-->前 while (num--) { *((char*)dest + num) = *((char*)src + num); //這里是什么意思?因?yàn)檫@是從后往前進(jìn)行拷貝的,把dest和src強(qiáng)制類型轉(zhuǎn)換成char*類型之后是一個(gè)字節(jié) // 當(dāng)我們再加上num,就是加上19個(gè)字節(jié)最后就成為了20個(gè)字節(jié),就是要拷貝的第五個(gè)數(shù)字的最后一個(gè)字節(jié) //那這里為什么是19因?yàn)閚um在進(jìn)來的時(shí)候就 -- 了 } } return ret; } int main() { int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; my_memmove(arr1 + 2, arr1, 20); int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr1[i]); } return 0; } 總結(jié):這就是這兩個(gè)函數(shù)的區(qū)別我們可以了解一下。 柚子快報(bào)激活碼778899分享:開發(fā)語言 C語言內(nèi)存函數(shù) 好文鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。