【C语言进阶篇】C语言内存函数

本文详细介绍了C语言中的四个重要内存操作函数:memcpy用于逐字节拷贝,memmove处理重叠内存,memset设置内存值,memcmp比较内存。通过实例演示了它们的使用和模拟实现方法。
摘要由CSDN通过智能技术生成

【C语言进阶篇】C语言内存函数

 🌈个人主页:开敲

🔥所属专栏:C语言

🌼文章目录🌼

1.memcpy函数及其模拟实现

    1.1 memcpy函数的使用

    1.2 memcpy函数的模拟实现

2.memmove函数及其模拟实现

    2.1 memmove函数的使用

    2.2 memmove函数的模拟实现

3.memset函数

4.memcmp函数

1.memcpy函数及其模拟实现
    1.1 memcpy函数的使用

  memcpy函数是用来拷贝内存的函数,其拷贝的方式为一个字节一个字节地拷贝,使用时需要包含 <string.h> 的头文件。上面的 size_t num 参数的作用就是接收我们输入的想要拷贝的字节数;destination的意思是目的地,void* destination 参数是拷贝存放的目的地;source是起源的意思,const void* source就是我们所要拷贝的数据的起始地。两个接收地址的变量用 void* 类型来定义,说明可以接收不同类型的地址。来看看具体使用:

  这里我们将 arr 数组里20个字节的内存拷贝到 arr1 数组中去,因为arr数组的类型为int型,每个元素的大小为4个字节,因此,拷贝20个字节的内容相当于拷贝了 arr 中5个元素进 arr1 中。

  需要注意的是,如果 arr1 数组中本身有元素,在拷贝的时候,拷贝过去的元素会覆盖掉 arr1 中原有的元素:

  操作字符串:

    1.2 memcpy函数的模拟实现

  下面我们来自己动手模拟实现一下memcpy函数:

//模拟实现memcpy函数
void* my_memcpy(void* dest, const void* src, size_t num)
{
	void* ret = dest;
	//这一步是为了保存dest最开始指向的地址,因为在后续循环里的操作里,
	//dest的地址已经跑到后面去了,不指向最开始的地址

	while (num--)//这里是总共循环的次数,需要拷贝多少个字节就循环多少次
	{
		*(char*)dest = *(char*)src;

		// 因为dest与src都是void*类型,没法直接解引用操作,又因为
		// memcpy函数是一个字节一个字节拷贝的,因此我们在这进行拷贝操作的时候
		//将dest与src都强制类型转换为char*类型,这样就可以达到一个字节一个字节拷贝的目的了

		dest = (char*)dest + 1;
		src = (char*)src + 1;

		//这里的操作是在拷贝完一个字节以后,dest与src的地址都+1
		//去找下一个字节地址,进行下一个字节的拷贝

	}
	return ret;
}


int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr1[10] = { 0 };
	my_memcpy(arr1, arr, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}
2.memmove函数及其模拟实现
    2.1 memmove函数的使用

  memmove函数的作用和memcpy函数几乎一样,使用时也需要包含<string.h>的头文件但是memcpy函数相比于memmove函数来讲有一个缺陷,下面来看一段代码:

这里我们想要将 arr 数组中 1,2,3,4,5 的数据拷贝到 arr 数组中 3,4,5,6,7 的位置,那么结果按理来说应该最后输出打印的是 1,2,1,2,3,4,5,8,9,10。但实际上跟我们想的一样吗?

没错,想的和我们就是一样的,可能这个时候就有人想说我在水字数了。哎!此言差矣。虽然在这里最后输出的结果和我们设想的是一样的,但是,这仅是在VS编译器环境下一样而已,换做别的编译器,可能最后输出的就是下列结果:

为什么可能输出这个结果呢?我们来画图理解:

那么我们如果想要在一个数组里实现我们想要的效果,该怎么办呢?

  这就需要用到memmove函数了,memmove函数就可以专门用来处理这种拷贝内存与存放内存有重叠的情况:

在VS编译器中,memcpy函数也能够完成memmove的作用,我们不妨大胆猜测,在VS中memcpy函数的实现是和memmove函数一样的。

    2.2 memmove函数的模拟实现

  下面我们来手动模拟实现一下memmove函数。

  在模拟实现memmove函数之前,我们需要搞清楚memmove函数的原理,memmove函数的模拟实现相较于memcpy函数更为复杂,我们来逐个讨论:
 

  如何避免在拷贝内存的时候将后面需要拷贝的内存给改变呢?就像上面所说的改为 1,2,1,2,1,2,1,8,9,10 的情况。这时候我们可以想到,将内存从后往前拷贝不就行了,就像这样:

  ② 

  用从前往后的方法就可以达到我们上面的目的,但是,这里又会出现一个新的问题,如果我需要拷贝的内存在存放的内存后面呢,就像下面这种情况:

  这种情况从前往后存还适用吗?我们画图来探究一下:
  

  显然,这个时候再采用从后往前的方法就不行了。既然从前往后不行,那我们从前往后可行吗?画图探究下:

可以发现,这种情况从前往后拷贝存储是可行的,那么除了这两种情况还有别的情况吗?没有了,需要拷贝的内存拷贝内存目的地重复的情况一共就三种:  ① 需要拷贝的内存拷贝内存目的地前并且两者有重复部分   ② 需要拷贝的内存拷贝内存目的地后并且两者有重复部分  ③ 两者完全重复 。而第三种情况不管怎么拷贝都能达到我们的目的,因此,在模拟实现memmove函数时,我们只需要考虑前两种情况即可。下面来看代码:

  

void* my_memmove(void* dest, const void* src, size_t num)
{
		if (dest > src)//拷贝内存在拷贝存放的内存的前面,并且有内存叠加
		{
			dest = (char*)dest + num - 1;//将dest和src分别指向各自的最后一个字节
			src = (char*)src + num - 1;
			while (num--)//将内容一个字节一个字节进行拷贝
			{
				*(char*)dest = *(char*)src;
				dest = (char*)dest - 1;
				src = (char*)src - 1;
			}
		}
		else
		{
			while (num--)//拷贝内存在拷贝存放的内存的后面,并且有内存叠加
			{
				*(char*)dest = *(char*)src;//直接从第一个字节拷贝
				dest = (char*)dest + 1;
				src = (char*)src + 1;
			}
		}
}

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

  memset函数顾名思义就是用来设置内存,将需要设置的内存中的值按照字节来设置成想要的内容,使用时也需要包含<string.h>的头文件

  

这里我们用memset函数将字符串s的前三个字节的内容改为了字符 ' x '。 

4.memcmp函数

memcmp函数是用来比较内存的,用法与strcmp函数十分相似,不同的是,strcmp函数是专门用来比较字符串的函数,而memcmp函数则可以用来比较各种类型。

这里的意思就是:当所比较的两个字符串,前一个大于后一个则返回一个大于0的数,反之则返回小于0的数,相等则返回0

这里我们调用的memcmp的时候,将 与 s1 进行比较,如果 s1 ,则返回一个大于0的数,反之,则返回小于0的数,如果相等,则返回0。这里 的第一个字符是a,而 s1 的第一个字符是b,在第一个字符就判断出了大小,后面也不用判断了,直接返回了小于0的数。

                                                       创作不易,点个赞再走呗,求求啦~😊

               

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值