C语言内存函数

1.memcpy函数使用和模拟实现

2.memmove使用和模拟实现

3.memset函数的使用

4.memcmp函数的使用

(使用这些函数需要引用头文件 string.h)

1.memcpy使用和模拟

1.void* memcpy(void* destination,const void* source,size_t num)

1.函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置。

2.这个函数在遇到  '\0'  的时候并不会停下来(与strcpy函数不同)。

3.如果source和destination有任何的重叠,复制的结果是未定义的(达不到预期)。

int main()
{
	int arr1[] = { 0,1,2,3,4,5,6,7,8,9,10 };

	int arr2[20] = { 0 };
	memcpy(arr2, arr1, 20);
	//printf("%d", arr2);
	for (int i = 0; i < 10; i++)
	{
		printf("%d", arr2[i]);
	}
	return 0;
}

 下面是目标位置与来源位置有重叠的情况:

目标位置在数组arr1 2(元素)的位置上 ,来源位置在数组的起始位置,复制的大小是五个字节,有重复的位置,按照原来的功能是应该按下图来的,在第二次的时候sre指向已经被覆盖的dest原位置,此时会把已经覆盖的数据作为来源数据,当来源数据应该是2和3,所以结果是不符合的,没有的原因是函数优化了(实现功能与下面的memmove基本无差)。

接下来是如何模拟memcpy函数:

#include<stdio.h>
#include<stdlib.h>

void* my_memcpy(void* dest, const void* sre, size_t num)
{
	void* ret = dest;
	while (num--)
	{
		*(char*)dest = *(char*)sre;
		dest = (char*)dest + 1;
		sre = (char*)sre + 1;
	}
	return ret;
}
int main()
{
	int arr1[] = { 0,1,2,3,4,5,6,7,8,9,10 };

	int arr2[20] = { 0 };
	my_memcpy(arr2, arr1, 20);
	//printf("%d", arr2);
	for (int i = 0; i < 10; i++)
	{
		printf("%d", arr2[i]);
	}
	return 0;
}

 my_memcpy需要的参数是俩个void型的指针,因为不确定是什么类型的地址传过来,num是复制的字节大小,第一步是先用临时变量来存储dest的位置,因为后续的操作会改变dest的起始位置,

而函数的返回值是一个地址的起始位置,把dest和sre强制转化的原因是num是字节大小,使用变为char*类型刚好是一个字节大小,通过一个一个字节的赋值,直到把num个字节大小都给赋值,最后在返回临时变量ret(起始位置)。

用模拟的函数可以看到重叠时的效果(未定义的)

 函数库里的memcpy原本应该是这个效果。

2.memmove使用和模拟实现

1 void* memmove(void* destination,const void* source,size_t num); 

1.和memcpy的差别就是memmove函数处理的原内存块和目标内存块是可以重叠的。

2.如果原空间和目标空间出现折叠,就要使用memmove函数去处理。

memmove与memcpy定义的区别是重叠问题的处理,但是通过上面可以知道,其实俩者没什么区别,能实现一样的效果。

 接下来是memmove函数的实现:

#include<stdio.h>
#include<stdlib.h>
void* my_memmove(void* dest, const void* sre, size_t num)
{
	void* ret = dest;
	if (dest < sre)
	{
		while (num--)//从前往后
		{
			*(char*)dest = *(char*)sre;
			((char*)dest)++;
//括号是一定有的,(char*)dest++是不行的,强制转化临时的,转化之后没有使用,++之后已经不是强制转化之后的结果了。
			((char*)sre)++;
		}
	}
	else
	{
		while (num--)//从后往前
		{
			*((char*)dest + num) = *((char*)sre + num);
//num进来会-1,最后面的位置是起始位置+覆盖的字节数量-1,所以强制转化的dest+num刚好为最后面位置。
		}
	}
	return ret;//memmove返回值是目标空间的起始位置
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };
	my_memmove(arr1 + 2, arr1, 20);
	for (int i = 0; i < 10; i++)
	{
		printf("%d", arr1[i]);
	}
	return 0;
}

对于重叠会有三种情况:

第一种情况:

当dest的位置比sre的位置大,此时若按照从前往后覆盖会出现上面memcpy函数实现中重叠的情况,所以需要从后往前覆盖,这样可以保证来源数据不会被覆盖改变(sre)。

 第二种情况:

当dest的位置小于sre位置,此时就不能从后往前的覆盖,会改变来源数据的值,需要从前往后的覆盖。

 第三种情况:

就是不重叠的情况,这时候用第一种或者第二种的方法都可以实行。

(模拟的)

3.memset函数的使用

1 void* memset(void* ptr,int value,size_t num); 

1.memset是用来设置内存的,将内存中的值以字节为单位设置成想要的内容。

从起始位置开始往后四个字节大小设置成‘x’,size_t num是以字节为单位的。

上图可知num字节单位,memset是对每个字节进行处理,int有四个字节,所以只会处理第一个字节,并不是处理这个int大小。

所以要谨慎使用memset函数来赋值。 

4.memcmp函数的使用

1 int memcmp(const void * ptr1,const void* ptr2,size_t num); 

1.比较从ptr1和ptr2指针指向的位置开始,先后的num个字节

2.返回值如下: 

 memcmp函数是对比num个字节大小的数据,16字节对于四个整型,就是对比前四个数据的大小,一样返回0。

而当对比五个字节大小时, 前四行一样,第五行时 05大于04,所以第二个地址大于第一个地址,返回-1.(存储是小端模式存储)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值