zoukankan      html  css  js  c++  java
  • memcpy的使用方法总结

    1、memcpy 函数用于 把资源内存(src所指向的内存区域) 复制到目标内存(dest所指向的内存区域);拷贝多少个?有一个size变量控制
    拷贝的字节数;
    函数原型:void *memcpy(void *dest, void *src, unsigned int count);
    使用方法:(1)能够拷贝不论什么类型的对象,由于函数的參数类型是void*(没有定义类型指针),也就是说传进去的实參能够是int*,short*,char*等等,
    可是由于函数拷贝的过程是一个字节一个字节的拷贝的,所以实际操作的时候要把void*强制转化为char*,这样在指针加的时候才会保证每次加一个字节,呵呵
    函数源码实现:
    void *memcpy1(void *desc,const void * src,size_t size)
    {
     if((desc == NULL) && (src == NULL))
     {
      return NULL;
     }
     unsigned char *desc1 = (unsigned char*)desc;
     unsigned char *src1 = (unsigned char*)src;
     while(size-- >0)
     {
      *desc1 = *src1;
      desc1++;
      src1++;
     }
     return desc;
    }

    int _tmain(int argc, _TCHAR* argv[])
    {
     int dest[2] = {0};
     const char src[5] = "1234";
     //printf(src);
     memcpy1(dest,src,sizeof(src));
     //*(dest+5) = '/0';
     printf((char *)dest);
     int m = -1;
     return 0;
    }
    注意事项:(1)void* 一定要返回一个值(指针),这个和void不太一样!
              (2)首先要推断指针的值不能为空,desc为空的话肯定不能拷贝内存空间,src为空相当于没有拷贝;所以之间return掉;
              (3)""空串是指内容为0,NULL是0,不是串;两个不等价;
              (4)int dest[2] = {0};这是对int 类型的数组初始化的方法;假设是char类型,就用char a[5] = "1234";  注意数组下标要
                   多于实际看到的字符数,由于还有'/0'
              (5)printf((char *)dest);这句话,是把 char 类型 src 传到 int 类型的 dest的内存强制转化成char类型,然后打印出来;
                   由于直接看int类型的dest是看不到里面的内容的;由于有unsigned char *desc1 = (unsigned char*)desc;所以字符能够传
                   到dest里面保存起来,dest所指向的内存长度4个字节,强制转化为char 就是把四个字节分成一个一个的字节,这样就能够看到
                   一个个字符了,假设定义成char dest[5] = "1234";就不用转化;呵呵,表达起来真累人;
              (6)memcpy1(dest,src,sizeof(src));注意里面的sizeof(src),这个是包括字符串的结束符'/0'的;所以不用操心printf(dest);
                   可是假设用memcpy1(dest,src,4);没有'/0'就要*(dest+5) = '/0';这样保证是一个完整的字符串;
              (7)假设初始化的时候:
     char dest[1024] = "12345666";//{0};
     const char src[5] = "3333";
                   那么拷贝的时候,假设用memcpy1(dest,src,sizeof(src));则printf(dest);出来是3333
                   假设memcpy1(dest,src,4);则printf(dest);出来是33335666;由于上面的sizeof(src),包括'/0',所以拷贝过去的字符串以'/0'
                   结束,就仅仅有3333,而假设传4个字符,'/0'是第五个字符,那就遇到dest[1024] 的'/0'结束,所以是33335666
                   字符串的'/0'问题一定要注意啊!!!

    实际应用:
    unsigned char g_pData[1024] = "";
    DWORD g_dwOffset = 0;
    bool PackDatatoServer(const unsigned char *pData, const unsigned int uSize)
    {
     memcpy(g_pData+g_dwOffset, pData, uSize);
     g_dwOffset += uSize;
     //g_pData += uSize;
     return true;
    }

    void main()
    {
     const unsigned char a[4] = "123";
     PackDatatoServer(a, 3);
     PackDatatoServer(a, 1111);
     int b = -1;
    }

    PackDatatoServer()函数的作用是把每次的资源内存复制到目标内存里面,并且是累加的拷贝;也就是后一次紧接着上一次的拷贝;
    显然用到了memcpy函数;
    实现原理是用到了一个全局变量g_dwOffset 保存之前拷贝的长度,最開始没有想到这一点,结果每次拷贝都是一次性的,下一次拷贝把
    上一次的冲掉了;所以用全局变量记录拷贝的长度;
    第二个须要注意的是,拷贝的过程中注意不要改变目标指针的指向,即目标指针始终指向初始化的时候指向的位置;那么怎么实现累积拷贝呢?
    就是用的指针偏移;第一次实现的时候,把g_pData += uSize;写到了函数里面,这样写是可以实现指针位移的目标,可是指针指向也发生改变;
     另外:g_pData += uSize;也有报错:left operand must be l-value,原因是:把地址赋值给一个不可更改的指针!
    比方:
      char   a[100];  
      char   *p   =   new   char[10];  
      a   =   p;   //这里出错,注意了:数组的首地址也是一个常量指针,指向固定不能乱改的~~
       
      char   *   const   pp   =   new   char[1];  
      pp   =   a;   //也错  
    所以既不能改变首地址,又要满足累积赋值(就是赋值的时候要从赋过值的地方開始向下一个内存块赋值,想到指针加),所以想到把指针加写到
    函数參数里面,这时就要充分了解memcpy的实现过程,里面是一个一个字符的赋值的,想连续赋值,就要把指针指向连续的内存的首地址,所以,
    真的非常不好表达,呵呵,就这样了,一大推零散的知识。。。

  • 相关阅读:
    Smart Client Architecture and Design Guide
    Duwamish密码分析篇, Part 3
    庆贺发文100篇
    .Net Distributed Application Design Guide
    New Introduction to ASP.NET 2.0 Web Parts Framework
    SPS toplevel Site Collection Administrators and Owners
    来自Ingo Rammer先生的Email关于《Advanced .Net Remoting》
    The newsletter published by Ingo Rammer
    深度探索.Net Remoting基础架构
    信道、接收器、接收链和信道接受提供程序
  • 原文地址:https://www.cnblogs.com/blfshiye/p/4008404.html
Copyright © 2011-2022 走看看