C语言之内存覆盖

时间:2020-12-09 01:32:29

   在实现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\n",str1);

 

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

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

}

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

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

C语言之内存覆盖
    当源字符串给目标字符串赋值时,即从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;

}