在实现memcpy函数的时候,我们说过要考虑内存覆盖的问题,到底什么是内存覆盖呢,他的出现对程序到底有什么影响呢?我们又要如何去解决这种问题的发生?

首先先看一般人经常实现的memcpy函数:

#include<stdio.h>

#include<assert.h>

#include<string.h>

void *my_memcpy(void *dest, const void *src, size_t count)

{

assert(dest!=NULL || src!=NULL);

char *ptmpDest = (char *)dest;

const char *ptmpSrc = (const char *)src;

while(count-- > 0)

{

*ptmpDest++ = *ptmpSrc++;

}

return dest;

}

乍一看这段代码,好像很有道理,经过一些测试也是对的,但程序到底是哪里出了问题呢?首先我们来测试一下:

void main()

{

char str[20] = "abcdefghij";

char str1[20];

my_memcpy(str1,str,strlen(str)+1);//正确拷贝

printf("str1 = %s\n",str1);

my_memcpy(str+2,str,4);//错误,拷贝出现了内存覆盖

printf("str = %s\n",str);

}

我们发现当字符串自己给自己赋值时,当目标字符串大于源字符串要拷贝的字符的个数时,程序就会出现错误,这里就涉及到了内存覆盖问题。

我们首先分析源字符串与目标字符串之间的关系:

    当源字符串给目标字符串赋值时,即从src给dest赋值时,情况二会出现问题。我们知道目标字符串和源字符串都是在操作一个字符串,在情况二中,当src给dest赋值直到dest的开始时,即不超过dest的偏移量时都没有什么问题,但是一旦超过偏移量,由于前面的赋值操作已经将字符串给改变了,然后再用改变过后的字符串再给dest赋值,这就导致了前面内容复制重复了,也就是发生内存覆盖了。在分析其他情况时我们可以发现程序都不会出现内存覆盖问题。
    要解决这个问题其实也不难,我们先明确要拷贝几个字符,找到要拷贝的最后一个字符,然后从后向前依次拷贝:

while(count-- > 0)

{

*(ptmpDest + count) = *(ptmpSrc + count);

}

我们再来分析其他五种情况,可以得出他们的判断条件是:

ptmpSrc >= ptmpDest || ptmpDest >= ptmpSrc+count

只要满足上面的条件就不需要考虑内存重叠的问题,所以实现整体自己实现memcpy的函数代码为:

#include<stdio.h>

#include<assert.h>

#include<string.h>

void *my_memcpy(void *dest, const void *src, size_t count)

{

assert(dest!=NULL || src!=NULL);

char *ptmpDest = (char *)dest;

const char *ptmpSrc = (const char *)src;

//源地址在目的地址的右边,或者目的地址在源地址的右边,但没有交集

//直接拷贝

if(ptmpSrc >= ptmpDest || ptmpDest >= ptmpSrc+count)

{

while(count-- > 0)

{

*ptmpDest++ = *ptmpSrc++;

}

}

else //源地址在目的地址左边,并产生交集,形成内存覆盖,反着拷贝

{

while(count-- > 0)

{

*(ptmpDest + count) = *(ptmpSrc + count);

}

}

return dest;

}

 

