c语言指针 ppt,嵌入式C语言存储器及指针.ppt

这篇博客深入探讨了嵌入式C语言中存储器的组织、指针的使用以及内存管理的陷阱。讨论了数组与指针的关系,包括多维数组的概念和操作。讲解了函数指针的应用,如多态性、回调和多线程。还介绍了内存映像布局,包括TEXT、DATA、BSS段以及堆和栈的区别。此外,博客重点分析了动态内存分配的问题,如内存泄漏和野指针,提供了避免内存陷阱的建议。最后,阐述了栈的作用,如参数传递、函数调用和局部变量存储。
摘要由CSDN通过智能技术生成

《嵌入式C语言存储器及指针.ppt》由会员分享,可在线阅读,更多相关《嵌入式C语言存储器及指针.ppt(30页珍藏版)》请在装配图网上搜索。

1、嵌入式C语言编程存储器及指针,GDAIB,Memory and Pointers,目录,指针与数组(Pointers and arrays) 函数指针(Function pointers) 内存陷阱(Memory pitfalls) 栈(Stacks),Page 2,指针与数组,C语言中只支持一维数组,且只支持静态数组。 数组的大小在编译的时候就必须作为一常数确定下来。 虽然C的数组只有一维,但是它的数组元素可以是任何数据类型的对象,因此一个数组的元素也可以是另外一个数组,这样就可以模拟出多维数组。 有关数组的操作即使是通过数组下标进行运算的,实际上都是通过指针进行的。,Page 3,多维数组。

