本文和大家分享的主要是C++中的內(nèi)存重疊的解決辦法,希望對大家學(xué)習(xí)C++有幫助,一起來看看吧。
?。?nbsp;內(nèi)存重疊 ,直到做到一個筆試題才知道了什么是內(nèi)存重疊。先上題目吧,是一個淘寶的筆試題,當(dāng)時有點(diǎn)懵,不知道這個名詞是啥子意思。
. 題目:補(bǔ)充下面函數(shù)代碼:
如果兩段內(nèi)存重疊,用memcpy函數(shù)可能會導(dǎo)致行為未定義。 而memmove函數(shù)能夠避免這種問題,下面是一種實(shí)現(xiàn)方式,請補(bǔ)充代碼。
.
#include using namespace std;void* memmove(void* str1,const void* str2,size_t n){
char* pStr1= (char*) str1;
const char* pStr2=(const char*)str2;
if ( ) {
for(size_t i=0;i!=n;++i){
*(pStr1++)=*(pStr2++);
}
}
else{
pStr1+=n-1;
pStr2+=n-1;
for(size_t i=0;i!=n;++i){
*(pStr1--)=*(pStr2--);
}
}
return ( );
}
在上面的兩個括號中插入對應(yīng)的內(nèi)容
答案:pstr1<pstr2 str1
?。?/span>
在這里我理解的內(nèi)存重疊大致上應(yīng)該是在strcpy以及memcpy等內(nèi)存拷貝函數(shù)出現(xiàn)的問題。strcpy函數(shù)內(nèi)存重疊可能會使程序崩潰,這里我先講一個比較簡單的例子來看一下。
.
?。?/span>
#include #include #include int main(){
char *p = NULL;
p = (char *)malloc(10);
memcpy(p,"1234679",strlen("1246789"));
printf("before p = %s/n", p);
strcpy(p+1,p);//這重疊了
printf("after p = %s/n", p);
free(p);
}
?。?/span>
上面的這個例子中發(fā)生了內(nèi)存重疊問題,這就導(dǎo)致了拷貝發(fā)生了異常,不會拷貝一樣的數(shù)據(jù)。我跑這個代碼的時候居然沒有報(bào)錯,程序也沒炸,我也就有點(diǎn)好奇了。按理來memcpy,strcpy這兩個函數(shù)沒有對內(nèi)存重疊進(jìn)行處理。使用這兩個函數(shù)的時候只有程序員自己保證源地址與目標(biāo)地址內(nèi)存不重疊。所以當(dāng)會發(fā)生內(nèi)存重疊的時候最好使用memmov函數(shù)進(jìn)行內(nèi)存拷貝。
?。?/span>
自己查了一些資料,原來memcpy有一個長度參數(shù),只拷貝cnt個字節(jié)就結(jié)束了,所以會得到正確的結(jié)果,但是strcpy函數(shù)知道拷貝到\\0這個標(biāo)志符才會結(jié)束,所以就會導(dǎo)致程序崩潰了。
?。?/span>
?。?nbsp;memcpy和memmov函數(shù)原型和區(qū)別
?。?/span>
1.memmove
?。?/span>
函數(shù)原型:void *memmove(void *dest, const void *source, size_t count)
?。?/span>
返回值說明:返回指向dest的void *指針
?。?/span>
參數(shù)說明:dest,source分別為目標(biāo)串和源串的首地址。count為要移動的字符的個數(shù)
?。?/span>
函數(shù)說明:memmove用于從source拷貝count個字符到dest,如果目標(biāo)區(qū)域和源區(qū)域有重疊的話,memmove能夠保證源串在被覆蓋之前將重疊區(qū)域的字節(jié)拷貝到目標(biāo)區(qū)域中。
?。?/span>
.
2.memcpy
?。?/span>
函數(shù)原型:void *memcpy(void *dest, const void *source, size_t count);
.
返回值說明:返回指向dest的void *指針
?。?/span>
函數(shù)說明:memcpy功能和memmove相同,但是memcpy中dest和source中的區(qū)域不能重疊,否則會出現(xiàn)未知結(jié)果。
.
?。?nbsp;實(shí)現(xiàn)一個memmov函數(shù)
.
#include #include using namespace std;
void *memmove(void * dst, const void *src, size_t count){
//特殊情況錯誤處理
if (src == NULL || dst == NULL)
return NULL;
unsigned char *pdst = (unsigned char *)dst;
const unsigned char *psrc = (const unsigned char *)src;
//判斷內(nèi)存是否重疊
bool flag1 = (pdst >= psrc && pdst < psrc + count);
bool flag2 = (psrc >= pdst && psrc < pdst + count);
//上面兩個標(biāo)志其中有一個成立,保證內(nèi)存并不是重疊的,與拷貝的長度有關(guān)
if (flag1 || flag2){//內(nèi)存重疊
//倒序拷貝
while (count){
*(pdst + count - 1) = *(psrc + count - 1);
count--;
}
}
else{//不重疊
while (count--){
*pdst = *psrc;
pdst++;
psrc++;
}
}
return dst;
}
int main(){
//內(nèi)存重疊的情況
char str[] = "hello world";
memmove(str + 3, str, 8);
cout<<"memmove result is :"<<str<<endl;
//內(nèi)存不重疊
char str2[] = "hello world";
char str3[] = "you are ";
memmove(str2, str3, 8);
cout<<"memmove result is :"<<str2<<endl;
}
?。?nbsp;實(shí)現(xiàn)思路就是要去判斷是否內(nèi)存重疊,重疊的話就倒序的拷貝,非重疊的話就從前往后拷貝就行了。這個例子也很好的解釋了前面的那個題目的情況。其實(shí)前面的那個情況還可以用一個圖片來解釋。
. 這張圖片就是這兩種情況的實(shí)現(xiàn)。
文章來源:博客園