日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

对内存重叠的深入认识

發(fā)布時(shí)間:2025/3/11 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 对内存重叠的深入认识 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

內(nèi)存重疊:拷貝的目的地址在源地址范圍內(nèi)。所謂內(nèi)存重疊就是拷貝的目的地址和源地址有重疊。

在函數(shù)strcpy和函數(shù)memcpy都沒有對內(nèi)存重疊做處理的,使用這兩個(gè)函數(shù)的時(shí)候只有程序員自己保證源地址和目標(biāo)地址不重疊,或者使用memmove函數(shù)進(jìn)行內(nèi)存拷貝。

memmove函數(shù)對內(nèi)存重疊做了處理。

現(xiàn)在來看函數(shù)strcpy

原型:extern char *strcpy(char *dest,char *source);

功能:把source所指由NULL結(jié)束的字符串復(fù)制到dest所指的數(shù)組中。

說明:source和dest所指內(nèi)存區(qū)域不可以重疊且dest必須有足夠的空間來容納source的字符串。

返回指向dest的指針。

重疊從兩方面考慮:

(1).dest數(shù)據(jù)覆蓋了source; 如:dest(8byte) 地址:1000

source(8byte) 地址:1002

(2).dest所指的區(qū)域本來就是source的一部分; 如:dest(8byte) 地址:1000

source(8byte) 地址:0998

例如:針對第一種交叉情況情況,dst<src且dst+count>src,memcpy和memmove的結(jié)果是一樣的。請看下面的例子講解:

string s = "hello world";

memmove(&s[0],&s[5],10);

舉個(gè)內(nèi)存重疊環(huán)境的例子:

int main()

{char *p = NULL;

p=(char*)malloc(100);

memcpy(p,"123456789",strlen("123456789")); //會等到錯(cuò)誤的結(jié)果,有一個(gè)長度參數(shù),只能拷貝cnt個(gè)

//字節(jié)就結(jié)束了

printf("before p =%s\n",p);

strcpy(p+1,p); //注意:這里重疊了,而strcpy是根據(jù)判斷原串中的'\0'

printf("after p =%s\n",p);

free(p);

}

1.下面來看strcpy()原型寫法: 字符串拷貝.?
char *strcpy(char *strDest, const char *strSrc)
{
assert((strDest!=NULL) && (strSrc !=NULL));
char *address = strDest;?
while( (*strDest++ = * strSrc++)·1 != '/0')?
NULL ;?
return address ;?
}

2.下面來看下memcpy函數(shù)的原型寫法:內(nèi)存拷貝

void *memcpy(void *dest, const void *source, size_t count)
{
assert((NULL != dest) && (NULL != source));

char *tmp_dest = (char *)dest;
char *tmp_source = (char *)source;
while(count --)//不對是否存在重疊區(qū)域進(jìn)行判斷
*tmp_dest ++ = *tmp_source ++;
return dest;
}

3.下面來看下memmove函數(shù)的原型寫法:

void *memmove(void *dest, const void *source, size_t count)
{
assert((NULL != dest) && (NULL != source));
char *tmp_source, *tmp_dest;
tmp_source = (char *)source;
tmp_dest = (char *)dest;
if((dest + count<source) || (source + count) <dest))
{// 如果沒有重疊區(qū)域
while(count--)
*tmp_dest++ = *tmp_source++;
}
else
{ //如果有重疊(反向拷貝)
tmp_source += count - 1;
tmp_dest += count - 1;
while(count--)
*--tmp_dest = *--tmp;
}
return dest;
}

深入分析:

void *memcpy(void *dst, const void *src, size_t count):
void *memmove(void *dst, const void *src, size_t count);

先看一個(gè)測試:

#include <string.h>

#include <stdio.h>

int main()

