内存重叠:拷贝的目的地址在源地址范围内。所谓内存重叠就是拷贝的目的地址和源地址有重叠。

在函数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) 地址:1000

source(8byte) 地址:1002

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

source(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 9

for(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 length

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

考虑了内存重叠的内存拷贝函数 memcpy ,相当于memmove

考虑内存重叠的字符串拷贝函数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--; //倒过来拷贝

}

转载写明出处 http://blog.csdn.net/feitianxuxue/article/details/7195158

对内存重叠的深入认识相关推荐

  1. 函数 —— strncpy() (内存重叠) memcpy() memmove() 一个字符串拷贝给另一个字符串

    char *strncpy(char *dest, const char *src, size_t n) *strncpy(char *dest, const char *src, size_t n) ...

  2. memcpy和memmove的区别以及内存重叠问题

    memcpy和memmove的区别以及内存重叠问题 转自:https://www.codecomeon.com/posts/89/ 区别 memcpy() 和 memmove() 都是C语言中的库函数 ...

  3. 从memcpy到memmove,内存函数拷贝与内存重叠问题(重点内容)

    有一个关于拷贝的问题,假如有这样一个字符串 char a[]="hello"; 我需要把这个字符串拷进另一个变量中 char a1[10]; 好像方法蛮多的,比如strcpy #d ...

  4. memcpy内存重叠的解决

    内存重叠:拷贝的目的地址在源地址范围内.所谓内存重叠就是拷贝的目的地址和源地址有重叠. 在函数strcpy和函数memcpy都没有对内存重叠做处理的,使用这两个函数的时候只有程序员自己保证源地址和目标 ...

  5. 面试题:strcpy考虑内存重叠

    面试时遇到些strcpy()函数,本来挺简单的,但是面试官的一番描述让我有些不知道怎么下手 我当时觉得考虑内存重叠问题就可以了,但是他说的不是我理解的那样,然后就一直卡在那了,不过面试官很有耐心,我自 ...

  6. memcpy内存重叠问题

    memcpy内存重叠 之前一直没有注意到内存复制函数的内存重叠问题.今天偶遇遂琢磨了一下,记之. 函数简介:c和c++使用的内存拷贝函数,memcpy函数的功能是从源src所指的内存地址的起始位置开始 ...

  7. 内存重叠的拷贝--memmove

    1.memmove要解决的问题 strcpy只能拷贝字符串,为了解决这一问题,则有了memcpy这一函数.但是针对重叠内存的拷贝,memcpy最初并不能解决这一问题(后期优化过的memcpy能够实现重 ...

  8. STM32两个APP跳转间,内存的重叠,冲突和影响

    文章目录 一.前言 二.原因 三.问题 四.处理 方法1 内存划分开 方法2 初始化前做memset清零 方法3 逐个对变量清零 五.其他 一.前言 目前,通用的做法,STM32的Flash分成两块A ...

  9. Linux内核初始化阶段内存管理的几种阶段

    本系列旨在讲述从引导到完全建立内存管理体系过程中,内核对内存管理所经历的几种状态.阅读本系列前,建议先阅读memblock的相关文章. 一些讲在前面的话 在很久很久以前,linux内核还是支持直接从磁 ...

最新文章

  1. 《数学之美》第9章 图论和网络爬虫
  2. 第五章 面向方面编程___AOP入门
  3. 服务器虚拟化底层系统安装,Hyper-V是底层的虚拟机程序,位于操作系统和硬件之间,很薄一层...
  4. python灰度图像为什么显示成彩色的_python opencv image 怎么变成伪彩色
  5. 96.2. Yum 安装
  6. vmw6.5安装Freebsd8.1桌面gnome
  7. javascript (BOM DOM)
  8. 【web前端面试题整理05】做几道前端面试题休息休息吧
  9. java书籍_还搞不定Java多线程和并发编程面试题?你可能需要这一份书单!
  10. swagger入门和实践(含docker部署swagger)
  11. Delphi2010Excel导入数据库
  12. 学习笔记(12):Google开发专家带你学 AI:入门到实战(Keras/Tensorflow)(附源码)-深度学习“四件套”:数据、模型、损失函数与优化器
  13. 联邦学习 OR 迁移学习?联邦迁移学习不香吗
  14. 人工智能换脸python_AI换脸(手把手教你实现吴彦祖变苏大强)
  15. 人生的极致:大道至简 知行合一
  16. コナン純黒のナイトメア20180715
  17. 兄弟们,加入 Lyra Trading 竞赛
  18. 据采集的三种方式-如何获取数据
  19. Map阶段分析之Spill阶段
  20. 基于win32控制台应用程序的双人俄罗斯方块小游戏

热门文章

  1. 智慧园区-楼宇建模技巧之【建楼篇】
  2. 【载誉】致远互联荣获“2017最佳协同管理解决方案”殊荣
  3. ActiveReports 9实战教程(1): 手把手搭建环境Visual Studio 2013 社区版
  4. iphone viewdidLoad运行以及参数的传递。
  5. OCP之5 管理数据库存储结构
  6. 转换和编辑的sony的MTS硬盘摄像机格式文件。
  7. 详解:设计模式之-策略设计模式
  8. 进入IT行业,要不要参加培训班?
  9. Oracle表的并行度
  10. 输入年份和月份输出该月有多少天python_Python实现用户输入年月日,程序打印出这是这一年的第多少天...