2、,看左边的几个声明,请思考: Calendar4 是什么意思?,Page 4,数组名与指针,int a10; int *p; p = a; a+; p+; printf(“The size of a is %dn”, sizeof(a); printf(“The size of p is %dn”, sizeof(p); ,/*语法错误!a是常量!*/,/*语法正确! p是变量!*/,/*对于大多数32位系统,输出的结果是40 */,/*输出的结果是4 */,请指出下列代码中的错误及输出结果?,Page 5,数组作为函数的入口参数,char b10=“123456789”; main( ) f。

3、(b); void f(char a ) char c; a+; c = a0; printf(“The size of a is %dn”, sizeof(a); printf(“The size of b is %dn”, sizeof(b); ,void f(char *a) . ,/* a是指针,输出的结果是4*/,/*形参看起来是数组,实际已退化为指针*/,/*a是指针,因此自增运算是合法的!*/,/*a通过下标可以看起来像数组,但是它不是数组,而且此时c的值应该是”2”而不是”1”因为前面a做了自增运算*/,/* b是数组,输出的结果是10*/,/*真正传入f函数的是数组b的首地址。

4、指针*/,请分析这个程序?,Page 6,字符串数组与指向字符串的指针, char *p = “hello world! ”; char a = “hello world!”; p0 = H; a0 = H; p = a; ,在很多编译器中可能是非法的,因为p所指向的串可能存放在只读的存储空间,比如ROM或Flash,P重新指向a,但p原来指向的串将永远丢失,因为不知道原来那个串存放内存的地方,Page 7,指出左边的程序段有何不妥?,指针与数组(Pointers and arrays) 函数指针(Function pointers) 内存陷阱(Memory pitfalls) 栈(Stack。

5、s),Page 8,目录,函 数 指 针 定 义,int (*fp)(int); int *fp(int); int *(*fp_array10)(int); int *fp_array10(int);,声明一个函数指针变量fp,它指向一个入口参数与返回值都是整数的函数,声明一个函数fp(),该函数有一个整数参数,并且返回一个指向整数的指针,声明一个函数指针数组,它的每个元素都指向一个入口为整数且返回在值也为整数指针的函数,从运算符的结合性来看,为是一个函数数组,但C中没有这个概念,故这个声明有语错误!,Page 9,int *myfunction(int); int *(*fp)(int);。

6、 int *ptr; fp = myfunction; ptr = (*fp)(3); ptr = fp(3);,函 数 指 针 调 用,/*为fp赋初值,使它指向函数myfunction*/,/*通过函数指针调用函数,与myfunction(3) 的效果一样*/,/*这也是通过函数指针调用函数,与myfunction(3) 的效果一样*/,Page 10,多态(Polymorphism) 指用一个名字定义不同的函数,这些函数不同但操作类似,从而实现“一个接口,多种方法” 回调(Call_Back) 指操作系统来调用用户编写的函数,或由底层函数调用上层函数 多线程(Multithreading。

7、) 操作系统按一定的条件请允许多任务调度,则调用调度器选择合适的任务进行运行。,函 数 指 针 的 作 用,Page 11,指针与数组(Pointers and arrays) 函数指针(Function pointers) 内存陷阱(Memory pitfalls) 栈(Stacks),Page 12,目录,程序内存映像布局,1.静态映像(可执行文件): TEXT段、DATA段、BSS段; 2.动态映像(可执行文件运行): BSS段消失 增加堆和栈,Page 13,1. TEXT:保存指令代码、立即数等只读信息, 函数地址就在该段中分配 2. DATA:保存已初始化全局变量、静态变量。 其中。

8、又分为RODATA,保存字符串常量等只读数据 3. BSS: 记录未初始化全局变量、静态变量的标号的内存大小, 程序运行后为这里数据在DATA段分配内存并初始化为0 4、堆(Heap):保存临时动态分配内存 5、栈(Stack):保存临时静态分配内存,内存映像定义,Page 14,变量内存分配方式,1、静态分配: 在程序执行时由系统自动分配,使用完毕后由系统自动回收 根据类型大小自动在数据段、栈分配静态内存 好处是不存在内存泄露问题,但静态分配的内存有限 2、动态分配: 需要在代码中手动分配,使用完毕后必须在代码中手动回收 根据运行时的要求在堆上分配动态内存 好处是能动态分配很大的内存,但一旦。

9、忘记回收,内存泄露严重影响系统性能,Page 15,变量生存期,1、临时生存期:在栈上分配内存 在函数执行时为变量分配内存,函数执行结束回收内存 生存期是从进入函数起,到退出函数时结束 2、永久生存期:在数据段分配内存 在程序开始执行时为变量分配内存,程序结束回收内存 生存期是从进入程序起,到退出程序时结束,Page 16,看看这段代码有什么问题?,char *DoSomething() char i32*1024; memset(i,0,32*1024); return i; ,两个重大问题: 1、自动变量数组i 是通过堆栈实现的,太大的临时变量数组会冲掉堆栈 2、返回堆栈中的地址是非常危险。

10、的,因为堆栈中的值永远是不确定的,Page 17,将i所指向的内存中的每个字节的内容全部设置为0 . 这个函数通常为新申请的内存做初始化工作,看看这段代码有什么问题?,void DoSomething() int i; int j; int k; memset( ,这段代码的作用是将3个局部变量清零 但是这段代码有两个假设: 1、编译器将I,j,k三个变量通过堆栈表示 2、压栈顺序是 I, j , k (假设堆栈是满递减堆栈) 3、如果K在寄存器怎么办?对K取地址操作将产生Data Abort(中止),Page 18,关于临时变量,不要对临时变量作取地址操作,因为你不知道编译器是否将这个变量映。

11、射到了寄存器 不要返回临时变量的地址,或临时指针变量,因为堆栈中的内容是不确定的(出了这个函数,存放在堆栈中的局部变量就没有意义了!) 不要申请大的临时变量数组,你的临时变量是在堆栈中实现的,你有多大的堆栈呢?,局 部 变 量,Page 19,由函数malloc() 和free() 管理动态存储区,这个存储区一般称为“堆”(Heap),问题: 现在要为一个矩形区域(宽x,高y)申请一块内存保存这块的数据,如果每个像素点(Pixle)占用2个bit,如何分配内存?(参考P.131) char *buffer; buffer = malloc (x*y/4);,修正方法:buffer = mall。

12、oc(x*y/4 + 1); (课本中还有其它修正方法),动 态 存 储 区,Page 20,看看这段代码有什么问题? (参考P.132),char *DoSomething() char *p, *q; if ( (p = (char*) malloc(1024) = NULL ) return NULL; if ( (q = (char*) malloc(2048) = NULL ) return NULL; return p; ,如果p申请成功,而q没有申请到,首先应该释放p,然后再返回NULL,否则p所指的1024字节空间就永远被“遗忘”,将永远占据Heap的空间造成“内存泄漏”,内 。

13、存 泄 漏Memory Leakage,if ( (q = malloc(2048) = NULL ) free(p); return NULL; ,在使用malloc()时,先检查函数的返回值是否为空很有必要,Page 21,忘记释放已分配的动态存储空间 A程序员分配的一块内存,B程序员使用了它,但没有沟通好由谁来释放 free()只能释放由malloc()返回的指针,如果free()的入口参数不是正确的指针或malloc()分配空间的头部信息被破坏, 造成free() 释放无效。,内 存 泄 漏 的 原 因,Page 22,Free()释放无效 示例,void DoSomething(ch。

14、ar* ptr;) char *p; int i; if (ptr = NULL) return; if (p =(char*)malloc(1024) = NULL ) return ; for(i = 0; i 1024; i+) *p+ = *ptr+; free(p); return ; ,/*入口参数合法性检查*/,/*分配空间,并检查是否为空*/,/*语句无效,因p的值已发生改变,free()将无法释放,Page 23,void FreeWindowsTree(windows *Root) if(Root != NULL) window *pwnd; for(pwnd = Root。

15、-Child;pwnd != NULL;pwnd = pwnd-Sibling) FreeWindowTree(pwnd); if(Root-strWndTitle != NULL) FreeMemory(Root-strWndTitle); FreeMemory(Root); ,“野”指针,“野”指针:指那些不知指向什么内容或者指向的内容已经无效的指针,思考这个代码有什么问题?,/* 释放pwndRoot 的子窗口. */,/* pwnd已经被释放了,但在for循环中被再次引用*/,Page 24,规避动态存储区的内存陷阱的方法(P.137),总是检查动态内存分配是否成功后再引用该指针! 对。

16、分配成功的动态存储区需要将其初始化后再使用 要特别小心访问越界,如数组下标或循环次数等 分配内存空间是总是使用sizeof,并且别忘了加1 总是释放由malloc()函数返回的指针 错误处理时不要忘了其他已分配空间的释放 为了避免“野”指针,对于被释放的动态内存,最好立刻将指向这块内存区的指针变量赋值为NULL,Page 25,指针与数组(Pointers and arrays) 函数指针(Function pointers) 内存陷阱(Memory pitfalls) 栈(Stacks),Page 26,目录,定义:指一块内存区域,该区域的管理(内存空间的分配与回收)采用类似数据结构中“栈”的特点进行操作。 特点: 遵循“后进先出、先进后出”的特点 相关术语:压栈(进栈)、退栈(出栈)、 栈的清理,栈(Stacks),Page 27,栈的四种类型(p.141),Page 28,传递函数调用的参数 保存函数调用的返回地址 (对于中断处理程序及程序状态字寄存器) 保存函数在被调用函数中需要使用的寄存器的值 实现局部变量,堆栈的作用(p.142),Page 29,利用堆栈有以下四个作用:,Page 30,End。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值