对内存重叠的深入认识

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

在函数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包中提供的一种可以用来进行精确运算的类型…

日期getUTCMonth()方法以及JavaScript中的示例

JavaScript Date getUTCMonth()方法 (JavaScript Date getUTCMonth() method) getUTCMonth() method is a Dates class method and it is used to get the current month’s value according to the UTC (Universal time coordinated) between the range of 0 to 11, where 0 f…

VB另类技巧(可以用于VBA)-指针的使用

大家都知道C中可以使用指针&#xff0c;但现在VB&#xff08;当然也有VBA&#xff09;也可以使用指针了&#xff0c;这是我在网上看的一篇文章&#xff0c;大家参考一下。想当年东方不败&#xff0c;黑木崖密室一战&#xff0c;仅凭一根绣花针独战四大高手&#xff0c;神出鬼没…

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

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

Java中的异常处理

1 class YiChang{2 public static void main(String[] args){3 A anew A();4 a.show();5 }6 }7 8 class A{9 int[] i{1,2,3}; 10 public void show(){ 11 System.out.println(i[3]); 12 } 13 } 运行上面代码&#xff0c;会抛出这样…

数组copyWithin()方法以及JavaScript中的示例

JavaScript copyWithin()方法 (JavaScript copyWithin() method) copyWithin() method is used to copy the specified elements from an array and replace from specified index within the same array. It changes the this array (actual array). copyWithin()方法用于从数…

多图带你彻底理解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…

作文议论文开头结尾

一、 开头篇 1. Nowadays, it is commonly/widely/generally believed that…., but I wonder… 如今&#xff0c;人们普遍认为……&#xff0c;但是我怀疑…… 2. With the rapid growth of… … have/has become increasingly important in our daily life. 随着……的快速…

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

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

dumpstack_Java Thread类的静态void dumpStack()方法(带示例)

dumpstack线程类静态void dumpStack() (Thread Class static void dumpStack()) This method is available in package java.lang.Thread.dumpStack(). 软件包java.lang.Thread.dumpStack()中提供了此方法。 This method is used to print or display stack tracing of the cur…

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…

Of Study - Francis Bacon

Of StudyFrancis Bacon 弗朗西斯培根Studies serve for delight, for ornament, and for ability. Their chief use for delight, is in privateness and retiring; for ornament, is in discourse;and for ability, is in the judgment and disposition of business.For expe…

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

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

Java日历的getMinimalDaysInFirstWeek()方法和示例

Calendar类的getMinimalDaysInFirstWeek()方法 (Calendar Class getMinimalDaysInFirstWeek() method) getMinimalDaysInFirstWeek() method is available in java.util package. getMinimalDaysInFirstWeek()方法在java.util包中可用。 getMinimalDaysInFirstWeek() method is…

HighCharts: 设置时间图x轴的宽度

这个x轴宽度的设置整了好久&#xff0c;被老板催的要死highcharts的api文档很难找&#xff0c;找了半天也没找到&#xff0c;网上资料少&#xff0c;说的试了下&#xff0c;也没有&#xff0c;我用的图里api文档里没有介绍&#xff0c;这个属性不知道的话&#xff0c;根本不好找…

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

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

C++总结篇(1)命名空间及引用

1、命名空间 1.1概念&#xff1a; 用我自己的话说就是规定一个空间&#xff0c;在该空间内定义的变量和函数只限于在该空间内使用&#xff0c;在该空间外无法直接调用。需要调用须加域名&#xff0c;这也就使得避免了同名变量或者函数引起的冲突。 1.2命名空间定义: 定义命名空…