对内存重叠的深入认识

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

在函数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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/545828.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android特效 五种Toast具体解释

Toast是Android中用来显示显示信息的一种机制&#xff0c;和Dialog不一样的是&#xff0c;Toast是没有焦点的&#xff0c;并且Toast显示的时间有限&#xff0c;过一定的时间就会自己主动消失。 1.默认效果: 代码:Toast.makeText(getApplicationContext(), "默认Toast样式&…

为什么阿里巴巴禁止使用BigDecimal的equals方法做等值比较?

△一个对Coding有着独特追求的人△作者 l Hollis来源 l Hollis&#xff08;ID&#xff1a;hollischuang&#xff09;BigDecimal&#xff0c;相信对于很多人来说都不陌生&#xff0c;很多人都知道他的用法&#xff0c;这是一种java.math包中提供的一种可以用来进行精确运算的类型…

动图演示:手撸堆栈的两种实现方法!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;正式开始之前&#xff0c;先和各位朋友聊聊公众号后期的一些打算&#xff0c;后面的文章计划写一些关于数据结构和算法的内容…

多图带你彻底理解Java中的21种锁!

作者 | 悟空聊架构来源 | 悟空聊架构&#xff08;ID&#xff1a;PassJava666&#xff09;本篇主要内容如下&#xff1a;本篇主要内容本篇文章已收纳到我的Java在线文档、 Github我的SpringCloud实战项目持续更新中帮你总结好的锁&#xff1a;序号锁名称应用1乐观锁CAS2悲观锁sy…

杨辉三角——数组解决

杨辉三角如图下所示&#xff0c;每一行的第一个数和最后一个数都为1&#xff0c;每一行中间的数&#xff08;出去第一个和最后一个&#xff09;a等于上一行与其相同列数的数b与数b前面的数之和。例&#xff1a; 第3行第2列的数是3&#xff0c;它就等于第2行第2列的数&#xff…

VS生成的exe文件如何在其他电脑上运行

在VS编译器上编写的程序都会生成一个exe文件&#xff0c;有时候写了一个很装逼的程序想在别人电脑炫耀一下&#xff0c;奈何将这个exe文件拷贝过去并不能运行&#xff0c;直接宣告装逼失败。为此将介绍一下如何将生成的exe文件在其他电脑上运行&#xff0c;步骤如下&#xff1a…

netty websocket 简单消息推送demo

2019独角兽企业重金招聘Python工程师标准>>> 今天心情很不好&#xff01;&#xff01;&#xff01; 原因保密。 这篇是基于"netty与websocket通信demo"。 错误想法&#xff1a;大量客户请求&#xff0c;共用一个worker&#xff0c;来实现推送。 正确作法&…

给 JDK 官方提了一个 Bug,结果...

图 by&#xff1a;石头北京-望京关于作者&#xff1a;程序猿石头(ID: tangleithu)&#xff0c;现任阿里巴巴技术专家&#xff0c;清华学渣&#xff0c;前大疆后端 Leader。背景分享一下之前踩的一个坑&#xff0c;背景是这样的&#xff1a;我们的项目依赖于一个外部服务&#x…

解决exe文件在别人电脑上运行缺失文件情况

这里就以vs2013为例&#xff1a;编译后生成的exe文件拷贝到别人电脑上运行是会弹出一个窗口说缺失MSVCR120.dll和MSVCR120D.dll这两个文件。&#xff08;其他vs版本的编译器在所提示的缺失文件按下述方法也可解决&#xff09;下面就介绍一种方法解决。 1、在VS2013软件中找到MS…

32张图带你彻底搞懂事务和锁!

作者 | 悟空聊架构来源 | 悟空聊架构&#xff08;ID&#xff1a;PassJava666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;PassJava&#xff09;本篇主要内容如下&#xff1a;本篇主要内容一、事务1.1 什么是事务为单个工作单元而执行的一系列操作。如查询、修改数…

分布式映射与集中式映射_K映射上的表达式映射和组包围

分布式映射与集中式映射In the previous article (Karnaugh Map 2, 3 and 4- variable) we have already discussed the designing of K-Map and various forms in which they are represented based on either they are being mapped for minterm or maxterm. 在上一篇文章( 卡…

JDK 竟然是这样实现栈的?

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;前面的文章《动图演示&#xff1a;手撸堆栈的两种实现方法&#xff01;》我们用数组和链表来实现了自定义的栈结构&#xff…

关于微信,运营商们就这点志向?

2019独角兽企业重金招聘Python工程师标准>>> 近期关于运营商威逼微信收费之事闹得沸沸扬扬&#xff0c;在虎嗅上看到有不少人发表了自己的看法也不乏给运营商或微信出点子的人&#xff0c;但我觉得都不是很妥&#xff0c;还是谈谈我的看法吧。 陈旧的思路&#xff…

阿里巴巴开源的Excel操作神器!

前提导出数据到Excel是非常常见的后端需求之一&#xff0c;今天来推荐一款阿里出品的Excel操作神器&#xff1a;EasyExcel。EasyExcel从其依赖树来看是对apache-poi的封装&#xff0c;笔者从开始接触Excel处理就选用了EasyExcel&#xff0c;避免了广泛流传的apache-poi导致的内…

再谈指针

C语言为什么高效&#xff1f;因为C语言有指针。指针是C语言的精华&#xff0c;同时也是C语言的难点&#xff0c;很多人一学到指针就表示头大&#xff0c;指针的指向往往把人搞得晕头转向&#xff0c;甚至有的人为了避免使用指针居然不惜多写几十行代码&#xff0c;无疑增加了工…

Word 2003中为什么修改一个段落的文章结果整篇文档的格式都变?

问题比如说&#xff0c;我选定某一段把颜色改成***&#xff0c;结果整篇文档都变成***了&#xff0c;按撤退健&#xff0c;才能达到效果&#xff08;只有这段变成***&#xff0c;其他的不变&#xff09;。答案打开格式菜单中的[样式和格式]&#xff0c;找到样式中的“正文”。 …

链表反转的两种实现方法,后一种击败了100%的用户!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;链表反转是一道很基础但又非常热门的算法面试题&#xff0c;它也在《剑指Offer》的第 24 道题出现过&#xff0c;至于它有多…

squid代理服务器(捎带的SNAT)

1.传统代理传统代理可以隐藏IP地址 多用于Internet 在Linux中 默认没有安装squid 所以要安装 在red hat中 还要安装perl 语言包的支持 squid代理服务器需要两块网卡 首先保证你的流量是从linux服务器上过的 所以先保证做完SNAT可以互相通信1&#xff09;配置网络参数在试验中一…

MySQL开源工具推荐,有了它我卸了珍藏多年Nactive!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;最近无意间发现了一款开源免费的 MySQL 客户端管理工具&#xff0c;磊哥试用了两天感觉还行&#xff0c;所以今天推荐给各位…

memoryTraining记忆训练小游戏

无聊的时候用C写了一个记忆训练的小游戏、、、 灵感源于一个flash的小游戏学到C语言就用C语言实验了一下&#xff0c;做出来。好久以前的东西了&#xff0c;数组用的还不咋样&#xff0c;现在看看把数组下标0漏掉了、、、掉了修补了修补&#xff0c;先扔这儿吧。源码下载