C语言进阶【3】---C语言内存函数(你确定你很了解内存函数吗?)

本章函数概述

我们在本章的博客中讲的内容是有关内存的操作,我们 直接通过内存块对数据进行操作。 因为我们是直接对内存块操作,所以可以对任意类型数据进行操作(我们没必要管它是什么类型的数据,我们只对这个内存块操作)。接下来所讲的这些内存函数的头文件为:<string.h>这些内存函数是对每个字节进行操作

memcpy使用和模拟

  • memcpy的功能:和strcpy函数的功能类似strcpy函数是对元素进行拷贝,而memcpy函数是对内存块进行拷贝所以内存块里面的数据类型没意义。比如,前面咱们讲过了strcpy和strncpy函数,它们只能对字符串进行拷贝。但是,当我们想进行两个整形数据的拷贝时候,就不能用strcpy和strncpy函数了,就只能用memcpy函数了。memcpy函数能拷贝的数据类型比strcpy和strncpy函数拷贝的数据库类型要广泛些
  • memcpy函数的结构:
//	void * memcpy ( void * destination, const void * source, size_t num );
//	因为我们进行内存块的拷贝,所以里面是什么类型的数据咱们是不知道的,所以当你传给我地址的时候我只能用void*指针来接收。
//	因为咱们是进行内存块的拷贝,所以要知道具体拷贝多少个字节的空间,size_t num 就是要拷贝的字节数。
//	返回的是传给des的首元素地址,因为是什么类型咱不知道,所以返回void*指针数据类型。
//	des和source的地址是可以被我们指定的。

由于size_t num是表示要拷贝的字节数,咱们是第一次见到它的这种意义,所以我给大家放个它的截图,给大家看一下。如图:在这里插入图片描述

  • memcpy函数的使用:----->对字符串的拷贝
#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[] = "abcdefghu"; 	
	char arr2[30] = {0};
	void* p = memcpy(arr2, arr1, 4 * sizeof(char));
	printf("%s\n", (char*)p);
	return 0;
}

结果运行图:在这里插入图片描述
------->对整形数据进行拷贝

#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
int main()
{
	int arr3[] = { 1,2,3,4,5,6 };
	int arr4[10] = { 0 };
	int sz = sizeof(arr4) / sizeof(arr4[0]);
	  memcpy(arr4, arr3, 4 * sizeof(int));
	  printf("arr4: ");
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr4[i]);
	}
	return 0;
}

结果运行图:在这里插入图片描述

  • memcpy函数的模拟:因为这个函数对内存进行操作,所以它能够拷贝多种数据类型模拟的核心思想我们要对单个内存进行操作,也就是把各种指针类型全部转换为char *(因为char *能够访问单个字节),进行代码展示:
#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
#include <assert.h>

void* my_memcpy(void* des, const void* str, size_t num)
{
	void* p = des;
	assert(des && str);
	while (num--)
	{
		*(char*)des = *(char*)str;
		des = (char*)des + 1;
		str = (char*)str + 1;

	}
	return p;
}
int main()
{
	int arr3[] = { 1,2,3,4,5,6 };
	int arr4[10] = { 0 };
	int sz = sizeof(arr4) / sizeof(arr4[0]);
	my_memcpy(arr4, arr3, 4 * sizeof(int));
	printf("arr4: ");
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr4[i]);
	}
	return 0;
}

结果运行图:在这里插入图片描述

  • 拓展使用:------->当我们用memcpy函数进行自己给自己拷贝数据(重叠数据拷贝)
#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
#include <assert.h>
int main()
{
	int arr3[] = { 1,2,3,4,5,6,7,8,9 };
	int sz = sizeof(arr3) / sizeof(arr3[0]);
	  memcpy(arr3+2, arr3, 4 * sizeof(int));
	  printf("arr4: ");
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr3[i]);
	}
	return 0;
}

结果运行图:在这里插入图片描述
--------->当我们用my_memcpy函数进行自己给自己拷贝数据(重叠数据拷贝)

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

