详解内存操作函数

 前言

者:小蜗牛向前冲

名言:我可以接收失败,但我不能接收放弃

 如果觉的博主的文章还不错的话,还请点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正。


目录

memcpy内存拷贝函数

memmove函数

memcmp内存拷贝函数

memset内存设置函数

总结


这次主要为大家分析内储操作函数的使用。

memcpy内存拷贝函数

该函数主要用来拷贝各类型的数据。

 参数

 我们要传给该函数的参数有:

dest:指向要在其中复制内容的目标数组的指针,类型转换为 void* 类型的指针。

src:指向要复制的数据源的指针,类型转换为 const void* 类型的指针。

num:要复制的字节数,size_t是无符号整数类型。

头文件 

#include <string.h>

 下面进行代码演示:

#define  _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<string.h>
int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[10] = { 0 };
	memcpy(arr2, arr1, sizeof(arr1));
	return 0;
}

 从上面代码我们可以看出,拷贝整形成功,那么mencpy到底是如何拷贝的呢?为什么strcpy函数就仅仅只能拷贝字符串,而memcpy却能够拷贝所有的内存数据呢?

首先我可以告诉大家,memcpy是对内存中的数据进行一个一个字节进行拷贝的。

其次,strcpy的拷贝方式是让数组中的字符直接经行交换,所以这样整形,浮点型,结构体都不可以进行拷贝。

那么,由于mencpy函数是一个一个字节进行拷贝的,而所有的内存单元都是由字节组成,内存的最小单位是1个字节,所以当mencpy函数进行一个一个字节进行拷贝,能够拷贝所有的内存单元。

基本上面对mencpy函数内存拷贝方式的理解,下面我们进行该函数实现的模拟。

memcpy函数的模拟实现 

void* my_memcpy(void* dest, const void* src, size_t num)
{
	assert(dest && src);//断言
	char* start =(char*)dest;//标记目标数组的地址
	//一个一个字节进行拷贝
	while (num--)
	{
		*(char*)dest = *(char*)src;
		++(char*)dest;
		++(char*)src;
	}
	return start;
}

当我们实现完memcpy函数,这个函数真的能够拷贝所有的内存数据吗?

下面继续看:

void* my_memcpy(void* dest, const void* src, size_t num)
{
	assert(dest && src);//断言
	char* start =(char*)dest;//标记目标数组的地址
	//一个一个字节进行拷贝
	while (num--)
	{
		*(char*)dest = *(char*)src;
		++(char*)dest;
		++(char*)src;
	}
	return start;
}

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10};
	//int arr2[10] = { 0 };
     my_memcpy(arr1+3, arr1, 20);
	return 0;
}

本来按理来说arr1拷贝完的结果为{1,2,3,1,2,3,4,5,9,10};但实际结果是:

 为什么会出现这种状况呢?

这是和我们的memcpy的实现方法有关,我们是从前向后拷贝的,但是这样就会造成一个问题,当源内存块和目标内存块是重叠时,我们在拷贝前面的内存时后面的内存也会改变,这样就会使得拷贝失败。专门写了用来拷贝源内存块和目标内存块是重叠时这种情形的函数memmove。

memmove函数

 其实我们从函数的定义是看,memmove和memcpy都是相同的,但不同的是memmove函数可以处理源内存块和目标内存块是重叠的情形。

参数

 二者参数都是相似的,这里就不在多说,下面我们要讨论一下,源内存块和目标内存块是重叠的不同情形。

情形1(dest<src)

我们都是一个一个字节拷贝的,但怎么才能实现内存拷贝呢?,如果是情形1我们只有进行从前-->后拷贝就可实现(memcpy的实现方式) 

情形2(dest>src&&dest<src+num)

 如果是情形2如果我们仍然是从前-->后拷贝,这样就会出现数据覆盖的现象,但我们可以从后-->前拷贝就可以避免数据覆盖。

情形3(dest>scr+num)

 如果是发现情形3的情形,既然目标空间都和内存空间都不重叠了,那么拷贝的方式无论是从前-->后或者从后-->前都是可以的。

我们理解上面的三种拷贝情况,我们继续举例说明一下memmove函数的功能。

 为了更好的理解menmove函数的功能,下面我们模拟实现。

//模拟实现memmove
void* my_memmove(void* dest, const void* src, size_t num)
{
	assert(dest && src);//断言
	char* start = (char*)dest;
	if (dest < src)
	{
		while (num--)
		{
			*(char*)dest = *(char*)src;
			++(char*)dest;
			++(char*)src;
		}
	}
	else
	{
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	return start;
}

memcmp内存拷贝函数

我们前面学习了,字符拷贝函数,下面我们来见识一下内存拷贝函数吧!

 该函数是用来比较两个内存块

参数

 ptr1:

指向内存块的指针。

ptr2:

指向内存块的指针。

num:

要比较的字节数。

返回值 

该函数返回一个整数值,指示内存块内容之间的关系:

<0:

在两个内存块中不匹配的第一个字节在 ptr1 中的值低于在 ptr2 中的值

0:

两个内存块的内容相等

>0:

在两个内存块中不匹配的第一个字节在 ptr1 中的值大于在 ptr2 中的值

代码举例:

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 1,2,3,4,6 };
	int ret = memcmp(arr1, arr2, 20);
	if (ret > 0)
	{
		printf("前20字节数中在两个内存块中不匹配的第一个字节在arr1中的值>arr2中的值\n");
	}
	else if(ret<0)
	{
		printf("前20字节数中在两个内存块中不匹配的第一个字节在arr1中的值<arr2中的值\n");
	}
	else
	{
		printf("两个内存块的内容相等\n");
	}
	
	return 0;
}

memset内存设置函数

有时候我们需要对内存中值经行修改,就可以用到memset函数。

 参数

 ptr:

指向要填充的内存块的指针。

value:

要设置的值。该值作为 int 传递,但该函数使用此值的无符号 char 转换来填充内存块。

num:

要设置为该值的字节数。
size_t是无符号整数类型。

返回值

 代码举例:

int main()
{
	char mane[20] = "Xiao  ming";
	memset(mane + 5, '*', 1);//设置内存
	printf("%s", mane);//打印
	return 0;
}

 那么我们可以用memset对数组初始化吗?

大家可以看到,我本意(误用)是想把arr的内容都初始化为1,但却最后初始化的值并不是我想要的结果,为什么呢?

原来是我对memset的函数的理解不到位,该函数是一个字节一个字节进行设置的,而不是直接设置一个整形。

所以在数组中设置的第1元素其实是01 01 01 01(十六进制,一个字节=8bit位)。其实用memset初始化数组也是可以,但是比较麻烦,所以还是要慎重使用。

 好了就分析这些内存函数,下面对本篇博主的重点进行简单总结。

总结

memcpy函数是用来进行内存拷贝的,但要注意C语言规定:该函数只要能拷贝内存不重叠的内存即可,但在有些编译器中也是可以拷贝内存重叠的内存的。(如VS)

memmove是C语言用来拷贝内存重叠的内存的。

memcmp可以比较两个内存块。

memset函数可能并不一定试用于数组内容的初始化(大家可以动手试试)。

大家喜欢的来个三连支持博主吧!

评论 67
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小蜗牛~向前冲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值