最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語(yǔ)言內(nèi)存操作函數(shù)使用示例梳理講解

 更新時(shí)間:2022年09月22日 08:29:51   作者:碳基肥宅  
這篇文章主要介紹了C語(yǔ)言庫(kù)函數(shù)中的內(nèi)存操作函數(shù)memcpy()、memmove()、memset()、memcmp()使用示例分析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

一、memcpy()

函數(shù)原型

void * memcpy ( void * dest, const void * src, size_t num );

參數(shù)說(shuō)明

  • 函數(shù) memcpy 從 src 位置開(kāi)始向后復(fù)制 num 個(gè)字節(jié)的數(shù)據(jù)到 dest 的內(nèi)存位置。
  • void * dest 代表目標(biāo)的內(nèi)存地址,const void * src 代表源內(nèi)存地址。其中二者的數(shù)據(jù)類型均為 void * 。void * 可以存儲(chǔ)任何類型地址的值。因此,該函數(shù)拷貝的內(nèi)存數(shù)據(jù)可以是任意類型(如果int、float、double等均可)。
  • size_t 即unsigned int類型。注意:num代表的是要拷貝的字節(jié)數(shù),而非元素個(gè)數(shù)!如要從src拷貝一個(gè)int類型的數(shù)據(jù)到dest,則num應(yīng)傳入4,而非1.
  • 該函數(shù)的返回值類型也為 void * ,也即只返回目標(biāo)地址的數(shù)值。后續(xù)如何按照基類型取出數(shù)據(jù)、使用數(shù)據(jù),可以由調(diào)用方在調(diào)用函數(shù)后實(shí)現(xiàn)。

模擬算法

void* my_memcpy(void* dest, const void* src, size_t num) {
    void *ret = dest;    //保存dest,用于最終輸出
    assert(dest);
    assert(src);
	while (num--) {
		*(char*)dest = *(char*)src1;    //(char*): 取出每一個(gè)字節(jié)(8 bit)的值,以單個(gè)字節(jié)為單位進(jìn)行賦值
		dest = (char*)dest + 1;    
		src = (char*)src + 1;
	}    //void * 類型是不能直接運(yùn)算的,因?yàn)闆](méi)有步長(zhǎng)。(char*)將dest與src轉(zhuǎn)換為以char為步長(zhǎng),再向后移動(dòng)
	return ret;
}
  • 該函數(shù)用于實(shí)現(xiàn)沒(méi)有重疊部分內(nèi)存的內(nèi)存數(shù)據(jù)拷貝。如果source和destination有任何的重疊,復(fù)制的結(jié)果都是未定義的。
  • 拷貝內(nèi)存值按從低地址到高地址的順序進(jìn)行,多用于數(shù)組。

根據(jù)memcpy()的模擬算法,如果src與dest的內(nèi)存空間有重疊部分,則可能導(dǎo)致src中的內(nèi)容被覆蓋,無(wú)法輸出正確的值。

src中元素3的位置恰好也是dest中首元素的位置。dest的首元素被更改的同時(shí),src中的元素也被更改。因此,memcpy()是不可用于“自己拷貝到自己后面”這樣的操作的。這一問(wèn)題留給了memmove()來(lái)解決。

使用示例

1.簡(jiǎn)單

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	memcpy(arr2, arr1, 20);    //拷貝20個(gè)字節(jié),即5個(gè)int元素
	float arr3[] = { 1.0f,2.0f,3.0f,4.0f };
	float arr4[5] = { 0.0 };
	memcpy(arr3, arr4, 8);    //拷貝8個(gè)字節(jié),即2個(gè)float元素
	return 0;
}

2.進(jìn)階

//示例來(lái)自cplusplus官網(wǎng)
/* memcpy example */
#include <stdio.h>
#include <string.h>
struct {
  char name[40];
  int age;
} person, person_copy;
int main ()
{
  char myname[] = "Pierre de Fermat";    //定義一個(gè)字符串
  /* 用 memcpy 拷貝字符串 */
  //每個(gè)char類型占一個(gè)字節(jié),因此要拷貝的字節(jié)數(shù)即strlen()+1,加一是因?yàn)橐?\0'也拷貝過(guò)去。
  memcpy ( person.name, myname, strlen(myname)+1 );
  person.age = 46;
  /* 用 memcpy 拷貝結(jié)構(gòu)體 */
  //sizeof操作符,可以直接得到結(jié)構(gòu)體變量在內(nèi)存中所占的字節(jié)數(shù)。
  memcpy ( &person_copy, &person, sizeof(person) );
  //直接完成了結(jié)構(gòu)體之間的數(shù)據(jù)拷貝:從person拷貝到person_cpy,不用手動(dòng)轉(zhuǎn)義,非常方便
  printf ("person_copy: %s, %d \n", person_copy.name, person_copy.age );
  return 0;
}

