内存操作函数

308 阅读5分钟

内存操作函数

1.11 memcpy

memory–记忆–内存

cpy–copy–拷贝

memcpy–内存拷贝,参数类型为void* 泛型指针,没有具体类型(任意类型地址)

memcpy(目标地址,源头地址,大小(单位字节))

 void * memcpy ( void * destination, const void * source, size_t num );
  • 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
  • 这个函数在遇到 '\0' 的时候并不会停下来。
  • 如果source和destination有任何的重叠,复制的结果都是未定义的。

strcpy、strncpy只能拷贝字符串,如果要拷贝整型数据,浮点型数据,等等呢?

 #include<stdio.h>
 #include<ctype.h>
 ​
 int main()
 {
     int arr1[] = { 1,2,3,4,5,6,7 };
     int arr2[10] = { 0 };
     memcpy(arr2, arr1, 28);
     
     return 0;
 ​
 }
 ​

结果:

屏幕截图 2024-12-03 190222.png

模拟实现memcpy

 #include<stdio.h>
 #include<ctype.h>
 #include<assert.h>
 void* my_memcpy(void* dest, void* src, size_t num)
 {
     assert(dest && src);
     void* ret = dest;
     //*dest=*str;//err void* 的指针不能解引用
     //*(int*)des = *(int*)src;//一次拷贝4个字节,如果num=25就不能拷贝了
     while (num--)
     {
         *(char*)dest = *(char*)src;//一个一个字节拷贝
         //void*不能直接dest++;
         dest = (char*)dest + 1;
         src = (char*)src + 1;
     }
     return ret;//返回目标空间起始地址,但是dest已经被改了
 ​
 }
 ​
 int main()
 {
     int arr1[] = { 1,2,3,4,5,6,7};
     int arr2[10] = { 0 };
     my_memcpy(arr1+2, arr1, 28);
     return 0;
 ​
 }

调试结果:

屏幕截图 2024-12-01 180620.png

 //如果将arr1中的1,2,3,4,5拷贝到3,4,5,6,7中,想要得到的结果为
 //arr1:1,2,1,2,3,4,5,8,9,10
 //能得到结果吗?
 #include<stdio.h>
 #include<ctype.h>
 #include<assert.h>
 void* my_memcpy(void* dest, void* src, size_t num)
 {
     assert(dest && src);
     void* ret = dest;
     while (num--)
     {
         *(char*)dest = *(char*)src;
         dest = (char*)dest + 1;
         src = (char*)src + 1;
     }
     return ret;
 }
 ​
 int main()
 {
     int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
     my_memcpy(arr1 + 2, arr1, 20);
     int i = 0;
     for (i = 0; i < 10; i++)
     {
         printf("%d ", arr1[i]);
     }
     return 0;
 ​
 }

打开调试窗口可以看到

屏幕截图 2024-12-03 191652.png

并没有拷贝成那样,为什么呢?

因为arr[2]改成1,arr[3]改成了2,arr[4]拷贝的是arr[2]的值,但是arr[2]的值也被修改

所以:

memcpy负责拷贝两块独立空间中的数据,不用来处理重叠的内存之间的数据拷贝

重叠内存的拷贝,是怎么的做呢? memmove

1.12 memmove

 void * memmove ( void * destination, const void * source, size_t num );
  • 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
  • 如果源空间和目标空间出现重叠,就得使用memmove函数处理。
 #include <stdio.h>
 #include <string.h>
 int main()
 {
     char arr1[100] = "abcdefghij";
     memmove(arr1 +2 , arr1, 20);
     
     int i = 0;
     printf("%s", arr1);
     return 0;
 }
 ​

结果:

屏幕截图 2024-12-03 193226.png

 #include <stdio.h>
 #include <string.h>
 int main()
 {
     char arr1[100] = "abcdefghij";
     memcpy(arr1 +2 , arr1, 20);
     
     int i = 0;
     printf("%s", arr1);
     return 0;
 }

我们发现在vs编译器下memcpymemmove结果相同,过度的完成了任务,将重叠现象也处理了,但专业的事交给专业的函数

