欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語(yǔ)言全部?jī)?nèi)存操作函數(shù)的實(shí)現(xiàn)詳細(xì)講解

 更新時(shí)間:2021年02月26日 11:10:02   作者:貧僧愛(ài)用飄柔  
這篇文章主要介紹了C語(yǔ)言全部?jī)?nèi)存操作函數(shù)的實(shí)現(xiàn)詳細(xì)講解,作者用圖文代碼實(shí)例講解的很清晰,有感興趣的同學(xué)可以研究下

memcpy內(nèi)存拷貝函數(shù)

void* memcpy(void* destination, const void* source, size_t num);
  • memcpy函數(shù)從source的位置開(kāi)始向后拷貝num個(gè)字節(jié)的數(shù)據(jù)到destination的內(nèi)存位置
  • 這個(gè)函數(shù)在遇到\0的時(shí)候并不會(huì)停下來(lái)
  • 如果source和destination有任何的重疊,復(fù)制的結(jié)果都是未定義的

使用方法:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>

int main()
{
	char arr1[20] = { 0 };
	char arr2[] = "hello world!";
	int arr3[10] = { 0 };
	int arr4[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int i = 0;

	memcpy(arr1, arr2, 12);
	memcpy(arr3, arr4, 16);
	printf("%s\n", arr1);

	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr3[i]);
	}

	return 0;
}

輸出結(jié)果:


image-20210224094511895

如果源頭和目的地是同一塊內(nèi)存它進(jìn)行拷貝的時(shí)候會(huì)出現(xiàn)覆蓋的情況。

如:

#include <stdio.h>
#include <string.h>

int main()
{
 int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
 int i = 0;
 
 memcpy(arr + 2, arr, 16);
 
 for (i = 0; i < 10; i++)
 {
 printf("%d ", arr[i]);
 }
 
 return 0;
}

image-20210224095909038

可以看到它并沒(méi)有如我們預(yù)期的輸出來(lái)輸出結(jié)果,我們預(yù)期的結(jié)果應(yīng)該是:1 2 1 2 3 4 7 8 9 10

可是memcpy拷貝的時(shí)候會(huì)覆蓋,而C語(yǔ)言對(duì)memcpy的標(biāo)準(zhǔn)是只要能實(shí)現(xiàn)拷貝即可,不考慮同一塊內(nèi)存拷貝會(huì)覆蓋的情況,這種情況是由另一個(gè)函數(shù)來(lái)處理。

當(dāng)然有些編譯器對(duì)memcpy函數(shù)的實(shí)現(xiàn)是有優(yōu)化過(guò)的,目前我個(gè)人知道的編譯器是VS它是對(duì)memcpy有優(yōu)化的,如果拷貝的是同一塊內(nèi)存它不會(huì)覆蓋,而是如預(yù)期的那樣進(jìn)行拷貝。

memcpy函數(shù)的實(shí)現(xiàn)

#include <assert.h>

void* my_memcpy(void* dest, const void* src, unsigned int count)
{
	assert(dest && src);//斷言
	void* temp = dest;//temp保存dest的起始地址

	while (count--)
	{
		*(char*)dest = *(char*)src;//復(fù)制src的內(nèi)容到dest
		++(char*)dest;//下一個(gè)字節(jié)的拷貝
		++(char*)src;
	}

	return temp;//返回dest起始地址
}

void* my_memcpy(void* dest, const void* src, unsigned int count);

參數(shù)一:void* dest

  • dest設(shè)置成空類型,因?yàn)榭疹愋涂梢越邮杖魏未笮〉臄?shù)據(jù),但是有一個(gè)缺陷它不能自增或者自減,也不能直接解引用因給它空類型是一個(gè)沒(méi)有具體類型,它不知道它能訪問(wèn)多少個(gè)字節(jié),所以使用空類型的時(shí)候我們需要強(qiáng)制類型轉(zhuǎn)換。
  • dest是緩沖區(qū)

參數(shù)二:void* src

  • 它的類型和dest一樣不過(guò),它和參數(shù)一不同的是它被const保護(hù)起來(lái)了,因?yàn)樗皇潜粡?fù)制也就是說(shuō)我們只是訪問(wèn)它里面的內(nèi)容并不需要修改它,所以我們就加一個(gè)const把它保護(hù)起來(lái),防止我們不小心對(duì)它進(jìn)行修改

參數(shù)三:unsigned int counst

  • counst是我們要修改多少字節(jié)的參數(shù),修改是以字節(jié)為單位的,它的類型是unsigned int (無(wú)符號(hào)整整形)也就是說(shuō)不能出現(xiàn)負(fù)數(shù)

返回類型:void*

  • 返回dest的首地址

assert(dest && src)這個(gè)是用來(lái)保證代碼的健壯性,assert()函數(shù)是斷言,如果傳過(guò)來(lái)的是空指針,那么就是假因?yàn)镹ULL的值是0,只有兩邊都為真才不會(huì)有提示。

