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

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

 更新時(shí)間:2021年02月26日 11:10:02   作者:貧僧愛用飄柔  
這篇文章主要介紹了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的位置開始向后拷貝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指針開始的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)文章

最新評(píng)論