• 内存函数的介绍和模拟实现


    目录

    1.memcpy的使用(内存拷贝)

    2.memcpy的实现

    3.memmove的使用(内存拷贝)

     4.memmove的实现

    5.memset 的使用(内存设置)

    6.memcmp的使用(内存比较)


    1.memcpy的使用(内存拷贝)

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

    注意:对于拷贝时候内存存在重叠的情况,尽量不要使用memcpy。

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include
    4. //memcpy的使用
    5. struct {
    6. char name[40];
    7. int age;
    8. person,
    9. person_copy
    10. };
    11. int main()
    12. {
    13. char myname[] = "Pierre de Fermat";
    14. memcpy(person.name, myname, strlen(myname) + 1);//将‘\0’也拷贝过去
    15. person.age = 46;
    16. memcpy(&person_copy, &person, sizeof(person));
    17. printf("person_copy: %s, %d \n", person_copy.name, person_copy.age);
    18. return 0;
    19. }

    将myname数组中的数据拷贝到person.name中。

    2.memcpy的实现

    我们使用对内存进行操作的函数。因此我们应当想到为了在处理不同数据类型时候一个函数便能解决大部分问题,因此我们可以看出内存函数的参数和返回值大部分都是void类型,并且我们在对内存操作时想到的是对内存一个字节一个字节进行操作。

    1. #include
    2. void* my_memcpy(const void* des, const void* src, size_t num)
    3. {
    4. assert(des && src);
    5. const void* ret = des;
    6. //一个字节一个字节拷贝过去由此我们想到了char * 类型数据
    7. //数据拷贝
    8. int i = 0;
    9. for (i = 0; i < num; i++)
    10. {
    11. *(char*)des = *(char*)src;//转换类型便于对内存进行一个字节的操作
    12. des = (char*)des + 1;
    13. src = (char*)src + 1;
    14. }
    15. return ret;
    16. }
    17. int main()
    18. {
    19. char name1[20] = "zhouhaotianxxx";
    20. char name2[] = "wangxilong";
    21. //使用模拟的memcpy函数实现将name2中的数据拷贝到name1中
    22. puts("name1最初的字符串是:zhouhaotian\0");
    23. printf("name1中的数据经过拷贝后变成了:%s\n", my_memcpy(name1, name2, strlen(name2))); //注意memcpy函数在遇到 '\0' 的时候并不会停下来,他是忠心以字节个数来进行拷贝的
    24. return 0;
    25. }

    3.memmove的使用(内存拷贝)

    void * memmove ( void * destination, const void * source, size_t num );
    • 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
    • 如果源空间和目标空间出现重叠,就得使用memmove函数处理
    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include
    4. #include
    5. void* memmove(void* destination, const void* source, size_t num);
    6. 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
    7. 如果源空间和目标空间出现重叠,建议使用memmove函数处理。
    8. int main()
    9. {
    10. int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
    11. memcpy(arr, arr + 5, 20);
    12. for (int i = 0; i < 10; i++)
    13. {
    14. printf("%d ", arr[i]);
    15. }
    16. printf("\n");
    17. return 0;
    18. }//可以看出在vs2022下memcpy也可以对源空间和目标空间出现重叠情况进行处理。
    19. int main()
    20. {
    21. int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
    22. memmove(arr, arr + 5, 20);
    23. for (int i = 0; i < 10; i++)
    24. {
    25. printf("%d ", arr[i]);
    26. }
    27. printf("\n");
    28. return 0;
    29. }//如果源空间和目标空间出现重叠,建议使用memmove函数处理。

     4.memmove的实现

    由于我们知道了memcpy函数无法对内存块重叠情况下进行内存拷贝,由此我们需要使用或者实现一个新的函数能够完成此情况下的功能实现。

    我们先画图分析一下:

     我们可看到当源头指针和目的地指针在指向同一块内存空间的内容时,他们两指向的前后顺序将会影响我们内存的拷贝。

    第一种:

    •  src在dst之前,并且两者内容存在重叠的情况下:当我们仍然从前往后拷贝内容会发现我们想要拷贝的内容将会被覆盖,因此这种情况下我们应当从后往前拷贝。

     

    •  src在dst之后,并且两者内容存在重叠的情况下:当我们从后往前拷贝内容会发现我们想要拷贝的内容将会被覆盖,因此这种情况下我们应当从前往后拷贝。 

    •  而当内容并无内存重叠情况下我们从前往后拷贝或者从后往前拷贝便可以根据我们个人意愿来实现如何拷贝,下面给出代码实现。
    1. #include
    2. #include
    3. #include
    4. void* my_memmove(const void* dst, const void* src, size_t num)
    5. {
    6. assert(dst && src);
    7. const void* ret = dst;
    8. //一个字节一个字节拷贝
    9. //数据拷贝
    10. int i = 0;
    11. //从后往前拷贝
    12. if (dst > src)
    13. {
    14. src = (char*)src + num - 1;
    15. dst = (char*)dst + num - 1;
    16. for (i = 0; i < num; i++)
    17. {
    18. *(char*)dst = *(char*)src;
    19. dst = (char*)dst - 1;
    20. src = (char*)src - 1;
    21. }
    22. }
    23. //从前面往后面拷贝
    24. if (dst <= src)
    25. {
    26. for (i = 0; i < num; i++)
    27. {
    28. *(char*)dst = *(char*)src;
    29. dst = (char*)dst + 1;
    30. src = (char*)src + 1;
    31. }
    32. }
    33. return ret;
    34. }
    35. int main()
    36. {
    37. int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
    38. my_memmove(arr, arr + 2, 8);//模拟实现重叠内存拷贝函数
    39. for (int i = 0; i < 10; i++)
    40. {
    41. printf("%d ", arr[i]);
    42. }
    43. //结果应该是3 4 3 4 5 6 7 8 9 10
    44. printf("\n");
    45. return 0;
    46. }

    5.memset 的使用(内存设置)

    void * memset ( void * ptr, int value, size_t num );
    • 这个函数用于将 prt 指向的内存区域的前 num 个字节设置为 value 指定的值。它返回 ptr 的起始地址。
    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include
    4. //memset的使用
    5. //以字节为单位设置内存
    6. int main()
    7. {
    8. char arr[] = "hello world";
    9. memset(arr + 2, 'x', 3);
    10. printf("%s\n", arr);
    11. return 0;
    12. }

    注意:memset是以字节为单位来设置内存的 !

    6.memcmp的使用(内存比较

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

    返回值如下图:

    • memcmp比较比较的是内存块(可以指定比较字节数)
    • 而strcmp只能比较字符串

     

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include
    4. //memcmp的使用
    5. int main()
    6. {
    7. int a[] = { 1,2,3,4,5,6,7 };
    8. int b[] = { 1,2,3,5, };
    9. printf("%d\n", memcmp(a, b, 12));
    10. printf("%d\n", memcmp(a, b, 16));
    11. return 0;
    12. }


    希望大佬们一键三连,您的支持是对我最大的鼓励! 

  • 相关阅读:
    Spring源码解析——事务的回滚和提交
    如何通过函数获取股票量化交易行情数据?
    事务(1)
    MSQL系列(八) Mysql实战-SQL存储引擎
    大规模 IoT 边缘容器集群管理的几种架构-0-边缘容器及架构简介
    pytorch 介绍以及常用工具包展示
    【Linux篇】之常用命令
    51单片机-DS1302可调时钟(实现代码)
    day51
    声网自研传输层协议 AUT 的落地实践丨Dev for Dev 专栏
  • 原文地址:https://blog.csdn.net/AlanTZT/article/details/133322444