C语言----内存函数

         当我们学习了字符函数,那内存函数的我们肯定也是要了解的吧。但我们需要了解的是内存函数可在任意类型使用,字符串函数只能比较字符串,内存函数不关注’\0’, 只关注要拷贝的字节数。这是内存函数与字符串函数最明显的一个区别。那么内存函数大概有哪些嘞。我们可以先看一下memcpy(复制),memmove(复制),memset(设置内容),memcmp(比较)。这是鄙人现在知道的常见的内存函数。也许还有很多的函数,鄙人不知道。当然也希望大家可以在下方评论区留言。

memcpy

        大家如果看过我的上一篇博客的话,大家可能还记得一个字符串函数strcpy。虽然,大家会把这两个函数混为一谈。但我们在上面也讲过。内存函数与字符串函数最大的却别就是memcpy是任意类型都可以使用,但字符串函数却只能是字符函数。那么下来看一下memcpy的最开始的样子:

void * memcpy ( void * destination, const void * source, size_t num );

        这样大家可能对memcpy的使用方法还是不了解,那么我们直接来用代码演示:
2b52e1cd51c74b9b8e22673297a2f95e.png

         这样大家看见了吧,memcpy可以将一个数组内容赋值给另外一个数组,但是不能将自己赋给自己,如果想自己给自己的话那么接下来要讲的memove,它可以直接给自己。

        并且大家看到我们前面的数组是目标数组,后面的数组的源数组,而后面的数值却是字节数。这个是大家需要特别注意的。我们可以看到int类型是4个字节,然后我们直接数写的是20,那么4/20那么就是5。刚刚好5个int类型,那么打印刚刚好。当然后面更改数据类型的话,我们可以依据实际需要更改直接数就可以了。

      当我们写了普通的memcpy那么我们尝试一下my_mcpy:

80b7d0b108d54483ba4769ad91c69d9e.png

void* my_mecpy(void *arr1, void *arr, size_t ret)
{
	assert(arr1);
	assert(arr);//确保参数准确性
	void *cc = arr1;//建立一个地址,方便后面传参
	while (ret--)//参数减一,那么循环次数减一
	{
		*(char*)arr1 = *(char *)arr;//用char类型,char只有一个字节,方便交换
		arr1 = (char*)arr1 + 1;//换下一个
		arr = (char*)arr + 1;
	}
	return (cc);
}
int main()
{
	int arr[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int arr1[20] = { 0 };
	my_mecpy(arr1, arr, 20);
	return 0;
}

       这里大家看了的话,其实很好理解因为函数就是可以接收任意类型,那么我们用void来接收,然后确认参数正确。接下里我们创建一个临时变量来存放地址(但这个在这里是可以不用写的,因为我们本来就是用void,没用返回值的,所以最后return有无皆可),剩下的就是最简单的交换了,既然交换肯定要循环吧,并且我们也将循环次数传过来了。那么直接while循环然后循环次数减一就可以了。但:我们需要注意的是需要将数据强转为char类型,这个大家都知道吧,比较C语言中char类型只有一个字节,然后我们循环20次,那是不是就将5个int类型交换过去了。

        然后不知道大家是否觉得我每次传参子函数的时候,基本上都判断了参数的正确型的。比较我们写代码肯定是为了后面去大厂嘛,虽然我们直接写代码知道传递的参数是没有错的,但要是一个不知道的人用这个代码,却传递了一个错误的参数,那且不是就很麻烦了,所以算是一个好的代码习惯吧,希望大家也可以养成这个习惯。

    memmove

       在上面我们也讲过,memcpy不能直接给自己,只能是两个数组。但memmove却可以重叠。所以当源空间和⽬标空间出现重叠,就得使⽤memmove函数处理。那我们还是看一下memmove的基本格式:

void * memmove ( void * destination, const void * source, size_t num );

        虽然大家看到格式里面的两个数组是不一样的,那是因为如果数组一模一样,并且位置都不变的话,那我复制干什么嘞,不就是自己嘛,干嘛要交换呀,所以呀,这两个数组名多多少少都有一点区别,那还是上代码:

0ce388ad7ff14df5a28cc9db2dd6527e.png

      我们可以看到我们第一个数组是加了2的,然后我们交换20个字节所以就是5个int类型。那么原本的3,4,5,6,7变为了1,2,3,4,5。这样大家也知道了memmove的使用方法了吧。

     既然我们学习了普通的memmove使用方法,那么my_memmove肯定是也要安排:

3e76e8456dca44c0bf34d133f2517c56.png

void *my_memmove(void *arr1, void *arr2, size_t ret)
{
	void *yy = arr1;
	if (arr1 <= arr2 || (char *)arr1 >= ((char *)arr2 + ret))//判断前后循环
	{
		while (ret--) {//前循环
			*(char *)arr1 = *(char *)arr2;
			arr1 = (char *)arr1 + 1;
			arr2= (char *)arr2 + 1;
		}
	}
	else//后循环
	{
		arr1 = (char *)arr1 + ret - 1;//将循环地方确定下来
		arr2 = (char *)arr2 + ret - 1;
		while (ret--) {
			*(char *)arr1 = *(char *)arr2;
			arr1 = (char *)arr1 - 1;//因为是向前所以是减1
			arr2 = (char *)arr2 - 1;
		}
	}
	return yy;
}
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]);
	}
}

        我们知道交换方法有两个方法吧,可以从开头直接交换也可以从末尾交换是吧。但我们知道既然两种方法,肯定有各自的优点,我们需要区分在什么时候使用从前向后什么时候需要从后向前。其实这也比较简单,我们可以直接理解为当目标数组的位置小于源数组的话,那么就从前向后,反之亦然。