void* my_memcpy(void* des, const void* str, size_t num)
{
	void* p = des;
	assert(des && str);
	while (num--)
	{
		*(char*)des = *(char*)str;
		des = (char*)des + 1;
		str = (char*)str + 1;

	}
	return p;
}
int main()
{
	int arr3[] = { 1,2,3,4,5,6,7,8,9 };
	int sz = sizeof(arr3) / sizeof(arr3[0]);
	  my_memcpy(arr3+2, arr3, 4 * sizeof(int));
	  printf("arr4: ");
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr3[i]);
	}
	return 0;
}

结果运行图:在这里插入图片描述
当自己给自己进行重复数据拷贝的时,memcpy函数能达到我们的预想值。但是,我们自己模拟的my_memcpy函数就无法达到预想值,难道是我们的模拟函数有问题?答案是否。我们来举个生活中的例子,100分的试卷。考到60分就欧克了,但是你却偏偏考到80多分,说明有能考到60分的能力,但是你还能超越自己。memcpy函数就是这个道理 ,它有拷贝数据的能力(不重叠数据),但是,它还能超越自己(拷贝重叠数据)。而我们自己模拟的my_memcpy函数完成了它的基本功能。memcpy函数不太常用于拷贝重叠数据我们常用memmove函数拷贝重叠数据。

memmove使用和模拟

  • memmove函数的功能它的功能比memcpy函数要广泛些,它既能拷贝不重叠的数据,有能拷贝重叠的数据
  • memmove函数的结构:
//	void * memmove ( void * destination, const void * source, size_t num );

memmove函数的结构与memcpy函数的结构相同,但是它的功能比memcpy函数要广泛些。

  • memmove函数的使用:进行代码展示---------->数据不重叠
#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
int main()
{
	int arr3[] = { 1,2,3,4,5,6,7,8,9 };
	int arr4[10] = { 0 };
	int sz = sizeof(arr3) / sizeof(arr3[0]);
	memmove(arr4, arr3, 4 * sizeof(int));
	printf("arr4: ");
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr4[i]);
	}
	return 0;
}

结果运行图:在这里插入图片描述
进行代码展示---------->数据重叠

#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
int main()
{
	int arr3[] = { 1,2,3,4,5,6,7,8,9 };
	int sz = sizeof(arr3) / sizeof(arr3[0]);
	memmove(arr3+2, arr3, 4 * sizeof(int));
	printf("arr4: ");
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr3[i]);
	}
	return 0;
}

结果运行图:在这里插入图片描述

  • memmove函数的模拟:进行代码展示:
#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memmove(void* des, void* str, size_t num)
{
	void* p = des;
	assert(des&&str);
	const void* s1 = des;
	const void* s2 = str;
	if (des < str)
	{
		while (num--)
		{
			*(char*)des = *(char*)str;
			des = (char*)des + 1;
			str = (char*)str + 1;
		}
	}
	else
	{
		while (num--)
		{
			des = s1;
			str = s2;
			str = (char*)str + num;
			des = (char*)des + num;
			*(char*)des = *(char*)str;
		}
	}
	return p;
}
int main()
{
	int arr[] = {1,2,3,4,5,6,7,8,9};
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	my_memmove(arr + 2, arr, 4 * sizeof(int));
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

  • memmove函数的模拟讲解:我们对于这个函数的模拟实现要分为两种情况第一种情况就是:des<str时的的拷贝情况第二种情况就是:des>=str的拷贝情况。当为第一种情况的时候,要向后拷贝。进行如图所示:在这里插入图片描述
    是第二种情况的时候,要向前拷贝,如图所示:在这里插入图片描述
    对于向前拷贝的时候,等于的情况是满足的(这是最好的状态),哪怕它越界访问也是满足的(只要str<des

memset函数的使用

  • memset函数的功能具有设置数据的功能能把整型数组里面的元素全部设为0,也能改变字符串中的某些字符元素。
  • memset函数的结构:
//	 void * memset ( void * ptr, int value, size_t num );
// 因为被改变的数据类型我们不知道(既能改变整型,也能改变字符型……),所以用void*指针接收
//	int value为我们想要改变的数据。
// size_t num为我们要改变的内存字节数目。
//	我们还可以指定改变的起始位置。
  • memset函数的使用:进行代码展示--------->改变整型数组
#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz; i++) //	我们以前改变整形数组里面元素的方法
	{
		arr[i] = 0;
		printf("%d ", arr[i]);
	}
	return 0;
}

结果运行图:在这里插入图片描述

#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	memset(arr, 0, sz * sizeof(int)); //	使用memset函数直接全部置0
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

结果运行图:在这里插入图片描述
进行代码展示--------->改变整形数组的起始位置

#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	memset(arr+2, 0, 5 * sizeof(int)); //	改变起始位置,从3开始后面置0,
									//要注意要改变的元素个数不能超过数组的范围,否则报错
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

结果运行图:在这里插入图片描述
进行代码展示--------->改变字符串

#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
int main()
{
	char arr[] = "hello world";
	memset(arr, 'x', 6 * sizeof(char));
	printf("%s\n", arr);
	return 0;
}

结果运行图:在这里插入图片描述
我们还可以改变字符串要改变的起始位置,大家可以自行尝试一下。

  • memset函数使用注意事项对于改变整形数组时,我们使用memset函数主要是置0,不能置其它的数字,否则得不到想要的结果。也就是说,memset函数对于改变整形数组里面的元素,只能置0。进行代码展示:
//	假如,我们给整形数组全部置1
#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	memset(arr, 1, sz * sizeof(int)); 
	for (i = 0; i < sz; i++)
	{
		printf("%d \n", arr[i]);
	}
	return 0;
}

