• C-内存函数(大量图解,函数实现)


    目录

    一.memcpy

    二.memmove

    三.memcmp

    四.memset


    一.memcpy

    头文件:

    #include

    函数原型: 

    功能解析:

    • 目的地址和源头地址,类型是void*可以接收任意类型
    • 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
    • 这个函数在遇到 '\0' 的时候并不会停下来。
    • 如果source和destination有任何的重叠,复制的结果都是未定义的(在VS2022中,是不会出现重叠的

     函数模拟实现:

    在实现函数前我们需要测试一下,几种常见的异常情况:

    1.拷贝0字符

    2.传入空指针

     我们再来看这个代码正常运行情况:

    程序居然没有崩溃什么都没有发生

    3.拷贝数传入负数

    小数就不用多说了,类型都完全不同 

    实现: 

      异常判断

    1. void* my_memcpy(void* dest, const void* src, size_t num)
    2. {
    3. //异常判断
    4. if ((dest == NULL) || (src == NULL))
    5. {
    6. perror("my_memcpy");
    7. return NULL;//结束函数
    8. }
    9. if (num == 0)//如果拷贝0个直接返回目的地地址,就不用浪费时间了
    10. {
    11. return dest;
    12. }
    13. }

     模拟实现:

    1. void* my_memcpy(void* dest, const void* src, size_t num)
    2. {
    3. //异常判断
    4. if ((dest == NULL) || (src == NULL))
    5. {
    6. perror("my_memcpy");
    7. return NULL;
    8. }
    9. if (num == 0)
    10. {
    11. return dest;
    12. }
    13. //正常拷贝
    14. void* str = dest;
    15. while (num--)
    16. {
    17. *(char*)str = *(char*)src;
    18. src = (char*)src + 1;
    19. str = (char*)str + 1;
    20. }
    21. return dest;
    22. }

    运行结果: 

    补充:!!! 

    这个时候可能就有朋友会说,啊!你负数都没有处理,我也想过去处理发现各种方式都不行,后来才知道,有的时候就不用去处理,库里面的函数num是siz_t类型,你要传负数可以,那他就会变成一个很大的数,大不了就是栈溢出,栈溢出是你使用函数不当,我函数没有问题

    还有一种情况,重合的空间:

    1.前到后地址

     

     2.后到前地址

     我们得出结论:

    • 从前(低地址) -> 后(高地址)反方向拷贝
    • 从后(高地址) -> 前(低地址)从前拷贝

    在C语言中用memmove函数就可以实现

    二.memmove

    函数头文件:

    #include

    函数原型:

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

     模拟实现:

    1. void* my_memmove(void* dest, const void* src, size_t num)
    2. {
    3. //异常判断
    4. if ((dest == NULL) || (src == NULL))
    5. {
    6. perror("my_memcpy");
    7. return NULL;
    8. }
    9. if (num == 0)
    10. {
    11. return dest;
    12. }
    13. //正常拷贝
    14. void* str = dest;
    15. if (str < src)
    16. {
    17. while (num--)
    18. {
    19. *(char*)str = *(char*)src;
    20. src = (char*)src + 1;
    21. str = (char*)str + 1;
    22. }
    23. }
    24. else
    25. {
    26. while (num--)
    27. {
    28. *((char*)str + num) = *((char*)src + num);
    29. }
    30. }
    31. return dest;
    32. }

    代码段解析:

     代码结果: 

    memmove:

    memcpy:

    但是在vs2022中memcpy也是可以完成重叠空间的拷贝的,这就得取决于编译器了

    三.memcmp

    函数头文件:

    #include

    函数原型:

     返回值解析:

    函数细节:

    1.他是一个一个字节比较的,两个地址的字节相同,就比较下一个字节,一直比较到不同的,根据规定返回,或者到末尾返回0

    函数实现准备:

    老样子先去测试一下常见的一些意外情况

    1.空指针

    2.

    3.num传入0

     4.num传入负数和上面的memcpy不处理就好

    模拟实现:

    1.意外判断

    1. int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
    2. {
    3. //异常判断
    4. if ((ptr1 == NULL) || (ptr2 == NULL))
    5. {
    6. perror("my_memcmp:");
    7. return NULL;//结束函数
    8. }
    9. if (num == 0)
    10. {
    11. return -1;
    12. }
    13. }

    2. 正确实现

    1. int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
    2. {
    3. //意外判断
    4. if ((ptr1 == NULL) || (ptr2 == NULL))
    5. {
    6. perror("my_memcmp:");
    7. return NULL;//结束函数
    8. }
    9. if (num == 0)//如果没有这个if下面的返回值任然会计算
    10. {
    11. return -1;
    12. }
    13. //正常运转
    14. const char* str1 = (const char*)ptr1;
    15. const char* str2 = (const char*)ptr2;
    16. while ((*str1 == *str2) && (num > 0))//不大于0为假
    17. {
    18. str1++;
    19. str2++;
    20. num--;
    21. }
    22. if (*str1 - *str2 > 0)
    23. return 1;
    24. else if (*str1 == *str2)
    25. return 0;
    26. return -1;
    27. //也可以直接 return (*str1 - *str2);
    28. }

    运行结果:

     各种情况都是正确的


    四.memset

    头文件:

    #include

    函数原型:

     函数使用:

    1.

    2.

     3.

    制作不易,你们的支持是作者最大的动力!!!

  • 相关阅读:
    三篇论文入选国际顶会SIGMOD,厉害了腾讯云数据库
    MapReduce & YARN 的部署
    武田公司2022财年第一季度业绩强劲;正稳步实现全年的管理层指引目标
    Qt+openCV学习笔记(十六)Qt6.6.0rc+openCV4.8.1+emsdk3.1.37编译静态库
    【postgresql 基础入门】插入数据的多种方式 单条,多值,查询结果,插入数据冲突处理,批量导入,多种方式让数据插入更灵活
    MATLAB | 那些你不得不知道的MATLAB小技巧(三)
    2022年最新河北建筑八大员(机械员)模拟考试题库及答案
    第七章第一节:顺序查找和折半查找
    OFDM 十六讲 6 Inter symbol Interference
    865. 具有所有最深节点的最小子树
  • 原文地址:https://blog.csdn.net/Lizhihao_/article/details/127434029