• 内存重叠,直到做到一个笔试题才知道了什么是内存重叠。先上题目吧,是一个淘宝的笔试题,当时有点懵,不知道这个名词是啥子意思。
  • 题目:补充下面函数代码:
    如果两段内存重叠,用memcpy函数可能会导致行为未定义。 而memmove函数能够避免这种问题,下面是一种实现方式,请补充代码。

    • #include <iostream>
      using namespace std;
      void* memmove(void* str1,const void* str2,size_t n)
      {
      char* pStr1= (char*) str1;
      const char* pStr2=(const char*)str2;
      if ( ) {
      for(size_t i=;i!=n;++i){
      *(pStr1++)=*(pStr2++);
      }
      }
      else{
      pStr1+=n-;
      pStr2+=n-;
      for(size_t i=;i!=n;++i){
      *(pStr1--)=*(pStr2--);
      }
      }
      return ( );
      } 在上面的两个括号中插入对应的内容 答案:pstr1<pstr2 str1

      在这里我理解的内存重叠大致上应该是在strcpy以及memcpy等内存拷贝函数出现的问题。strcpy函数内存重叠可能会使程序崩溃,这里我先讲一个比较简单的例子来看一下。

    • #include <string.h>
      #include <stdlib.h>
      #include <stdio.h>
      int main(){
      char *p = NULL;
      p = (char *)malloc();
      memcpy(p,"",strlen(""));
      printf("before p = %s/n", p);
      strcpy(p+,p);//这重叠了
      printf("after p = %s/n", p);
      free(p);
      }

      上面的这个例子中发生了内存重叠问题,这就导致了拷贝发生了异常,不会拷贝一样的数据。我跑这个代码的时候居然没有报错,程序也没炸,我也就有点好奇了。按理来memcpy,strcpy这两个函数没有对内存重叠进行处理。使用这两个函数的时候只有程序员自己保证源地址与目标地址内存不重叠。所以当会发生内存重叠的时候最好使用memmov函数进行内存拷贝。

      自己查了一些资料,原来memcpy有一个长度参数,只拷贝cnt个字节就结束了,所以会得到正确的结果,但是strcpy函数知道拷贝到\0这个标志符才会结束,所以就会导致程序崩溃了。

  •   memcpy和memmov函数原型和区别
    •   1.memmove

      函数原型:void *memmove(void *dest, const void *source, size_t count)

      返回值说明:返回指向dest的void *指针

      参数说明:dest,source分别为目标串和源串的首地址。count为要移动的字符的个数

      函数说明:memmove用于从source拷贝count个字符到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。

    •   2.memcpy

      函数原型:void *memcpy(void *dest, const void *source, size_t count);

      返回值说明:返回指向dest的void *指针

      函数说明:memcpy功能和memmove相同,但是memcpy中dest和source中的区域不能重叠,否则会出现未知结果。

  •   实现一个memmov函数
    •   

      #include <iostream>
      #include <string.h>
      using namespace std; void *memmove(void * dst, const void *src, size_t count){
      //特殊情况错误处理
      if (src == NULL || dst == NULL)
      return NULL;
      unsigned char *pdst = (unsigned char *)dst;
      const unsigned char *psrc = (const unsigned char *)src; //判断内存是否重叠
      bool flag1 = (pdst >= psrc && pdst < psrc + count);
      bool flag2 = (psrc >= pdst && psrc < pdst + count);
      //上面两个标志其中有一个成立,保证内存并不是重叠的,与拷贝的长度有关 if (flag1 || flag2){//内存重叠
      //倒序拷贝
      while (count){
      *(pdst + count - ) = *(psrc + count - );
      count--;
      }
      }
      else{//不重叠
      while (count--){
      *pdst = *psrc;
      pdst++;
      psrc++;
      }
      }
      return dst;
      } int main(){
      //内存重叠的情况
      char str[] = "hello world";
      memmove(str + , str, );
      cout<<"memmove result is :"<<str<<endl; //内存不重叠
      char str2[] = "hello world";
      char str3[] = "you are ";
      memmove(str2, str3, );
      cout<<"memmove result is :"<<str2<<endl;
      }

      实现思路就是要去判断是否内存重叠,重叠的话就倒序的拷贝,非重叠的话就从前往后拷贝就行了。这个例子也很好的解释了前面的那个题目的情况。其实前面的那个情况还可以用一个图片来解释。

    • 这张图片就是这两种情况的实现。

