• C++中的内存重叠问题


    • 内存重叠,直到做到一个笔试题才知道了什么是内存重叠。先上题目吧,是一个淘宝的笔试题,当时有点懵,不知道这个名词是啥子意思。
    • 题目:补充下面函数代码:
      如果两段内存重叠,用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=0;i!=n;++i){
                    *(pStr1++)=*(pStr2++);
                }
            }
            else{
                pStr1+=n-1;
                pStr2+=n-1;
                for(size_t i=0;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(10);
                memcpy(p,"1234679",strlen("1246789"));
                printf("before p = %s/n", p);
                strcpy(p+1,p);//这重叠了
                printf("after p = %s/n", p);
                free(p);
        }

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

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

    •   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 - 1) = *(psrc + count - 1);
                    count--;
                }
            }
            else{//不重叠
                while (count--){
                    *pdst = *psrc;
                    pdst++;
                    psrc++;
                }
            }
            return dst;
        }
        
        int main(){
            //内存重叠的情况
            char str[] = "hello world";
            memmove(str + 3, str, 8);
            cout<<"memmove result is :"<<str<<endl;
        
            //内存不重叠
            char str2[] = "hello world";
            char str3[] = "you are ";
            memmove(str2, str3, 8);
            cout<<"memmove result is :"<<str2<<endl;
        }
        实现思路就是要去判断是否内存重叠,重叠的话就倒序的拷贝,非重叠的话就从前往后拷贝就行了。这个例子也很好的解释了前面的那个题目的情况。其实前面的那个情况还可以用一个图片来解释。


      • 这张图片就是这两种情况的实现。
  • 相关阅读:
    模板方法模式
    外观模式
    《那些年啊,那些事——一个程序员的奋斗史》——128 (终章)
    《那些年啊,那些事——一个程序员的奋斗史》——127
    《那些年啊,那些事——一个程序员的奋斗史》——127
    分布式系统开发里必须要解决的3个技术问题
    《那些年啊,那些事——一个程序员的奋斗史》——128 (终章)
    列举几种系统调用
    linux core文件设置
    《那些年啊,那些事——一个程序员的奋斗史》——127
  • 原文地址:https://www.cnblogs.com/Kobe10/p/6023177.html
Copyright © 2020-2023  润新知