模拟实现memmove

怎么拷贝呢?

方法1:重新创建一个数组———可以,但浪费空间

方法2:在一个数组中拷贝,那么就分为从前向后拷贝和从后向前拷贝

情况1:

1 2 3 4 5 6 7 8 9 10—src是4 5 6 7 8,dest是2 3 4 5 6 ,destsrc之前

从前向后拷贝

情况2:

1 2 3 4 5 6 7 8 9 10—src是4 5 6 7 8,dest是6 7 8 9 10,dest首在src之后有重叠

从后向前拷贝

情况3:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15—src是4 5 6 7 8,dest是9 10 11 12 13 ,destsrc之后没有重叠

从前向后拷贝和从后向前拷贝都可以

所以我们可以

情况1选择从前向后拷贝,情况2 情况3选择从那个后向前拷贝

 #include <stdio.h>
 #include <string.h>
 #include<assert.h>
 void* my_memmove(void* dest, void* src,size_t num)
 {
     assert(dest && src);
     void* ret = dest;
     if (dest < src)
     {
         //前->后
         while (num--)
         {
             *(char*)dest = *(char*)src;
             dest = (char*)dest + 1;
             src = (char*)src + 1;
         }
     }
     else
     {
         //后->前
         while (num--)
         {
             *((char*)dest + num) = *((char*)src + num);
 ​
         }
 ​
     }
     return ret;
 }
 ​
 ​
 int main()
 {
     int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
     my_memmove(arr1+2, arr1, 20);//结果1
     my_memmove(arr1, arr1+2, 20);//结果2
     
     int i = 0;
     for (i = 0; i < 10; i++)
     {
         printf("%d ", arr1[i]);
     }
     return 0;
 }
 ​
 //结果1:1 2 1 2 3 4 5 8 9 10
 //结果2:3 4 5 6 7 6 7 8 9 10

1.13 memcmp

内存比较,可以比较任意类型数据

 int memcmp ( const void * ptr1,  const void * ptr2, size_t num );
  • 比较从ptr1和ptr2指针开始的num个字节
  • 返回值如下:

屏幕截图 2024-12-03 203038.png

 #include<stdio.h>
 #include<string.h>
 int main()
 {
     int arr1[] = { 1,2,3,4,5 };
     //     1            2            3            4            5
     //01 00 00 00  02 00 00 00  03 00 00 00  04 00 00 00  05 00 00 00
     //     1            3             2
     //01 00 00 00  03 00 00 00  02 00 00 00 
     int arr2[] = { 1,3,2 };
     int ret = memcmp(arr1, arr2,12);
     printf("%d", ret);
     return 0;
 }
 ​
 //结果:-1

1.14 memsrt

内存设置

 void * memset ( void * ptr, int value, size_t num );
  • ptr 指向要填充的内存块的指针
  • value 待设定值,该值作为int传递,但该函数使用该值的unsigned char转换来填充内存块
  • num 要设置为value的字节数。size_t是无符号整数类型。
 示例1:
 #include <stdio.h>
 #include <string.h>
 int main()
 {
     char arr[] = "hhhhh hello";
     memset(arr, 'x', 5);
     printf("%s", arr);
     return 0;
 }
 ​
 //结果:xxxxx hello
 ​
 示例2:
 #include <stdio.h>
 #include <string.h>
 int main()
 {
     char arr[] = "hhhhh hello";
     memset(arr+6, 'x', 5);
     printf("%s", arr);
     return 0;
 }
 ​
 //结果:hhhhh xxxxx
 ​
 示例3:
 #include <stdio.h>
 #include <string.h>
 int main()
 {
     int arr[10] = { 0 };
     //把arr初始化为全1
     memset(arr, 1, 40);
     int i = 0;
     for (i = 0; i < 10; i++)
     {
         printf("%d\n", arr[i]);
     }
     return 0;
 }

结果:

屏幕截图 2024-12-03 205959.png

打印结果并不是全为1

memset是将40个字节每个字节都给成1,以字节为单位初始化