C++中的内存重叠问题的更多相关文章

  1. C++中两块内存重叠的string的copy方法

    如果两段内存重叠,用memcpy函数可能会导致行为未定义. 而memmove函数能够避免这种问题,下面是一种实现方式: #include <iostream> using namespac ...

  2. Windows内核中的内存管理

    内存管理的要点 内核内存是在虚拟地址空间的高2GB位置,且由所有进程所共享,进程进行切换时改变的只是进程的用户分区的内存 驱动程序就像一个特殊的DLL,这个DLL被加载到内核的地址空间中,Driver ...

  3. memmove 和 memcpy的区别以及处理内存重叠问题

    区别: memcpy和memmove()都是C语言中的库函数,在头文件string.h中,作用是拷贝一定长度的内存的内容,原型分别如下: void *memcpy(void *dst, const v ...

  4. [整理]内存重叠之memcpy、memmove

    函数原型: void *memcpy( void *dest, const void *src, size_t count ); void *memmove( void* dest, const vo ...

  5. strcpy,memcpy,memmove和内存重叠分析

    一:strcpy函数用法和实现: /* GNU-C中的实现(节选): */ char* strcpy(char *d, const char *s) { char *r=d; while((*d++= ...

  6. C语言标准库函数memcpy和memmove的区别以及内存重叠问题处理

    ①memcpy()和memmove()都是C语言中的标准库函数,定义在头文件string.h中,作用是拷贝一定长度的内存的内容,原型分别如下: void *memcpy(void *dst, cons ...

  7. 转:Linux中的内存管理

    前一段时间看了<深入理解Linux内核>对其中的内存管理部分花了不少时间,但是还是有很多问题不是很清楚,最近又花了一些时间复习了一下,在这里记录下自己的理解和对Linux中内存管理的一些看 ...

  8. C++ 浅析调试,内存重叠查看

    这里举个例子查看内存, 环境为:vs 2017 测试为strcpy[因为测试老api,需要在 预处理中 添加 _CRT_SECURE_NO_WARNINGS ] 测试问题:内存溢出 源码: #incl ...

  9. 在 CUDA C/C++ kernel中使用内存

    在 CUDA C/C++ kernel中使用内存 如何在主机和设备之间高效地移动数据.本文将讨论如何有效地从内核中访问设备存储器,特别是 全局内存 . 在 CUDA 设备上有几种内存,每种内存的作用域 ...

随机推荐

  1. main函数的参数的用法

    说明:main函数的参数的用法源代码: #include <stdio.h>#include <stdlib.h>int main(int argc, char *argv[] ...

  2. Qt之事件处理机制

    思维导读 一.事件简介 QT程序是事件驱动的, 程序的每个动作都是由内部某个事件所触发.QT事件的发生和处理成为程序运行的主线,存在于程序整个生命周期. 常见的QT事件类型如下: 键盘事件: 按键按下 ...

  3. webrtc windows下的编译

    mkdir webrtc-checkoutcd webrtc-checkout set DEPOT_TOOLS_WIN_TOOLCHAIN=0set GYP_GENERATORS=ninjaset G ...

  4. 【Linux网络编程】基于TCP流 I/O多路转接(poll) 的高性能http服务器

    服务器比较简陋,为了学习poll的使用,只向客户端回写一条html语句.启动服务器后,浏览器发起请求,服务端向浏览器写回html,响应字符串,然后可以看到,浏览器解析并显示 Hello Poll!. ...

  5. 数据格式化和ModelAttribute注解的介绍

    关于数据传递: 客户端传递数据到服务端: 1.使用普通的形式 A.传递简单的数据 如果是说你传递的数据的名称跟控制层中的形参的名称不一致的情况下需要使用 注解: @RequestParam()如果存在 ...

  6. springboot或者jetty等启动服务器后,如何去停止这个服务

    首先在win7下找到运行,但是win7的运行不像XP那么好找,win7运行的位置在:开始→所有程序→附件→运行.   然后在对话框中,输入cmd(大小写均可).   然后是如何查看80端口的方法,一般 ...

  7. IDEA编译器如何去掉注释中参数错误的提示

    在使用idea的导入别人的项目的时候经常会在方法注释中出现参数错误的提示,这时我们可以参考下面的配置,将方法注释中的参数错误的提示,更新为警告提示~~ 具体使用方法,参考下图~

  8. 最新版CocoaPods的安装流程

    1.移除现有Ruby默认源 $gem sources --remove https://rubygems.org/ 2.使用新的源 $gem sources -a https://ruby.taoba ...

  9. C# IL中间代码注入实现切面编程

    背景及现状:之前分享的那篇“面向切面编程–渲染监控日志记录方案”中提供了利用RealProxy作为代理类来生成代理的面向切面的编程方法,那个方法可以实现面向切面编程进行日志记录,现在渲染主程序也是采用 ...

  10. jackson2.x与Jackson1.9的比较

    Jackson可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json.xml转换成Java对象.Jackson库于2012.10.8号发布了最新的2.1版.Jackson源码目前 ...