嵌入式C编程01指针的使用.ppt
指针的使用,课程安排,指针的概念指针数据类型指针与其他数据类型指针修饰符,一般的32位CPU都有硬件MMU单元,能将有限的硬件内存(如512M)虚拟成一个较大(如2G)的虚拟内存这样软件可以在一个非常大的范围里使用内存每个内存单元(8bits组成一个内存单元byte)都有一个地址地址是一个无符号的整数表示,通常与CPU字长相等(在32位CPU上就是4byte的空间),内存与地址,1、变量是对程序中数据存储空间(地址和值)的抽象 int num=100;printf(“num is%d,num addr is%pn”,num,3、问题是,怎么通过addr简接获取该地址内保存的值(100)?,变量与地址,1、C定义了一种专门用于表示地址的变量指针 int*addr;/定义指针变量2、将内存中数据的地址赋值给指针变量:表示将指针指向该数据 addr=,指针的由来,用好指针可以:使程序简洁、紧凑、高效有效地表示复杂的数据结构动态分配内存得到多于一个的函数返回值直接操作地址造就了C/C+的强大用不好指针造成:非法内存访问,程序死机或异常内存泄露,减低系统性能指针属于间接访问,指来指去最终变得不可维护,指针是把双刃剑,课程安排,指针的概念指针数据类型指针与其他数据类型指针修饰符,指针的定义,实例:int*pi;char*pc;double*pd;info_t*pinfo;static int*pi;static char*pc;static info_t*pinfo;关键概念:1、指针类型与指针指向对象类型2、指针的值与指针指向对象的值,指针内存大小,指针变量用来表示内存地址,32位CPU上用4byte空间表示地址int*pi;char*pc;double*pd;info_t*pinfo;sizeof(pi)=?sizeof(pc)=?sizeof(pd)=?sizeof(pinfo)=?,指针初始化与赋值,1、初始化为指向对象的地址 int num=100;int paddr=,指针运算,1、取值运算符 int num=100;int*paddr=*paddr=?paddr+1=?*(int*)paddr=?(int*)paddr+1=?,通用(void)指针,指针变量的类型表示指针所指向对象的类型能不能定义一种通用指针,将来根据需要再指向特定对象?void*point=NULL;/void指针,定义不指定指针指向哪种类型数据sizeof(point)=?point+?point-?使用时需要进行强制类型转换:int num=100;char ch=a;void*point=NULL;point=,课程安排,指针的概念指针数据类型指针与其他数据类型指针修饰符,数组与指针,1、数组与指针的关系数组名表示数组首地址,可以把数组名可作指针常量 int arr3=1,2,3;int*p=arr;p+?arr+?*p=?*(p+1)=?*(p+2)=?数组下标操作符内部实现机制:通过指针取值运算符实现 arr2 相当于*(arr+2)数组作为函数参数,实际是转化为指针实现str_cpy(char src,char des)=str_cpy(char*src,char*des)数组作为函数返回值,必须通过指针实现char*str_cpy(char*src,char*des),数组与指针,2、指针数组:即数组的元素为指针类型。char*var10;/10个int型指针的数组 sizeof(var)=?var+1?3、数组指针:即指针的类型为数组(指向数组的指针)。char(*var)10;/指向10个int型数组的指针 sizeof(var)=?var+1?4、字符串与指针字符串是属于典型的字符数组,因而通常通过char型指针处理字符串,数组与指针,将字符串直接赋值给指针,表示指针指向字符串内存首地址注意:字符串常量内存分配在只读数据区(RODATA)实例:char*p=“xnf”;char arr=“xnf”;*p?*p+?*+p?*p=X?arr0=X?strcpy(p,“XNF”)?strcpy(arr,“XNF”)?,数组与指针,通过指针数组表示字符串数组char a16=“welcome”,“to”,“xnf”;主函数参数就是通过指针数组实现的:int main(int argc,char*argv),结构与指针,1、结构包含指针:结构体中包含指针域变量 如:学生信息中name与phone定义为指针 注意:在程序中动态修改学生信息表中的 name和phone域可行么?,结构与指针,2、指向结构体的指针 结构体变量域通过.访问,而结构体指针域通过-访问 sizeof(info)=?sizeof(p)=?下面这段代码错在哪里?,结构与指针,通过结构体指针传递参数比直接传递结构体变量更高效 实参传递给形参时只拷贝了4个字节,指针与指针,1、指向指针变量的指针 int num=100;int*p=实现指针二级访问:,函数与指针,1、指针作为函数的参数向函数传递数组、字符串、结构:如strc_py、show_info作为函数的输出参数例如:实现交换两个整数的函数 void swap(int a,int b)传值,形参值改变并不能带回给实参 传址,在函数内改变地址内保存的内容,函数与指针,问题:要在函数能改变指针的值,怎么通过输出参数返回?例如:void get_mem(char*pmem,int size)pmem=malloc(size);动态分配的内存能通过pmem带回么?不能!要将实参指针的地址传递给形参(二级指针)才能实现!更直接的方法是通过函数返回值实现,函数与指针,2、指针作为函数的返回值 返回字符串、动态分配的内存等,如*strcpy,*malloc 注意返回地址的有效性(函数执行完毕后该地址未被回收)下面两个函数哪个是合法的?,函数与指针,3、指向函数的指针 函数存放在TEXT段,同样具有地址 函数名就是函数在TEXT段的入口地址 跟数组名一样,函数名也可以看作是一个指针常量 所以,函数名也可以赋值给指针变量,那么该指针变量类型呢?函数指针类型!通过函数指针,也可以间接调用函数。,函数与指针,函数指针的应用:1、作为函数参数实现回调函数 所谓回调函数是指通过调用其他函数反 过来调用某个函数 模拟面向对象的多态,在UI组件的大量使 用,函数与指针,2、作为结构体的动作域 模拟面向对象的类,在Linux内核中大量使用 作为一个现实中的对象,不但有数据属性,还需要有行为属性 使用对象行为,课程安排,指针的概念指针数据类型指针与其他数据类型指针修饰符,const修饰符,1、const修饰符的作用:限定一个变量不允许被改变(只读)如:const int num=100;/num是只读整型变量 const int arr3=10,20,30;/arr是只读整型数组 num=200?arr0=100?arr1=200?2、const指针:指向变量的只读指针,指针本身只读,但指向的对象非只读 如:int num1=100;int num2=200;int*const p=*p=200?p=&num2?,const修饰符,3、指向const变量的指针:指向只读变量的指针,而指针本身不是只读的 如:const int num1=100;const int num2=200;const int*p=*p=200?p=&num2?,volatile修饰符,1、编译器总是试图优化编译使代码运行得更快 如果程序中变量未被改变,对变量的访问尽量用寄存器代替内存储存 寄存器属于CPU内部的存储单元,比起内存访问来得更快2、但对于硬件驱动程序来说,这样做就存在风险 const unsigned int*paddr=0 x0012ff7c;/假定0 x0012ff7c表示一个网卡内存地址 data=*paddr;/第一次取网卡数据 data=*paddr;/第二次取网卡数据 由于*paddr从未被程序改变,所以第二次取值从寄存器中进行,跟第一次值一样 但网卡内存数据会随时在通信中发生改变!,volatile修饰符,3、使用volatile修饰符 volatile告诉编译器,不要对其修饰的变量作优化 总是从内存进行读写,而不是仅仅在寄存器 volatile const unsigned int*p=0 x0012ff7c;/假定0 x0012ff7c表示一个网卡内存地址,typedef修饰符,1、指针相关数据类型,typedef修饰符,2、更复杂的指针相关数据类型 从变量名括号开始解释,括号外面表示类型可以用typedef自定义类型来简化int(*p3)(int);typedef int(func_t)(int);/定义返回整数的函数类型 funct_t*p3;/定义包含3个函数指针的数组int*(*p3)(int);typedef int*(func_t)(int);/定义返回整数指针的函数类型 func_t*p3;/定义包含3个函数指针的数组,typedef修饰符,int(*p)3(int);/错误,不能声明函数的数组如何定义指向包含3个返回整数函数指针数组的指针?typedef int(func_t)(int);/定义返回整型函数指针类型 typedef func_t*pfarr_t3;/定义包含3个函数指针数组类型 pfarr_t*p;/定义指向数组的指针,上机实验,1、指针应用(1)用指针实现char*str_cpy(char*des,char*src)void set_info(info_t*pinfo)函数(2)封装获取动态内存函数get_mem,分别通过返回值和输出参数带回内存分配结果2、函数指针使用 在学生信息info_t中增加reading读书行为,并通过回调函数调用reading3、指针数据表示(1)如果显卡内存地址是0 x345ff000(假定),用指针表示并模拟读写显卡操作(2)解释void(*var10)(void(*)(void),并通过typedef简化表示,