内存函数的介绍(memcpy、memmove、memcmp)以及模拟实现

目录

memcpy

        使用举例:

        模拟实现:

memmove

        使用举例:        

        模拟实现:

 memcmp        

        使用举例:        

        模拟实现:


memcpy

memcpy是一个内存拷贝函数,它可以从源地址处拷贝n个字节到目的地地址处。

头文件:

#include<string.h>

库中的声明:

void *memcpy( void *dest, const void *src, size_t count );

  • dest:目的地(即要把数据拷贝到哪个数组)
  • src:源(即从哪里拷贝数组)
  • count:要拷贝的个数,单位是字节(byte)

使用举例:

比如我们要从src数组中,拷贝前三个元素到dest数组中,那么我们就可以这么写:

int main()
{
	int src[] = { 1,2,3,4,5 };
	int dest[20] = { 0 };
	memcpy(dest, src, 12);
	return 0;
}

可以看到src是一个int数组,所以每个元素都是4个字节(环境32位,16位则是2个字节),因为memcpy是按照字节拷贝的,所以要拷贝前三个元素就是12个字节,需要注意的是dest数组中应该有足够大的空间,以便于接收拷贝来的数据。

 在我们的监视窗口可以看到确确实实是把前三个元素拷贝过来了。

模拟实现:

接下来来模拟实现一下memcpy:

//模拟实现memcpy
void* my_memcpy(void* dest, const void* src, size_t byte)
{
	void* ret = dest;
	assert(dest && src);
	while (byte--)
	{
		*(((char*)ret)++) = *(((char*)src)++);
	}
	return dest;
}

因为是模拟实现,所以函数的返回值和形参的类型,都是按照库中来的,形参void*的设计也是因为memcpy可以拷贝不同类型的数据,而因为它是按照字节来拷贝的,所以函数体中把dest和src都强制转换成char*,因为char所占大小时一个字节,所以解引用就可以访问一个字节的大小,这样就可以做到一个字节一个字节的拷贝了。

可以看到模拟实现的my_memcpy也可以完成拷贝。 

memmove

memmove是一个内存移动函数,其实和memcpy类似,都是可以用来拷贝数据的,只不过memmove可以拷贝重叠的区域。

头文件:

#include<string.h>

库中的声明:

void *memmove( void *dest, const void *src, size_t count );

重叠的区域怎么理解呢?

举个例子:

假设在同一块内存空间中,我们要把红框src的内容移动到绿框src+2的位置,这就是重叠区域的拷贝,可以看到memcpy会拷贝失败,而memmove可以拷贝成功,这是为什么呢?

很显然是因为两个函数的实现不同,memcpy是从前往后拷贝,这样在拷贝1的时候3就会被覆盖,所以到时了绿框的最后一个元素不是3而是1,而memmove根据不同的情况,可以有不同的拷贝的方法,就比如这里src+2的地址是大于src的,所以它在移动的时候采取的是从后往前拷贝的方法,也就是先把3拷贝到5的位置,再把2拷贝到4的位置,再把1拷贝到3的位置,这样就避免了元素可能被覆盖的问题。

使用举例:

  • 不重叠区域的拷贝:
int main()
{
	char src[] = { 'a','b','c','d','e'};
	char dest[5] = { 0 };
	memmove(dest, src, 3);
	return 0;
}

 可以看到使用和功能都是和memcpy是一致的,拷贝了3个字节的数据到目的地数组。

  • 重叠区域的拷贝:
int main()
{
	char src[] = { 'a','b','c','d','e'};
	char dest[5] = { 0 };
	memmove(src + 2, src, 3);
	return 0;
}

把src的前三个字母a、b、c拷贝到了src + 2的地址处,拷贝了memcpy所无法拷贝的重叠区域。

模拟实现:

接下来来模拟实现一下memmove:

//模拟实现memmove
void* my_memmove(void* dest, const void* src, size_t byte)
{
	void* ret = dest;
	assert(dest && src);
	if (dest >= src)
	{
		while (byte--)
		{
			*(((char*)ret) + byte) = *(((char*)src) + byte);
		}
	}
	else 
	{
		while (byte--)
		{
			*(((char*)ret)++) = *(((char*)src)++);
		}
	}
	return dest;
}

 可以看到在模拟实现中,分为了两种情况:

  1. dest地址 ≥ src地址
  2. dest地址 < src地址

dest地址大于等于src地址的情况我所采用的是从后往前拷贝,而小于的情况和memcpy是一致的,之前从前往后拷贝即可。

看图可能更方便理解,如下图:

dest地址大于src地址时,为了最后一个元素不被覆盖,所以要从后往前拷贝。

dest地址小于src地址时,为了第一个元素不被覆盖,所以要从前往后拷贝。

dest地址等于src地址时,从前往后拷贝亦或从后往前拷贝都可以。

 memcmp

memcmp是一个内存比较函数,它和strcmp不同,strcmp是比较每一个字符,而memcmp是比较每一个字节,根据返回值来判断双方的大小。

头文件:

#include<string.h>

库中的声明:

int memcmp( const void *buf1, const void *buf2, size_t count );

判断大小:

  • buf1 > buf2(返回大于0的数)
  • buf1 < buf2(返回小于0的数)
  • buf1 == buf2(返回0)

使用举例:

  • 接收返回值:

memcmp的返回值是int,所以用一个int变量来接收返回值,最后判断返回值属于哪种情况即可。

  • 链式访问:

 

直接把memcmp的返回值,作为if语句中的一个参数,这样写也是可以的。

模拟实现:

//模拟实现memcmp
int my_memcmp(const void* buf1, const void* buf2, size_t count)
{
	assert(buf1 && buf2);
	while (*((char*)buf1) == *((char*)buf2) && count--)
	{
		((char*)buf1)++;
		((char*)buf2)++;
	}
	return (*(char*)buf1) - (*(char*)buf2);
}

 因为是一个字节一个字节的比较,所以强制转换为char*就非常合适,然后再循环比较,最后返回buf1和buf2的差值,根据差值来判断大小关系。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值