国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【c++中內(nèi)存拷貝函數(shù)(C++ memcpy)詳解】

這篇具有很好參考價值的文章主要介紹了【c++中內(nèi)存拷貝函數(shù)(C++ memcpy)詳解】。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。


原型:void*memcpy(void*dest, const void*src,unsigned int count);?

功能:由src所指內(nèi)存區(qū)域復(fù)制count個字節(jié)到dest所指內(nèi)存區(qū)域。 ?

說明:src和dest所指內(nèi)存區(qū)域不能重疊,函數(shù)返回指向dest的指針。 ? ?

舉例:?

// ? memcpy.c ? ? ? ? ? ? ? ? ? ? ? ??
#include ? <stdlib.h> ? ? ? ? ? ??
#include ? <string.h> ? ? ? ? ? ??
main() ? ? ? ? ? ??
{ ? ? ? ? ? ? ? ??
? ? char *s= "Golden ?Global ? View "; ?
? ? char d[20]; ?
? ? clrscr(); ?
? ? memcpy(d,s,strlen(s)); ?
? ? d[strlen(s)]=0; ?
? ? printf( "%s ",d); ?
? ? getchar(); ?
? ? return ? 0; ?
} ?


下面自行實(shí)現(xiàn)這個函數(shù)

程序清單 1 V0.1版程序?

void MyMemMove(char *dst,char *src,int count) ??
{ ??
? ? while(count--) ??
? ? ? ? *dst++ = *src++; ??
} ?


程序清單 2 測試V0.1用例?

void Test() ??
{ ??
? ? char p1[256] = ”hello,world!”; ??
? ? char p2[256] = {0}; ??
? ? MyMemMove(p2,p1,strlen(p1)); ??
? ? printf(“%s”,p2); ??
} ??

????????客觀地講,相比那些交白卷或者函數(shù)聲明都不會寫的同學(xué)來說,能夠?qū)懗鲞@段代碼的同學(xué)已經(jīng)非常不錯了,至少在C語言這門課程上已經(jīng)達(dá)到了現(xiàn)行高校的教育目標(biāo),但是離企業(yè)的用人要求還有一定的距離。我們不妨將上面的程序稱為V0.1版本,看看還有沒有什么地方可以改進(jìn)。?
????????首先我們看看函數(shù)聲明是否合理,V0.1版的程序?qū)⒃吹刂泛湍康牡刂范加胏har *來表示,這樣當(dāng)然也沒有什么問題,但是讓其他人使用起來卻很不方便,假如現(xiàn)在要將count個連續(xù)的結(jié)構(gòu)體對象移動到另外一個地方去,如果要使用v0.1的程序的話,正確的寫法如下:?
???????

?MyMemMove((char *)dst,(char *)src,sizeof(TheStruct)*count);?

? ? ? ? 也就是說我們需要將結(jié)構(gòu)體指針強(qiáng)制轉(zhuǎn)換成char * 才能夠正常工作,這樣除了字符串以外其它的類型都不可避免地要進(jìn)行指針強(qiáng)制轉(zhuǎn)換,否則編譯器就會呱呱叫,比如在VC++2008下就會出現(xiàn)這樣的錯誤:?

error C2664: 'MyMemMove' : cannot convert parameter 1 from 'TheStruct *'to 'char *' ;

那么如何解決這個問題呢?其實(shí)很簡單,我們知道有一種特別的指針,任何類型的指針都可以對它賦值,那就是void *,所以應(yīng)該將源地址目的地址都用void*來表示。當(dāng)然函數(shù)體的內(nèi)容也要作相應(yīng)的改變,這樣我們就得到了V0.2版的程序。?
程序清單 3 V0.2版程序?

void MyMemMove(void *dst,void *src,int count) ??
{ ??
? ? while (count--) ??
? ? { ??
? ? ? ? *(char *)dst = *(char *)src; ??
? ? ? ? dst = (char *)dst + 1; ??
? ? ? ? src = (char *)src + 1; ??
? ? } ??
} ??

