http://blog.csdn.net/lovemysea/article/details/5275612 2010 1,、memcpy 函數(shù)用于 把資源內(nèi)存(src所指向的內(nèi)存區(qū)域) 拷貝到目標(biāo)內(nèi)存(dest所指向的內(nèi)存區(qū)域),;拷貝多少個(gè),?有一個(gè)size變量控制 拷貝的字節(jié)數(shù); 函數(shù)原型:void *memcpy(void *dest, void *src, unsigned int count); 用法:(1)可以拷貝任何類型的對象,,因?yàn)楹瘮?shù)的參數(shù)類型是void*(未定義類型指針),也就是說傳進(jìn)去的實(shí)參可以是int*,,short*,,char*等等, 但是由于函數(shù)拷貝的過程是一個(gè)字節(jié)一個(gè)字節(jié)的拷貝的,,所以實(shí)際操作的時(shí)候要把void*強(qiáng)制轉(zhuǎn)化為char*,,這樣在指針加的時(shí)候才會保證每次加一個(gè)字節(jié),呵呵 函數(shù)源代碼實(shí)現(xiàn): 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; } 注意事項(xiàng):(1)void* 一定要返回一個(gè)值(指針),,這個(gè)和void不太一樣,! (2)首先要判斷指針的值不能為空,desc為空的話肯定不能拷貝內(nèi)存空間,src為空相當(dāng)于沒有拷貝,;所以之間return掉,; (3)""空串是指內(nèi)容為0,NULL是0,,不是串,;兩個(gè)不等價(jià); (4)int dest[2] = {0};這是對int 類型的數(shù)組初始化的方法,;如果是char類型,,就用char a[5] = "1234"; 注意數(shù)組下標(biāo)要 多于實(shí)際看到的字符數(shù),因?yàn)檫€有'/0' (5)printf((char *)dest);這句話,,是把 char 類型 src 傳到 int 類型的 dest的內(nèi)存強(qiáng)制轉(zhuǎn)化成char類型,,然后打印出來; 因?yàn)橹苯涌磇nt類型的dest是看不到里面的內(nèi)容的,;因?yàn)橛衭nsigned char *desc1 = (unsigned char*)desc;所以字符可以傳 到dest里面保存起來,,dest所指向的內(nèi)存長度4個(gè)字節(jié),強(qiáng)制轉(zhuǎn)化為char 就是把四個(gè)字節(jié)分成一個(gè)一個(gè)的字節(jié),,這樣就可以看到 一個(gè)個(gè)字符了,,如果定義成char dest[5] = "1234";就不用轉(zhuǎn)化;呵呵,,表達(dá)起來真累人,; (6)memcpy1(dest,src,sizeof(src));注意里面的sizeof(src),這個(gè)是包括字符串的結(jié)束符'/0'的,;所以不用擔(dān)心printf(dest); 但是如果用memcpy1(dest,src,4);沒有'/0'就要*(dest+5) = '/0';這樣保證是一個(gè)完整的字符串,; (7)如果初始化的時(shí)候: char dest[1024] = "12345666";//{0}; const char src[5] = "3333"; 那么拷貝的時(shí)候,如果用memcpy1(dest,src,sizeof(src));則printf(dest);出來是3333 如果memcpy1(dest,src,4);則printf(dest);出來是33335666,;因?yàn)樯厦娴膕izeof(src),,包含'/0',所以拷貝過去的字符串以'/0' 結(jié)束,,就只有3333,而如果傳4個(gè)字符,,'/0'是第五個(gè)字符,,那就遇到dest[1024] 的'/0'結(jié)束,所以是33335666 字符串的'/0'問題一定要注意啊!!!
實(shí)際應(yīng)用: 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()函數(shù)的作用是把每次的資源內(nèi)存拷貝到目標(biāo)內(nèi)存里面,,而且是累加的拷貝,;也就是后一次緊接著上一次的拷貝; 顯然用到了memcpy函數(shù),; 實(shí)現(xiàn)原理是用到了一個(gè)全局變量g_dwOffset 保存之前拷貝的長度,,最開始沒有想到這一點(diǎn),結(jié)果每次拷貝都是一次性的,,下一次拷貝把 上一次的沖掉了,;所以用全局變量記錄拷貝的長度; 第二個(gè)需要注意的是,,拷貝的過程中注意不要改變目標(biāo)指針的指向,,即目標(biāo)指針始終指向初始化的時(shí)候指向的位置;那么怎么實(shí)現(xiàn)累積拷貝呢,? 就是用的指針偏移,;第一次實(shí)現(xiàn)的時(shí)候,把g_pData += uSize;寫到了函數(shù)里面,,這樣寫是能夠?qū)崿F(xiàn)指針位移的目標(biāo),,但是指針指向也發(fā)生改變; 另外:g_pData += uSize;也有報(bào)錯(cuò):left operand must be l-value,,原因是:把地址賦值給一個(gè)不可更改的指針,! 比如: char a[100]; char *p = new char[10]; a = p; //這里出錯(cuò),注意了:數(shù)組的首地址也是一個(gè)常量指針,,指向固定不能亂改的~~ char * const pp = new char[1]; pp = a; //也錯(cuò) 所以既不能改變首地址,,又要滿足累積賦值(就是賦值的時(shí)候要從賦過值的地方開始向下一個(gè)內(nèi)存塊賦值,想到指針加),,所以想到把指針加寫到 函數(shù)參數(shù)里面,,這時(shí)就要充分了解memcpy的實(shí)現(xiàn)過程,里面是一個(gè)一個(gè)字符的賦值的,,想連續(xù)賦值,,就要把指針指向連續(xù)的內(nèi)存的首地址,所以,, 真的很不好表達(dá),,呵呵,就這樣了,,一大推零散的知識,。,。。
|