结果运行图:在这里插入图片描述
是不是与我们的预期大相径庭,按理来讲应该全是1,结果全是很大的整数,这是为什么呢? 前面,咱们讲过了这些函数都是对单个字节操作的,由于int 是四个字节,所以每个字节都会改为1。到最后对Int进行解读的时候还是按照4个字节,就会导致解读的数据与期望值不同。结果调试图:如图在这里插入图片描述
从调试图中可以看出来,每个字节都被改为1。所以,我们一般用memset函数置0.

memcmp函数的使用

  • memcmp函数的功能:它和strcmp函数的功能类似,都是用来比较大小的strcmp函数是用来比较字符元素的大小的,而且只能比较字符元素的大小。而memcmp函数是进行内存单个字节比较,它会每个每个字节进行比较,它不管里面存的什么数据。
  • memcmp函数的结构:
//	 int memcmp ( const void * ptr1, const void * ptr2, size_t num );
//	它和strcmp函数一样,参数放的位置决定比较的前后。
//	ptr1大于ptr2返回大于0的值,ptr1等于ptr2返回0的,ptr1小于ptr2返回小于0的值。
//	size_t num 为要比较的字节数。
  • memcmp函数的使用:进行代码展示--------->整形比较
#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
int main()
{
	int arr1[] = { 1,2,3,5,6 };
	int arr2[] = { 1,2,3,4 };
	printf("%d\n", memcmp(arr1, arr2, 3 * sizeof(int)));
	printf("%d\n", memcmp(arr1, arr2, 13));
	return 0;
}

结果调试图:在这里插入图片描述
这是arr1的内存数据存储的形式,arr2也是一样的。前面,咱们已经讲过了,memcmp函数是每个每个字节进行比较,比如,printf("%d\n", memcmp(arr1, arr2, 13));这行代码,我们比较了13个字节的空间,arr1和arr2前面12个字节都一样,第13个字节的内容不一样——05大于04
如图所示的逻辑图:在这里插入图片描述
在这里插入图片描述
由于arr1第13个字节的内容大于arr2的内容,所以结果就会输出大于0的值,结果运行图:在这里插入图片描述
-------->字符型比较

#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[] = "abcde";
	char arr2[] = "abcf";
	printf("%d\n", memcmp(arr1, arr2, 4 * sizeof(char)));
	return 0;
}

姐果运行图:在这里插入图片描述

彩蛋时刻!!!

https://www.bilibili.com/video/BV1pT421r7kJ/?spm_id_from=333.1007.tianma.6-3-21.click&vd_source=7d0d6d43e38f977d947fffdf92c1dfad在这里插入图片描述
每章一句永远相信美好的事情即将发生。感谢你能看到这里,点赞+关注+收藏+转发是对我最大的鼓励,咱们下期见!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值