????????有的同學(xué)可能會問,這里面不是還有指針強(qiáng)制轉(zhuǎn)換嗎?只不過是換了地方。沒錯,強(qiáng)制指針轉(zhuǎn)換確實(shí)是從使用者的代碼轉(zhuǎn)移到了庫的代碼里,但我們可以將 MyMemMove理解為庫,而將Test理解為使用者,事實(shí)上通過調(diào)整之后的效果卻有天壤之別,V0.1是一逸永勞,而V0.2是一勞永逸!?
????????還有幾個細(xì)節(jié)需要注意,為了實(shí)現(xiàn)鏈?zhǔn)奖磉_(dá)式,我們應(yīng)該將返回值也改為void *。此外,如果我們不小心將“*(char *)dst = *(char *)src;”寫反了,寫成“*(char *)src =*(char *)dst;”編譯照樣通過,而為了找出這個錯誤又得花費(fèi)不少時間。注意到src所指向的內(nèi)容在這個函數(shù)內(nèi)不應(yīng)該被改變,所有對src所指的內(nèi)容賦值都應(yīng)該被禁止,所以這個參數(shù)應(yīng)該用const修飾,如果有類似的錯誤在編譯時就能夠被發(fā)現(xiàn):?

error C3892: 'src' : you cannot assign to a variable that is const ;

????????作為程序員犯錯誤在所難免,但是我們可以利用相對難犯錯誤的機(jī)器,也就是編譯器來降低犯錯誤的概率,這樣我們就得到了V0.3版的程序。?
程序清單 4 V0.3版程序?

void * MyMemMove(void *dst,const void *src,int count) ??
{ ??
? ? void *ret=dst; ??
? ? while (count--) ??
? ? { ??
? ? ? ? *(char *)dst = *(char *)src; ??
? ? ? ? dst = (char *)dst + 1; ??
? ? ? ? src = (char *)src + 1; ??
? ? } ??
? ? return ret; ?
} ??

????????現(xiàn)在再來考慮這樣一種情況,有使用者這樣調(diào)用庫:MyMemMove(NULL,src, count),這是完全可能的,因?yàn)橐话銇碚f這些地址都是程序計算出來的,那就難免會算錯,出現(xiàn)零地址或者其它的非法地址也不足為奇??梢灶A(yù)料的是,如果出現(xiàn)這種情況的話,則程序馬上就會down掉,更糟糕的是你不知道錯誤出在哪里,于是不得不投入大量的精力在浩瀚的代碼中尋找bug。解決這類問題的通用辦法是對輸入?yún)?shù)作合法性檢查,也就是V0.4版程序。?
程序清單 5 V0.4版程序

void * MyMemMove(void *dst,const void *src,int count) ??
{ ??
? ? void *ret=dst; ??
? ? if (NULL==dst||NULL ==src) ??
? ? { ??
? ? ? ? return dst; ??
? ? } ??
? ? while (count--) ??
? ? { ??
? ? ? ? *(char *)dst = *(char *)src; ??
? ? ? ? dst = (char *)dst + 1; ??
? ? ? ? src = (char *)src + 1; ??
? ? } ??
? ? return ret; ??
}?