{ int a[10];

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

a[i] = i;

memcpy (&a[4],a,sizeof(int)*6); //結(jié)果為:1 2 3 0 1 2 3 0 1

//memcpy(&a[4], a, sizeof(int)*6); //結(jié)果為:1 2 3 0 1 2 3 0 1(vc下和下面一個(gè)相同)

//MemMove(&a[4],a,sizeof(int)*6); //結(jié)果為:1 2 3 0 1 2 3 4 5

//memmove(&a[4],a,sizeof(int)*6); //結(jié)果為:1 2 3 0 1 2 3 4 5

//MemMove(a,&a[4],sizeof(int)*6); //結(jié)果為:5 6 7 8 9 6 7 8 9

//memmove(a, &a[4], sizeof(int)*6);//結(jié)果為:5 6 7 8 9 6 7 8 9

//memcpy(a, &a[4], sizeof(int)*6); //結(jié)果為:5 6 7 8 9 6 7 8 9

//MemCopy(a,&a[4],sizeof(int)*6); //結(jié)果為:5 6 7 8 9 6 7 8 9

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

printf("%d ",a[i]);

printf("/n");

return 0;

}
它們都是從src所指向的內(nèi)存中復(fù)制count個(gè)字節(jié)到dst所指內(nèi)存中,并返回dst的值。當(dāng)源內(nèi)存區(qū)域和目標(biāo)內(nèi)存區(qū)域無交叉時(shí),兩者的結(jié)果都是一樣的。但有交叉時(shí)不一樣。源內(nèi)存和目標(biāo)內(nèi)存交叉的情況有以下兩種:(左邊為低地址)

即:dst<=src 且 dst+count>src

?

針對第一種交叉情況情況,dst<=src且dst+count>src,memcpy和memmove的結(jié)果是一樣的。請看下面的例子講解:
int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
memcpy(a, a+4, sizeof(int)*6);和

memmove(a, a+4, sizeof(int)*6);結(jié)果一樣,都是:4567896789

?

針對第二種情況,src<dst且src+count>dst,memcpy和memmove的結(jié)果是不一樣的。請看下面的例子:
int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
memcpy(a+4, a, sizeof(int)*6) 結(jié)果按照分析應(yīng)該是:0123012301

但是在vs2005上運(yùn)行卻是:0123012345(有知道的,請告訴我原因)

memmove(a+4, a, sizeof(int)*6) 結(jié)果是:0123012345

總結(jié):

1. 當(dāng) src 和 dest 所指內(nèi)存區(qū)有重疊時(shí),memmove 相對 memcpy 能提供保證:保證能將 src 所指內(nèi)存區(qū)的前 n 個(gè)字節(jié)正確的拷貝到 dest 所指內(nèi)存中;
2. 當(dāng) src 地址比 dest 地址低時(shí),兩者結(jié)果一樣。換句話說,memmove 與 memcpy 的區(qū)別僅僅體現(xiàn)在 dest 的頭部和 src 的尾部有重疊的情況下;

綜上所述在進(jìn)行內(nèi)存重疊的考慮時(shí),strcpy,memcpy都要做一個(gè)內(nèi)存重疊的判斷:

對于memcpy需要加上一個(gè)斷言:Assert(dst<=src || src+count<dst);

source和dest所指內(nèi)存區(qū)域不可以重疊且dest必須有足夠的空間來容納source的字符串。

返回指向dest的指針。

對于strcpy需要加上一個(gè)斷言:

int count = strlen(src) + 1;//src length

Assert (dest<src || dest>(src+count))

考慮了內(nèi)存重疊的內(nèi)存拷貝函數(shù) memcpy?,相當(dāng)于memmove

考慮內(nèi)存重疊的字符串拷貝函數(shù)strcpy

char * strcpy(char *dest, const char *src)

{

??? char *d = dest; //backup input

??? char *s = src;

??? int count = 0;

??? assert(dest); //非空指針檢查

??? assert(src);

??? if(src == dest)

???????? return src;

??? count = strlen(src) + 1;//src length

??? if(count<=1)

???????? return 0; //empty src

??? if(dest<src || dest>(src+count))

??? {

???????? while(count--)

???????????? *d++ = *s++;

??? }

??? else //dest 位于src+count中間,

??? {

???????? d = dest+count;

???????? s = src+count;

???????? while(count--)

???????????? *d-- = *s--; //倒過來拷貝

??? }


轉(zhuǎn)載寫明出處 http://blog.csdn.net/feitianxuxue/article/details/7195158

總結(jié)

以上是生活随笔為你收集整理的对内存重叠的深入认识的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。