*(char*)dest = *(char*)src因?yàn)槭?code>void* 類型所以我們要強(qiáng)制轉(zhuǎn)換才能解引用進(jìn)行拷貝操作,而我們要操作的是一個(gè)字節(jié)所以轉(zhuǎn)為字符型指針最合適。

++(char*)dest;和上面的同理,要強(qiáng)制類型轉(zhuǎn)換才能進(jìn)行++和–操作。


memmvoe函數(shù)

void* memmove(void* destination, const void* source, size_t num);
  • 和memcpy的差別就是memmove函數(shù)處理的源內(nèi)存塊和目標(biāo)內(nèi)存塊是可以重疊的。
  • 如果源空間和目標(biāo)空間出現(xiàn)重疊,就得使用memmove函數(shù)處理

使用方法:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <assert.h>

int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int i = 0;

	memmove(arr + 2, arr, 16);

	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}

memmovememcpy的使用方法一樣,沒(méi)什么大區(qū)別。

memmove函數(shù)的實(shí)現(xiàn)

#include <assert.h>

void* my_memmove(void* dest, const void* src, unsigned int count)
{
	assert(dest && src);//斷言
	void* temp = dest;

	if (dest < src)//小于src從前向后
	{
		while (count--)
		{
			*(char*)dest = *(char*)src;
			++(char*)dest;
			++(char*)src;
		}
	}
	else//大于從后向前
	{
		while (count--)
		{
			*((char*)dest + count) = *((char*)src + count);
		}
	}

	return temp;
}

為了處理同塊內(nèi)存的拷貝,這里我們分為了兩種方法。

  1. 從前向后拷貝
  2. 從后向后拷貝

memcpy用的是從前向后拷貝,所以會(huì)出現(xiàn)被覆蓋的情況。

那么問(wèn)題來(lái)了,我們什么情況才從前向后拷貝和從后向前拷貝呢?

image-20210224105035626

我們可以以src為分界線,如果dest小于src我們就從前向后,這樣就避免了src的內(nèi)容被覆蓋之后被拷貝到dest里面去,如果dest大于src,我們就從后向前。

那有人問(wèn)如果等于呢?等于的話你從前向后還是從后向前不都一樣?

所以按照這個(gè)思路我們寫成兩個(gè)拷貝順序,從后向前我們不用思考了,想在我們只需要思考從后向前拷貝。

	while (count--)
		{
			*((char*)dest + count) = *((char*)src + count);
		}

從后向前我們只需要先得到dest和src末尾的地址就能進(jìn)行從后向前操作了,count + dest不就得到了末尾了嗎?counst + dest得到末尾的\0的地址,但是我們不需要修改\0所以count + dest之前我們對(duì)count自減。

后面就不需要dest自減的操作了,因?yàn)?code>count每次減一我們就得到前面一個(gè)的地址,當(dāng)count減完了,我們也拷貝完了。

memcmp內(nèi)存塊比較函數(shù)

int memcmp(const void* ptr1, const void* ptr2, size_t num);
  • 比較從ptr1和ptr2指針開(kāi)始的num個(gè)字節(jié)
  • 返回值,當(dāng)ptr1大于ptr2就返回大于1的值,當(dāng)ptr1小于ptr2就返回小于0的值,當(dāng)?shù)扔诘臅r(shí)候返回0

使用案列:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <assert.h>

int main()
{
	char arr1[] = "abcz";
	char arr2[] = "abcd";

	if ( 0 < memcmp(arr1, arr2, 4))
	{
		printf("大于\n");
	}
	else if(0 > memcmp(arr1, arr2, 4))
	{
		printf("小于\n");
	}
	else
	{
		printf("等于\n");
	}

	return 0;
}

memcpy函數(shù)的實(shí)現(xiàn)

#include <assert.h>

int my_memcmp(void* dest, const void* src, unsigned int count)
{
	assert(dest && src);//斷言

	if (!count)
	{
		return 0;
	}

	while (--count && *(char*)dest == *(char*)src)
	{
		++(char*)dest;
		++(char*)src;
	}

	return *(char*)dest - *(char*)src;
}
	if (!count)
	{
		return 0;
	}

如果count是0的話就直接返回0

while (count-- && *(char*)dest == *(char*)src)
	{
		++(char*)dest;
		++(char*)src;
	}

當(dāng)count個(gè)數(shù)比較完或者dest不等于src,我們就停止循環(huán)。

return *(char*)dest - *(char*)src;

直接返回dest - src,如果它們兩相等一定返回0,dest小于src返回的是小于0的值,大于則返回大于0的值。

memset修改內(nèi)存塊

void *memset( void *dest, int c, size_t count )
  • dest是目的
  • 地第二個(gè)修改成什么?
  • 第三個(gè)修改內(nèi)存的個(gè)數(shù)

memset是以1字節(jié)為單位來(lái)修改,第二個(gè)參數(shù)是要修改成什么字符,第三個(gè)參數(shù)是修改內(nèi)存?zhèn)€數(shù)以1字節(jié)為單位

使用案列:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>