C语言之内存覆盖的更多相关文章

  1. C语言和内存

    1.程序的运行 对cpu来说,内存只是一个存放指令和数据的地方,具体的运算在cpu内完成. 1.寄存器(Register) 是CPU内部非常小.非常快速的存储部件,它的容量很有限,对于32位的CPU, ...

  2. 记一次难忘的排错debug经历(找了5天左右)(涉及内存覆盖)

    strcpy和memcpy都没有处理内存覆盖问题. 函数描述 The memcpy function copies count bytes of src to dest. If the source ...

  3. C语言中内存的申请函数

    C语言跟内存申请相关的函数主要有 alloca,calloc,malloc,free,realloc,sbrk等. alloca是向栈申请内存,因此无需释放. malloc分配的内存是位于堆中的,并且 ...

  4. JVM内存管理------JAVA语言的内存管理概述

    引言 内存管理一直是JAVA语言自豪与骄傲的资本,它让JAVA程序员基本上可以彻底忽略与内存管理相关的细节,只专注于业务逻辑.不过世界上不存在十全十美的好事,在带来了便利的同时,也因此引入了很多令人抓 ...

  5. 不可或缺 Windows Native (9) - C 语言: 动态分配内存,链表,位域

    [源码下载] 不可或缺 Windows Native (9) - C 语言: 动态分配内存,链表,位域 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 动态分配内存 链 ...

  6. c语言之内存的申请malloc() 和释放free()

    c语言之内存的申请malloc() 和释放free() 1.如何使用 malloc 函数 malloc是一个函数,专门用来从堆上分配内存.使用malloc函数需要几个要求: 内存分配给谁?分配多大内存 ...

  7. C语言的内存管理

    C语言的内存管理 转载:http://blog.csdn.net/wind19/article/details/5964090   对于一个C语言程序而言,内存空间主要由五个部分组成代码段(.text ...

  8. (十一)C语言中内存堆和栈的区别

    在计算机领域,堆栈是一个不容忽视的概念,我们编写的C语言程序基本上都要用到.但对于很多的初学着来说,堆栈是一个很模糊的概念. 堆栈:一种数据结构.一个在程序运行时用于存放的地方,这可能是很多初学者的认 ...

  9. C语言堆内存管理上出现的问题,内存泄露,野指针使用,非法释放指针

    C语言堆内存管理上出现的问题,内存泄露,野指针使用,非法释放指针 (1)开辟的内存没有释放,造成内存泄露 (2)野指针被使用或释放 (3)非法释放指针 (1)开辟的内存没有释放.造成内存泄露,以下的样 ...

随机推荐

  1. Sqli-labs less 56

    Less-56 与less54.55形式是一致的,我们关注sql语句, $sql="SELECT * FROM security.users WHERE id=('$id') LIMIT 0 ...

  2. CAS登录后回传除了ticket参数以外的其他自定义参数

    在一次项目的技术选型中,选择了easyui+cas+shiro+spring的组合,cas实现了单点登录,这使得在一个应用中嵌入另一个应用的页面来展示数据所涉及到的授权方面变得简单. 由于shiro在 ...

  3. hdu 4618(最大回文子矩阵)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4618 昨天多校的一道题,说多了都是泪啊,为了一道图论题,磨了那么久,结果是别的题都没看,没办法,补呗. ...

  4. android自动化环境搭建

    android自动化环境安装指南 1.appium相关安装(eclipse下)见http://www.cnblogs.com/wangcp-2014/p/5717589.html参考selenium的 ...

  5. 在Unity中使用贝塞尔曲线(转)

    鼎鼎大名的贝塞尔曲线相信大家都耳熟能详.这两天因为工作的原因需要将贝塞尔曲线加在工程中,那么MOMO迅速的研究了一下成果就分享给大家了哦.贝塞尔曲线的原理是由两个点构成的任意角度的曲线,这两个点一个是 ...

  6. C#DataGridView 美化

    private void dataGridView(DataGridView dataGridView) { System.Windows.Forms.DataGridViewCellStyle da ...

  7. Wireshark 网络抓包工具Wireshark的使用

    阅读目录 wireshark介绍 wireshark不能做的 wireshark VS Fiddler 同类的其他工具 什么人会用到wireshark wireshark 开始抓包 wireshark ...

  8. jQuery常见面试题(转)

    代码以jQuery 1.83 为例 一 :Q: What is the difference between .get(), [], and .eq()? A: eq返回原生jQuery对象,截取某些 ...

  9. iOS:实现MKAnnotation协议,在地图上设置大头针,点击显示具体的位置信息

    如何添加大头针(地标): 通过MapView的addAnnotation方法可以添加一个大头针到地图上 通过MapView的addAnnotations方法可以添加多个大头针到地图上 –(void)a ...

  10. iOS:UIAlertController和UIAlertAction的详解

    提示框控制器:UIAlertController 提示框按钮:UIAlertAction   功能:用来提示信息,并给出一些可以进行选择的按钮来处理相应的要求.   注意:在Xcode的iOS8 SD ...