• Cyuyanzhong的内存函数


    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


    前言

    提示:这里可以添加本文要记录的大概内容:


    提示:以下是本篇文章正文内容,下面案例可供参考
    前面已经介绍了关于字符串和单个字符的操作,本文主要介绍(任意类型)内存层面的操作函数,主要介绍
    memcpy:内存拷贝
    memmove:内存移动
    memset:内存设置
    memcmp:内存比较
    这四类关于内存函数的 相关知识.它们的头文件都是

    一、memcpy函数的使用与模拟实现

    • 函数库函数原型:
    void*memcpy(void*destination,const void*source,size_t num);
    

    这个函数作用就是从source位置开始向后复制num个字节的数据到destination指向的内存位置。

    • 关于这个函数注意以下几点:
      num的单位是字节!!!一定要注意;
      这个函数在遇到’\0’的时候不会停下来
      如果source和destination有任何重叠,复制的结果是未定义,换句话说memcpy不负责重叠空间的拷贝!!,它只负责非重叠空间的拷贝,即destination和source所指向的空间没有重叠。
    • memcpy函数的使用
    #include
    #include
    int main()
    {
    	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
    	int arr2[20] = { 0 };
    	memcpy(arr2, arr1 + 2, 20);//计算的是字节数
    	int sz = sizeof(arr2) / sizeof(int);
    	for (int i = 0; i < sz; i++)
    	{
    		printf("%d,", arr2[i]);
    	}
    }
    

    运行结果:
    在这里插入图片描述
    这里很显然将arr1的数组中从3开始以后的20个字节内容(即4个整形)拷贝到arr2的前4个元素中。

    • memcpy函数的模拟实现
    void* my_memcpy(void*dest,const void*src,size_t num)
    {
    	//转换成char*,一个字节一个节搞,这样我们可以照顾所有数据类型
    	void* ret = dest;
    	for (int i = 0; i < num; i++)
    	{
    		*(char*)dest = *(char*)src;
    		//这里不能用自加加,因为强转是临时型的。要展开来写
    		//(char*)dest++;这种写法不可以
    		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[20] = { 0 };
    	my_memcpy(arr2, arr1 + 2, 20);//计算的是字节数
    	int sz = sizeof(arr2) / sizeof(int);
    	for (int i = 0; i < sz; i++)
    	{
    		printf("%d,", arr2[i]);
    	}
    }
    

    运行结果如下:
    在这里插入图片描述

    • 如果用memcpy处理重叠区域会出现bug的现象
    void* my_memcpy(void*dest,const void*src,size_t num)
    {
    	//转换成char*,一个字节一个节搞
    	void* ret = dest;
    	for (int i = 0; i < num; i++)
    	{
    		*(char*)dest = *(char*)src;
    		//这里不能用自加加,因为强转是临时型的。要展开来写
    		//(char*)dest++;这种写法不可以
    		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[20] = { 0 };
    	my_memcpy(arr1+2, arr1, 20);//计算的是字节数
    	int sz = sizeof(arr2) / sizeof(int);
    	for (int i = 0; i < sz; i++)
    	{
    		printf("%d,", arr2[i]);
    	}
    }
    

    我们期待的结果是:
    在这里插入图片描述
    可实际结果如下:

    在这里插入图片描述
    这里就出现了用memcpy函数处理重叠空间arr1的时候,出现BUG的现象。我们的memcpy对处理重叠空间的结果不负责

    二、memmove函数的使用和模拟实现

    • memmove 函数的原型:
    void*memmove(void*destination,const void*source,size_t num);
    

    关于memmove 函数注意:memmove比memcpy的功能更加强大,它除了可以处理非重叠空间的拷贝,更重要的是它可以处理重叠空间的拷贝,换句话说,如果源空间和目标空间出现重叠,就得使用memmove函数处理。

    • 函数的使用:
    #include
    #include
    int main()
    {
    	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
    	int arr2[20] = { 0 };
    	memmove(arr1, arr1+2, 20);
    	int sz = sizeof(arr1) / sizeof(int);
    	for (int i = 0; i < sz; i++)
    	{
    		printf("%d,", arr1[i]);
    	}
    }
    

    这里是在重叠空间arr1中进行的拷贝,故而用到memmove 函数
    运行结果:
    在这里插入图片描述

    • memmove 函数的模拟实现:
    #include
    #include
    #include
    void* my_memmove(void* dest,const void* src, size_t num)
    {
    	assert(dest && src);
    	void* ret = dest;
    	//从前向后拷贝
    	if (dest < src)
    	{
    		for (int i = 0; i < num; i++)
    		{
    			*(char*)dest = *(char*)src;
    			dest = (char*)dest + 1;
    			src = (char*)src + 1;
    		}
    	}
    	//从后向前拷贝
    	else
    	{
    		while (num--)
    		{
    			//首先要找到第num个字节的地址
    			*((char*)dest + num) = *((char*)src + num);
    		}
    	}
    	return ret;
    }
    int main()
    {
    	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
    	int arr2[20] = { 0 };
    	my_memmove(arr1, arr1+2, 20);
    	int sz = sizeof(arr1) / sizeof(int);
    	for (int i = 0; i < sz; i++)
    	{
    		printf("%d,", arr1[i]);
    	}
    
    }
    
    

    我们通过分析可得,如果目标空间指针所指向的地址小于源空间指针所指向的地址,那么我们从前向后拷贝,可以避免数据覆盖的现象,如果目标空间指针所指向的地址大于源空间指针,那我们从后向前拷贝,可以有效避免数据覆盖的现象。
    运行结果如下:
    在这里插入图片描述

    三、memset函数与memcmp函数的使用

    (一)、memset函数(内存块设置)

    • memset函数的原型:
    void*memset(void*ptr, int value, size_t num);
    

    memset 是用来设置内存的,将内存中的值以字节为单位设置成想要的内容;
    这里ptr指向要被填充内存块的指针;value 是要设置的内存值;num是要设置的字节个数为多少,这里都用void*指针是为了进行泛型编程,容纳所有数据类型。

    • memset函数的使用
    #include
    #include
    int main()
    {
    char arr[] = "hello word";
    memset(arr + 6, 'x', 4);
    printf("%s\n", arr);
    return 0;
    }
    

    这里我们从"hello word"的‘w’字符往后的4字符设置为’x’字符
    运行结果如下:
    在这里插入图片描述

    (二)、memcmp函数(内存块比较)

    • memcmp函数原型:
    int memcmp ( const void * ptr1, const void * ptr2, size_t num );
    

    memcmp函数是用来比较从ptr1和ptr2指针指向的位置开始,向后的num个字节。
    返回值如下:
    在这里插入图片描述

    • memcmp函数的使用
    #include
    #include
    int main()
    {
    
    	int arr1[] = { 1,2,3,4,5 };
    	int arr2[] = { 1,2,3,6,5 };
    	int ret1=memcmp(arr1, arr2, 12);
    	int ret2=memcmp(arr1, arr2, 16);
    	printf("%d\n", ret1);
    	printf("%d\n",ret2);
    	return 0;
    }
    

    很显然前三个整形数据arr1与arr2是相同的,而比较到第四个整形数据的时候,显然4<6,所以输出结果如下:
    在这里插入图片描述

    总结

    本文主要介绍了C语言中几类内存函数——memcpy(内存拷贝)、memmove(内存移动)、memset(内存设置)、memcmp(内存比较).如有错误,请批评指正。

  • 相关阅读:
    k8s-svc外界访问pod容器服务-4
    实现VLAN间通信&以太网链路聚合与交换机堆叠、集群&华为ICT网络赛道
    [C++随笔录] vector模拟实现
    设计模式03———包装器模式 c#
    git:一个本地仓库绑定多个远程的方法以及遇到的问题
    单链表的模拟实现
    Oracle 查询 SQL 语句
    黑猫带你学UFS协议栈第3篇:UFSHCI系统框架介绍
    [Python从零到壹] 四十九.图像增强及运算篇之顶帽运算和底帽运算
    谷歌浏览器如何设置和恢复纯黑界面
  • 原文地址:https://blog.csdn.net/m0_74949249/article/details/140039375