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

03-18 1422阅读

目录

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函数的使用

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

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

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

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

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

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

  操作字符串:

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

    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  
2.memmove函数及其模拟实现
    2.1 memmove函数的使用

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

  memmove函数的作用和memcpy函数几乎一样,使用时也需要包含的头文件但是memcpy函数相比于memmove函数来讲有一个缺陷,下面来看一段代码:
【C语言进阶篇】C语言内存函数

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

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

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

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

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

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

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

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

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

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

    2.2 memmove函数的模拟实现

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

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

  ①

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

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

  ② 

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

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

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

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

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

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

可以发现,这种情况从前往后拷贝存储是可行的,那么除了这两种情况还有别的情况吗?没有了,需要拷贝的内存和拷贝内存目的地重复的情况一共就三种:  ① 需要拷贝的内存在拷贝内存目的地前并且两者有重复部分   ② 需要拷贝的内存在拷贝内存目的地后并且两者有重复部分  ③ 两者完全重复 。而第三种情况不管怎么拷贝都能达到我们的目的,因此,在模拟实现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  
3.memset函数

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

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

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

4.memcmp函数

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

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

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

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

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

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

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

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

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]