????????上面之所以寫成“if(NULL==dst||NULL ==src)”而不是寫成“if (dst == NULL || src == NULL)”,也是為了降低犯錯誤的概率。我們知道,在C語言里面“==”和“=”都是合法的運(yùn)算符,如果我們不小心寫成了“if (dst = NULL || src = NULL)”還是可以編譯通過,而意思卻完全不一樣了,但是如果寫成“if (NULL=dst||NULL =src)”,則編譯的時候就通不過了,所以我們要養(yǎng)成良好的程序設(shè)計習(xí)慣:常量與變量作條件判斷時應(yīng)該把常量寫在前面。V0.4版的代碼首先對參數(shù)進(jìn)行合法性檢查,如果不合法就直接返回,這樣雖然程序down掉的可能性降低了,但是性能卻大打折扣了,因?yàn)槊看握{(diào)用都會進(jìn)行一次判斷,特別是頻繁的調(diào)用和性能要求比較高的場合,它在性能上的損失就不可小覷。如果通過長期的嚴(yán)格測試,能夠保證使用者不會使用零地址作為參數(shù)調(diào)用MyMemMove函數(shù),則希望有簡單的方法關(guān)掉參數(shù)合法性檢查。我們知道宏就有這種開關(guān)的作用,所以V0.5版程序也就出來了。?

程序清單 6 V0.5版程序

void * MyMemMove(void *dst,const void *src,int count) ??
{ ??
? ? void *ret=dst; ??
#ifdef DEBUG ??
? ? if (NULL==dst||NULL ==src) ??
? ? { ??
? ? ? ? return dst; ??
? ? } ??
#endif ??
? ? while (count--) ??
? ? { ??
? ? ? ? *(char *)dst = *(char *)src; ??
? ? ? ? dst = (char *)dst + 1; ??
? ? ? ? src = (char *)src + 1; ??
? ? } ??
? ? return ret; ??
} ??

????????如果在調(diào)試時我們加入“#defineDEBUG”語句,增強(qiáng)程序的健壯性,那么在調(diào)試通過后我們再改為“#undef DEBUG”語句,提高程序的性能。事實(shí)上在標(biāo)準(zhǔn)庫里已經(jīng)存在類似功能的宏:assert,而且更加好用,它還可以在定義DEBUG時指出代碼在那一行檢查失敗,而在沒有定義DEBUG時完全可以把它當(dāng)作不存在。assert(_Expression)的使用非常簡單,當(dāng)_Expression為0時,調(diào)試器就可以出現(xiàn)一個調(diào)試錯誤,有了這個好東西代碼就容易多了。?
程序清單 7 V0.6版程序

void * MyMemMove(void *dst,const void *src,int count) ??
{ ??
? ? assert(dst); ??
? ? assert(src); ??
? ? void *ret=dst; ??
? ? while (count--) ??
? ? { ??
? ? ? ? *(char *)dst = *(char *)src; ??
? ? ? ? dst = (char *)dst + 1; ??
? ? ? ? src = (char *)src + 1; ??
? ? } ??
? ? return ret; ??
} ??

????????到目前為止,在語言層面上,我們的程序基本上沒有什么問題了,那么是否真的就沒有問題了呢?這就要求程序員從邏輯上考慮了,這也是優(yōu)秀程序員必須具備的素質(zhì),那就是思維的嚴(yán)謹(jǐn)性,否則程序就會有非常隱藏的bug,就這個例子來說,如果用戶用下面的代碼來調(diào)用你的程序。?
程序清單 8 重疊的內(nèi)存測試。

void Test() ??
{ ??
? ? char p [256]= "hello,world!"; ??
? ? MyMemMove(p+1,p,strlen(p)+1); ??
? ? printf("%s\n",p); ??
} ??

????????如果你身邊有電腦,你可以試一下,你會發(fā)現(xiàn)輸出并不是我們期待的“hello,world!”(在“hello world!”前加個h),而是“hhhhhhhhhhhhhh”,這是什么原因呢?原因出在源地址區(qū)間和目的地址區(qū)間有重疊的地方,V0.6版的程序無意之中將源地址區(qū)間的內(nèi)容修改了!有些反映快的同學(xué)馬上會說我從高地址開始拷貝。粗略地看,似乎能解決這個問題,雖然區(qū)間是重疊了,但是在修改以前已經(jīng)拷貝了,所以不影響結(jié)果。但是仔細(xì)一想,這其實(shí)是犯了和上面一樣的思維不嚴(yán)謹(jǐn)?shù)腻e誤,因?yàn)橛脩暨@樣調(diào)用還是會出錯:?

MyMemMove( p, p+1, strlen(p)+1); 

【c++中內(nèi)存拷貝函數(shù)(C++ memcpy)詳解】???????

????????所以最完美的解決方案還是判斷源地址和目的地址的大小,才決定到底是從高地址開始拷貝還是低地址開始拷貝,所以V0.7順利成章地出來了。?
程序清單 9 V0.7版程序?

void * MyMemMove(void *dst,const void *src,int count) ??
{ ??
? ? assert(dst); ??
? ? assert(src); ??
? ? void * ret = dst; ??
? ? if (dst <= src || (char *)dst >= ((char *)src + count)) { ??
? ? ? ? while (count--) { ??
? ? ? ? ? ? *(char *)dst = *(char *)src; ??
? ? ? ? ? ? dst = (char *)dst + 1; ??
? ? ? ? ? ? src = (char *)src + 1; ??
? ? ? ? } ??
? ? } ??
? ? else { ??
? ? ? ? dst = (char *)dst + count - 1; ??
? ? ? ? src = (char *)src + count - 1; ??
? ? ? ? while (count--) { ??
? ? ? ? ? ? *(char *)dst = *(char *)src; ??
? ? ? ? ? ? dst = (char *)dst - 1; ??
? ? ? ? src = (char *)src - 1; ??
? ? ? ? } ??
? ? } ??
? ? return(ret); ??
} ?

