以前发表过关于字符串拷贝函数的实现和分析,那么为什么有了字符串拷贝函数,还需要内存拷贝函数?

    一.关于内存拷贝函数的原型和实现。

    原型:

    void *memmove( void *dest, const void *src, size_t count );

    实现:

    void* my_memmove(void* p1, void* p2, size_t count)

     {

     assert(p1);

     assert(p2);

     char *dest = (char *)p1;

     char *src = (char *)p2;

     if ((dest > src) && (dest < src + count))

     {

     while (count--)

     {

     *(dest + count) = *(src + count);

     }

     }

         else

         {

         while (count--)

         {

     *dest = *src;

     dest++;

     src++;

     }

     }

     return p1;

     }

   二.内存拷贝函数的意义

    1).首先关注函数的参数,void类型指针,告诉我们内存拷贝函数可以接受任意类型。所以就产生一个问题--类型强制转换。为了说明这个问题我们首先看一段程序分析一下。

    void *my_memmove(char *dest,const char *src,size_t count)

    {

       assert(dest);

        assert(src);

        ......

    }

上面写的也是内存拷贝函数的一种实现,但是是比较挫的一种实现方式。试着分析一下,这个函数只接收char类型的指针,那么如果要改变的是float型的指针,要怎么办?在传参的时候强制类型转换?那岂不是很麻烦,每当使用这个函数的时候,只要不是char类型的指针都需要强制类型转换。那么,有没有一种一劳永逸的做法?肯定是有,将函数的参数设置成void型,就万事大吉了。只需要在函数实现的内部强制类型转换。

    2).内部强制类型转换需要注意的问题

    首先应该知道在32位平台上,int型占4字节,float型占4字节,char型占1字节,double型占8字节。那么在函数内部强制类型转换的时候应该转换成什么型呢?

    看一个小程序:

void* my_memmove(void* p1, void* p2, size_t count)

     {

     assert(p1);

     assert(p2);

     double *dest = (double *)p1;

     double *src = (double *)p2;

     if ((dest > src) && (dest < src + count))

     {

     while (count--)

     {

     *(dest + count) = *(src + count);

     }

     }

         else

     {

     while (count--)

     {

     *dest = *src;

     dest++;

     src++;

     }

     }

     return p1;

     }

    

    

     int main()

     {

     int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

     int i = 0;

     my_memmove(arr + 4, arr + 2, 16);

     for (i = 0; i < 10; i++)

     {

     printf("%d\n", arr[i]);

     }

     system("pause");

     return 0;

     }

   当把传进来的参数强制转化为double 程序出现奔溃。试着分析一下。

    (1).在内存中数组arr是以4个字节存储,但是在内存拷贝的时候是以8个字节为单位拷贝,说的直白一点就是,要把数组中第一个和第二个元素(1和2)拷贝到8个字节中,那么在输出的时候是用四个字节输出的。输出的内容就是

wKiom1ZPEzvCQ5vdAAAozGEQk9w053.png


    我们会发现输出的并不是我们想要的。我们要的是 1 2 3 4 3 4 5 6 9 10.

    (2)那么用强制转换成什么类型最合适?

    不难发现,让指针转换成char类型不会出错。原因就不再啰嗦了。

    三.程序为什么分为两种情况?

    1).一种情况是从后向前拷贝,一种是从前向后拷贝。

    2).试着分析

         int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        my_memmove(arr + 4, arr + 2, 16);

    从前向后拷贝的时候,3放在5的位置,4放在6的位置,该拷贝5的时候,5已经变成了3.和我们的初衷不一样,所以引入了从后向前拷贝的情况。

    
    以上就是本人在学习过程中的一些经验总结。当然,本人能力有限,难免会有纰漏,希望大家可以指正。