柚子快報激活碼778899分享:c語言 C:內(nèi)存函數(shù)
目錄
前言:
一、memcpy 函數(shù)的使用及實現(xiàn)
1、memcpy函數(shù)的介紹
?1.1 memcpy函數(shù)參數(shù)解讀
?2、memcpy函數(shù)的使用
3、memcpy函數(shù)的模擬實現(xiàn)
二、memmove函數(shù)的使用及模擬
1、memmove函數(shù)的使用
2、memmove函數(shù)的模擬實現(xiàn)
三、memset 函數(shù)的使用
1、memset函數(shù)的介紹(cplusplus)
2、memset函數(shù)的使用
2.1 memset函數(shù)對數(shù)組的應(yīng)用
2.2 memset函數(shù)對字符串的應(yīng)用
?編輯
?四、memcmp函數(shù)的使用
1、memcmp函數(shù)的介紹
2、memcmp函數(shù)的使用
前言:
上篇文章介紹了C語言字符串函數(shù),我們學(xué)會了一些對字符串的操作,比如說將字符串從一個字符數(shù)組拷貝到另一個字符數(shù)組中,我們可以通過使用strcpy函數(shù)實現(xiàn)。但是,如果我們想要拷貝一個整型數(shù)組到另一個整型數(shù)組中時,strcpy函數(shù)就失效了,那我們應(yīng)該怎么才能實現(xiàn)這個操作呢?不要著急,本篇文章將帶大家搞定這個問題。
一、memcpy函數(shù)的使用及實現(xiàn)
1、memcpy函數(shù)的介紹
cplusplus上的介紹:
作用介紹:
參數(shù)介紹:
返回值介紹:
?1.1 memcpy函數(shù)參數(shù)解讀
(1)void* destination
該參數(shù)的作用是目標(biāo)空間,用來存放將要拷貝的內(nèi)存,為什么返回值是 void* 呢?這是因為這個函數(shù)的作用是內(nèi)存拷貝,既然是內(nèi)存拷貝,內(nèi)存中又可能存放的是整型數(shù)組,也有可能存放的是字符數(shù)組……,因此我們不關(guān)心存放數(shù)據(jù)的類型,因此使用void*指針來接收任意類型的數(shù)據(jù)的地址。
(2)const void* source
source是源頭,也就是要拷貝的內(nèi)存數(shù)據(jù),這里也是void*指針是因為我們不知道我們未來要拷貝的數(shù)據(jù)是什么類型的,可能是整型,可能是字符,也可能是結(jié)構(gòu)體,因此我們也使用void*。
用const修飾是因為我們不希望要拷貝的數(shù)據(jù)被修改,因此使用const修飾會使得整個工程更加穩(wěn)定。
(3)size_t num
num的作用是限定拷貝的字節(jié)數(shù),比如說source中有十個字節(jié)的數(shù)據(jù),我們可以通過修改num的值來拷貝我們想要的個數(shù),num為5,我們就拷貝五個字節(jié)的數(shù)據(jù)到destination中;num的類型是size_t的原因是我們拷貝的個數(shù)最低都是0個,不會出現(xiàn)負數(shù)的情況,因此使用size_t類型最為合適。
?2、memcpy函數(shù)的使用
前面學(xué)習(xí)了memcpy函數(shù),接下來我們將使用memcpy函數(shù)來實現(xiàn)一些操作
比如說我們打算將整型數(shù)組arr1[ ] = {1,2,3,4,5,6,7,8,9,10}拷貝到整型數(shù)組 arr2[10] = { 0 };
#include
int main()
{
?? ?int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
?? ?int arr2[10] = { 0 };
?? ?memcpy(arr2, arr1, 5 * sizeof(int));
?? ?return 0;
}
調(diào)試結(jié)果:
源頭從 3 開始拷貝,比如說:
#include
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
memcpy(arr2, arr1+2, 5 * sizeof(int));
return 0;
}
?一些總結(jié):
函數(shù)memcpy從source的位置開始向后賦值num個字節(jié)的數(shù)據(jù)到destination指向的內(nèi)容;這個函數(shù)在遇到\0的時候并不會停下來,與字符串函數(shù)不同;如果source和destination有任何的重疊,賦值的結(jié)果都是未定義的。
3、memcpy函數(shù)的模擬實現(xiàn)
接下來我們嘗試自己寫一個函數(shù)來實現(xiàn)memcpy的功能
void* my_memcpy(void* dest, const void* src, size_t num)
{
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
my_memcpy(arr2, arr1, 5 * sizeof(int));
return 0;
}
注意:在my_memcpy中,源頭是void*指針類型的??
現(xiàn)在有一個問題,我們不知道我們要拷貝的是內(nèi)容是什么類型的,我們只知道要拷貝的是20個字節(jié),我們該怎么將這20個字節(jié)拿到arr2中呢?
在前面學(xué)習(xí)qsort函數(shù)的模擬實現(xiàn)中,我們用到了一個方法,我們可以一個字節(jié)一個字節(jié)的拷貝,那么就可以使用強制類型轉(zhuǎn)換將void*指針轉(zhuǎn)換為char*指針
void* my_memcpy(void* dest, const void* src, size_t num)
{
while (num--)//num是字節(jié)總數(shù),因此num每減1,就拷貝一個字節(jié)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
調(diào)試結(jié)果:?
總代碼:
#include
void* my_memcpy(void* dest, const void* src, size_t num)
{
// 保存目標(biāo)地址,以便最后返回
void* ret = dest;
// 循環(huán) num 次進行逐個字節(jié)的復(fù)制
while (num--)
{
// 將源地址指向的內(nèi)容復(fù)制到目標(biāo)地址指向的位置,并轉(zhuǎn)換為 char* 類型進行操作,確保每次只復(fù)制一個字節(jié)
*(char*)dest = *(char*)src;
// 目標(biāo)地址向后移動一個字節(jié)
dest = (char*)dest + 1;
// 源地址向后移動一個字節(jié)
src = (char*)src + 1;
}
// 返回復(fù)制后的目標(biāo)地址
return ret;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
my_memcpy(arr2, arr1, 5 * sizeof(int));
return 0;
}
如果我們向?qū)nt arr1[] = { 1,2,3,4,5,6,7,8,9,10 };中(1,2,3,4,5)拷貝放到(3,4,5,6,7)的位置上,這樣可以實現(xiàn)嗎?
my_memcpy(arr1+2, arr1, 5 * sizeof(int));
調(diào)試結(jié)果:
為什么這里會是(1,2,1,2,1)呢?其實也很好理解
?因此最終結(jié)果是(1,2,1,2,1,2,1,8,9,10)?
關(guān)于重疊問題,我們一般使用后面的這個函數(shù)memmove函數(shù)
而memcpy函數(shù)一般用來處理不重疊情況。
在vs2022中,memcpy的能力是比較強的,也是可以用來處理重疊問題,但是對于memcpy函數(shù),本來的作用是不包括處理重疊的問題的,這就像是老師說讓你考到60分就行,但是你能考100分。但是不能保證在所有的編譯器上memcpy都可以考到100分
也就是說無法確定其它編程環(huán)境是否可以實現(xiàn),因此,如果要處理重疊問題,最好還是交給memmove函數(shù).
二、memmove函數(shù)的使用及模擬
1、memmove函數(shù)的使用
memove函數(shù)的使用與memcpy函數(shù)是一樣的,也是用來實現(xiàn)內(nèi)存中數(shù)據(jù)的拷貝的,因此就不詳細介紹了。不過前面也說了memmove函數(shù)可以實現(xiàn)重疊拷貝,來測試一下
#include
#include
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr1+2, arr1, 5 * sizeof(int));
return 0;
}
調(diào)試結(jié)果:?可以看到的確將(1,2,3,4,5)的內(nèi)容拷貝到(3,4,5,6,7)的位置上了
那么memmove函數(shù)究竟是怎么實現(xiàn)這個操作的呢?我們來模擬了解一下
2、memmove函數(shù)的模擬實現(xiàn)
前面我們知道,如果拷貝1,會把3給覆蓋,拷貝2,會把4給覆蓋。
該怎么拷貝才能實現(xiàn)不被覆蓋呢?
可以從后向前拷貝,先拷貝5,覆蓋7,在拷貝4覆蓋6,這時候在拷貝3覆蓋5,拷貝2覆蓋4,拷貝1覆蓋3,由于3,4,5已經(jīng)拷貝完成,不會出現(xiàn)還沒有拷貝就被覆蓋的情況。
那是不是從后向前拷貝就一定正確呢?
我們在換一種情況試試:
這時候如果還是從后向前拷貝的話會出現(xiàn)什么問題呢?
8拷貝到6,7拷貝到5,這時候向拷貝6的時候已經(jīng)變成了8,因此從后向前失效了。
這時候我們在從前向后拷貝,3拷貝到1,4拷貝到2……恰好可以全部拷貝。
不知道大家有沒有發(fā)現(xiàn)一個規(guī)律:
如果dest在src的后面,則從后向前拷貝;
如果dest在src的前面,則從前向后拷貝;
如果沒有重疊,則隨意。
如果是 后->前,該怎么拷貝呢?
比如說先拷貝5,我們只需要在起始位置跳過num個字節(jié)即可
比如說:*((char*)src + num)
代碼實現(xiàn):
#include
#include
void* my_memmove(void* dest, const void* src, size_t num)
{
void* ret = dest;
if (dest < src)
{
//前->后
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
while (num--)
{
//后->前
//num進來減1,變?yōu)?9,src加上19后跳到最后一位上,也就是5,dest加上19跳到8的位置,然后將5賦值到8的位置
*((char*)dest + num) = *((char*)src + num);
}
}
return ret;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr+2, arr, 5 * sizeof(int));
return 0;
}
三、memset函數(shù)的使用
1、memset函數(shù)的介紹(cplusplus)
參數(shù)介紹:注意:
memset是以字節(jié)為單位來設(shè)置內(nèi)存的 ,而不是以一個元素為單位設(shè)置的。
?作用介紹:
返回值介紹:
2、memset函數(shù)的使用
2.1 memset函數(shù)對數(shù)組的應(yīng)用
那么memset函數(shù)究竟有什么作用呢?
比如說:
#include
int main()
{
int arr[10] = { 0 };
int i = 0;
for (i = 0; i < 10; i++)
{
arr[i] = i + 1;
}
return 0;
}
我們想將arr數(shù)組全部初始化為0,我們該怎么做呢?
你可能會說這不簡單?直接使用循環(huán)不就可以了嗎?
for (i = 0; i < 10; i++)
{
arr[i] = 0;
}
這樣的確可以,不過我們也可以使用庫函數(shù)memset函數(shù)來實現(xiàn)這個操作。
我們要設(shè)置的這個空間整型數(shù)組arr[10]的地址交給ptr,而數(shù)組的地址就是數(shù)組名arr,我們需要將該數(shù)組的元素都變?yōu)?,也就是要設(shè)置的值value為0,由于是整型數(shù)組,有十個元素,所以num就等于40字節(jié)。
代碼展示:
#include
#include
int main()
{
int arr[10] = { 0 };
int i = 0;
for (i = 0; i < 10; i++)
{
arr[i] = i + 1;
}
/*for (i = 0; i < 10; i++)
{
arr[i] = 0;
}*/
memset(arr, 0, 10 * sizeof(int));
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
調(diào)試過程:
結(jié)果展示:
?如果memset(arr, 1, 10 * sizeof(int));這是否是將每一個元素都改為1了呢?
調(diào)試監(jiān)控窗口
為什么沒有達到想要的結(jié)果呢?
我們在來看一下內(nèi)存窗口:
破案了,memset函數(shù)將每一個字節(jié)都設(shè)置為1,而不是把一個元素設(shè)置為1。
前面強調(diào)了memset是以字節(jié)為單位來設(shè)置內(nèi)存的 ,而不是以一個元素為單位設(shè)置的。
2.2 memset函數(shù)對字符串的應(yīng)用
代碼:
#include
#include
int main()
{
char arr[] = "hello world";
//如何將helo改為五個x
memset(arr, 'x', 5);
return 0;
}
調(diào)試結(jié)果:
如果我們想修改world呢?
memset(arr+6, 'x', 5);
從前向后數(shù)hello五個字符,還有一個空格,共6個字符。
注意:這個函數(shù)比較常見,因此需要熟練掌握!?。?
?四、memcmp函數(shù)的使用
memcmp函數(shù)與之前學(xué)習(xí)的strcmp函數(shù)的功能是比較相似的,不過strcmp函數(shù)只能用來做字符串的比較,而memcmp函數(shù)是用來做內(nèi)存塊的比較,不論是什么類型。
1、memcmp函數(shù)的介紹
參數(shù)介紹:?
返回值介紹:
2、memcmp函數(shù)的使用
直接上例題,比較arr1與arr2中前3個元素
#include
#include
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[] = { 1,2,3,3 };
int ret = memcmp(arr1, arr2, 12);
printf("%d\n", ret);
return 0;
}
結(jié)果:
如果我們比較前4個元素呢?
int ret = memcmp(arr1, arr2, 16);、
這里返回的就是1了。
結(jié)語:本篇文章到這里就結(jié)束啦!期待下次的相遇??!
柚子快報激活碼778899分享:c語言 C:內(nèi)存函數(shù)
好文鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。