C语言之内存覆盖
在实现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);
}
我们发现当字符串自己给自己赋值时,当目标字符串大于源字符串要拷贝的字符的个数时,程序就会出现错误,这里就涉及到了内存覆盖问题。
我们首先分析源字符串与目标字符串之间的关系:

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语言之内存覆盖的更多相关文章
- C语言和内存
1.程序的运行 对cpu来说,内存只是一个存放指令和数据的地方,具体的运算在cpu内完成. 1.寄存器(Register) 是CPU内部非常小.非常快速的存储部件,它的容量很有限,对于32位的CPU, ...
- 记一次难忘的排错debug经历(找了5天左右)(涉及内存覆盖)
strcpy和memcpy都没有处理内存覆盖问题. 函数描述 The memcpy function copies count bytes of src to dest. If the source ...
- C语言中内存的申请函数
C语言跟内存申请相关的函数主要有 alloca,calloc,malloc,free,realloc,sbrk等. alloca是向栈申请内存,因此无需释放. malloc分配的内存是位于堆中的,并且 ...
- JVM内存管理------JAVA语言的内存管理概述
引言 内存管理一直是JAVA语言自豪与骄傲的资本,它让JAVA程序员基本上可以彻底忽略与内存管理相关的细节,只专注于业务逻辑.不过世界上不存在十全十美的好事,在带来了便利的同时,也因此引入了很多令人抓 ...
- 不可或缺 Windows Native (9) - C 语言: 动态分配内存,链表,位域
[源码下载] 不可或缺 Windows Native (9) - C 语言: 动态分配内存,链表,位域 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 动态分配内存 链 ...
- c语言之内存的申请malloc() 和释放free()
c语言之内存的申请malloc() 和释放free() 1.如何使用 malloc 函数 malloc是一个函数,专门用来从堆上分配内存.使用malloc函数需要几个要求: 内存分配给谁?分配多大内存 ...
- C语言的内存管理
C语言的内存管理 转载:http://blog.csdn.net/wind19/article/details/5964090 对于一个C语言程序而言,内存空间主要由五个部分组成代码段(.text ...
- (十一)C语言中内存堆和栈的区别
在计算机领域,堆栈是一个不容忽视的概念,我们编写的C语言程序基本上都要用到.但对于很多的初学着来说,堆栈是一个很模糊的概念. 堆栈:一种数据结构.一个在程序运行时用于存放的地方,这可能是很多初学者的认 ...
- C语言堆内存管理上出现的问题,内存泄露,野指针使用,非法释放指针
C语言堆内存管理上出现的问题,内存泄露,野指针使用,非法释放指针 (1)开辟的内存没有释放,造成内存泄露 (2)野指针被使用或释放 (3)非法释放指针 (1)开辟的内存没有释放.造成内存泄露,以下的样 ...
随机推荐
- 编写更好的CSS
编写好的CSS代码能提升页面的渲染速度.本质上,一条规则都没有引擎解析的最快.MDN上将CSS选择符归拆分成四个主要类别,如下所示,性能依次降低. ID 规则 Class 规则 标签规则 通用规则 对 ...
- myeclipse 10的破解以及运行run.bat错误或者双击立即消失的问题
安装包下载: ed2k://|file|[myeclipse.10.0.更新发布].myeclipse-10.0-offline-installer-windows.exe|947752488|73b ...
- ExtJs之Ext.each
<!DOCTYPE html> <html> <head> <title>ExtJs</title> <meta http-equiv ...
- mysql之触发器
触发器 MySQL语句在需要时被执行,存储过程也是如此.但是,如果你想要某条语句(或某些语句)在事件发生时自动执行,怎么办呢?例如:每当增加一个顾客到某个数据库表时,都检查其电话号码格式是否正 ...
- IP TCP HTTP Socket的区别
网络由下往上分为 物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. 通过初步的了解,我知道IP协议对应于网络层,TCP协议对应于传输层,而HTTP协议对应于应用层, 三者从本质上来说没有可 ...
- c++继承中的内存布局
今天在网上看到了一篇写得非常好的文章,是有关c++类继承内存布局的.看了之后获益良多,现在转在我自己的博客里面,作为以后复习之用. ——谈VC++对象模型(美)简.格雷程化 译 译者前言 一个C ...
- ssh2框架搭建
原文:ssh2框架搭建 struts2+spring4.0+hibernate4.0 4.x版本与3.x版本有较大区别,要配置方法须要注意,用到的jar包如下 文件结构 src/application ...
- Head First HTML5 Programming笔记--chapter1 认识HTML5
升级到HTML5 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 //EN" "http://www.w3.org/TR/ ...
- C#中检测某个类(方法、程序集等各种部分)是否应用了指定的特性以及对特性的一些简单操作
前言:不管是自定义的一些特性,或者是C#中内置的特性,均继承自Attribute这个类,这个类也提供了一些方法,方便我们使用. Attribute类有三个静态方法:1.IsDefined,如果有指定的 ...
- MyBatis主键返回
在使用MyBatis做持久层时,insert语句默认是不返回记录的主键值,而是返回插入的记录条数:如果业务层需要得到记录的主键时,可以通过配置的方式来完成这个功能. 比如在表的关联关系中,将数据插入主 ...