二、memmove()

函數(shù)原型

void * memmove ( void * dest, const void * src, size_t num );

參數(shù)說(shuō)明

  • 該函數(shù)的參數(shù)與返回值類型與memcpy()函數(shù)相同。該函數(shù)同樣用作 從 src 位置開(kāi)始向后復(fù)制 num 個(gè)字節(jié)數(shù)據(jù)到 dest 的內(nèi)存位置。
  • memmove()函數(shù)與memcpy()函數(shù)主要的區(qū)別在于memmove()可以進(jìn)行有內(nèi)存重疊的數(shù)據(jù)拷貝,而memcpy()絕對(duì)不能。memmove()的功能比memcpy()更加完善。
  • 可以理解為:如果memcpy()函數(shù)夠到了60分,那么memmove()函數(shù)卻能到達(dá)90分。

模擬算法

#include<stdio.h>
#include<string.h>
//模擬實(shí)現(xiàn)memmove()
void* my_memmove(void* dest, const void* src, size_t num) 
{
	void* ret = dest;	//保存結(jié)果用于輸出
	//從前向后拷貝,也可以寫(xiě)成if(dest <= src || (char*)dest >= (char*)src + num)
	if (dest <= src)
	{
		while (num--) {
			*(char*)dest = *(char*)src;    //拷貝
			dest = (char*)dest + 1;   
			src = (char*)src + 1;     //指針從前向后移動(dòng)(從低地址向高地址移動(dòng))
		}
	}
	else    //從前向后拷貝
	{
		dest = (char*)dest + num - 1;    
		src = (char*)src + num - 1;    //初始化兩指針至各自范圍的最后
		while (num--) {
			*(char*)dest = *(char*)src;    //拷貝    
			dest = (char*)dest - 1;    
			src = (char*)src - 1;    //指針從后向前移動(dòng)
		}
	}
	return ret;    //返回值為dest
}
//測(cè)試代碼///
int main() {
	int arr1[] = { 2,3,4,5,6 };
	my_memmove(arr1+2, arr1, 8);
	//預(yù)計(jì) 2 3 2 3 6
	for (int i = 0; i < 5; i++) {
		printf("%d ", arr1[i]);
	}
	printf("\n-------------------\n");
	int arr2[] = { 2,3,4,5,6 };
	memmove(arr2 + 2, arr2, 8);
	for (int i = 0; i < 5; i++) {
		printf("%d ", arr2[i]);
	}
	return 0;
}

拷貝順序的結(jié)論如圖所示。上面提到,當(dāng)有內(nèi)存重疊時(shí),拷貝的順序是有講究的。若不遵守下圖的結(jié)論, 仍將導(dǎo)致src中原來(lái)的值被覆蓋,無(wú)法輸出正確的結(jié)果。

***錯(cuò)誤的模擬算法

如下代碼是錯(cuò)誤的:

//錯(cuò)誤的代碼
void* my_memmove(void* dest, const void* src, size_t num)
{
    void * ret = dest;
    while (num--) {
	//從前向后拷貝
	    if (dest <= src)
	    {
		    *(char*)dest = *(char*)src;
		    dest = (char*)dest + 1;
	    	src = (char*)src + 1;
	    }
	    else
	    {
		    dest = (char*)dest + num - 1;    //錯(cuò)誤
		    src = (char*)src + num - 1;    //錯(cuò)誤
		    *(char*)dest = *(char*)src;
		    dest = (char*)dest - 1;
		    src = (char*)src - 1;
	    }
    return ret;
}

有一些同學(xué)可能認(rèn)為,while(num--)語(yǔ)句與if語(yǔ)句的順序可以調(diào)換。正確的代碼是先進(jìn)行情況判斷,再進(jìn)入while(num--)進(jìn)行賦值與移動(dòng)。將二者順序調(diào)換,乍一看沒(méi)有什么問(wèn)題,是先設(shè)定一共要移動(dòng)num次,再進(jìn)入判斷進(jìn)行具體的操作。但是這樣書(shū)寫(xiě)是有問(wèn)題的,因?yàn)樵赿est > src && dest < src+num時(shí),需要從后向前拷貝,這意味著dest和src的起始位置要發(fā)生變化。

上述代碼中標(biāo)記“錯(cuò)誤”的語(yǔ)句便是dest和src初始化的語(yǔ)句。如果直接將while和if的位置調(diào)換,則每一次進(jìn)入循環(huán),都要初始化一遍dest和src。如此,dest與src的功能就被打亂了。

使用示例