????????經(jīng)過以上7個版本的修改,我們的程序終于可以算是“工業(yè)級”了?;仡^再來看看前面的測試用例,就會發(fā)現(xiàn)那根本就算不上是測試用例,因?yàn)樗徽{(diào)用了最正常的一種情況,根本達(dá)不到測試的目的。有了上面的經(jīng)歷,測試用例也就相應(yīng)地出現(xiàn)了,我們不妨用字符數(shù)組來模擬內(nèi)存。?
程序清單 10 相對全面的測試用例 。文章來源地址http://www.zghlxwxcb.cn/news/detail-418903.html

void Test() ??
{ ??
? ? char p1[256] = "hello,world!"; ??
? ? char p2[256] = {0}; ??
? ? MyMemMove(p2,p1,strlen(p1)+1); ??
? ? printf("%s\n",p2); ??
? ? MyMemMove(NULL,p1,strlen(p1)+1); ??
? ? MyMemMove(p2,NULL,strlen(p1)+1); ??
? ? MyMemMove(p1+1,p1,strlen(p1)+1); ??
? ? printf("%s\n",p1); ??
? ? MyMemMove(p1,p1+1,strlen(p1)+1); ??
? ? printf("%s\n",p1); ??
} 

void * memcpy ( void * dst,const void * src,size_t count) ?
{ ?
? ? void * ret = dst; ?
? ? while (count--) { ?
? ? ? ? *(char *)dst = *(char *)src; ?
? ? ? ? dst = (char *)dst + 1; ?
? ? ? ? src = (char *)src + 1; ?
? ? } ?
? ? return(ret); ?
} ?
char *strcpy(char *des, const char *src){ ?
? ? assert((des != NULL) && (src != NULL)); ?
? ? char *ret = des; // 防止改變des的地址 ?
? ? while ((*des++ = *src++) !='\0') ; ?
? ? return ret; ?
} ?

到了這里,關(guān)于【c++中內(nèi)存拷貝函數(shù)(C++ memcpy)詳解】的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【C語言】memcpy memmove memset memcmp 四大內(nèi)存操作函數(shù)(詳解+用法+模擬實(shí)現(xiàn))

    【C語言】memcpy memmove memset memcmp 四大內(nèi)存操作函數(shù)(詳解+用法+模擬實(shí)現(xiàn))

    頭文件string.h中常用內(nèi)存操作函數(shù)共有四大,學(xué)習(xí)完本篇文章,各種類型數(shù)組的常見處理輕松拿下。 對字符串(字符數(shù)組)的操作函數(shù)有很多,但是我們想要操作整型數(shù)組等呢: 這就需要內(nèi)存操作函數(shù)了, memory在計算機(jī)科學(xué)中是內(nèi)存的意思 ,這也是四大內(nèi)存操作函數(shù)都有mem頭

    2024年02月10日
    瀏覽(17)
  • 【C語言】memmove()函數(shù)(拷貝重疊內(nèi)存塊函數(shù)詳解)

    【C語言】memmove()函數(shù)(拷貝重疊內(nèi)存塊函數(shù)詳解)

    ?? 個人主頁 :修修修也 ?? 所屬專欄 :C語言 ?? 操作環(huán)境 : Visual Studio 2022 目錄 ?一.memmove()函數(shù)簡介 1.函數(shù)功能 2.函數(shù)參數(shù) 1.void * destination 2.onst void * source 3.size_t num 3.函數(shù)返回值 4.函數(shù)頭文件 二.memmove()函數(shù)的具體使用 1.使用memmove()函數(shù)完成拷貝整型數(shù)組數(shù)據(jù)(目的地與源重

    2024年02月06日
    瀏覽(21)
  • 【C++】vector問題解決(非法的間接尋址,迭代器失效 , memcpy拷貝問題)

    【C++】vector問題解決(非法的間接尋址,迭代器失效 , memcpy拷貝問題)

    送給大家一句話: 世界在旋轉(zhuǎn),我們跌跌撞撞前進(jìn),這就夠了 —— 阿貝爾 加繆 我們之前實(shí)現(xiàn)了手搓vector,但是當(dāng)時依然有些問題沒有解決: 迭代器區(qū)間拷貝(非法的間接尋址問題) 迭代器失效問題 使用memcpy拷貝問題 接下來,我們一點(diǎn)一點(diǎn)來解決這些問題!??! 來看這個

    2024年04月09日
    瀏覽(20)
  • 【C++學(xué)習(xí)手札】-引用與內(nèi)聯(lián)函數(shù)以及C++中對const拓展詳解(超詳細(xì)?。? decoding=

    【C++學(xué)習(xí)手札】-引用與內(nèi)聯(lián)函數(shù)以及C++中對const拓展詳解(超詳細(xì)!)

    ?????????????????????????????????????? 食用指南:本文在有C基礎(chǔ)的情況下食用更佳 ?????????????????????????????????????? ?? 這就不得不推薦此專欄了:C語言 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ?? 內(nèi)聯(lián)函數(shù)前置知識 :宏函數(shù)

    2024年02月14日
    瀏覽(107)
  • C語言——內(nèi)存操作函數(shù)(memcpy、memmove、memcmp、memset)

    C語言——內(nèi)存操作函數(shù)(memcpy、memmove、memcmp、memset)

    本文章會詳解C語言進(jìn)階內(nèi)容,有關(guān)內(nèi)存操作函數(shù)( memcpy,memmove,memcmp,memset )的使用說明、API文檔該類函數(shù)原型以及模擬實(shí)現(xiàn)內(nèi)存函數(shù) 首先我們從API文檔中搜索memcpy查看一下該函數(shù)的原型 可以看出該函數(shù)有三個參數(shù),那么這三個參數(shù)的作用分別是什么呢? 該函數(shù)的實(shí)現(xiàn)思

    2024年02月06日
    瀏覽(41)
  • 【C語言】內(nèi)存函數(shù)memcpy和memmove的功能與模擬實(shí)現(xiàn)

    【C語言】內(nèi)存函數(shù)memcpy和memmove的功能與模擬實(shí)現(xiàn)

    1.memcpy 功能:把source指向的前num個字節(jié)內(nèi)容拷貝到destination指向的位置去,可以拷貝任意類型的數(shù)據(jù)。 注:1.memcpy并不關(guān)心\\0,畢竟傳的也不一定是字符串,因此拷貝過程中遇到\\0也不會停下來。 2.num的單位是字節(jié),并不是要拷貝的元素個數(shù) 3.如果source和destination有任何的重疊

    2024年02月19日
    瀏覽(27)
  • 【C語言內(nèi)存函數(shù)精選】memcpy、memset、memmove及仿真實(shí)現(xiàn)!掌握內(nèi)存操作的藝術(shù)!

    【C語言內(nèi)存函數(shù)精選】memcpy、memset、memmove及仿真實(shí)現(xiàn)!掌握內(nèi)存操作的藝術(shù)!

    ?? 博客主頁: 小鎮(zhèn)敲碼人 ?? 歡迎關(guān)注:??點(diǎn)贊 ????留言 ??收藏 ?? 任爾江湖滿血骨,我自踏雪尋梅香。 萬千浮云遮碧月,獨(dú)傲天下百堅強(qiáng)。 男兒應(yīng)有龍騰志,蓋世一意轉(zhuǎn)洪荒。 莫使此生無痕度,終歸人間一捧黃。?????? ?? 我的努力求學(xué)沒有得到別的好處,只

    2024年02月15日
    瀏覽(22)
  • C++實(shí)現(xiàn)memcpy函數(shù)

    功能:memcpy為按字節(jié)拷貝內(nèi)存函數(shù),從源src所指的內(nèi)存地址開始拷貝n個字節(jié)到目標(biāo)dest為起始地址的內(nèi)存中。 返回值:函數(shù)返回指向目標(biāo)內(nèi)存區(qū)dest的指針。 注意事項(xiàng): memcpy應(yīng)該實(shí)現(xiàn)按字節(jié)拷貝指定長度的內(nèi)存內(nèi)容,但若傳入函數(shù)的實(shí)參dest和src指針的類型不同,直接自增++可

    2024年02月16日
    瀏覽(20)
  • 來不及哀悼了,接下來上場的是C語言內(nèi)存函數(shù)memcpy,memmove,memset,memcmp

    來不及哀悼了,接下來上場的是C語言內(nèi)存函數(shù)memcpy,memmove,memset,memcmp

    今天又來寫一篇C的文章,這里要講的是C語言中的幾個內(nèi)存函數(shù),主要是講解功能和用法,望能耐心觀看哦。望官方也多多曝光。 目錄 memcpy ?memmove memset ?memcmp ?memcpy??是?C?語言標(biāo)準(zhǔn)庫中的一個函數(shù),用于復(fù)制內(nèi)存塊的內(nèi)容。它的主要作用是將一個源內(nèi)存區(qū)域的內(nèi)容復(fù)制到

    2024年02月22日
    瀏覽(26)
  • 【C語言】memcpy,memmove,memcmp,memset函數(shù)詳解

    【C語言】memcpy,memmove,memcmp,memset函數(shù)詳解

    ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???? ?? ?? ?? 個人主頁 :阿然成長日記 ??點(diǎn)擊可跳轉(zhuǎn) ?? 個人專欄: ??數(shù)據(jù)結(jié)構(gòu)與算法??C語言進(jìn)階 ?? 不能則學(xué),不知則問,恥于問人,決無長進(jìn) ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? #includestring.h 與strn

    2024年02月17日
    瀏覽(26)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包