d25209cd9c134172b783b8ac76cac12a.jpeg

        大家可以看一下上面的图片应该会对大家判断前后交换方法以及为什么需要判断前后交换有帮助。

memset

        这个将内存中的值以字节为单位设置成想要的内容,但这个我不知道如何向大家解释,直接看代码吧

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

         普通的memset:

b9cfeb9c3e834712a471b4989a4e6421.png

        我们这里我们是直接替换的6个位置,就是是空格也被替换了。然后大家可以看一下下面的代码。我们使用两个不用的数据类型来memset:

4617a257d26545b1bb3e68b85e24ddd8.png

       因为我们接收的数组是char类型所以我们需要将int类型强转为char类型。但大家应该也看到了,我并没有直接给arr1数值存储1,2,3,4,5。我是存放的acsll值。因为我们将1强转为了char类型,如果用%c打印的话是看不见的,所以我们需要使用ascll来打印,那么这些也是可以在次延伸到其他的类型中的。

       接下来是my_memset

3580000a7e7c44628ba1783e4a395b53.png

void* my_memset(void* ptr, int a, size_t num)
{
	assert(ptr);
	void* ret = ptr;
	while (num--)
	{
		*(char*)ptr = (char)a;
		++(char*)ptr;
	}
	return ret;
}

        因为大家设置了数据的,所以我们只需要像上面的一样,用void来接收,然后再强转为char类型设置,就可以了。

memcmp

       这个与我上一个博客strcmp感觉是差不多的,都有比较意思,但是memcmp⽐较从ptr1和ptr2指针指向的位置开始,向后的num个字节。

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

       解释可能大家觉得比较陌生,还是上代码:

       那么接下来就是my_memcmp:

void* my_memcmp(const void* p1, const void* p2, int num)
{
	assert(p1);
	assert(p2);
	while (num--)
	{
		if (*(char*)p1 > *(char*)p2)//大于
		{
			return 1;
		}
		else if (*(char*)p1 < *(char*)p2)//小于
		{
			return -1;
		}
		else//等
		{
			p1 = (char*)p1 + 1;
			p2 = (char*)p2 + 1;
		}
     }
     return 0;
}
int main()
{
	int arr1[] = { 1, 2, 3, 4, 5 };
	int arr2[] = { 1, 2, 2, 5, 6 };
	int ret = my_memcmp(arr1, arr2, 9);
	printf("%d\n", ret);
	return 0;
}

       看了上面的代码大家应该也想到了,比较嘛,直接比较有可能是不同数据类型来比较,那么我们只能用都可以接受的来比较是吧。那么我们之前学习的ascll这不就用上了嘛!如果大于返回1小于返回-1相等则为0。这样大家肯定熟悉嘛。

       好了,这是鄙人写的4个内存函数了,还是上面的话,如果还有其他的,希望大家可以在评论区里面补充。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值