• 内存函数 memcpy 和 memmove 的讲解和模拟实现



    目录

    一.什么是 memcpy 函数

    模拟思路

    代码实现 

    二.什么是 memmove 函数

    模拟思路

    代码实现


    一.什么是 memcpy 函数

    我们打开 cplusplus 官网查看:

    memcpy - C++ Reference (cplusplus.com)

    官方文本显示:

    内存复制块

    • 将 num 字节的值从源指向的位置直接复制到目标指向的内存块
    • 源指针和目标指针所指向的对象的底层类型与此函数无关;结果是数据的二进制副本
    • 该函数不检查源中是否有任何终止null字符——它总是精确地复制num个字节
    • 为了避免溢出,目标参数和源参数所指向的数组的大小应该至少为 num 字节,并且不应该重叠(对于重叠的内存块,memmove 是一种更安全的方法)

    上述文本可能不够直观,我们使用官方提供的例子观察他的具体作用:

    1. /* memcpy example */
    2. #include
    3. #include
    4. struct
    5. {
    6. char name[40];
    7. int age;
    8. } person, person_copy;
    9. int main()
    10. {
    11. char myname[] = "Pierre de Fermat";
    12. /* using memcpy to copy string: */
    13. memcpy(person.name, myname, strlen(myname) + 1);
    14. person.age = 46;
    15. /* using memcpy to copy structure: */
    16. memcpy(&person_copy, &person, sizeof(person));
    17. printf("person_copy: %s, %d \n", person_copy.name, person_copy.age);
    18. return 0;
    19. }

     输出结果:

            结合代码和输出结果来看,我们申明了俩个结构体,并且我们手动给结构体 person 的俩个变量进行了赋值,而结构体 person_copy 我们并没有对其初始化赋值,我们使用了 memcpy 函数将结构体 person 中的值复制给了结构体 person_copy ,然后我们打印输出 person_copy 中的变量的值,发现我们确实是拿到了这俩个值

    模拟思路

    当我们拿到一个字符串后,首先要确定复制的起点位置和复制目标的起点位置

    然后逐一复制字节

    代码实现 

            在这里,我们使用 void* 的指针来拿到各种数据类型的地址,然后强制转化为 char* 方便我们对单个字节进行访问(字符型指针解引用只能访问一个字节),函数参数方面,只需要拿到俩个地址加上需要复制多少个字节的大小的值就可以了

    1. void* my_memcpy(void* dest, const void* src, size_t sz)
    2. {
    3. void* ret = dest;
    4. assert(dest && src);
    5. while (sz--)
    6. {
    7. *(char*)dest = *(char*)src;
    8. dest = (char*)dest + 1;
    9. src = (char*)src + 1;
    10. }
    11. return ret;
    12. }

    二.什么是 memmove 函数

    我们打开 cplusplus 官网查看:

    memmove - C++ Reference (cplusplus.com)

    官方文本显示:

    移动内存块

    • 将 num 字节的值从源指向的位置复制到目标指向的内存块。复制就像使用了中间缓冲区一样进行,从而允许目标和源重叠
    • 源指针和目标指针所指向的对象的底层类型与此函数无关;结果是数据的二进制副本
    • 该函数不检查源中是否有任何终止 null 字符——它总是精确地复制 num 个字节
    • 为了避免溢出,目的参数和源参数所指向的数组的大小至少为 num 字节

    上述文本可能不够直观,我们使用官方提供的例子观察他的具体作用:

    1. /* memmove example */
    2. #include
    3. #include
    4. int main ()
    5. {
    6. char str[] = "memmove can be very useful......";
    7. memmove (str+20,str+15,11);
    8. puts (str);
    9. return 0;
    10. }

    输出结果:

            我们可以看见,原本的字符串是 memmove can be very useful...... 但是输出的却是 memmove can be very useful. 也就是我们将后半部分的 very useful 往后移动了一段距离

    模拟思路

            在模拟实现这个功能之前,有一点值得注意,相较于之前的 memcpy 函数,这里的 memmove 函数在移动的时候,内部是有重复部分的,如果还是按照上面那种方法实现的话,会出现数据反复覆盖导致丢弃了真实数据的情况,如图所示

    对于这个情况,我们换一个交换字节的顺序就可以解决,如图

            也就是说,我们只需要做出合理的判断,选择正确的顺序,就可以实现功能,根据我们的经验,如果我们要实现的是从前往后移动拷贝的话,那我们就从后往前访问,反之,如果我们要从后往前移动拷贝的话,那我们就从前往后访问

    代码实现

    1. void* my_memmove(void* dest, const void* src, size_t sz)
    2. {
    3. assert(dest && src);
    4. void* ret = dest;
    5. if (dest < src)
    6. {
    7. //前->后
    8. int i = 0;
    9. for (i = 0; i < sz; i++)
    10. {
    11. *(char*)dest = *(char*)src;
    12. dest = (char*)dest + 1;
    13. src = (char*)src + 1;
    14. }
    15. }
    16. else
    17. {
    18. //后->前
    19. while (sz--)
    20. {
    21. *((char*)dest+sz) = *((char*)src + sz);
    22. }
    23. }
    24. return ret;
    25. }

    本次分享就到此为止了,如有错误欢迎积极指出,希望我的分享能给您带来帮助

  • 相关阅读:
    Vue-cli 搭建 SPA 项目,Vue 项目结构说明,开发示例,以及如何修改端口号,install 命令中的 -g,-S,-D 参数,嵌套路由,package.json 详解
    哈希及其应用
    ABAP技术总结2022.8.30(ALV和smart forms)
    2022谷粒商城学习笔记(二十二)rabbitMQ学习
    大工业用电计费及其相关知识
    互联网上门洗衣洗鞋店小程序开发;
    关于海量级存储用户标签体系架构
    (数字图像处理MATLAB+Python)第十二章图像编码-第三、四节:有损编码和JPEG
    二十一、数组(3)
    开发上门送桶装水小程序要考虑哪些业务场景
  • 原文地址:https://blog.csdn.net/m0_69519887/article/details/133180924