zoukankan      html  css  js  c++  java
  • C语言之内存覆盖

       在实现memcpy函数的时候,我们说过要考虑内存覆盖的问题,到底什么是内存覆盖呢,他的出现对程序到底有什么影响呢?我们又要如何去解决这种问题的发生?

    首先先看一般人经常实现的memcpy函数:

    #include<stdio.h>

    #include<assert.h>

    #include<string.h>

    void *my_memcpy(void *dest, const void *src, size_t count)

    {

         assert(dest!=NULL || src!=NULL);

         char *ptmpDest = (char *)dest;

         const char *ptmpSrc = (const char *)src;

         while(count-- > 0)

        {

             *ptmpDest++ = *ptmpSrc++;

        }

        return dest;

    }

       乍一看这段代码,好像很有道理,经过一些测试也是对的,但程序到底是哪里出了问题呢?首先我们来测试一下:

    void main()

    {

          char str[20] = "abcdefghij";

          char str1[20];

          my_memcpy(str1,str,strlen(str)+1);//正确拷贝

          printf("str1 = %s ",str1);

          my_memcpy(str+2,str,4);//错误,拷贝出现了内存覆盖

         printf("str = %s ",str);

    }

    我们发现当字符串自己给自己赋值时,当目标字符串大于源字符串要拷贝的字符的个数时,程序就会出现错误,这里就涉及到了内存覆盖问题。

    我们首先分析源字符串与目标字符串之间的关系:

        当源字符串给目标字符串赋值时,即从src给dest赋值时,情况二会出现问题。我们知道目标字符串和源字符串都是在操作一个字符串,在情况二中,当src给dest赋值直到dest的开始时,即不超过dest的偏移量时都没有什么问题,但是一旦超过偏移量,由于前面的赋值操作已经将字符串给改变了,然后再用改变过后的字符串再给dest赋值,这就导致了前面内容复制重复了,也就是发生内存覆盖了。在分析其他情况时我们可以发现程序都不会出现内存覆盖问题。
        要解决这个问题其实也不难,我们先明确要拷贝几个字符,找到要拷贝的最后一个字符,然后从后向前依次拷贝:

    while(count-- > 0)

    {

          *(ptmpDest + count) = *(ptmpSrc + count);

    }

        我们再来分析其他五种情况,可以得出他们的判断条件是:

       ptmpSrc >= ptmpDest || ptmpDest >= ptmpSrc+count

    只要满足上面的条件就不需要考虑内存重叠的问题,所以实现整体自己实现memcpy的函数代码为:

    #include<stdio.h>

    #include<assert.h>

    #include<string.h>

    void *my_memcpy(void *dest, const void *src, size_t count)

    {

         assert(dest!=NULL || src!=NULL);

         char *ptmpDest = (char *)dest;

         const char *ptmpSrc = (const char *)src;

    //源地址在目的地址的右边,或者目的地址在源地址的右边,但没有交集

    //直接拷贝

         if(ptmpSrc >= ptmpDest || ptmpDest >= ptmpSrc+count)

        {

             while(count-- > 0)

             {

                *ptmpDest++ = *ptmpSrc++;

             }

        }

         else //源地址在目的地址左边,并产生交集,形成内存覆盖,反着拷贝

        {

             while(count-- > 0)

            {

                 *(ptmpDest + count) = *(ptmpSrc + count);

            }

        }

         return dest;

    }

     
  • 相关阅读:
    写了个限制文本框输入最大长度的jquery插件
    A2D JS框架
    在.Net中执行js
    C# Socket的粘包处理
    分布式EventBus的Socket实现
    读写分离子系统
    缓存子系统如何设计(Cachable tag, Memcache/redis support, xml config support, LRU/LFU/本地缓存命中率)
    pip install在Windows下报错解决
    Centos 6.9安装配置MongoDB
    Centos6.9安装Node.js+npm爬坑
  • 原文地址:https://www.cnblogs.com/qingjiaowoxiaoxioashou/p/5689780.html
Copyright © 2011-2022 走看看