//示例來(lái)自cplusplus官網(wǎng)
/* memmove example */
#include <stdio.h>
#include <string.h>
int main ()
{
  char str[] = "memmove can be very useful......";
  memmove (str+20,str+15,11);    //表示將包括str+15向后11個(gè)字節(jié)的內(nèi)容移動(dòng)到str+20位置
  puts (str);
  return 0; 
}

輸出:

如下圖,將 src = str+11 位置開(kāi)始,包括該位置共向后拷貝11字節(jié)。每個(gè)char占一個(gè)字節(jié),因此拷貝了"very useful"這7個(gè)char字母至dest = str+20的位置。

三、memset()

函數(shù)原型

void * memset ( void * ptr, int value, size_t num );

參數(shù)說(shuō)明

  • 第一個(gè)參數(shù) ptr 為指針類型,表示要進(jìn)行操作的內(nèi)存的地址。如要對(duì)數(shù)組arr進(jìn)行內(nèi)存內(nèi)容設(shè)置,則該參數(shù)的值為arr。
  • 第二個(gè)參數(shù) value 為要設(shè)定的內(nèi)存的值。該值的數(shù)據(jù)類型是int型,但char值也是可以的。
  • 第三個(gè)參數(shù) num 為要設(shè)置值的內(nèi)存的字節(jié)數(shù)。注意:是字節(jié)數(shù),而不是元素的個(gè)數(shù)。如要改變兩個(gè)int類型的值,num應(yīng)為 8 ,而不是2.

使用說(shuō)明

例如,有數(shù)組arr:[ 1 2 3 4 5 ]

要將其前兩個(gè)元素值設(shè)定為0,則可使用memset函數(shù):memset(arr, 0 , 8)

輸出:[ 0 0 3 4 5 ].原理如下(以小端存儲(chǔ)的形式展現(xiàn)):

arr數(shù)組為int類型,一個(gè)int為4字節(jié)、32bit,內(nèi)存中的存儲(chǔ)如下(二進(jìn)制):

01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

memset(arr, 0, 8),將前8個(gè)字節(jié)(2個(gè)int)置為0(其實(shí)每個(gè)比特位都被置為0了,但由于其它的比特位已經(jīng)為0,故沒(méi)有標(biāo)出來(lái))

但若使用 memset(arr, 1, 8),并不是把數(shù)組前兩個(gè)元素置為 1 .因?yàn)閙emset()函數(shù)是針對(duì)內(nèi)存中每個(gè)字節(jié)的,memset(arr, 1, 8)的實(shí)際作用是將前8個(gè)字節(jié)中的內(nèi)容全部置為1.

00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 01

00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 01

03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

此時(shí),前4字節(jié)按照int類型解析出來(lái),結(jié)果為1000000010000000100000001,即16843009。

總結(jié):

  • int類型數(shù)組除了置0外,用memset置換成任何數(shù)都是錯(cuò)的。
  • memset只適用于每個(gè)元素只占1個(gè)字節(jié)的數(shù)組,比如char型數(shù)組。因?yàn)閙emset的操作單位就是每個(gè)字節(jié)。只有char類型的數(shù)組不會(huì)出現(xiàn)錯(cuò)誤。

使用示例

//示例來(lái)自cplusplus官網(wǎng)
/* memset example */
#include <stdio.h>
#include <string.h>
int main ()
{
  char str[] = "almost every programmer should know memset!";
  memset (str,'-',6);    //表示將從str開(kāi)始,包括str向后6個(gè)字節(jié)的內(nèi)存內(nèi)容置為'-'
  puts (str);
  return 0;
}

//輸出:------ every programmer should know memset!

四、memcmp()

函數(shù)原型

int memcmp ( const void * ptr1, const void * ptr2, size_t num );

參數(shù)說(shuō)明

  • 比較ptr1和ptr2指針開(kāi)始的num個(gè)字節(jié)。
  • ptr1和ptr2分別是兩個(gè)代表要比較的內(nèi)存空間(一般是數(shù)組)的指針。
  • num是要比較的字節(jié)數(shù)。(注意:不是元素個(gè)數(shù))。

使用說(shuō)明

返回值為整型,若返回值>0,則ptr1的內(nèi)存長(zhǎng)度大于ptr2;若返回值==0,則二者相等;若返回值<0,則ptr1的內(nèi)存長(zhǎng)度小于ptr2

使用示例

//示例來(lái)自cplusplus官網(wǎng)
/* memcmp example */
#include <stdio.h>
#include <string.h>
int main ()
{
  //創(chuàng)建兩個(gè)要用作比較的數(shù)組
  char buffer1[] = "DWgaOtP12df0";    
  char buffer2[] = "DWGAOTP12DF0";
  //接受比較的結(jié)果
  int n;
  //要比較的字節(jié)數(shù)為buffer1的長(zhǎng)度
  //兩字符串的比較可以用strcmp(buffer1,buffer2)函數(shù)實(shí)現(xiàn),原理大致相同。
  n = memcmp ( buffer1, buffer2, sizeof(buffer1) );
  if (n>0) printf ("'%s' is greater than '%s'.\n",buffer1,buffer2);
  else if (n<0) printf ("'%s' is less than '%s'.\n",buffer1,buffer2);
  else printf ("'%s' is the same as '%s'.\n",buffer1,buffer2);
  return 0;
}

