《指针的定义与应用.ppt》由会员分享,可在线阅读,更多相关《指针的定义与应用.ppt(65页珍藏版)》请在三一办公上搜索。
1、第15章 指 针,西南交通大学软件学院计算机基础教研室,C+编程导论,2,本章主要内容,C+中指针的基本概念指针类型变量的定义方法指针与地址运算符指针变量赋值、指针的运算通过指针类型的变量去访问某个变量或数组元素的值引用动态分配内存按引用调用,3,什么是地址?,计算机的内存储器就象一个巨大的一维数组,每个数组元素就是一个存储单元(在微型计算机中其大小通常为一个字节)。就象数组中的每个元素都有一个下标一样,每个内存单元都有一个编号,又称地址。,4,什么是地址?,在运行一个程序时,程序本身及其所用到的数据都要放在内存储器中:程序、函数、变量、常数、数组和对象等,在内存储器中占有一席之地。存放在内存
2、储器中的程序和数据都有一个地址,用它们占用的那片存储单元中的第一个存储单元的地址表示。,5,什么是地址?,在C+中,为某个变量或者函数分配内存储器的工作由编译程序完成。内存地址的访问方式直接访问方式:通过变量名访问间接访问方式:通过地址访问,6,如何知道某个变量、数组、函数的地址,+规定:变量的地址可以使用地址运算符函数的地址用函数名表示。,7,什么是指针,指针是C+语言中的一种数据类型,是专门用来处理地址的。指针是某个内存单元的首地址。,8,什么是指针变量?,指针变量是包含另一个变量地址的变量。指针变量也是一个变量,遵循先定义,后使用。定义指针变量的类型是由该指针指向的变量类型决定。,9,指
3、针变量的概念,定义例:int i;int*i_pointer;指向整型变量的指针,10,指针变量的声明,变量的指针:变量在内存中的存放起始地址指针变量的声明:类型标识符*指针变量 例如:int*p;定义语句中的“*”表示该变量为指针变量 一个指针变量只能存储同一种类型变量的地址,11,指针变量的初始化,语法形式 类型标识符*指针名初始地址;例:int*pa=,12,指针变量的初始化,注意事项用变量地址作为初值时,该变量必须在指针初始化之前定义。如:int a;int*pa=,13,指针与地址运算符,“,14,指针与地址运算符,*出现在声明语句和执行语句中的含义是不同的。int*p;/*在声明语
4、句中表示声明的是指针,声明p是整型指针 cout*p;/*在执行语句中表示指针所指对象的内容,15,指针变量的赋值运算,指针变量=地址 p=/将指针p2的值赋个指针p1,16,指针变量的赋值运算,指针变量=地址不能把常量或表达式的地址赋给指针变量。如:P=,17,例1 指针的定义、赋值与使用,#includeusing namespace std;void main()int*i_pointer;int i;i_pointer=,18,程序运行的结果是:Output int i=10Output int pointer i=10,19,指针变量的算术运算,指针与整数的加减运算指针 p 加上或减
5、去 n,其意义是指针当前指向位置的前方或后方第 n 个数据的地址。这种运算的结果值取决于指针指向的数据类型。指针加一,减一运算指向下一个或前一个数据。,20,pa,21,pb-1,pb,pb+1,pb+2,*(pb-1),*pb,*(pb+1),*(pb+2),int*pb,22,关系运算 两个指针变量指向同一个数组中的元素时,其关系运算的结果表明了这两个指针变量所指向的数组元素的先后关系 指针可以和零之间进行等于或不等于的关系运算。例如:p=0或p!=0,指针变量的关系运算,23,指针的关系运算,例如:char a10;char*p1,*p2;p1=a+2;p2=a+4;,p1+;p2-;,
6、24,指向数组元素的指针,定义与赋值例:int a10,*pa;pa=,25,指向数组元素的指针,通过指针引用数组元素经过上述声明及赋值后,在执行语句中*pa就是a0,*(pa+1)就是a1,.,*(pa+i)就是ai.ai,*(pa+i),*(a+i),pai都是等效的。不能写 a+,因为a是数组首地址是常量。,26,应用举例2,设有一个int型数组a,有10个元素。用四种方法访问数组的各个元素:使用数组名和下标使用数组名和指针运算使用指针变量使用下标表示法引用指针指向的数组元素,27,#include using namespace std;void main()int a10;int i
7、,*p;for(i=0;iai;for(i=0;i10;i+)cout*(a+i);for(p=a;p-a10;p+)cout*p;p=a;for(i=0;i10;i+)coutpi;,28,应用举例3,#include#include using namespace std;void main()const int M=20,N=10;int aM,bN,cM;int d,e,f=0,*pa,*pb,*pc;,从键盘输入整数集合a、b的元素个数和各个元素的值,计算并输出其交集,29,coutd;cout*pa;coute;cout*pb;,30,for(pa=a,pc=c;paa+d;pa+
8、)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;,31,应用举例4,#include#include using namespace std;void main()const int M=20,N=10;int aM,bN,cM+N;int d,e,f=0,*pa,*pb,*pc;,从键盘输入整数集合a、b的元素个数和各个元素的值,计算并输出其并集,32,coutd;cout*pa;coute;cout*pb;,33,for(pa=a,
9、pc=c;pa=a+d)*pc+=*pb;f+;cout“并集c的各个元素依次为:endl;for(pc=c;pcc+f;pc+)coutsetw(3)*pc;,34,字符指针来存储和处理字符串,字符指针与字符串字符串是由字符数组中的结束标志符“0”之前的字符组成的特殊数组,指向这一特殊数组的指针则称字符串指针。字符串指针的定义、赋值和引用与指向数组的指针基本相同,35,用字符数组存储和处理字符串,注意!若有如下定义:char a4=“abc”,*p2=a;cinp2;正确的/等价于cina;,36,字符指针的定义、赋值和引用-例5,#include#include using namespa
10、ce std;void main()char*p,sa20,sb20;int i;p=sa;strcpy(sa,“Today is Sunday.”);for(i=0;*(sa+i)!=0;i+)sbi=*p+;sbi=0;p=sb;coutp;,37,动态存储分配,静态存储分配:程序中使用的变量和数组的类型、数目、大小是由编写程序时确定的,程序运行时这些数据占用的存储空间数也是一定的。缺点:程序无法在运行时根据具体情况(如用户输入)灵活调整存储分配情况。动态存储分配:使用指针、运算符new和delete,在程序运行期间按照实际需要申请适量内存,克服了静态存储分配的缺点。,38,动态申请内存操
11、作符 new,=new=new()功能:在程序执行期间,申请用于存放类型对象的内存空间,并依初值列表赋以初值。结果值:成功:类型的指针,指向新分配的内存首地址。失败:0(NULL),39,动态申请内存操作符 new,例如:int x,*p=new int(6);x=*p;coutx*pendl;delete p;,40,动态申请内存操作符 new,new运算符为数组申请内存使用形式:=new,41,释放内存操作符delete,delete 指针功能:释放指针P所指向的内存。P必须是new操作的返回值。,42,使用动态存储分配时,应注意:确认分配成功后才能使用。分配成功后不宜变动指针的值。用运算
12、符new获取的内存空间,必须用delete进行释放。对一个指针只能调用一次delete。在使用delete运算符进行释放时,不用考虑数组的维数。,43,动态存储分配-例6,从内存中获取一个整型数组,赋值后并打印出来。#include#include using namespace std;void main()int n,i;/定义数组元素的个数 int*p;,coutn;if(p=new intn)=0)cout“cant allocate memory.”endl;exit(1);for(i=0;in;i+)pi=i*2;cout“now output the array:”endl;fo
13、r(i=0;in;i+)coutpi“;coutendl;delete p;,运行 结果为:please input the length of the array:6now output the array:0 2 4 6 8 10,46,引用,声明引用的格式 类型/有声明语句,47,按引用调用,C+用两种方式向函数传递数值:值调用 引用调用按引用调用时,调用者让被调用函数能够直接访问调用者的数据,并允许被调用函数能够修改其中的数据。按引用调用分为用引用参数按引用调用和用指针参数按引用调用。,48,按引用调用,用引用参数是其相应参数的别名。要表示函数的参数是按引用传递的,在函数原型和函数头中
14、该参数类型后面加上&。在函数调用中,只要指定变量名,该变量就会通过引用传递。在被调用函数体中,通过引用参数名指定的变量实际上就是引用了调用函数中的原始变量,被调用函数可以直接修改原始变量。,49,按引用调用,用指针参数按引用调用是用指针和间接运算符模拟按引用调用。调用函数并要修改参数时,传递该参数地址,在要修改数值的变量名前面加上&符号。,50,用引用参数按引用调用-例7,#include using namespace std;void cubeByReference(int,51,用引用参数按引用调用-例7,void cubeByReference(int,52,用指针参数按引用调用-例8
15、,#includeusing namespace std;void cubeByReference(int*);void main()int z=4;coutz=z;cubeByReference(,53,用指针参数按引用调用-例8,void cubeByReference(int*p)*p=*p*p*p;,54,数组名做函数参数,当数组名作为函数参数时,参数的传递方式为地址传递,即实参与形参表示同一个数组,因此被调函数中对形参数组内容的修改将修改主调函数中实参数组的内容。,55,数组名做函数参数,实参与形参都是数组名。实参数组与形参数组类型应一致,如不一致,结果将出错。实参数组与形参数组维数
16、大小可以不一致也可以一致。因为C+编译系统对形参大小不作检查,只是将实参数组的起始地址传给形参。如果要求形参数组得到实参数组全部的元素值,最好指定形参数组与实参数组大小一致。,56,数组名做函数参数,数组名作函数参数时,是“地址传递”,把实参数组的起始地址传递给形参数组,两个数组共同占用同一段内存单元。形参数组是多维数时,定义时可以指定每一维的大小,也可省略第一维大小的说明,但不能省略第二维以及其它高维大小的说明。,57,例9,将键盘输入的10个整数按从小到大的顺序排序(选择法)。,#includeusing namespace std;void invert(int a,int n)int
17、t=0;for(int i=0;iaj)t=ai;ai=aj;aj=t;,int main()int i;int a10;coutai;invert(a,10);coutThe sorted numbers is:endl;for(i=0;i10;i+)coutaiendl;return 0;,60,指向数组的指针变量作为函数参数,将一组同类型的数据(数组)从一个函数传递到另一个函数,可以采用数组名作为函数参数,也可以采用指向数组的指针变量作为函数参数。当函数的形参为指向数组的指针时,函数的实参即可以是数组名,也可以是指向数组起始地址的指针变量。,61,例10,将一个数组中的数据按相反顺序存放
18、。,#include using namespace std;void invert(int*p,int n)int i,j,temp;for(i=0,j=n-1;ij;i+,j-)temp=*(p+i);*(p+i)=*(p+j);*(p+j)=temp;,int main()int a10,i;/int*q=a;coutai;invert(a,10);/invert(q,10);for(i=0;i10;i+)coutaiendl;return 0;,64,练习-阅读程序写结果,#include#include using namespace std;void main()const int N=10;int aN+1,p,x,*t;cout*t;/(输入2,4,6,8,10,12,14,16,18,20)coutx;/(输入9),65,练习-阅读程序写结果,t=a;p=0;while(x*(t+p),