《指针的定义与应用课件.ppt》由会员分享,可在线阅读,更多相关《指针的定义与应用课件.ppt(65页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第第1515章章 指指 针针西南交通大学软件学院西南交通大学软件学院计算机基础教研室计算机基础教研室C+C+编程导论编程导论1本章主要内容本章主要内容vC+C+中指针的基本概念中指针的基本概念v指针类型变量的定义方法指针类型变量的定义方法v指针与地址运算符指针与地址运算符v指针变量赋值、指针的运算指针变量赋值、指针的运算v通过指针类型的变量去访问某个变量或数组元素通过指针类型的变量去访问某个变量或数组元素的值的值v引用引用v动态分配内存动态分配内存v按引用调用按引用调用2什么是地址什么是地址?l计算机的内存储器就象一个巨大的一计算机的内存储器就象一个巨大的一维数组维数组,每个数组元素就是一个存
2、储每个数组元素就是一个存储单元(在微型计算机中其大小通常为单元(在微型计算机中其大小通常为一个字节)。一个字节)。l就象数组中的每个元素都有一个下标就象数组中的每个元素都有一个下标一样一样,每个内存单元都有一个编号每个内存单元都有一个编号,又又称地址。称地址。3什么是地址什么是地址?l在运行一个程序时在运行一个程序时,程序本身及其所程序本身及其所用到的数据都要放在内存储器中:程用到的数据都要放在内存储器中:程序、函数、变量、常数、数组和对象序、函数、变量、常数、数组和对象等等,在内存储器中占有一席之地。在内存储器中占有一席之地。l存放在内存储器中的程序和数据都有存放在内存储器中的程序和数据都有
3、一个地址一个地址,用它们占用的那片存储单用它们占用的那片存储单元中的第一个存储单元的地址表示。元中的第一个存储单元的地址表示。4什么是地址什么是地址?l在在C+中,为某个变量或者函数分配中,为某个变量或者函数分配内存储器的工作由编译程序完成。内存储器的工作由编译程序完成。l内存地址的访问方式内存地址的访问方式直接访问方式:通过变量名访问直接访问方式:通过变量名访问间接访问方式:通过地址访问间接访问方式:通过地址访问5如何知道某个变量、数组、函数的地址如何知道某个变量、数组、函数的地址+规定规定:v变量的地址可以使用地址运算符变量的地址可以使用地址运算符&求得。求得。例如例如,&x表示变量表示变
4、量x的地址的地址;v数组的地址数组的地址,即数组第一个元素的地即数组第一个元素的地址址,可以直接用数组名表示可以直接用数组名表示;v函数的地址用函数名表示。函数的地址用函数名表示。6什么是指针什么是指针l指针是指针是C+语言中的一种数据类型,语言中的一种数据类型,是专门用来处理地址的。是专门用来处理地址的。l指针是某个内存单元的首地址。指针是某个内存单元的首地址。7什么是指针变量?什么是指针变量?v指针变量是包含另一个变量地址的变指针变量是包含另一个变量地址的变量。量。v指针变量也是一个变量,遵循先定义,指针变量也是一个变量,遵循先定义,后使用。后使用。v定义指针变量的类型是由该指针指向定义指
5、针变量的类型是由该指针指向的变量类型决定。的变量类型决定。8指针变量的概念定义例:int i;int*i_pointer;指向整型变量的指针内存用户数据区内存用户数据区变量变量i变量变量j变量变量i_pointer3620002000200430109指针变量的声明指针变量的声明变量的指针变量的指针:变量在内存中的存放起始地址:变量在内存中的存放起始地址指针变量的声明:指针变量的声明:类型标识符*指针变量例如:例如:int*p;定义语句中的定义语句中的“*”表示该变量为指针变量表示该变量为指针变量一个指针变量只能存储同一种类型变量的地址一个指针变量只能存储同一种类型变量的地址10指针变量的初始
6、化v语法形式语法形式类型标识符类型标识符*指针名初始地址;指针名初始地址;例:例:int*pa=&a;11指针变量的初始化v注意事项注意事项用变量地址作为初值时,该变量必须在指用变量地址作为初值时,该变量必须在指针初始化之前定义。针初始化之前定义。如:如:inta;int*pa=&a;已赋初值的指针可以初始化另一已赋初值的指针可以初始化另一个指针变个指针变量。量。int*pa=&a;int*pb;pb=pa;12指针与地址运算符指针与地址运算符l“&”在执行语句中作为取地址运算符,它是一元运算符,返回操作数的地址,操作数必须是变量名。l“*”除了可以在声明语句中声明指针时使用外,还可以在执行语
7、句中作为为指针运算符使用,也称为“间接访问”运算符,指针运算符是一元运算符,指针运算符*表示指针所指向的变量的值。&a&a:取变量:取变量a a的地址。的地址。*a*a:指针变量所指向的变量的值。:指针变量所指向的变量的值。int y=5;int*p;p=&y;cout*p;int y=5;int*p;p=&y;cout*p;13指针与地址运算符指针与地址运算符l*出现在声明语句和执行语句中出现在声明语句和执行语句中的含义是不同的。的含义是不同的。l int*p;int*p;/*/*在声明语句中表在声明语句中表示声明的是指针,声明示声明的是指针,声明p p是整型指是整型指针针l cout*p;
8、cout*p;/*/*在执行语句中表在执行语句中表示指针所指对象的内容示指针所指对象的内容14指针变量的赋值运算指针变量的赋值运算指针变量指针变量=地址地址v p=&a;p=&a;v p=array;/p=array;/将数组的首地址赋值给将数组的首地址赋值给p pv p=&arrayi;/p=&arrayi;/将数组的第将数组的第i i个元个元素的地址赋值给素的地址赋值给p pv p=max;/p=max;/将函数将函数maxmax的入口地址赋的入口地址赋给给p pv p1=p2;/p1=p2;/将指针将指针p2p2的值赋个指针的值赋个指针p1p115指针变量的赋值运算指针变量的赋值运算指针
9、变量指针变量=地址地址v不不能能把把常常量量或或表表达达式式的的地地址址赋赋给给指指针针变变量量。如:如:P=&67P=&67;P=&(i+5)P=&(i+5)是非法的是非法的 v不不能能将将一一个个整整数数赋赋给给指指针针变变量量,但但可可以以赋赋整整数值数值0 0,表示该指针空指针,不指向任何内容。,表示该指针空指针,不指向任何内容。v指针的类型是它所指向变量的类型。指针的类型是它所指向变量的类型。v允许声明指向允许声明指向 void void 类型的指针。该指针可类型的指针。该指针可以被赋予任何类型对象的地址。以被赋予任何类型对象的地址。例:例:void*general;void*gen
10、eral;16例例1 指针的定义、赋值与使用指针的定义、赋值与使用#includeusingnamespacestd;voidmain()int*i_pointer;inti;i_pointer=&i;i=10;cout“Outputinti=”iendl;coutOutputintpointeri=*i_pointerendl;17程序运行的结果是:程序运行的结果是:Outputinti=10Outputintpointeri=1018指针变量的算术运算指针变量的算术运算v指针与整数的加减运算指针与整数的加减运算指针指针 p p 加上或减去加上或减去 n n,其意义是指其意义是指针当前指向位
11、置的前方或后方第针当前指向位置的前方或后方第 n n 个数据的地址。个数据的地址。这种运算的结果值取决于指针指向的这种运算的结果值取决于指针指向的数据类型。数据类型。v指针加一,减一运算指针加一,减一运算指向下一个或前一个数据。指向下一个或前一个数据。19papa-2pa-1pa+1pa+2pa+3*(pa-2)*pa*(pa+1)*(pa+2)*(pa+3)*(pa-1)short*pa20pb-1pbpb+1pb+2*(pb-1)*pb*(pb+1)*(pb+2)int *pb21v关系运算关系运算 两个指针变量指向同一个数组中的元两个指针变量指向同一个数组中的元素时,其关系运算的结果表明
12、了这两个素时,其关系运算的结果表明了这两个指针变量所指向的数组元素的先后关系指针变量所指向的数组元素的先后关系 指针可以和零之间进行等于或不等于指针可以和零之间进行等于或不等于的关系运算。例如的关系运算。例如:p=0p=0或或p!=0p!=022指针的关系运算指针的关系运算例如:例如:char a10;char*p1,*p2;p1=a+2;p2=a+4;p1+;p2-;23指向数组元素的指针指向数组元素的指针v定义与赋值定义与赋值例:int a10,*pa;pa=&a0;或 pa=a;24指向数组元素的指针指向数组元素的指针v通过指针引用数组元素通过指针引用数组元素v经过上述声明及赋值后,在执
13、行语句经过上述声明及赋值后,在执行语句中中*pa就是就是a0,*(pa+1)就是就是a1,.,*(pa+i)就是就是ai.ai,*(pa+i),*(a+i),pai都是等效的。都是等效的。不能写不能写a+,因为因为a是数组首地址是常是数组首地址是常量。量。25应用举例应用举例2设有一个int型数组a,有10个元素。用四种方法访问数组的各个元素:E使用数组名和下标E使用数组名和指针运算E使用指针变量E使用下标表示法引用指针指向的数组元素26#includeusingnamespacestd;voidmain()inta10;inti,*p;for(i=0;iai;for(i=0;i10;i+)c
14、out*(a+i);for(p=a;p-a10;p+)cout*p;p=a;for(i=0;i10;i+)coutpi;27应用举例应用举例3#include#includeusingnamespacestd;voidmain()constintM=20,N=10;intaM,bN,cM;intd,e,f=0,*pa,*pb,*pc;从键盘输入整数集合从键盘输入整数集合a a、b b的元素个的元素个数和各个元素的值,计算并输出其交集数和各个元素的值,计算并输出其交集28cout输入数组输入数组a中元素的个数:中元素的个数:d;cout输入数组输入数组a的的d个元素:个元素:endl;for(p
15、a=a;pa*pa;cout输入数组输入数组b中元素的个数:中元素的个数:e;cout输入数组输入数组b的的e个元素:个元素:endl;for(pb=b;pb*pb;29for(pa=a,pc=c;paa+d;pa+)for(pb=b;pbb+e;pb+)if(*pa=*pb)*pc+=*pa;f+;break;cout交集交集c的各个元素依次为的各个元素依次为:endl;for(pc=c;pcc+f;pc+)coutsetw(3)*pc;30应用举例应用举例4#include#includeusingnamespacestd;voidmain()constintM=20,N=10;intaM
16、,bN,cM+N;intd,e,f=0,*pa,*pb,*pc;从键盘输入整数集合从键盘输入整数集合a a、b b的元素个的元素个数和各个元素的值,计算并输出其并集数和各个元素的值,计算并输出其并集31cout输入数组输入数组a中元素的个数:中元素的个数:d;cout输入数组输入数组a的的d个元素:个元素:endl;for(pa=a;pa*pa;cout输入数组输入数组b中元素的个数:中元素的个数:e;cout输入数组输入数组b的的e个元素:个元素:endl;for(pb=b;pb*pb;32for(pa=a,pc=c;paa+d;pa+,pc+)*pc=*pa;f+;for(pb=b;pbb
17、+e;pb+)for(pa=a;pa=a+d)*pc+=*pb;f+;cout“并集并集c的各个元素依次为的各个元素依次为:endl;for(pc=c;pcc+f;pc+)coutsetw(3)p2;cinp2;正确的正确的/等价于等价于cina;cina;35字符指针的定义、赋值和引用字符指针的定义、赋值和引用-例例5#include#includeusingnamespacestd;voidmain()char*p,sa20,sb20;inti;p=sa;strcpy(sa,“TodayisSunday.”);for(i=0;*(sa+i)!=0;i+)sbi=*p+;sbi=0;p=sb
18、;coutp;36动态存储分配动态存储分配v静态存储分配:静态存储分配:程序中使用的变量和数组的类型、数目、大小程序中使用的变量和数组的类型、数目、大小是由编写程序时确定的,程序运行时这些数据占是由编写程序时确定的,程序运行时这些数据占用的存储空间数也是一定的。用的存储空间数也是一定的。缺点:程序无法在运行时根据具体情况(如用户缺点:程序无法在运行时根据具体情况(如用户输入)灵活调整存储分配情况。输入)灵活调整存储分配情况。v动态存储分配:动态存储分配:使用指针、运算符使用指针、运算符newnew和和deletedelete,在程序运行在程序运行期间按照实际需要申请适量内存,克服了静态存期间按
19、照实际需要申请适量内存,克服了静态存储分配的缺点。储分配的缺点。37动态申请内存操作符动态申请内存操作符 new=new=new =new=new ()功能:在程序执行期间,申请用于存放功能:在程序执行期间,申请用于存放类型对象的内存空间,并依初值列表类型对象的内存空间,并依初值列表赋以初值。赋以初值。结果值:结果值:成功:类型的指针,指向新分配的内存成功:类型的指针,指向新分配的内存首地址。首地址。失败:失败:0 0(NULLNULL)38动态申请内存操作符动态申请内存操作符 newl例如:例如:lintx,*p=newint(6);lx=*p;lcoutx*pendl;ldeletep;3
20、9动态申请内存操作符动态申请内存操作符 newnewnew运算符为数组申请内存运算符为数组申请内存使用形式:使用形式:=new=new 40释放内存操作符释放内存操作符deletedelete指针指针功能:释放指针功能:释放指针P所指向的内存。所指向的内存。P必须必须是是new操作的返回值。操作的返回值。41使用使用动态存储分配时,应注意:时,应注意:确认分配成功后才能使用。确认分配成功后才能使用。分配成功后不宜变动指针的值。分配成功后不宜变动指针的值。用运算符用运算符new获取的内存空间,必须用获取的内存空间,必须用delete进行释放。进行释放。对一个指针只能调用一次对一个指针只能调用一次
21、delete。在使用在使用delete运算符进行释放时,不用考虑运算符进行释放时,不用考虑数组的维数。数组的维数。42动态存储分配动态存储分配-例例6从内存中获取一个整型数组,赋值后并打印出来。从内存中获取一个整型数组,赋值后并打印出来。#include#include#include#include using namespace std;using namespace std;void main()void main()int n,i;/int n,i;/定义数组元素的个数定义数组元素的个数 int *p;int *p;43cout“pleaseinputthelengthofthearr
22、ay:”n;if(p=newintn)=0)cout“cantallocatememory.”endl;exit(1);for(i=0;in;i+)pi=i*2;cout“nowoutputthearray:”endl;for(i=0;in;i+)coutpi“;coutendl;deletep;44运行运行结果为:结果为:pleaseinputthelengthofthearray:6nowoutputthearray:024681045引用引用1声明引用的格式声明引用的格式1 类型类型&引用名引用名 =变量名;变量名;例:例:intint a=1;a=1;intint&b=a;/&b=a;
23、/将引用将引用b b声明为变量声明为变量a a的别名的别名 intint&c=a;/&c=a;/将引用将引用c c声明为变量声明为变量a a的别名的别名1引用是实体的别名,对引用的存取就是对变量的引用是实体的别名,对引用的存取就是对变量的存取,引用与被引用的实体具有相同的地址。存取,引用与被引用的实体具有相同的地址。1无初始化的引用是无效的。无初始化的引用是无效的。coutcoutabc;/abc;/有声明语句有声明语句46按引用调用按引用调用lC+C+用两种方式向函数传递数值:用两种方式向函数传递数值:值调用值调用 引用调用引用调用l按引用调用时,调用者让被调用函数能够按引用调用时,调用者让
24、被调用函数能够直接访问调用者的数据,并允许被调用函直接访问调用者的数据,并允许被调用函数能够修改其中的数据。数能够修改其中的数据。l按引用调用分为用按引用调用分为用引用参数引用参数按引用调用和按引用调用和用用指针参数指针参数按引用调用。按引用调用。47按引用调用按引用调用l用用引用参数引用参数是其相应参数的别名。要是其相应参数的别名。要表示函数的参数是按引用传递的,在表示函数的参数是按引用传递的,在函数原型和函数头中该参数类型后面函数原型和函数头中该参数类型后面加上加上&。l在函数调用中,只要指定变量名,该在函数调用中,只要指定变量名,该变量就会通过引用传递。在被调用函变量就会通过引用传递。在
25、被调用函数体中,通过数体中,通过引用引用参数名指定的变量参数名指定的变量实际上就是引用了调用函数中的原始实际上就是引用了调用函数中的原始变量,被调用函数可以直接修改原始变量,被调用函数可以直接修改原始变量。变量。48按引用调用按引用调用l用指针参数用指针参数按引用调用是用指针按引用调用是用指针和间接运算符模拟按引用调用。和间接运算符模拟按引用调用。调用函数并要修改参数时,传递调用函数并要修改参数时,传递该参数地址,在要修改数值的变该参数地址,在要修改数值的变量名前面量名前面加上加上&符号。符号。49用引用参数用引用参数按引用调用按引用调用-例例7#includeusingnamespacest
26、d;voidcubeByReference(int&);voidmain()intz=4;coutz=z;cubeByReference(z);coutz=z;50用引用参数用引用参数按引用调用按引用调用-例例7voidcubeByReference(int&cRef)cRef=cRef*cRef*cRef;51用指针参数用指针参数按引用调用按引用调用-例例8#includeusingnamespacestd;voidcubeByReference(int*);voidmain()intz=4;coutz=z;cubeByReference(&z);coutz=z;52用指针参数用指针参数按引
27、用调用按引用调用-例例8voidcubeByReference(int*p)*p=*p*p*p;53数组名做函数参数数组名做函数参数 l当数组名作为函数参数时,参数的传当数组名作为函数参数时,参数的传递方式为地址传递,即实参与形参表递方式为地址传递,即实参与形参表示同一个数组,因此被调函数中对形示同一个数组,因此被调函数中对形参数组内容的修改将修改主调函数中参数组内容的修改将修改主调函数中实参数组的内容。实参数组的内容。54数组名做函数参数数组名做函数参数l实参与形参都是数组名。实参与形参都是数组名。l实参数组与形参数组类型应一致,如不一实参数组与形参数组类型应一致,如不一致,结果将出错。致,
28、结果将出错。l实参数组与形参数组维数大小可以不一致实参数组与形参数组维数大小可以不一致也可以一致。因为也可以一致。因为C+C+编译系统对形参大小编译系统对形参大小不作检查,只是将实参数组的起始地址传不作检查,只是将实参数组的起始地址传给形参。如果要求形参数组得到实参数组给形参。如果要求形参数组得到实参数组全部的元素值,最好指定形参数组与实参全部的元素值,最好指定形参数组与实参数组大小一致。数组大小一致。55数组名做函数参数数组名做函数参数l数组名作函数参数时,是数组名作函数参数时,是“地址传递地址传递”,把实参数组的起始地址传递给形,把实参数组的起始地址传递给形参数组,两个数组共同占用同一段内
29、参数组,两个数组共同占用同一段内存单元。存单元。l形参数组是多维数时,定义时可以指形参数组是多维数时,定义时可以指定每一维的大小,也可省略第一维大定每一维的大小,也可省略第一维大小的说明,但不能省略第二维以及其小的说明,但不能省略第二维以及其它高维大小的说明。它高维大小的说明。56 例例99l将键盘输入的将键盘输入的1010个整数按从小到大的个整数按从小到大的顺序排序(选择法)。顺序排序(选择法)。57#include#includeusing namespace std;using namespace std;void invert(int a,int n)void invert(int a
30、,int n)int t=0;int t=0;for(int i=0;in-1;i+)for(int i=0;in-1;i+)for(int j=i+1;jn;j+)for(int j=i+1;jaj)if(aiaj)t=ai;t=ai;ai=aj;ai=aj;aj=t;aj=t;58int main()int main()int i;int i;int a10;int a10;coutInput 10 numbers:endl;coutInput 10 numbers:endl;for(i=0;i10;i+)for(i=0;iai;cinai;invert(a,10);invert(a,10
31、);coutThe sorted numbers is:endl;coutThe sorted numbers is:endl;for(i=0;i10;i+)for(i=0;i10;i+)coutaiendl;coutaiendl;return 0;return 0;59指向数组的指针变量作为函数参数指向数组的指针变量作为函数参数 l将一组同类型的数据(数组)从一个将一组同类型的数据(数组)从一个函数传递到另一个函数,可以采用数函数传递到另一个函数,可以采用数组名作为函数参数,也可以采用指向组名作为函数参数,也可以采用指向数组的指针变量作为函数参数。数组的指针变量作为函数参数。l当函数的形参为
32、指向数组的指针时,当函数的形参为指向数组的指针时,函数的实参即可以是数组名,也可以函数的实参即可以是数组名,也可以是指向数组起始地址的指针变量。是指向数组起始地址的指针变量。60 例例1010l将一个数组中的数据按相反顺序存放。将一个数组中的数据按相反顺序存放。61#include#include using namespace std;using namespace std;void invert(int*p,int n)void invert(int*p,int n)int i,j,temp;int i,j,temp;for(i=0,j=n-1;ij;i+,j-)for(i=0,j=n-1
33、;ij;i+,j-)temp=*(p+i);temp=*(p+i);*(p+i)=*(p+j);*(p+i)=*(p+j);*(p+j)=temp;*(p+j)=temp;62int main()int main()int a10,i;int a10,i;/int*q=a;coutInput ten interger:endl;coutInput ten interger:endl;for(i=0;i10;i+)for(i=0;iai;cinai;invert(a,10);invert(a,10);/invert(q,10);for(i=0;i10;i+)for(i=0;i10;i+)cout
34、aiendl;coutaiendl;return 0;return 0;63练习练习-阅读程序写结果阅读程序写结果l#includel#includelusingnamespacestd;lvoidmain()llconstintN=10;lintaN+1,p,x,*t;lcout输入输入a数组数组:endl;lfor(t=a;t*t;/(输入输入2,4,6,8,10,12,14,16,18,20)lcout输入待插入的数输入待插入的数x:x;/(输入输入9)64练习练习-阅读程序写结果阅读程序写结果lt=a;lp=0;lwhile(x*(t+p)&p=a+p;t-)l*(t+1)=*t;lt=a+p;l*t=x;lfor(t=a;t=a+N;t+)lcoutsetw(4)*t;l65