c语言内存函数(memcpy),详细简介使用以及对应的模拟实现(动图详解)

1. memcpy使用和模拟实现

头文件是<string.h>,void* memcpy( void* destination,const void* source,size_t num);

  1. 这个参数是用来拷贝内存的,显而易见类型都是void*,他可不会管里面存的是什么数据,只负责拷贝内存里的数据。
  2. 每个参数对应的意思:destination表示目标地址   source表示源地址  size_t表示拷贝的大小,单位(字节)从源地址拷贝到目标地址
  3. 假如拷贝重叠部分的数据,这个就不归memcpy函数管了,归下面的memmove来处理
  4. #include <string.h>
    int main()
    {
    	char arr[] = "safgftdf";
    	char arr2[20] = "";
    	memcpy(arr2, arr, 4);
    	printf("%s", arr2);
    	return 0;
    }

    上面代码运行的结果是 safg,只会拷贝四个字符

  5. 接下来是模拟实现

  6. 传参部分要和实参对应上,特么要注意的是size_t的参数部分,写成5 * sizeof(int)会更好,但是写成  20字节也没问题。

  7. 函数内代码解释:

    1. sum直接解释为拷贝次数,当然是一个一个字节拷贝

    2. 为什么用强制转换(char*)指针呢,而不用int*呢,因为这样可以用于多种类型,就比如:假如是9个字节呢?那怎么办?那不就数据缺失了,char类型刚好是1个字节,所以可以面对更多的情况

      void* my_memcpy(void* dest,const void* src,size_t sum)
      {
      	assert(dest && src);//判断是否为NULL,否则报错
      	while (sum--)
      	{
      		*(char*)dest = *(char*)src;
      		dest = (char*)dest + 1;
      		src = (char*)src + 1;
      	}
      }
      int main()
      {
      	//memcpy模拟实现
      	int sum[] = { 1,2,3,4,5,6,7,8,9 };
      	int src[] = { 6,6,6,6,6 };
      	my_memcpy(sum, src, 5 * sizeof(int));
      	int sz = sizeof(sum) / sizeof(sum[0]);
      	for (int i = 0; i < sz; i++)
      	{
      		printf("%d ", sum[i]);
      	}
      	return 0;
      }

2. memmove使用和模拟实现

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

  1. 这个就是上面所说的,重叠部分用memmove函数更好,而且同样也可以实现memcpy的功能
  2. 那么这个函数对应参数是什么呢?其实和上面一个函数一样
  3. dest是目标地址,src是源地址 ,接下来我就用动图来解释一下原理
  4. 可以设想一下错误的:你按照从3 --> 5    4  --> 6   ,5  --> 7?真的5会过去吗,其实之前的3已经覆盖了   就变成了  3 (拷贝)-- > 7,那最终错结果会是  1  2 3  4  3  4  3  8  9

由上面两个图可以得出结论:

1.当dest > src 时 用数组的最后一个元素向目标元素最后拷贝

2.当 dest < src 时,用数组的前面的元素向目标前元素拷贝

最后是代码的实现:

my_memmove(void* dest, void* src, size_t sum)
{
	assert(dest && src);
	void* ret = dest;//返回目标空间地址
	if (dest > src)//从后向前拷贝
	{
		while (sum--)
		{
			*((char*)dest + sum) = *((char*)src + sum);//当前地址长度 + sum访问到数组的最后一个字节,然后对其解引用
		}
	}
	else//dest < src ,从数组的前面向后拷贝
	{
		while (sum--)
		{
			*(char*)dest = *(char*)src;
			((char*)dest)++;//解释:先对其强制转换,然后再++;(char*)dest++,没有意义因为先 ++,再强制类型转换有什么用?
			((char*)src)++;
		}
	}
	return ret;
}
int main()
{
	//memmove函数模拟实现
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };//3 4 5 6 7 6 7 8 9 10,这个是数组从前向后拷贝,dest < str
	int* reet = (int*)my_memmove(arr1 , arr1 + 2, 5 * sizeof(int));
	for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)
	{
		printf("%d ", *(arr1 + i));
	}
	return 0;
}

3. memset函数的使用 

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

int main()
{
	//memset的使用
	char arr[] = "abcdefg";
	memset(arr, 'Y', 3);
	//printf("%s", arr);

	int sum[] = { 1,2,3,4,5,6,7,8 };
	memset(sum, 2, 32);//内存的每个字节设置成 1,这个是设置内存
	for (int i = 0; i < 8; i++)
	{
		printf("%d ", sum[i]);
	}
	return 0;
}
  1. 因为这个函数不常用,就讲讲用法吧。memset,他是一个设置内存块的函数的
  2. 再来解释一下对应参数:ptr指向内存块的   value你要设置的值   size_t设置多少个字节
  3. 上面代码的运行结果是:  YYYdefg  
  4. 下面的结果估计你想不到,其实它是给每个字节设置成2,也就意味着结果变成了                   二进制的:00000010000000100000001000000010  -->  换算成10进制:33,686,018。
  5. 也就意味着它就是按照每个内存块来设置的

4. memcmp函数的使用 

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

int main()
{
	//memcmp,对比内存中数据的大小
	int s1[] = { 1,2,3,4,5,6,7,8 };
	int s2[] = { 1,2,3,4,6,6,6,6 };
	int ret = memcmp(s1, s2, 17);
	if (ret > 0)
		printf("1比2大");
	else if (ret < 0)
		printf("1比2小");
	else
		printf("相等");
	return 0;
}
  1. 比对内存中的数据大小
  2. 上面代码可以很好的说明了,s2 > s1;可能你会想为什么是17个字节啊,这数据不是不匹配吗
  3. 其实不然,因为拿到了数字6的第一个字节,而vs编译器中是以小段字节序存储的,自然会拿低地址的数据去比对
  4. 在内存中站在了地址低处

总结:一起加油吧!!!

  • 30
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值