存储器块清零c语言版,嵌入式C语言存储器及指针.ppt
嵌入式C语言存储器及指针.ppt嵌入式C语言编程 存储器及指针 GDAIB MemoryandPointers 目录 指针与数组 Pointersandarrays 函数指针 Functionpointers 内存陷阱 Memorypitfalls 栈 Stacks Page2 指针与数组 C语言中只支持一维数组 且只支持静态数组 数组的大小在编译的时候就必须作为一常数确定下来 虽然C的数组只有一
嵌入式C语言存储器及指针.ppt
嵌入式C语言编程 存储器及指针 GDAIB MemoryandPointers 目录 指针与数组 Pointersandarrays 函数指针 Functionpointers 内存陷阱 Memorypitfalls 栈 Stacks Page2 指针与数组 C语言中只支持一维数组 且只支持静态数组 数组的大小在编译的时候就必须作为一常数确定下来 虽然C的数组只有一维 但是它的数组元素可以是任何数据类型的对象 因此一个数组的元素也可以是另外一个数组 这样就可以模拟出多维数组 有关数组的操作即使是通过数组下标进行运算的 实际上都是通过指针进行的 Page3 多维数组 看左边的几个声明 请思考 Calendar 4 是什么意思 Page4 数组名与指针 inta 10 int p p a a p printf Thesizeofais d n sizeof a printf Thesizeofpis d n sizeof p 语法错误 a是常量 语法正确 p是变量 对于大多数32位系统 输出的结果是40 输出的结果是4 请指出下列代码中的错误及输出结果 Page5 数组作为函数的入口参数 charb 10 123456789 main f b voidf chara charc a c a 0 printf Thesizeofais d n sizeof a printf Thesizeofbis d n sizeof b voidf char a a是指针 输出的结果是4 形参看起来是数组 实际已退化为指针 a是指针 因此自增运算是合法的 a通过下标可以看起来像数组 但是它不是数组 而且此时c的值应该是 2 而不是 1 因为前面a做了自增运算 b是数组 输出的结果是10 真正传入f函数的是数组b的首地址指针 请分析这个程序 Page6 字符串数组与指向字符串的指针 char p helloworld chara helloworld p 0 H a 0 H p a 在很多编译器中可能是非法的 因为p所指向的串可能存放在只读的存储空间 比如ROM或Flash P重新指向a 但p原来指向的串将永远丢失 因为不知道原来那个串存放内存的地方 Page7 指出左边的程序段有何不妥 指针与数组 Pointersandarrays 函数指针 Functionpointers 内存陷阱 Memorypitfalls 栈 Stacks Page8 目录 函数指针定义 int fp int int fp int int fp array 10 int int fp array 10 int 声明一个函数指针变量fp 它指向一个入口参数与返回值都是整数的函数 声明一个函数fp 该函数有一个整数参数 并且返回一个指向整数的指针 声明一个函数指针数组 它的每个元素都指向一个入口为整数且返回在值也为整数指针的函数 从运算符的结合性来看 为是一个函数数组 但C中没有这个概念 故这个声明有语错误 Page9 int myfunction int int fp int int ptr fp myfunction ptr fp 3 ptr fp 3 函数指针调用 为fp赋初值 使它指向函数myfunction 通过函数指针调用函数 与myfunction 3 的效果一样 这也是通过函数指针调用函数 与myfunction 3 的效果一样 Page10 多态 Polymorphism 指用一个名字定义不同的函数 这些函数不同但操作类似 从而实现 一个接口 多种方法 回调 Call Back 指操作系统来调用用户编写的函数 或由底层函数调用上层函数多线程 Multithreading 操作系统按一定的条件请允许多任务调度 则调用调度器选择合适的任务进行运行 函数指针的作用 Page11 指针与数组 Pointersandarrays 函数指针 Functionpointers 内存陷阱 Memorypitfalls 栈 Stacks Page12 目录 程序内存映像布局 1 静态映像 可执行文件 TEXT段 DATA段 BSS段 2 动态映像 可执行文件运行 BSS段消失增加堆和栈 Page13 1 TEXT 保存指令代码 立即数等只读信息 函数地址就在该段中分配2 DATA 保存已初始化全局变量 静态变量 其中又分为RODATA 保存字符串常量等只读数据3 BSS 记录未初始化全局变量 静态变量的标号的内存大小 程序运行后为这里数据在DATA段分配内存并初始化为04 堆 Heap 保存临时动态分配内存5 栈 Stack 保存临时静态分配内存 内存映像定义 Page14 变量内存分配方式 1 静态分配 在程序执行时由系统自动分配 使用完毕后由系统自动回收根据类型大小自动在数据段 栈分配静态内存好处是不存在内存泄露问题 但静态分配的内存有限2 动态分配 需要在代码中手动分配 使用完毕后必须在代码中手动回收根据运行时的要求在堆上分配动态内存好处是能动态分配很大的内存 但一旦忘记回收 内存泄露严重影响系统性能 Page15 变量生存期 1 临时生存期 在栈上分配内存在函数执行时为变量分配内存 函数执行结束回收内存生存期是从进入函数起 到退出函数时结束2 永久生存期 在数据段分配内存在程序开始执行时为变量分配内存 程序结束回收内存生存期是从进入程序起 到退出程序时结束 Page16 看看这段代码有什么问题 char DoSomething chari 32 1024 memset i 0 32 1024 returni 两个重大问题 1 自动变量数组i 是通过堆栈实现的 太大的临时变量数组会冲掉堆栈2 返回堆栈中的地址是非常危险的 因为堆栈中的值永远是不确定的 Page17 将i所指向的内存中的每个字节的内容全部设置为0 这个函数通常为新申请的内存做初始化工作 看看这段代码有什么问题 voidDoSomething inti intj intk memset 这段代码的作用是将3个局部变量清零但是这段代码有两个假设 1 编译器将I j k三个变量通过堆栈表示2 压栈顺序是I j k 假设堆栈是满递减堆栈 3 如果K在寄存器怎么办 对K取地址操作将产生DataAbort 中止 Page18 关于临时变量 不要对临时变量作取地址操作 因为你不知道编译器是否将这个变量映射到了寄存器不要返回临时变量的地址 或临时指针变量 因为堆栈中的内容是不确定的 出了这个函数 存放在堆栈中的局部变量就没有意义了 不要申请大的临时变量数组 你的临时变量是在堆栈中实现的 你有多大的堆栈呢 局部变量 Page19 由函数malloc 和free 管理动态存储区 这个存储区一般称为 堆 Heap 问题 现在要为一个矩形区域 宽x 高y 申请一块内存保存这块的数据 如果每个像素点 Pixle 占用2个bit 如何分配内存 参考P 131 char buffer buffer malloc x y 4 修正方法 buffer malloc x y 4 1 课本中还有其它修正方法 动态存储区 Page20 看看这段代码有什么问题 参考P 132 char DoSomething char p q if p char malloc 1024 NULL returnNULL if q char malloc 2048 NULL returnNULL returnp 如果p申请成功 而q没有申请到 首先应该释放p 然后再返回NULL 否则p所指的1024字节空间就永远被 遗忘 将永远占据Heap的空间 造成 内存泄漏 内存泄漏MemoryLeakage if q malloc 2048 NULL free p returnNULL 在使用malloc 时 先检查函数的返回值是否为空很有必要 Page21 忘记释放已分配的动态存储空间A程序员分配的一块内存 B程序员使用了它 但没有沟通好由谁来释放free 只能释放由malloc 返回的指针 如果free 的入口参数不是正确的指针或malloc 分配空间的头部信息被破坏 造成free 释放无效 内存泄漏的原因 Page22 Free 释放无效示例 voidDoSomething char ptr char p inti if ptr NULL return if p char malloc 1024 NULL return for i 0 i 1024 i p ptr free p return 入口参数合法性检查 分配空间 并检查是否为空 语句无效 因p的值已发生改变 free 将无法释放 Page23 voidFreeWindowsTree windows Root if Root NULL window pwnd for pwnd Root Child pwnd NULL pwnd pwnd Sibling FreeWindowTree pwnd if Root strWndTitle NULL FreeMemory Root strWndTitle FreeMemory Root 野 指针 野 指针 指那些不知指向什么内容或者指向的内容已经无效的指针 思考这个代码有什么问题 释放pwndRoot的子窗口 pwnd已经被释放了 但在for循环中被再次引用 Page24 规避动态存储区的内存陷阱的方法 P 137 总是检查动态内存分配是否成功后再引用该指针 对分配成功的动态存储区需要将其初始化后再使用 要特别小心访问越界 如数组下标或循环次数等 分配内存空间是总是使用sizeof 并且别忘了加1 总是释放由malloc 函数返回的指针 错误处理时不要忘了其他已分配空间的释放 为了避免 野 指针 对于被释放的动态内存 最好立刻将指向这块内存区的指针变量赋值为NULL Page25 指针与数组 Pointersandarrays 函数指针 Functionpointers 内存陷阱 Memorypitfalls 栈 Stacks Page26 目录 定义 指一块内存区域 该区域的管理 内存空间的分配与回收 采用类似数据结构中 栈 的特点进行操作 特点 遵循 后进先出 先进后出 的特点相关术语 压栈 进栈 退栈 出栈 栈的清理 栈 Stacks Page27 栈的四种类型 p 141 Page28 传递函数调用的参数保存函数调用的返回地址 对于中断处理程序及程序状态字寄存器 保存函数在被调用函数中需要使用的寄存器的值实现局部变量 堆栈的作用 p 142 Page29 利用堆栈有以下四个作用 Page30 End
更多推荐
所有评论(0)