《C++程序设计第6章 指针与引用教学课件.ppt》由会员分享,可在线阅读,更多相关《C++程序设计第6章 指针与引用教学课件.ppt(34页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、C+程序设计第6章 指针与引用教学课件C C语言程序设计案例教程语言程序设计案例教程语言程序设计案例教程语言程序设计案例教程第6章 指针与引用指针和引用是C+中的重要内容。灵活使用指针可以使程序简洁、高效。指针的内容相对较难,读者需要多实践,从代码中体会指针的精髓。引用在实现了指针部分功能的同时,简化了指针的用法,另外,引用也实现了一些特有的功能。http:/ 目录6.1 指针的概念6.2 指针与数组6.3 函数与指针6.4 指针与动态内存分配6.5 const与指针6.6 引用3http:/ 6.1 指针的概念指针:是C语言的精华,也是C+必不可少的组成部分,其高效性不言而喻。6.1.1 指
2、针与内存的关系计算机运行时数据都是存在内存中的。内存的存储单元以字节为单位,每一个单元都有其唯一的地址编号。变量在内存中的首地址称为该变量的指针。计算机以位(bit)为数据的最小存储单元。其中存数的数据类型为0或1。每8位为一字节(byte),常见的数据都是以字节为单位计算占用内存大小的。图6-1表示的就是数据在内存中的状态。4http:/ 图6-1 变量与内存当定义一个整型数据并为其赋值时,例如:intnum=8;实际上程序是在内存中开辟了相应的物理空间用于存放数据,而这段物理空间就有它的地址编号即内存地址。指针变量就是一种存储内存地址的数据类型,通过直接查找内存地址访问数据。6.1.2 定
3、义指针变量定义指针变量时必须确定该指针所指向的数据类型,以确定该指针的类型。一个类型的指针只能指向相应类型的数据。例如,char型指针只能指向char型对象。5http:/ 2)指针的定义)指针的定义风格风格1)指针变量的定义)指针变量的定义double型指针变量的定义通常有以下两种风格:double*num;double*num;在C+中,定义符号*来声明指针类型。例如:int*num;char*cha;double*dnum;int num1,*num2 /定义了int型变量num1和int型指针 num23)定义多个指针)定义多个指针定义多个指针一般有两种风格:一是参考上面推荐的定义风格
4、,多次定义来实现这一目的;二是一次性定义多个同类型指针。例如:double*num;/第一种风格double*num2;double*num,*num2;/第二种风格6http:/ 6.1.3 使用指针指向数据1)指向数据)指向数据指针是一种存储内存地址的数据类型。在C+中,定义符号&为取地址运算符。&a即为a的内存首地址。&只能运用于已经声明的变量,因为只有这种数据才会在内存中拥有自己的内存地址。至于该变量是否已经定义,则并不重要。例如:int num;int*point=#num=10;/这一串操作是合法的int num=10;int*point=#/这一串操作是合法的in
5、t*point=#int num=10;/这一串操作是非的指 针的指向和普通变量一样是可以重新定义的,通 过修改其存储的内存地址就可以实现.例如:int num1,num2;int*point;point=&num1;point=&num2;7http:/ 2)获取数据在C+中,定义符号*为间接访问运算符。其使用格式如下。*指针名;例如:intnum=10;int*point=#cout*pointendl;与指向数据类似,使用间接访问运算符时,指针必须有一个确定的指向。下面几种使用方法就是非法的。int*point;*point=10;/访问错误,没有给指针一个确定的指向in
6、t*point=NULL;/将该指针悬空,不指向任何数据*point=10;/访问错误,指针指向为空8http:/ using namespace std;int main()int num=10;int*point;/定义int型指针point,并未初始化 point=#/把num的地址赋给point,使point指向num cout*point endl;*point=20;/通过指针修改其指向的数据 cout point endl*point ends num endl;return 0;程序运行结果如图6-2所示。9http:/ 6.2 指针与数组数组:在内存中是连续存放的。这
7、种存放方式,使得指针对于数组数据的访问非常方便。从首地址开始逐个位移就可以遍历整个数组。6.2.1 指向数组的指针C+中规定,数组的数组名即代表数组的首地址,也就是“数组名0”的地址。intarray10;int*point=array;/array为数组名,即代表了数组的首地址int*point2=&array0;/该操作和上一条指令效果相同需要注意的是,对于不同的数组,需要以相应的指针指向数组。例如:intarray10;char*point=array;/错误,不可以使用char型指针指向int型数组char*point2=&array0;/错误,同上指针可以指向任意同类型数组的任意位置
8、。例如:intarray10;int*point=&array5;/指向数组中的第六个元素10http:/ 6.2.2 使用指针访问数组指针访问数组的常用方法是,定义某一指针指向数组的首地址,然后通过对指针的加减来访问数组的每一个元素。指针的加减是指针的常用操作。当对指针进行加一的操作时,C+会自动地按照该指针类型,判断在内存中向下跳多少内存空间。例如,当指针为int型时,对其加1,则会在内存中向下跳4字节。当指针为char型时,对其加1,则会在内存中向下跳1字节。由于数组在内存中是连续存放的,对于数组来说,指针的加减即为访问下一个或上一个数组元素。例如:intarray10=0,1,2,3,
9、4,5,6,7,8,9;int*point=array;cout*(point+1)endl;/这里输出的结果就是1,为第二个元素11http:/ 下面的例子完整地演示了指针在数组中的使用。【例6-2】指向数组的指针。#includeusingnamespacestd;intmain()intarray10;int*point=array;/定义point指向数组array首地址int*point2=&array0;/定义point2指向数组array首地址for(inti=0;i!=10;i+)/使用for循环语句为数组array赋值*point=i;point+;/每次赋值之后使point
10、指向下一个元素for(inti=0;i!=10;i+)/使用for循环语句输出数组arraycout*(point2+i)ends;return0;12http:/ 程序运行结果如图6-3所示。指向字符串的指针与指向数组的指针类似。字符串在内存中也是连续存放的,所不同的是字符串是以char型存放在内存中的。可以参考指向数组的指针的使用方法。例如:6.2.3 指向字符串的指针chararray12=helloworld;char*point=array;/类似于指向数组的指针下面通过指向字符串的指针来实现复制char数组的功能。【例6-3】指针实现的char数组复制。#includeusingn
11、amespacestd;intmain()charcha115,cha215;strcpy(cha1,helloworld!);/对于char数组的赋值的一种方法char*point_char=cha1;/定义char型指针指向cha1inti;for(i=0;*point_char!=0;i+,point_char+)cha2i=*point_char;cha2i=0;/手动的添加字符串结束符coutcha1endlcha2endl;return0;13http:/ 程序运行结果如图6-4所示。【例6-3】中有一些细节需要注意,首先是对于char数组的赋值,通常有3种方法。(1)在声明的时候
12、初始化。例如:charcha15=helloworld;(2)使用strcpy函数。例如:charcha;strcpy(cha,helloworld);(3)对char数组的每个字符分别赋值。例如:chara10=h,e,l,l,o;【例6-3】中手动为cha2添加了0这一字符串结束符,目的在于使其完整。cout以0判断字符串是否结束。14http:/ 6.3 函数与指针函数有其地址,指向函数的指针即为函数指针。相对于直接使用函数名调用函数,函数指针除了在可读性上稍差一些,其他方面有诸多优势。6.3.1 函数地址函数在计算机中运行时会占用一定的内存。因此,函数是有地址的。将指针指向该函数的入口
13、地址,即定义了函数指针。通过函数指针同样可以调用函数,达到相应的目的。6.3.2 定义函数指针定义指向一个返回类型为int,拥有两个int型形参的函数的函数指针:int(*point_function)(int,int);看到这种相对复杂的定义方法时,先寻找变量名,找到point_function。通过其左边的“*”判断其为指针型变量。通过其右边的(int,int)判断其为指向函数的指针,且其指向的函数的形参为两个int型参数。需要注意的是,声明函数指针时,(*point_funciont)中的()是不能省略的.因为括号的优先级高,所以声明的才是指针变量而不是返回类型为指针的函数。15http
14、:/ 14典型的例子如下。典型的例子如下。void(*point_function)();/声明一个函数指针void*point_function();/声明一个函数熟悉函数指针的定义规则,就可以读懂一些复杂的定义和声明。例如:int(*(*point_function)(int,int)(int);定义了一个指向函数的指针point_function,该函数有两个int型形参,返回一个函数指针。返回的函数指针指向的函数有一个int型形参,返回一个int型数据。typedef double(*(*(*point_function)(int,int)10)();point_function po
15、int1;使用typedef可以简化这种复杂的定义方法。这里首先定义了一种数据类型point_function。这是一个函数指针,指向的函数有两个int型形参。返回一个指针,指向含有10个函数指针的指针数组。这些函数不接受参数且返回类型为double。第二行中定义了一个这种类型的数据point1。http:/ 6.3.3 使用函数指针调用函数一旦定义了函数指针,在使用之前就一定要为其赋上函数的地址。类似于用数组名代表数组的地址,函数名也代表函数的地址。由此可以按照如下方法为函数指针赋值。intfunction(inta,intb);int(*point_function)(int,int);p
16、oint=function/通过函数名来为函数指针赋值也可以在定义时就将其初始化:voidfunction();void(*point_function)()=function;/在声明时就将其初始化【例6-4】使用函数指针调用函数。#includeusingnamespacestd;intmain()inta,b;intfunction(inta,intb);/声明一个函数int(*point)(int,int);/声明一个函数指针point=function;/使函数指针指向指定函数cinab;point(a,b);15http:/ cout-endl;int(*point_functio
17、n2)(int,int)=function;point_function2(a,b);return0;intfunction(inta,intb)coutaandbthebiggerisb?a:b)endl;/使用条件表达式return0;程序运行结果如图6-5所示。图6-5 函数指针的使用16http:/ 6.3.4 函数指针的用途函数指针解决了在很多场合不能直接使用函数名的问题。合理地使用函数指针会使程序变得更加简洁。【例6-5】函数指针的合理使用。#includeusingnamespacestd;voidfunction_addition();/连续声明4个函数voidfunction
18、_subtraction();voidfunction_multiplication();voidfunction_division();intmain()void(*point_function4)();/声明一组函数指针point_function0=function_addition;/依次将函数指针指向对应的函数point_function1=function_subtraction;point_function2=function_multiplication;point_function3=function_division;inti;while(1)coutputtheiendl
19、;17http:/ cout0-addition#1-subtraction#2-multiplication#3-division#10-endi;if(i=10)return0;point_functioni();return0;voidfunction_addition()coutthisisaddition:endlputtwonumab;couta+bendlendl;voidfunction_subtraction()coutthisissubtraction:endlputtwonumab;couta-bendlendl;18http:/ voidfunction_multipl
20、ication()coutthisismultiplication:endlputtwonumab;couta*bendlendl;voidfunction_division()coutthisisdivision:endlputtwonumab;couta/bendlendl;程序运行结果如图6-6所示。图6-6 通过函数指针实现多函数的调用19http:/ 6.4 指针与动态内存分配21指针是存储内存地址的变量。我们可以将指针指向同类型的变量,这是让指针发挥作用的一种方法;也可以在定义指针时为其分配内存空间,这样就如同定义了一个该类型的变量,并且使该指针指向这个变量。6.4.1 程序中内存
21、的分配方式程序中内存的分配方式 在C+中,内存分为5个区域,分别是栈、堆、自由存储区、全局/静态存储区和常量存储区。下面分别介绍 每个区域的功能。1)栈栈 由编译器在需要时分配,不需要的时候自动清除的存储区域。里面存放的通常是局部变量和函数的参数。2)堆)堆 由new分配的内存空间,由delete释放。它的申请和释放不由编译器控制,而是由开发者负责。一般情况下,每一个new都会对应一个delete,不然就会造成内存泄露。它的空间可以很大,但是效率上要低于栈。3)自由存储区)自由存储区 是由malloc分配的内存区域,它和堆类似,用free来释放内存。一般在C+中多使用堆,自由存储区使用较少。4
22、)全局)全局/静态存储区静态存储区 静态变量和全局变量存储在该区域。在C语言中全局变量又分为初始化和未初始化的,但在C+中没有这一区别,都存储在同一区域。5)常量存储区)常量存储区 是存储常量的区域,这一区域存储的内容不可以修改。清楚地了解不同的数据存储在哪个区域有助于我们理解C+。下面来看一段程序,并解释各个变量的存储区域。http:/ 6.4.2 在堆上分配内存堆上的内存空间由new关键字来申请,下面重点介绍关键字的使用方法。通常我们要使用new关键字申请内存空间时,会在声明指针时为其申请内存空间。例如:int*point_int=newint;/为int型指针申请一个内存空间int*po
23、int_int2=newint10;/为该指针申请了10个内存空间int*point_int3=newint(10);/为指针申请内存空间的同时为其赋值也可以在指针声明之后,再为其指定内存空间。例如:int*point_int;/声明int型指针point_intpoint_int=newint;/为point_int申请内存空间在堆上分配内存的一个好处就是申请的空间大小可以是不确定的,即可以是一个变量,而数组就不可以。例如:inti;/需要的空间大小cini;/给定需要的空间大小intai;/错误!数组的大小一定是确定的inti;/需要的空间大小cini;/给定需要的空间大小int*a=ne
24、winti;/正确,堆上申请的空间大小可以不定使用new字符申请空间可以完成数组的功能。23http:/ 6.4.3 释放堆上的内存每使用new申请了一块内存空间,就要显式地使用delete关键字来删除相应的内存空间,不然就会造成内存泄漏,直到程序结束时再由系统收回释放一个由指针指向的内存空间的格式为:delete指针名;例如:int*point_int=newint;deletepoint_int;释放一个由指针指向的内存数组空间的格式为:deleten数组名;/n为数组大小,可省略为例如:int*point_int=newint10;deletepoint_int;/省略ndelete10
25、point_int;/不省略24http:/ delete关键字的使用25http:/ 6.5 const与指针使用const修饰变量时,该变量在程序运行中不可以被修改。修饰不同类型的变量时,const有不同的含义。6.5.1 指向const的指针我们知道,指针可以修改它所指向的内存空间的值。而const对象是不可被修改的,所以即便是指针也不允许修改const对象的值。在C+中,我们要求指向const对象的指针也要有const的性质。指向const的指针指向非const变量是合法的,这个指针仍然拥有const特性,又称为常量指针。定义指向const的指针的格式为:const类型名*指针名;例如
26、:constint*point_int;const类型的变量在声明时需要进行初始化,而指向const的指针可以不初始化,也可以初始化。26http:/ 例如:inta;constintb=10;/声明const变量时需要进行初始化constintc;/错误!没有初始化,无法通过编译int*point=&a;/定义指针int*point2=&b;/错误!constint*point3=&b/定义指向const对象的指针,且初始化constint*point4=&a;/正确!*point3=10;/错误!不可以修改const对象的值*point4=10;/错误!不可以通过有const特性的指针修改
27、对象的值不可以使用void指针保存const对象的地址,而要使用constvoid。例如:constinta=10;constvoid*point=&a;/正确!void*point2=&a;/错误!需要说明的是,指向const对象的指针,其指向的对象是不可以通过该指针修改的。但是指针本身的指向可以修改。例如:constinta=10;intb=40;constint*point_int=&a;/声明指针指向const对象apoint_int=&b;/改变该指针的指向。27http:/ 6.5.2 const指针一个const指针,本身就是常量了。它的指向不可改变,但是其指向的数据可以修改。由
28、于指针本身是const类型,所以在声明时要初始化。定义const指针的格式为:类型名*const指针名=&a;/这里随意进行初始化仅作参考例如:inta,b;int*constpoint_int1;/错误!定义const指针要初始化int*constpoint_int=&a;/定义const指针*point_int=10;/正确!point_int=&b;/错误!const指针的指向不可改变!6.5.3 指向const的const指针有指向const的指针和const指针,自然就有指向const的const指针,又称指针常量。inta=10;constint*constpoint_int=&a
29、;intconst*constpoint_int1=&a;指向const的const指针既不可以改变指向,也不可通过该指针修改其指向的变量。这里推荐使用第一种方法在6.1.2中,我们讨论过关于指针的声明风格的问题。推荐使用类型名和*放在一起的声明方式。例如:int*point_int;因为在这里,我们暂且把int*作为一个整体,看为一个类型。从某种程度来说这方便我们理解程序。而实际上,int*point_int,point_int1;却不是如我们所想一样定义了两个指针,而是定义了一个指针point_int和一个int型变量point_int1。为了避免这个误解,请养成一行只定义一个指针的习惯。
30、28http:/ 6.6 引 用指针对数据的修改和传递非常方便,但是也有它的缺点,那就是容易出错。C+中引入了引用这一概念,在一定程度上完成了指针的功能,同时也较为安全。6.6.1 定义引用引用就像是给变量取了一个别名,通过引用对变量的修改等同于对变量本身的修改。我们也可以把它看做一种常量指针,它的定义通过&来完成。例如:inta;int&b=a;/定义变量a的一个引用引用可以单独使用,但通常被应用在函数的形参中。以前我们要编写一个函数用于交换两个变量的值时,需要使用指针,这会显得比较麻烦,但是在学习了引用之后,这个过程就变得简单多了。29http:/ 引用应用在形参对于引用的使用需要注意以下
31、两个方面:(1)引用在声明时需要对其进行初始化。(2)引用在定义之后,不可以修改其指向的对象。有时,我们会遇到引用指针的情况。30http:/ 6.6.2 常引用引用给了一个变量修改和读取另一个变量的权限,如果我们只想通过另一个变量读取它而不能修改它,就可以使用常引用。常引用的格式如下。const变量类型*引用名=目标变量名;例如:inta;constint*b=a;/定义了常引用a=10;/正确b=20;/错误!常引用不可修改其值这里相当于只可以通过常引用访问数据,不可以修改。类似于指向const的const指针,既不可以修改其指向,也不可以通过该指针修改其指向的内存空间的值。我们会发现引用
32、都是在完成指针的功能,因其初衷就是在多数情况下完成指针的功能的同时避免像指针一样易错。常引用的另一个特点是可以使用常量来初始化。例如:constint&a=10;/使用常量为其赋值6.6.3 引用和指针的区别引用的出现就是在完成指针多数功能的同时又简单易懂,避免像指针一样容易出错。引用相当于对一个变量取了别名,而指针则是存储了其指向的变量的地址。需要明确的是,引用是直接访问,指针是间接访问。虽然多数情况下引用可以实现指针的功能,但是我们也需要清楚地了解指针并熟练地使用。下面总结几点引用和指针的区别。(1)在声明引用时就要为其初始化,而对指针则不必。(2)引用在初始化之后不可以再成为其他对象的引用,而指针可以改变其指向31Thanks第6章 指针与引用C C语言程序设计案例教程语言程序设计案例教程语言程序设计案例教程语言程序设计案例教程