对内存重叠的深入认识
2013-12-05 17:03
204 查看
内存重叠:拷贝的目的地址在源地址范围内。所谓内存重叠就是拷贝的目的地址和源地址有重叠。在函数strcpy和函数memcpy都没有对内存重叠做处理的,使用这两个函数的时候只有程序员自己保证源地址和目标地址不重叠,或者使用memmove函数进行内存拷贝。memmove函数对内存重叠做了处理。现在来看函数strcpy原型:extern char *strcpy(char *dest,char *source);功能:把source所指由NULL结束的字符串复制到dest所指的数组中。说明:source和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳source的字符串。返回指向dest的指针。重叠从两方面考虑:(1).dest数据覆盖了source; 如:dest(8byte) 地址:1000source(8byte) 地址:1002(2).dest所指的区域本来就是source的一部分; 如:dest(8byte) 地址:1000source(8byte) 地址:0998例如:针对第一种交叉情况情况,dst<src且dst+count>src,memcpy和memmove的结果是一样的。请看下面的例子讲解:string s = "hello world";memmove(&s[0],&s[5],10);举个内存重叠环境的例子:int main(){char *p = NULL;p=(char*)malloc(100);memcpy(p,"123456789",strlen("123456789")); //会等到错误的结果,有一个长度参数,只能拷贝cnt个//字节就结束了printf("before p =%s\n",p);strcpy(p+1,p); //注意:这里重叠了,而strcpy是根据判断原串中的'\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函数的原型写法:内存拷贝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 --)//不对是否存在重叠区域进行判断
*tmp_dest ++ = *tmp_source ++;
return dest;
}3.下面来看下memmove函数的原型写法: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))
{// 如果没有重叠区域
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);先看一个测试:#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); //结果为:1 2 3 0 1 2 3 0 1//memcpy(&a[4], a, sizeof(int)*6); //结果为:1 2 3 0 1 2 3 0 1(vc下和下面一个相同)//MemMove(&a[4],a,sizeof(int)*6); //结果为:1 2 3 0 1 2 3 4 5//memmove(&a[4],a,sizeof(int)*6); //结果为:1 2 3 0 1 2 3 4 5//MemMove(a,&a[4],sizeof(int)*6); //结果为:5 6 7 8 9 6 7 8 9//memmove(a, &a[4], sizeof(int)*6);//结果为:5 6 7 8 9 6 7 8 9//memcpy(a, &a[4], sizeof(int)*6); //结果为:5 6 7 8 9 6 7 8 9//MemCopy(a,&a[4],sizeof(int)*6); //结果为:5 6 7 8 9 6 7 8 9for(i = 0; i < 10; i++)printf("%d ",a[i]);printf("/n");return 0;}
它们都是从src所指向的内存中复制count个字节到dst所指内存中,并返回dst的值。当源内存区域和目标内存区域无交叉时,两者的结果都是一样的。但有交叉时不一样。源内存和目标内存交叉的情况有以下两种:(左边为低地址)即:dst<=src 且 dst+count>src
针对第一种交叉情况情况,dst<=src且dst+count>src,memcpy和memmove的结果是一样的。请看下面的例子讲解:
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);结果一样,都是:4567896789
针对第二种情况,src<dst且src+count>dst,memcpy和memmove的结果是不一样的。请看下面的例子:
int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
memcpy(a+4, a, sizeof(int)*6) 结果按照分析应该是:0123012301但是在vs2005上运行却是:0123012345(有知道的,请告诉我原因)memmove(a+4, a, sizeof(int)*6) 结果是:0123012345总结:1. 当 src 和 dest 所指内存区有重叠时,memmove 相对 memcpy 能提供保证:保证能将 src 所指内存区的前 n 个字节正确的拷贝到 dest 所指内存中;
2. 当 src 地址比 dest 地址低时,两者结果一样。换句话说,memmove 与 memcpy 的区别仅仅体现在 dest 的头部和 src 的尾部有重叠的情况下;综上所述在进行内存重叠的考虑时,strcpy,memcpy都要做一个内存重叠的判断:对于memcpy需要加上一个断言:Assert(dst<=src || src+count<dst);source和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳source的字符串。返回指向dest的指针。对于strcpy需要加上一个断言:int count = strlen(src) + 1;//src lengthAssert (dest<src || dest>(src+count))[b]考虑了内存重叠的内存拷贝函数 memcpy ,相当于memmove[/b]考虑内存重叠的字符串拷贝函数strcpychar * 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--; //倒过来拷贝 }
转载写明出处 http://blog.csdn.net/feitianxuxue/article/details/7195158
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函数的原型写法:内存拷贝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 --)//不对是否存在重叠区域进行判断
*tmp_dest ++ = *tmp_source ++;
return dest;
}3.下面来看下memmove函数的原型写法: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))
{// 如果没有重叠区域
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);先看一个测试:#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); //结果为:1 2 3 0 1 2 3 0 1//memcpy(&a[4], a, sizeof(int)*6); //结果为:1 2 3 0 1 2 3 0 1(vc下和下面一个相同)//MemMove(&a[4],a,sizeof(int)*6); //结果为:1 2 3 0 1 2 3 4 5//memmove(&a[4],a,sizeof(int)*6); //结果为:1 2 3 0 1 2 3 4 5//MemMove(a,&a[4],sizeof(int)*6); //结果为:5 6 7 8 9 6 7 8 9//memmove(a, &a[4], sizeof(int)*6);//结果为:5 6 7 8 9 6 7 8 9//memcpy(a, &a[4], sizeof(int)*6); //结果为:5 6 7 8 9 6 7 8 9//MemCopy(a,&a[4],sizeof(int)*6); //结果为:5 6 7 8 9 6 7 8 9for(i = 0; i < 10; i++)printf("%d ",a[i]);printf("/n");return 0;}
它们都是从src所指向的内存中复制count个字节到dst所指内存中,并返回dst的值。当源内存区域和目标内存区域无交叉时,两者的结果都是一样的。但有交叉时不一样。源内存和目标内存交叉的情况有以下两种:(左边为低地址)即:dst<=src 且 dst+count>src
针对第一种交叉情况情况,dst<=src且dst+count>src,memcpy和memmove的结果是一样的。请看下面的例子讲解:
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);结果一样,都是:4567896789
针对第二种情况,src<dst且src+count>dst,memcpy和memmove的结果是不一样的。请看下面的例子:
int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
memcpy(a+4, a, sizeof(int)*6) 结果按照分析应该是:0123012301但是在vs2005上运行却是:0123012345(有知道的,请告诉我原因)memmove(a+4, a, sizeof(int)*6) 结果是:0123012345总结:1. 当 src 和 dest 所指内存区有重叠时,memmove 相对 memcpy 能提供保证:保证能将 src 所指内存区的前 n 个字节正确的拷贝到 dest 所指内存中;
2. 当 src 地址比 dest 地址低时,两者结果一样。换句话说,memmove 与 memcpy 的区别仅仅体现在 dest 的头部和 src 的尾部有重叠的情况下;综上所述在进行内存重叠的考虑时,strcpy,memcpy都要做一个内存重叠的判断:对于memcpy需要加上一个断言:Assert(dst<=src || src+count<dst);source和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳source的字符串。返回指向dest的指针。对于strcpy需要加上一个断言:int count = strlen(src) + 1;//src lengthAssert (dest<src || dest>(src+count))[b]考虑了内存重叠的内存拷贝函数 memcpy ,相当于memmove[/b]考虑内存重叠的字符串拷贝函数strcpychar * 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--; //倒过来拷贝 }
转载写明出处 http://blog.csdn.net/feitianxuxue/article/details/7195158
相关文章推荐
- 对内存重叠的深入认识
- 对内存重叠的深入认识
- 对内存重叠的深入认识
- 对内存重叠的深入认识
- 深入理解内存模型——Memory Barriers/Fences
- memcpy memmove区别和实现(如何处理内存重叠问题)
- 深入理解JVM(一)——JVM内存模型
- C语言中的内存分配深入
- Android中关于Volley的使用(八)缓存机制的深入认识
- 深入Java核心 Java内存分配原理精讲
- 深入理解计算机系统-之-数值存储(六)--以不同的方式窥视内存
- 深入理解Java 内存模型
- 深入理解JVM之JVM内存区域详解
- 火星人谚语系列之四:对问题最深入的认识是知道答案
- Strcpy,memcpy函数的内存重叠
- 深入Java核心 Java内存分配原理精讲
- 【转】Java内存管理:深入Java内存区域
- C++内存分配深入详解
- 深入理解JVM笔记二---垃圾收集器及内存分配策略
- 深入JVM系列(一)之内存模型与内存分配