内存函数:memcpy(拷贝),memmove(拷贝),memcmp(比较),memset(设置)

内存函数:memcpy(拷贝),memmove(拷贝),memcmp(比较),memset(设置)

码农世界 2024-05-17 后端 65 次浏览 0个评论

内存函数

  • 一.memcpy(内存拷贝1)
    • 1.函数使用
    • 2.模拟实现
    • 二.memmove(内存拷贝2)
      • 1.函数使用
      • 2.模拟实现
      • 三.memcmp(内存比较)
        • 1.函数使用
        • 2.模拟实现
        • 四.memset(内存设置)
          • 1.函数使用
          • 2.模拟实现

            前言:

            • 之前我们学习了一些字符串库函数,并且模拟实现了它们。但是它们只能作用于字符串,那有没有适用于各种数据类型的函数呢?答案是有的,现在我将为你介绍——内存函数(memory function)
            • 内存函数头文件——string.h

              一.memcpy(内存拷贝1)

              1.函数使用

              void* memory(void* destination, const void* source, size_t num);
              
              • memcpy函数用于拷贝两块独立空间中的数据(不可重叠),将源内存块按照每一个字节拷贝到目标内存块,num表示要拷贝字节的数目。destination 与 source 都是拷贝与被拷贝的起始地址。
                #include
                #include
                int main()
                {
                	int arr1[] = { 1,2,3,4,5,6,7 };
                	int arr2[10] = { 0 };
                	int arr3[] = { 1,2,3,4,5,6,7,8,9,10 };
                	memcpy(arr2, arr1, 24);
                	memcpy(arr3 + 2, arr3, 20);
                	return 0;
                }
                

                内存函数:memcpy(拷贝),memmove(拷贝),memcmp(比较),memset(设置)

                • 观察到arr1将前6个整形拷贝到了arr2中,也就是24个字节,是没有问题的。
                • 而第二个操作本来打算:将 arr3 中的 1,2,3,4,5 拷贝到 arr3 中的 3,4,5,6,7 上,但是得到的是1,2,1,2,1这是因为将1,2拷贝到3,4上,原来的内容就被修改了,达不到要求的效果。

                  总结:

                  1. 函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置。
                  2. 这个函数在遇到 ‘\0’ 的时候并不会停下来。
                  3. 用于拷贝两块独立空间中的数据,如果source和destination有任何的重叠,复制的结果都是未定义的。
                  4. 由于不知道拷贝什么样的数据,所以参数的指针类型为void*(可接收任意类型指针),在函数内部强制类型转换为 char*,可以用于每个字节拷贝。

                  2.模拟实现

                  • 首先是必不可少的断言操作,其次就是要保留目标空间的起始地址便于之后的返回。然后拷贝每一个字节中的内容,所以要循环 num 次。每拷贝一个字节,两个指针向后移动,直到循环结束为止。拷贝结束后返回起始地址即可。
                    void* my_memcpy(void* destination, const void* source, size_t num)
                    {
                    	assert(destination && source);//断言,当二者之一指针为NULL则报错
                    	void* ret = destination;//存起始地址便于返回
                    	while (num--)//循环拷贝,每次拷贝一个字节
                    	{
                    		*(char*)destination = *(char*)source;
                    		destination = (char*)destination + 1;
                    		source = (char*)source + 1;
                    	}
                    	return ret;
                    }
                    

                    注意:在对 destination 和 source 指针进行操作时,要先将它们强制类型转换为 char* 类型的指针。(char* 类型的指针解引用操作时向后访问一个字节的内容)。而 void* (泛型指针)是不能进行解引用操作的。

                    二.memmove(内存拷贝2)

                    1.函数使用

                    • 上面学习了memcpy函数,得知其不能用于处理重叠的内存之间的数据拷贝,那么这样实现重叠部分的数据拷贝呢?memmove会带你实现。
                      void* memmove(void* destination, const void* source, size_t num);
                      
                      • memmove函数用于拷贝两块空间中的数据(可以重叠),将源内存块按照每一个字节拷贝到目标内存块,num表示要拷贝字节的数目。destination 与 source 都是拷贝与被拷贝的起始地址。
                        #include
                        #include
                        int main()
                        {
                        	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
                        	memmove(arr1 + 2, arr1, 20);
                        	return 0;
                        }
                        

                        内存函数:memcpy(拷贝),memmove(拷贝),memcmp(比较),memset(设置)

                        总结:

                        1. memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
                        2. 如果源空间和目标空间出现重叠,就得使用memmove函数处理。

                        2.模拟实现

                        分析:

                        1.当要将紫色区间拷贝到蓝色区间,若采用从前往后(1,2,3,4,5)拷贝,会改变紫色区间中要进行拷贝的数据。换个思路:采用从后往前拷贝,能避免这个问题。

                        内存函数:memcpy(拷贝),memmove(拷贝),memcmp(比较),memset(设置)

                        2.当要将紫色区间拷贝到蓝色区间,若采用从后往前(7,6,5,4,3)拷贝,会改变紫色区间中要进行拷贝的数据。换个思路:采用从前往后拷贝,能避免这个问题。

                        内存函数:memcpy(拷贝),memmove(拷贝),memcmp(比较),memset(设置)

                        总结:

                        1. 在同一块内存中:重叠时,当dest指针 > src指针,采用从前向后拷贝。
                        2. 在同一块内存中:重叠时,当dest指针 < src指针,采用从后向前拷贝。
                        3. 在同一块内存中:若没有重叠,二者都可以采用。
                        4. 在不同块内存中:二者都可以采用。
                        void* my_memmove(void* destination, const void* source, size_t num)
                        {
                        	assert(destination && source);//断言
                        	void* ret = destination;//保存起始地址
                        	if (destination < source)//从前向后拷贝
                        	{
                        		while (num--)
                        		{
                        			*(char*)destination = *(char*)source;
                        			destination = (char*)destination + 1;
                        			source = (char*)source + 1;
                        		}
                        	}
                        	else//从后向前拷贝
                        	{
                        		while (num--)
                        		{
                        			*((char*)destination+num) = *((char*)source+num);
                        		}
                        	}
                        	return ret;//返回起始地址
                        }
                        

                        三.memcmp(内存比较)

                        1.函数使用

                        int memcmp(const void* ptr1, const void* ptr2, size_t num);
                        
                        • memcmp函数用于比较两个内存块大小的函数。它会比较从 ptr1 和 ptr2 指针开始的第一个字节。当 *ptr1 大于 *ptr2 的时候返回一个大于0的数;当 *ptr1 等于 *ptr2 的时候返回0;当 *ptr1 小于 *ptr2 的时候返回一个小于0的数。比较完一次,ptr1 与 ptr2 指向下一个字节,循环 num 次,直到结束为止 。
                          #include
                          #include
                          int main()
                          {
                          	int arr1[] = { 1,257 };//01 00 00 00 01 01 00 00
                          	int arr2[] = { 1,2 };  //01 00 00 00 02 00 00 00
                          	int ret = memcmp(arr1, arr2, 8);
                          	printf("%d\n", ret);
                          	return 0;
                          }
                          

                          内存函数:memcpy(拷贝),memmove(拷贝),memcmp(比较),memset(设置)

                          内存函数:memcpy(拷贝),memmove(拷贝),memcmp(比较),memset(设置)

                          1. 在VS中内存采用的是小端存储方式。
                          2. 数字在内存中是以2进制补码的形式存储的,但是为了更好的观察,以16进制展现出来。
                          3. arr1与arr2中的前4个字节的内容都相同;但第5个字节,1<2,所以arr1 < arr2。

                          2.模拟实现

                          • 首先就是断言,比较字节中的内容,若相同比较下一个字节中的内容,num–。直到字节内容不同或num==0,停止循环,返回二者字节内容的差值。
                            int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
                            {
                            	assert(ptr1 && ptr2);
                            	while (*(char*)ptr1 == *(char*)ptr2 && num--)//1.*(char*)ptr1 != *(char*)ptr2  2.num==0                
                            	{
                            		ptr1 = (char*)ptr1 + 1;
                            		ptr2 = (char*)ptr2 + 1;
                            	}
                            	if(num==0)//二者相同
                            		return 0;
                            	else//二者不同
                            		return  *(char*)ptr1 - *(char*)ptr2;
                            }
                            

                            四.memset(内存设置)

                            1.函数使用

                            void* memset(void* destination, int value, size_t num);
                            
                            • memset函数可以将内存块的某一部分设置为特定的字符。三个参数中,第一个参数是开始设置内存的起始位置,第二个参数是要将内存设置成的字符,第三个参数是从起始位置开始需要设置的内存的字节数。memset函数设置内存的时候是一个字节一个字节地设置的。
                              #include
                              #include
                              int main()
                              {
                              	char arr[] = "hello world";
                              	memset(arr + 6, 'x', 5);
                              	printf("%s\n", arr);
                              	return 0;
                              }
                              

                              内存函数:memcpy(拷贝),memmove(拷贝),memcmp(比较),memset(设置)

                              再比如:将arr初识化为全1(每个字节都初始化为1)

                              #include
                              #include
                              int main()
                              {
                              	int arr[10] = { 0 };
                              	memset(arr, 1, 40);
                              	int i = 0;
                              	for (i = 0; i < 10; i++)
                              	{
                              		printf("%d\n", arr[i]);
                              	}
                              	return 0;
                              }
                              

                              内存函数:memcpy(拷贝),memmove(拷贝),memcmp(比较),memset(设置)

                              因为改变一次改变一个字节,而不是所以不适合初始化整形数组。适合修改字符串内容。

                              2.模拟实现

                              void* my_memset(void* destination, int value, size_t size)
                              {
                              	assert(destination);
                              	void* ret = (char*)destination;//保留目标空间的起始地址便于之后的返回
                              	while (size--)
                              	{
                              		*(char*)destination = value;
                              		destination = (char*)destination + 1;
                              	}
                              	return ret;
                              }
                              

                              创作不易,如果能帮到你的话能赏个三连吗?感谢啦!!!

                              内存函数:memcpy(拷贝),memmove(拷贝),memcmp(比较),memset(设置)

转载请注明来自码农世界,本文标题:《内存函数:memcpy(拷贝),memmove(拷贝),memcmp(比较),memset(设置)》

百度分享代码,如果开启HTTPS请参考李洋个人博客
每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,65人围观)参与讨论

还没有评论,来说两句吧...

Top