在实现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. 141029 V7 异步通知测试,15分钟循环代码重构,同步更新payInfo测试,支付成功timer测试成功说明

    支付成功之后的1分钟定时任务:测试成功. 2014-10-29 17:16:06,892 DEBUG [http-bio-8086-exec-1] org.springframework.web.se ...

  2. Ruby中的Profiling工具

    看看如何调试Ruby的性能问题 李哲 - APRIL 08, 2015 Ruby内置的profiler 内置的profiler实现的很简单,在ruby2.2中只有150行代码,大家可以看看它的实现pr ...

  3. LA 3350

    The NASA Space Center, Houston, is less than 200 miles from San Antonio, Texas (the site of the ACM ...

  4. POJ 2992 Divisors (求因子个数)

    题意:给n和k,求组合C(n,k)的因子个数. 这道题,若一开始先预处理出C[i][j]的大小,再按普通方法枚举2~sqrt(C[i][j])来求解对应的因子个数,会TLE.所以得用别的方法. 在说方 ...

  5. HDU 2709 Sumsets(递推)

    Sumsets http://acm.hdu.edu.cn/showproblem.php?pid=2709 Problem Description Farmer John commanded his ...

  6. Xamarin for Mac 2.0.2.35 稳定版 破解补丁 Preview 2

    注意:该破解补丁未经过广泛测试 前提概要 1.该补丁,仅涉及以下产品,所有版权归 Xamarin 所有,仅供学习练手: ① Xamarin.iOS 8.10.2.37 Xamarin.iOS 8.10 ...

  7. hdu 3092 Least common multiple

    思路: 容易知道,分解成素数的lcm肯定是最大的,因为假设分解成2个合数,设定x为他们的 最大公约数, 那么他们的最小公倍数就要减少x倍了 然后如果是素数之间的最小公倍数,那么就只是他们的乘积,同样的 ...

  8. C# Socket 入门1(转)

    1.   服务端程序  1 using System;  2 using System.Collections.Generic;  3 using System.Text;  4 using Syst ...

  9. gcc 优化选项 -O1 -O2 -O3 -Os 优先级

    http://hi.baidu.com/xiaole10368/item/7cea9b1369cc240db88a1a5c 少优化->多优化: O0 -->> O1 -->&g ...

  10. Linux基础--例行工作

    1.仅进行一次的工作排程--at at的工作情况其实是这样的: 1)先找寻/etc/at.allow这个档案,写在这个档案中的使用者才能使用at,没有在这个档案中的使用者则不能使用at(即使没有写在a ...