到此這篇關(guān)于C語(yǔ)言內(nèi)存操作函數(shù)使用示例梳理講解的文章就介紹到這了,更多相關(guān)C語(yǔ)言內(nèi)存操作函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語(yǔ)言 自增自減運(yùn)算的區(qū)別詳解及實(shí)例

    C語(yǔ)言 自增自減運(yùn)算的區(qū)別詳解及實(shí)例

    這篇文章主要介紹了C語(yǔ)言中的++a和a++的區(qū)別詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • C語(yǔ)言的字符函數(shù)和字符串函數(shù)詳解

    C語(yǔ)言的字符函數(shù)和字符串函數(shù)詳解

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言的字符函數(shù)和字符串函數(shù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-03-03
  • C++驗(yàn)證LeetCode包圍區(qū)域的DFS方法

    C++驗(yàn)證LeetCode包圍區(qū)域的DFS方法

    這篇文章主要介紹了C++驗(yàn)證LeetCode包圍區(qū)域的DFS方法,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • 解析C++中派生的概念以及派生類成員的訪問(wèn)屬性

    解析C++中派生的概念以及派生類成員的訪問(wèn)屬性

    這篇文章主要介紹了解析C++中派生的概念以及派生類成員的訪問(wèn)屬性,是C++入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-09-09
  • C++ 詳細(xì)講解stack與queue的模擬實(shí)現(xiàn)

    C++ 詳細(xì)講解stack與queue的模擬實(shí)現(xiàn)

    C++ Stack(堆棧) 是一個(gè)容器類的改編,為程序員提供了堆棧的全部功能,也就是說(shuō)實(shí)現(xiàn)了一個(gè)先進(jìn)后出(FILO)的數(shù)據(jù)結(jié)構(gòu),許多程序都使用了 queue 容器。queue 容器可以用來(lái)表示超市的結(jié)賬隊(duì)列或服務(wù)器上等待執(zhí)行的數(shù)據(jù)庫(kù)事務(wù)隊(duì)列
    2022-04-04
  • 詳解C++中的isunordered函數(shù)

    詳解C++中的isunordered函數(shù)

    這篇文章主要介紹了C++中的isunordered函數(shù),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • C語(yǔ)言中的奇技淫巧

    C語(yǔ)言中的奇技淫巧

    學(xué)習(xí)C語(yǔ)言的過(guò)程中,總會(huì)遇到很多令人眼前一亮的代碼,尤其是你寫(xiě)了幾十行的代碼,別人只用了簡(jiǎn)單幾行的遞歸就實(shí)現(xiàn)的功能。下面我就總結(jié)幾個(gè)C語(yǔ)言中 比較新手向的代碼。讓你有一種woc!還能這么寫(xiě)的想法
    2018-08-08
  • C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易掃雷小游戲

    C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易掃雷小游戲

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易掃雷小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • 基于Qt實(shí)現(xiàn)Android的圖案密碼效果

    基于Qt實(shí)現(xiàn)Android的圖案密碼效果

    這篇文章主要為大家詳細(xì)介紹了如何基于Qt實(shí)現(xiàn)Android的圖案密碼效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下
    2024-12-12
  • C++ EasyX學(xué)習(xí)之鼠標(biāo)操作詳解

    C++ EasyX學(xué)習(xí)之鼠標(biāo)操作詳解

    EasyX是針對(duì)C/C++的圖形庫(kù),可以幫助使用C/C++語(yǔ)言的程序員快速上手圖形和游戲編程。本文將為大家詳細(xì)講講EasyX的鼠標(biāo)操作,需要的可以參考一下
    2022-07-07

最新評(píng)論

简阳市| 黄骅市| 海宁市| 黑河市| 航空| 鄂伦春自治旗| 南漳县| 鄄城县| 岳池县| 腾冲县| 广灵县| 沈阳市| 盐亭县| 万山特区| 广河县| 武穴市| 青州市| 五大连池市| 阜阳市| 金溪县| 连平县| 忻州市| 金昌市| 驻马店市| 平潭县| 深水埗区| 长宁区| 石首市| 石屏县| 黑河市| 建阳市| 介休市| 邻水| 湄潭县| 赞皇县| 赣榆县| 泸溪县| 招远市| 湘潭县| 吕梁市| 富源县|