
 前言
上一期讲的函数都是和字符串相关的,但是我们在操作数据的时候,不仅仅是操作字符串的数据,还得需要内存函数的应用
内存函数的应用
- 1. memcpy
 - 1.1 memcpy的介绍
 - 1.2 memcpy的使用
 - 1.3 模拟实现memcpy库函数
 - 1.4 我想在1,2后面打印1,2,3,4,5会怎么样?
 
- 2. memmove
 - 2.1 memmove的介绍
 - 2.2 memmove的使用
 - 2.3 模拟实现memmove库函数
 
- 3. memcmp
 - 3.1 memcmp的介绍
 - 3.2 memcmp的使用
 
- 4. memset
 - 4.1 memset的介绍
 - 4.2 memset的使用
 
1. memcpy
1.1 memcpy的介绍
void * memcpy ( void * destination, const void * source, size_t num );
 
- 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
 - 这个函数在遇到 ‘\0’ 的时候并不会停下来。
 - 如果source和destination有任何的重叠,复制的结果都是未定义的。
 
1.2 memcpy的使用
用代码举例:
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[8] = { 0 };
	//把arr1中的前5个数据拷贝到arr2中
	memcpy(arr2, arr1, 20);//strcpy不能用,它只针对字符串拷贝,而上面的是整型数据
	return 0; 
}
 

 试试浮点型看看可不可以:
int main()
{
	float arr1[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
	float arr2[8] = { 0 };
	//把arr1中的前5个数据拷贝到arr2中
	memcpy(arr2, arr1, 12);
	return 0; 
}
 

从中发现memcpy它并不在乎整型还是浮点型,所以叫他内存拷贝
void * memcpy ( void * destination, const void * source, size_t num );
 
在分析一下上面的信息:
 void* – 通用类型的指针,可以接受任意类型数据的地址,但是这种指针不能直接解引用和加减运算!
 memcpy函数的设计者,不知道未来程序员使用memcpy拷贝什么类型的数据!
 size_t num 表示拷贝多少个字节
1.3 模拟实现memcpy库函数
//memcpy函数返回的是目标空间的起始地址
#include <assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{
	void* ret = dest;
	assert(dest && src);
	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[8] = { 0 };
	//把arr1中的前5个数据拷贝到arr2中
	my_memcpy(arr2, arr1, 20);
	return 0; 
}
 
调试监视结果如下:

1.4 我想在1,2后面打印1,2,3,4,5会怎么样?
#include <assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{
	void* ret = dest;
	assert(dest && src);
	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	//   你先打印  1 2 1 2 3 4 5 8 9 10
	//   结果却是  1 2 1 2 1 2 1 8 9 10
	
	my_memcpy(arr1 + 2, arr1, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
}
 

 红色框框:目标空间
 绿色框框:想要拷贝的原数据
结论:
 所以我们发现:在内存重叠的时候,使用memcpy可能会出现意想不到的结果
 建议在内存重叠的情况,使用memmove函数.
2. memmove
2.1 memmove的介绍
void * memmove ( void * destination, const void * source, size_t num );
 
- 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
 - 如果源空间和目标空间出现重叠,就得使用memmove函数处理。
 
2.2 memmove的使用
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	//   你先打印  1 2 1 2 3 4 5 8 9 10
	//   结果却是  1 2 1 2 3 4 5 8 9 10
	//说明没有问题
	
	memmove(arr1 + 2, arr1, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
}
 
代码结果:
 
2.3 模拟实现memmove库函数

 红色框框:目标空间
 蓝色框框:想要拷贝的原数据
 
 当dest在src前面,也就是dest的地址更低,src的地址更高的时候
 
 整个图片概念图:
 
 从而有两种方案,综合比较,B方案效果更好
 
 B方案图片解释:
 
 代码样子:
if (dest < src)
{
	//前->后
}
else
{
	//后->前
}
 
完整版代码:
//memcpy函数返回的是目标空间的起始地址
#include <assert.h>
void* my_memmove(void* dest, const void* src, size_t num)
{
	void* ret = dest;
	assert(dest && src);
	if (dest < src)
	{
		//前->后
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		//后->前
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	return ret;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	//             1 2 1 2 3 4 5 8 9 10
	my_memmove(arr1 + 2, arr1, 20);
	//my_memmove(arr1, arr1+2, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
}
 
总结:
C语言:memcpy拷贝不重叠的内存
重叠的就交给memmove
memmove > memcpy 100 60
VS:100 100
3. memcmp
3.1 memcmp的介绍
int memcmp ( const void * ptr1,  const void * ptr2,  size_t num );
 
- 比较从ptr1和ptr2指针开始的num个字节
 - 返回值如下:

 
3.2 memcmp的使用
int main()
{
	int arr1[] = { 1,2,3,4,5 };//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00
	int arr2[] = { 1,2,3,4,6 };//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 06 00 00 00
	int ret = memcmp(arr1, arr2, 17);
	printf("%d\n", ret);
}
 
代码结果:
 
4. memset
4.1 memset的介绍
void * memset ( void * ptr, int value, size_t num );
 
将 ptr 指向的内存块的第一个字节数设置为指定值(解释为无符号字符)。
4.2 memset的使用
int main()
{
	char arr[] = "hello world";//以字节为单位来进行设置的
		memset(arr, 'x', 5);
		printf("%s\n", arr);
}
 
代码结果:
 
 注意:memset是以字节为单位来进行设置的!!
 什么意思呢?
int main()
{
	int arr[10] = { 0 };
	//01 01 01 01
	memset(arr, 1, sizeof(arr));//这种写法无法将数据的每个元素设置为1
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%x ", arr[i]);
	}
}
 
体会代码结果:
这种写法无法将数据的每个元素设置为1

如果这份博客对大家有帮助,希望各位给恒川一个免费的点赞作为鼓励,并评论收藏一下,谢谢大家!!!
制作不易,如果大家有什么疑问或给恒川的意见,欢迎评论区留言。














![Prompt工程师指南[从基础到进阶篇]:用于开发和优化提示,以有效地使用语言模型(LMs)进行各种应用和研究主题](https://img-blog.csdnimg.cn/img_convert/ed258197ba9c79ff2534a8eff66e28da.png)




