




免费预览已结束,剩余26页可下载查看
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
本科生毕业设计 论文 学院 系 软件学院 专 业 软件工程 学 生 成 指导教师 完成日期 年 4 月 学院本科生毕业设计 论文 C 语言内存检测代码库的分析与设计 The analysis and design of C language memory test code library 总 计 24 页 表 格 0 个 插 图 17 幅 学学 院院 本本 科科 毕毕 业业 设设 计 论文 计 论文 C 语言内存检测代码库的分析与设计 The analysis and design of C language memory test code library 学 院 系 软件学院 专 业 软件工程 学 生 姓 名 学 号 8 指 导 教 师 职称 评 阅 教 师 完 成 日 期 2011 年 4 月 C 语言内存检测代码库的分析与设计 C 语言内存检测代码库的分析与设计 软件工程专业 摘 要 程序员在 C 语言编程的过程中极易出现内存泄露 内存写越界 等一系列问题 从而导致计算机的性能降低 最终 过多的可用内存被分配 掉导致全部或部分设备停止正常工作 或者应用程序崩溃 本系统针对这 一问题做了研究 通过对 C 语言常用库函数中的动态分配内存所有到如 malloc realloc calloc free 等一些函数进行重写设计封装 并且对每次申 请内存进行记录并标示 在内存释放的时候调用封装后释放函数对其内存信息 标示进行修改 在程序结后调用 atexit 函数进行内存信息块的检索与统计内存 使用信息 最终查出内存泄露 内存越界写等错误同时提示用户并保存出错信 息 关键词 内存泄露 动态分配内存 检测内存 The analysis and design of C language memory test code library The major of software engineering LV Xiao cheng Abstract Memory leaks and the series of problems appear easily in the processing of the C programming language such as memory write cross border resulting in computer performance reduced Finally the excessive available memory assigned off cause all or part of the equipment to stop work normally or application collapse This system according to this problem based on C language commonly used in the library functions such as dynamic memory allocations all to realloc calloc malloc some function free to design encapsulation and rewrite record for each application and labeled memory in memory when calls after release of its release function package labeling modified memory information After the program atexit function call memory information retrieval and statistics block memory use information finally find out memory leaks memory cross border written ect error and prompt the user and save the error messages Key words Memory leaks Dynamic memory allocations Detection memory C 语言内存检测代码库的分析与设计 目目 录录 1 绪论 1 1 1 课题背景与意义 1 1 2 国内外发展及现状 1 1 2 1 ECI executable code interception 1 1 2 2 OCI object code insertion 2 1 2 3 SCI source code instrumentation 2 1 3 论文研究的主要内容 2 1 3 1 内存分配问题 2 1 3 2 内存泄露 3 1 3 3 内存越界存储 3 2 需求分析 3 2 1 总体需求 3 2 1 1 自动检测尽可能多的错误 尽可能的提高软件质量水平 3 2 1 2 提供完整而准确的诊断错误 使错误调试工作更有效更简单 3 2 2 系统功能分析 3 2 2 1 获取动态内存分配的行记录 4 2 2 2 获取动态内存分配对同一块内存的使用频率 4 2 2 3 获取动态内存分配所使用的内存大小 4 2 2 4 获取动态内存释放空指针的行为 4 2 2 5 获取动态内存分配未释放的内存块 4 2 2 6 获取可能存在内存越界存储的内存块 4 2 3 系统要求 4 3 总体设计 5 3 1 获取动态内存分配的行记录 5 3 2 获取动态内存分配对同一块内存的使用频率 5 3 3 获取动态内存分配所处的文件 5 3 4 获取动态内存分配所使用的内存大小 7 3 5 获取动态内存释放空指针的行为 7 3 6 获取动态内存分配未释放的内存块 7 3 7 内存越界存储 8 4 实现与测试 9 C 语言内存检测代码库的分析与设计 4 1 系统内存信息的获取 10 4 2 系统内存信息的操作 10 4 3 用指针处理链表 12 4 3 1 基于链表实现内存信息使用次数 13 4 4 系统内存越界存储操作 14 4 5 系统内存信息的保存 14 4 6 C 语言预编译 16 4 6 1 C 语言头文件的结构 16 4 6 2 C 语言头文件作用 16 4 6 3 通过宏提高代码可用性 17 4 6 4 通过宏实现函数的重写 17 4 7 程序的结束 17 4 8 系统的调试 19 4 8 1 C 语言内存检测系统 19 4 8 2 对于没有申请即进行释放或已经释放进行二次释放 20 4 8 3 申请的内存没有释放 20 4 8 4 内存越界写操作 21 4 9 系统的使用 22 结束语 23 致谢 24 C 语言内存检测代码库的分析与设计 1 1 绪论 1 1 课题背景与意义 计算机软件在当今社会中发挥着越来越重要的作用 无论是在人们的日常 生活中 还是在一些关键系统中 例如银行系统 飞行控制器和医疗系统 都大 量地使用软件 软件运行的正确与否影响到人们的正常生活 软件的失效甚至 会引发巨大的损失 作为一种重要的编程语言 C 语言至今仍被大量应用于开 发各种系统软件与应用软件 同其它一些语言一样 C 显式地支持指针操作以 及动态内存的处理 这大大地提高了语言的表达能力 但是 使用带指针的语 言编程是一项容易出错的工作 有可能产生大量的内存错误 又因为有些这样 的错误不易重现 难以查找诱发错误的原因 所以内存错误通常很难检测 C 语言使得用户能够直接控制程序内存资源的使用 这对于实现运行程序 的高性能或提高计算机资源的利用率是至关重要的 但正是因为 C 语言中灵活 的内存管理机制 使 C 程序很容易产生内存泄漏等内存方面的程序错误 同时 内存泄露和体现具有隐蔽性和积累性的特征 往往容易被人们忽视 由于程序的 复杂性以及人类思维的局限性等主客观原因 程序员在利用 C 编程语言这一特点 管理动态内存时 很容易造成程序内存泄漏 如果不及时发现并解决程序中内存 泄漏的问题 内存泄漏故障在 C 中是非常危险的 通常难以观察到的 但随着 故障的积累 程序的整体性能会下降 严重时会导致死机或异常退出 与此同 时长时间运行存在内存泄漏的程序 将浪费大量宝贵的系统内存资源 从而导致 系统运行速度减慢甚至系统崩溃等严重后果 为了提高软件的性能 保证软件的 可靠性 C 程序的内存检测具有重要的意义 目前各种内存泄漏检测系统通过对 内存泄漏动态检测法以及内存泄漏产生原因的分析与研究 提出了结合内存泄漏 动态检测法 数据流分析以及程序执行路径跟踪技术的内存泄漏检测和分析方 法来对内存错误产生路径和原因的分析 提供分配动态内存的源代码位置信息 检测被测程序中是否存在内存错误 1 2 国内外发展及现状 1 2 1 ECI executable code interception ECI 并不对源码或目标码进行分析 而是在链接或执行时直接替换相应的 系统调用 例如现在常见的 code test 就是采用的这种技术 直接的查找系统 调用 迫使程序调用自己的函数 为了做到这一点 需要大量的系统调用名 或者替换系统调用 1 C 语言内存检测代码库的分析与设计 2 1 2 2 OCI object code insertion OCI 直接对目标码进行分析 并加入相应的汇编代码 例如 purify 和 test RT 的 puritfylt 就是采用这种技术 OCI 读入目标文件 并在汇编一级对其进 行加入 它也有自己的内存分配和释放函数库 并用它们获取系统的相应调用 OCI 只能检测动态内存的破坏问题 它所使用的技术与 ECI 类似 为每一个内 存块建一堵墙 如果在执行过程中程序试图写入墙的地址就会报告错误 这也 意味着 OCI 不能检测跳墙事件 因此不能检测到所有的内存破坏错误 为了检 测未初始化内存的读操作 OCI 使用了着色技术在程序的开始 假设所有的内 存未初始化 当程序执行时 记录每次写操作及内存位置 并标为初始化 问 题是 OCI 技术没有理解其操作的数据结构 因此也无法知道读写操作是否有正 确的类型和形式 只能看到发生在不允许的内存地址 这样的检查是相当的虚 弱的 1 2 3 SCI source code instrumentation SCI 对源程序进行扫描分析 收集所有必要的检测信息 并加入相应的检 测代码 保存在临时文件中 并对编译生成目标码供边接用 例如 insure 就是采用的就种技术 SCI 技术对每个指针操作内存读写和其它操作进行加工 处理 它比其它技术更完整地理解程序的行为 SCI 更高的准确性就是其结果 在执行过程中 SCI 建立了一个数据库 包含每个动态静态内存信息块 SCI 还 有一个程序使用的指针数据库 对每次操作进行准确的跟踪 因此没有跳墙的 可能 1 3 论文研究的主要内容 1 3 1 内存分配问题 在 C 语言中内存分配一直是一个核心的内容 它直接关系到程序的运行状 态 运行结果 所以内存的分配是否清晰是非常重要的 内存逻辑分为四大部分 代码区 堆区 栈区和全局数据区 静态数据区 这四大部分包含程序运行过程中所有的数据内容 代码区 存放程序的二进制代码 全局数据区 静态数据区 程序启动时分配的空间 在程序运行期间一 直都存在 如全局变量 static 变量等 栈区 用来存放自动变量 既函数的局部变量 在函数运行时申请 函数 结束时自动释放 在程序编译时确定 堆区 由程序员自由控制的内存区域 可根据需要自主分配空间大小 在 程序调用时候通过 C 语言标准库中 malloc 来分配内存 但在程序结束时并不会 C 语言内存检测代码库的分析与设计 3 自动释放 因此需要程序员自己调用 C 语言标准库中 free 来释放内存 有了上面的 C 语言中动态分配内存的原理 现在就可以来研究内存泄露与 内存越界的问题 1 3 2 内存泄露 内存泄露通常是指分配出去的内存使用完毕后没有释放掉 未被收回 长 此以往 当再要求分配内存时 没有足够的内存可以分配 就会报出内存泄露 memory leak 它的一般表现方式是程序运行时间越长 占用内存越多 最 终用尽全部内存 整个系统崩溃 由程序申请的一块内存 且没有任何一个指 针指向它 那么这块内存就泄露了 内存泄露的原因实质是没有释放向系统申 请的内存 有许多情况会导致内存泄露 如程序员编写程序时对内存管理的考 虑不是十分周全 没有在程序的全部执行路径中释放内存 2 1 3 3 内存越界存储 在 C 语言中并不对越界读取进行检测 因为 C 语言完全是依赖程序员 这 些事情都是由程序来完成的 C 语言越界读取 overread 是指读取了比它应 用还多的字节 这还不会引起大太的问题 然而一旦 C 语言越界存储数据的话 可能遗失这个数据 更有可能更改了其它不可知的数据 2 需求分析 2 1 总体需求 随着网络经济时代的到来 社会飞速的发展 人们的生活发生着日新月异 的变化 高新技术正驱赶着人们生活的脚步 人们对工作生活的要求也日益提 高 特别是计算机的应用及普及到经济和社会生活的各个领域 程序编程的代 码量也随之急剧的增加 代码的调试问题也随之而来 面对大量的代码如何快 速的找出程序中存在的动态内存分配问题是每个程序员都要考虑的事情 从软 件开发的整体上考虑 总体要满足以下两个方面的要求 2 1 1 自动检测尽可能多的错误 尽可能的提高软件质量水平 检测系统就是为了找出程序中存在内存操作错误 对于能检测出越多错误 的系统是设计所需要的结果 2 1 2 提供完整而准确的诊断错误 使错误调试工作更有效更简单 检测系统中存在的内存错误 本质上是为了之后对系统进行修改加强之用 的 在检测中应能够给出详细的出错行 以及所表现出来的错误类型 以便更 好的对程序进行调试修改 C 语言内存检测代码库的分析与设计 4 2 2 系统功能分析 2 2 1 获取动态内存分配的行记录 我们事先并不会知道在程序的什么地方会出现内存泄露问题 我们只能记 录出每一个可能出现内存泄露的地方 在该代码库中将使用 行记录来完成这 一功能 即在程序中每一次将要分配内存的地方 将自动调用代码库中的相应函数 进行相应的替换 在分配内在的代码所在的行号 写进相应的信息记录块中 为以后相应的检测内存泄露 以及一旦出现内存泄露的问题从而进行很好的定 位提供了很好的依据 2 2 2 获取动态内存分配对同一块内存的使用频率 我们在一个程序的运行过程中是否很好的利用了内存 从而对内存的利用 是否是重复利用的 我们将会在代码库中增加一个变量 用来记录程序中每一 块内存的使用情况 进行统计汇总 最后为分析程序对内存的使用是否合理进 行评价提供可靠依据 2 2 3 获取动态内存分配所使用的内存大小 对每一次的内存使用的情况进行分析 得出这一次所使用的最大内存 2 2 4 获取动态内存释放空指针的行为 在程序每次调用 free 函数进行动态内存的释放的时候 将会对已分配的地 址进行一次遍历从而查出这个指针是否是已存在的 从而进一步得到是否存在 使用未分配内存的情况 2 2 5 获取动态内存分配未释放的内存块 每当程序运行结束时 对程序中未释放的内存块进行统计输出 以便程序 员的进一步调试 2 2 6 获取可能存在内存越界存储的内存块 每当程序结束时 对程序中存在的内存越界写操作的指针操作进行统计输 出 以便宜程序员的进一步的调试 2 3 系统要求 1 准确性 系统可以找出并保存在程序运行过程中所有的动态内存操作 并可以将其信息进行全部的保存 并统计出信息 2 安全性 程序运行过程中所产生的动态内存分配信息以及内存泄露 的信息应能够长久的保存 便于随时的查阅 C 语言内存检测代码库的分析与设计 5 3 易用性 其它程序的设计与代码的编写应尽可能的减少与本代码的 交叉的地方 其它程序的编写应及可能不做修改 3 总体设计 3 1 获取动态内存分配的行记录 存检测错误应该首先确定出错行 才能准确定位 对 C 语言中原有的 malloc 等内存申请函数进行替换 并在参数列表中加入 line 宏 从而准确 的捕捉到行记录信息 如下图 3 1 所示 开始 main主函数 入口 是否存在内存分配 调用宏替换 Xmalloc等 加入行记录 调用add main主函数结束 结束 Y ERROR 是否存在内存分配 Y N N 图 3 1 行记录流程图 3 2 获取动态内存分配对同一块内存的使用频率 系统中对内存的使用率 在于对同一块内存的使用次数的统计 故在 C 语 言中原先的 malloc 等申请动态内存的函数进行重写 每当申请内存成功时 紧 接着下面应该查找这一块动态内存是否已存在在链表中 并进行计数 如下图 3 2 所示 3 3 获取动态内存分配所处的文件 C 语言内存检测代码库的分析与设计 6 存检测错误也该确定出错文件 以便日后查阅 对 C 语言中原有的 malloc 等内存申请函数进行替换 并在参数列表中加入 file 宏 从而准确的捕捉 到文件信息 如下图 3 3 所示 开始 main主函数 入口 是否存在内存分配 调用宏替换 Xmalloc等 加入行记录 调用add 结束 N Y 次数加一遍历链表上否存在 次数设为一 Y main函数结束 N 图 3 2 内存使用频率记录流程图 C 语言内存检测代码库的分析与设计 7 开始 main主函数 入口 是否存在内存分配 调用宏替换 Xmalloc等 加入文件记录 调用add main主函数结束 结束 N Y 图 3 3 程序文件记录流程图 3 4 获取动态内存分配所使用的内存大小 对于统计内存使用的效率与总使用内存大小则应该对每一次申请的内存大 小进行统计以便程序结束的时候能够统计出内存使用的效率与总大小 如下图 3 4 所示 开始 main主函数 入口 是是否否存存在在内内存存分分配配 调用宏替换 Xmalloc等 size进行记录 调用add main主函数结束 结束 N Y 图 3 4 内存大小记录流程图 C 语言内存检测代码库的分析与设计 8 3 5 获取动态内存释放空指针的行为 检测系统应该能够检测出对空指针的释放行为 每当程序使用 free 函数时 系统进行调用重写后的 free 函数进行计算其释放的指针是否存在在链表信息中 如下图 3 5 所示 3 6 获取动态内存分配未释放的内存块 每当程序执行结束的时候 由系统自动调用程序 atexit 函数 对程序过 程中存在的一系列动态内存申请与释放信息进行检查 对链表中未标记释放的 内存块进行统计并警告用户 如下图 3 6 所示 开始 main主函数 入口 是否存在释放内存 调用宏替换 xfree 调用delete 结束 N Y 正常释放 遍历链表上否存在 空指针释放 Y main函数结束 N 图 3 5 释放空指针记录流程图 C 语言内存检测代码库的分析与设计 9 开始 main函数结束 atexit函数 调用put 标示位是否为1未释放 结束 N 链表是否结束 Y 已释放 N Y 图 3 6 未释放内存记录流程图 3 7 内存越界存储 在用户申请的内存块前后增加一块一定大小的内存块 并写入特定的数据 一旦程序中存在越界的写操作 那么相应的检测块的特定数据就会被更改 那 么对内存块进行检查就可以检测出内存是否存在越界写操作 如下图 3 7 所示 开始 main主函数 入口 是否存在动态分配 调用宏替换 Xmalloc等 增加检测块 结束 N Y 初始化检测块 main函数结束 图 3 7 内存越界记录流程图 C 语言内存检测代码库的分析与设计 10 3 8 系统的结构流程 开始 main主函数 入口 是否存在动态分配 封闭函数 保存信息 结束 N Y main函数结束 调用atexit 统计输出信息 图 3 8 系统结构流程图 4 实现与测试 本系统采用传统的软件开发生命周期的方法 采用自定向下 逐步求精的 结构化的软件设计方法进行实现 4 1 系统内存信息的获取 对于系统中出错查找的依据 行记录 是相当重要的 这是系统中能否快 速的查找出内存泄露的关键 如果你知道存在内存泄露但不知道在什么位置 对有存在于大量代码中的程序这是相当痛苦的一件事 LINE 宏表示当前 c 语句在源文件中的行数 3 main printf nline d LINE getch C 语言内存检测代码库的分析与设计 11 图 4 1 行记录结果图 有了 C 语言自带的行记录宏就可以很好的记录每个动态内存分配所在的行 数 用于后面的内存泄露分析将有很大的帮助 4 2 系统内存信息的操作 对系统内存信息的操作主要是通过结构体来临时存储动态内存分配时产生 的一些信息 然后通过链表操作存储在链表中 当程序结束时 由系统自动将 动态内存分配使用情况进行输出到指定的文件中 结构体的使用 有时需要将不有类型的数据组合成一个有机的整体 以便于引用 这些组 合在一个整体中的数据是互相联系的 应当把它们组织成一个组合项 在一个 组合项中包含若干个类型不同的数据项 在 C 语言中这种结构就叫着结构体 4 定义一个结构的一般形式为 Struct 结构体名 类型标识符 1 成员名 1 类型标识符 2 成员名 2 类型标识符 n 成员名 n 在本系统中主要用到结构来临时的存储一个动态内存分配过程中产生的一 系列的内存数据进行保存 整个系统的内存信息的获取 分为以下几个方面 1 申请内存块的首地址 用于以后释放该块内存块使用 2 申请内存块的大小 用于记录所分配内存的大小 3 申请内存块的行记录 这对于出现内存泄露有着至关重要的地位 内存 块的行记录即为程序中调用申请内存块的行 这样一旦出现内存泄露问题可以 很好的定位出错的地方 这样更方便去修改程序 这也体现出本系统的方便与 C 语言内存检测代码库的分析与设计 12 实用 不用在成千上万行代码中去寻找 1 申请内存块次数 记录该内存块的被分配的次数 可以用来统计系统使 用内存的情况 方便找寻使用内存块的大小 也可以为进一步优化内存的使用 提供可靠数据进行分析 2 申请内存块的释放标记符 这是系统中另一个关键的信息 对于所申请 的内存块的释放进行信息的统计 也是能否发现系统中存在内存泄露的关键所 在 struct info unsigned int address unsigned int size unsigned int line unsigned int count unsigned char flase struct info lxc 每当有动态内存分配的时候通过 Xmalloc 对该结构内写入动态分配内存时 所产生的信息 void ptr malloc size if ptr NULL lxc address ptr lxc size size lxc line line add lxc address lxc size lxc line return ptr 在其中依然使用原 malloc 进行内存的动态分配并将地指针返回 保证明其 动态分配内存不受影响 结构中的 count flase 的值将会在 add 中进行相应的 修改 q data address address q data size size q data line line q data count 1 q data flase 1 q next head next C 语言内存检测代码库的分析与设计 13 head next q 4 3 用指针处理链表 在实际的程序设计过程中 链表是一种常用的数据结构 由若干个节点组 成 它可以在程序的执行过程中动态地建立起来 这种数据结构在程序的执行 过程中是动态可变的 本系统中所使用的链表结构如下 1 头指针 存放一个地址 该地址指向第一个元素 2 结点 用户的实际数据和链表节点的指针 该链表的一般结构如下图所示 其中 head 是链表的头指针 它指向第一个 元素 第一个元素又指向第二个元素 第二个元素指向第三个元素 直到最 后一个元素 最后一个元素不再指向其它元素 称其为 表尾 NULL 是链表 的结束标志 图 4 2 指针操作链表图 这种链表的数据结构必须利用指针变量才能实现 即一个结点中应包含一 个指针变量 用它存放下一结点的地址 链表是线性表 又可分为静态链表和 动态链表 静态链表的节点在程序开始时运行时生成的 它们有自己的名称 在各个程序的运行期间占据固定的存储单元 不能动态开辟结点 也不能释放 自己开辟的结点 动态链表可以动态分配内存避免内存的浪费 因为本系统中 无法事先知道动态申请内存的情况与次数 故本系统采用动态分配方式的链表 4 链表的声明如下 Struct 链表名 类型标识符 1 成员名 1 类型标识符 2 成员名 2 C 语言内存检测代码库的分析与设计 14 类型标识符 n 成员名 n Struct 链表名 next 本系统中采用链表的形式来保存每一次动态分配内存时所产生的数据 其 声明结构如下所示 struct node struct info data struct node next 4 3 1 基于链表实现内存信息使用次数 关键在于 对同一块内存在释放之后再次进行分配时 应记住上一次的分 配情况 并通过遍历链表进行信息对比 如发现这一块内存已分配过时 就不 用再增加链表进行写入内存信息 而是将这块内存的信息进行中的内存使用次 数进行加一 并更新其中的行记录 因为这一块内存既然进行了再次分配 那 么就可以表明它上一次的分配已经成功的释放不会造成内存泄露问题的存在故 可将其修改为最新的内存分配的行记录 while p next p p next if p data address address p data line line 以上为遍历链表时所要进行修改的内存分配记录 4 4 系统内存越界存储操作 在 C 语言中动态申请内存的时候 重写的函数会申请一块比用户所需内存 更大一点的内存 从而使用额外的内存作为检测是否存在内存越界操作的依据 define xmalloc size xxmalloc size 1 LINE 在宏定义的预处理过程中对每个内存申请的函数增加一个额外的内存来做 为检测的内存块 并且在申请动态内存的时候 将额外的内存块事先写入检测 C 语言内存检测代码库的分析与设计 15 的数据 ptr1 ptr size ptr 0 在程序结束时对其额外检测内存块进行检测 如其内存块数据不一致则可 认为其内存块存在内存越界的操作 if p data ptr 0 printf else printf nline d p data line printf nMemory out of bounds 4 5 系统内存信息的保存 在程序动态分配内存所产生的一系列数据 以及检测内存泄露所产生的一 系列数据都应能够长时间的保存方便程序员查看 因此应将其信息保存在文件 中 在 C 语言中应使用文件进行处理 在对文件进行操作时 必须遵守以下步 骤 1 打开文件 2 处理文件 包括读文件 写文件等 3 关闭文件 每一个文件被打开或创建之后 都存在一个唯一确定该文件的文件标识 以后对文件的处理 包括读 写等 就可以通过文件标识来进行 而不需要使 用文件名 对于 缓冲文件系统 来说 其文件标识被称为 文件类型指针 它的定 义形式如下 FILE fp 其中 FILE 是由编译系统定义的一种结构类型 其中存放着有关文件的一 些信息 这些信息对用户来说是不需要了解的 fp 是指向 FILE 结构类型的指 针变量 它是在打开或创建文件时获得的 5 FILE fp if fp fopen f lxc txt at NULL C 语言内存检测代码库的分析与设计 16 printf nCannot open file strike any key exit getch exit 1 if head 0 fputs nyou do not malloc t t t fp else p head while p next p p next fputs naddress is t t t fp fprintf fp d p data address fputs nsize is t t t fp fprintf fp d p data size fputs nline is t t t fp fprintf fp d p data line fputs ncount is t t t fp fprintf fp d p data count fputs nflase is t t t fp fprintf fp s p data flase fclose fp 以上为系统结束时通过Atexit zzh 调用put将其信息输到指定的文件中 进行保存 方便日后的查询 4 6 C 语言预编译 C 语言中 并没有任何内在机制来完成如下一些功能 在编译时包含其他 源文件 定义宏 根据条件决定编译时是否包含一些代码 要完成这些工作 就需要使用预处理程序 尽管在目前绝大多数编译器都包含了预处理程序 但 通常认为它们是独立于编译器的 在预处理过程读入源代码 检查包含预处理 C 语言内存检测代码库的分析与设计 17 的语句和宏定义 并对源代码进行响应的转换 预处理还会删除程序中的注释 和多余的空白字符 6 C 语言采用模块化的编程思想 需合理的将一个很大的软件划分为一系列 功能独立的部分合作完成系统的需求 在模块划分上主要依据功能 模块由头 文件和实现文件组成 头文件用于保存程序的声明 实现文件用于保存程序的 实现 C 语言中头文件以 h 为后缀 实现文件的定义以 c 为后缀 4 6 1 C 语言头文件的结构 1 头文件开头处的版权和版本声明 2 预处理块 3 函数和全局变量的声明 7 ifndef LXC H 作用 防止 lxc h 被重复引用 define LXC H include 作用 引用标准库的头文件 include 作用 引用非标准库的头文件 void Function1 作用 全局函数声明 struct 作用 结构体声明 endif 4 6 2 C 语言头文件作用 在 C 语言中使用头文件可以方便全局变量的声明 在头文件中进行声明即 可 只要是包含这个头文件的 C 文件都以使用 同时也防止了全局变量的多次 赋值造成的影响 C 语言头文件可以方便模块化的开发 减少程序员的代码量 只需将要使 用的头件进行包含即可使用其中的函数 而且 C 语言头文件可以起到隐藏源代码的作用 在发行过程中只给用户头 文件 当用户看到头文件中的函数就可以知道该头文件中的函数的功能 从而 隐藏了其实现代码 提供给用户的只是一个函数的接口 8 4 6 3 通过宏提高代码可用性 C 语言内存检测代码库的分析与设计 18 在动态内存分配函数中插入定位所使用的行记录 将会使函数的参数变的 过于庞大 这样不利用代码的使用 故在 C 语言头文件中对动态内存分配函数 调用预处理宏进行函数的替换 从而提高代码的可用性 9 在其头文件中将使用如下的预编译进行函数参数的替换 define calloc elements size xxcalloc elements size LINE define malloc size xxmalloc size LINE define free mem ref xxfree mem ref 从而使以后程序进行动态内存泄露的检测时可以 很好的进行行记录的定 位 但这样的预处理会对其实现函数中的动态内存分配造成影响 故在其实现 文件中不应出现这样的预处理 这样的预处理只应在程序员的代码中进行体现 在其实现文件中将使用以下的预编译 消除头文件中的函数参数替换所造 成的影响 undef malloc undef calloc undef free 4 6 4 通过宏实现函数的重写 学习语言的人大概都已经习惯了 java 中函数的重载了 因为那在面向对象 的世界里好像处处皆是 可到了 c 语言中就迷惑了 怎么一下了 想写几个功能类 似 但参数不同的函数 好像就得重复写几个不同名字 麻烦而且弱智 其实 c 中 也可以 重载 利用 va 函数及宏 10 在 C 语言用利用宏和预处理进行实现其类似的函数重写 define fun size size fun size size line Void fun int size int size 通过以上的预处理后 fun 函数中就可以增加一个 line 的参数 从而实 现 C 语言中函数的重写 4 7 程序的结束 在C语言中main作为函数的唯一入口 正常结束程序也是从main中结束的 在C语言程序中 程序员不知道什么地方不再用动态内存分配 故也不知道什么 时候进行信息的保存是最好的 故在使用本代码库的时候应该在要检测的代码main函数未尾加上一句如下 代码 Atexit zzh C 语言内存检测代码库的分析与设计 19 函数名 atexit 功 能 注册终止函数 即 main 执行结束后调用的函数 用 法 int atexit atexit t func 注意 atexit 注册的函数类型应为不接受任何参数的 void函数 exit调用这些注册函数的顺序与它们 登记时候的顺序相反 11 void zzh put print getch 系统结束中的 zzh只是对系统运行过程中的动态内存分配情况进行处理 输出 当系统调用本代码库时若能正确运行 那么在程序结束时将会输出以下 的动态内存分配信息 图 4 3 程序在屏幕上输出结果 其相应的文本文件中也会有类似的记录 C 语言内存检测代码库的分析与设计 20 图 4 4 程序在文件中保存结果 4 8 系统的调试 系统的调试可以分为两部分 其一是看是否按照需求 实现了所有的功能 其二是尽可能的考虑所有特殊情况 包括大量的申请释放内存操作对系统时间 及内存方面的影响 对输出的内容进行定位等 由于没有真正的用户 一切测 试工作都是自己完成的 4 8 1 C 语言内存检测系统 调试工作与编程是同时进行的 我每编一个模块 都会测试一下此模块的 功能是否实现 但通常 这时的测试只考虑到正常的情况 以及一些可以想到 的错误情况 不可能也没有精力解决所有可能发生的问题 由于此系统是基于 C 语言的内存检测系统 故要对各种可能出现的情况进 行一一测试 由于个人问题不可能想到所有的情况 现对自己在开发过程中能 想到的问题进行了一一测试如下 1 程序没有进行动态内存操作 如果一个 C 语言程序从开始到结尾都没有用到 C 语言动态内存分配那么也 就不会出现内存泄露的问题 当然也就没有必要进行内存检测 但有的时候由 于代码过长 程序员自己也搞不清楚到底有没有进行动态内存分配 如果输出 文本为空则让程序员无法知道到底是内存检测系统出错还是根本没有错误 故对没有进行内存分配的程序应给予明确的提出该程序没有进行动态内存 分配 include lxc c include lx h void main C 语言内存检测代码库的分析与设计 21 char ptr1 atexit zzh 图 4 5 未进行动态分配 4 8 2 对于没有申请即进行释放或已经释放进行二次释放 程序员在大量的代码中可能会对一个已经释放了的内存进行再次释放 虽 然这对系统不会造成太大的影响 但我在程序的书写过程中也进行了检测 进 行能够提醒程序员对内存动态分配尽可能的书写规范 include lxc c include lx h void main char ptr1 ptr1 char malloc 10 free ptr1 free ptr1 atexit zzh 图 4 6 多次释放 4 8 3 申请的内存没有释放 C 语言内存检测代码库的分析与设计 22 这是该系统的核心 也是必须要实现的功能 在大量的操作中进行一两个 内存不释放的例行对系统进行测试 include lxc c include lx h void main char ptr1 char ptr2 ptr1 char malloc 10 atexit zzh 图 4 7 未释放内存 4 8 4 内存越界写操作 在 C 语言中的内存越界写操作 可能会造成数据的遗失无法读取 也有可 能造成其它内存块的数据被覆盖 造成意想不到
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年硼粉系列合作协议书
- 医院健康教育工作方案
- 2025年防控专员考试题及答案
- 慢性病防治课件教学
- 慢性宫颈炎与宫颈癌
- 弱电系统投标文件-技术部分
- 情绪气象站课件
- 护士面试操作考试题及答案
- 媒介传播考试题目及答案
- 泰安语文考试题目及答案
- 机器学习及应用PPT完整全套教学课件
- 【高中语文】《红烛》课件24张+统编版高中语文必修上册
- 国家开放大学毕业生登记表-
- 手术室无菌技术操作
- 表格式部编版语文六年级上册全册(教案)
- 矢量分析:旋度、散度、梯度
- 2013-2022年上海市近10年中考语文现代文二记叙文篇目及考点
- 建筑工程项目施工现场安全生产风险点清单
- -成长型思维课件
- 项目1 Windows Server 安装与基本配置
- 一年级新生报名登记表
评论
0/150
提交评论