int main()
{
	char arr[10] = { 0 };
	int i = 0;

	memset(arr, '6', 10);

	for (i = 0; i < 10; i++)
	{
		printf("arr[%d]=%c\n", i, arr[i]);
	}

	return 0;
}

memset函數(shù)實(shí)現(xiàn)

#include <assert.h>

void* my_memset(void* dest, int a, unsigned int count)
{
	assert(dest);//斷言
	void* temp = dest;//記錄dest的首地址

	while (count--)
	{
		*(char*)dest = a;
		++(char*)dest;
	}

	return temp;//返回dest的首地址
}
while (count--)
{
	*(char*)dest = a;
	++(char*)dest;
}

把a(bǔ)的值給dest,來(lái)進(jìn)行修改,每次修改一個(gè)字節(jié)就自增一修改下個(gè)字節(jié)。

到此這篇關(guān)于C語(yǔ)言全部?jī)?nèi)存操作函數(shù)的實(shí)現(xiàn)詳細(xì)講解的文章就介紹到這了,更多相關(guān)C語(yǔ)言內(nèi)存操作函數(shù)的實(shí)現(xiàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解C語(yǔ)言中的函數(shù)、數(shù)組與指針

    詳解C語(yǔ)言中的函數(shù)、數(shù)組與指針

    這篇文章主要介紹了C語(yǔ)言中的函數(shù)、數(shù)組與指針,本文給大家介紹的非常詳細(xì),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-02-02
  • VC創(chuàng)建DLL動(dòng)態(tài)鏈接庫(kù)的方法

    VC創(chuàng)建DLL動(dòng)態(tài)鏈接庫(kù)的方法

    這篇文章主要介紹了VC創(chuàng)建DLL動(dòng)態(tài)鏈接庫(kù)的方法,實(shí)例分析VC創(chuàng)建動(dòng)態(tài)鏈接庫(kù)的完整步驟,需要的朋友可以參考下
    2015-05-05
  • C語(yǔ)言實(shí)現(xiàn)反彈球小游戲

    C語(yǔ)言實(shí)現(xiàn)反彈球小游戲

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)反彈球小游戲,利用函數(shù)寫的C語(yǔ)言小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • C語(yǔ)言超詳細(xì)講解結(jié)構(gòu)體與聯(lián)合體的使用

    C語(yǔ)言超詳細(xì)講解結(jié)構(gòu)體與聯(lián)合體的使用

    結(jié)構(gòu)體和聯(lián)合體用于描述事物的屬性,如一只鳥的信息,可能包括它的品種,體重,顏色,年齡等,接下來(lái)大家一起來(lái)詳細(xì)看看吧
    2022-05-05
  • 新手向超詳細(xì)的C語(yǔ)言實(shí)現(xiàn)動(dòng)態(tài)順序表

    新手向超詳細(xì)的C語(yǔ)言實(shí)現(xiàn)動(dòng)態(tài)順序表

    本文主要介紹了C語(yǔ)言實(shí)現(xiàn)動(dòng)態(tài)順序表,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • C++插件化 NDD源碼的插件機(jī)制實(shí)現(xiàn)解析

    C++插件化 NDD源碼的插件機(jī)制實(shí)現(xiàn)解析

    這篇文章主要介紹了C++插件化 NDD源碼的插件機(jī)制實(shí)現(xiàn)解析,這里再介紹推薦下優(yōu)秀的國(guó)產(chǎn)軟件開(kāi)源項(xiàng)目?NDD(notepad--),一個(gè)支持windows/linux/mac的文本編輯器,目標(biāo)是要國(guó)產(chǎn)替換同類軟件,需要的朋友可以參考下
    2023-03-03
  • C++中的三種繼承public,protected,private詳細(xì)解析

    C++中的三種繼承public,protected,private詳細(xì)解析

    我們已經(jīng)知道,在基類以private方式被繼承時(shí),其public和protected成員在子類中變?yōu)閜rivate成員。然而某些情況下,需要在子類中將一個(gè)或多個(gè)繼承的成員恢復(fù)其在基類中的訪問(wèn)權(quán)限
    2013-09-09
  • C++ 結(jié)構(gòu)體初始化與賦值詳解

    C++ 結(jié)構(gòu)體初始化與賦值詳解

    本文主要介紹了C++ 結(jié)構(gòu)體初始化與賦值詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • C++實(shí)現(xiàn)LeetCode(48.旋轉(zhuǎn)圖像)

    C++實(shí)現(xiàn)LeetCode(48.旋轉(zhuǎn)圖像)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(48.旋轉(zhuǎn)圖像),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • Qt+OpenCV實(shí)現(xiàn)目標(biāo)檢測(cè)詳解

    Qt+OpenCV實(shí)現(xiàn)目標(biāo)檢測(cè)詳解

    這篇文章主要介紹了如何利用Qt和OpenCV中自帶xml文件實(shí)現(xiàn)目標(biāo)檢測(cè),文中的實(shí)現(xiàn)過(guò)程講解詳細(xì),感興趣的小伙伴可以動(dòng)手試一試
    2022-03-03

最新評(píng)論