1第10讲指针(上)参考教材的10.1到10.3节2指针是C++语言中的一个重要概念。掌握指针的用法,可使程序简洁、高效、灵活,不难学也不容易学。关键是理解下列故事含义。故事:很久很久以前,特务阿宝接到上级指令,要去寻找一个密钥。几经周折,线人告之:密钥藏在某墓地的看幕人所住的一栋小楼的房间中。一个风雨交加的夜晚,阿宝潜入了小楼,房间很多,不知该进哪一间,正在一筹莫展之际,忽然走廊上的电话铃声响起。艺高人胆大,阿宝毫不迟疑,抓起听筒,一个陌生人说:“去打开小姐卧室,那里有线索”。阿金疾步上楼,打开小姐卧室,用电筒一照,只见桌上赫然6个大字:1000房间。阿宝眼睛一亮,迅速找到1000房间,取出重要数据66(密钥),完成任务。310.1指针的概念指针(pointer):是内存中某存储单元的地址(编号)。指针变量:也是内存中的一个变量,只是其值存放的是另一个变量的地址。1000661000房间(b)小姐卧室(a)410.1指针的概念引进指针以后,变量的访问(访问是指取出其值或向它赋值)方式有两种:(1)直接访问,通过变量名访问,如通过变量名i直接访问(2)间接访问,通过该变量的指针(地址)来访问,如通过i_pointer访问变量i张强(父亲)张强(儿子)余雨(母亲)5§10.2指针变量指针变量:存放其他变量地址(指针)的变量指针变量有三个属性:(1)指针变量指向的变量类型。如i_pointer指向的变量i是整型。(2)指针变量在内存中占多少内存单元。如i_pointer占两个内存单元,称为“近指针”,用near表示。如果该变量在内存中占4个内存单元,称为“远指针”,用far表示。如果未指定near或far,缺省是near(3)指针变量指向哪一个变量,即该指针变量的值(地址值)是多少。如i_pointer的值是20006§10.2指针变量指针变量定义的一般形式:基类型*标识符其中:“*”表示定义指针变量“标识符”是指针变量名“基类型”表示该指针变量所指向的变量类型例、inti,j;/*定义两个整型变量*/int*pointer_1,*pointer_2;float*pointer_3;char*pointer_4;7指针赋值例inta=66;//定义一个整型变量aint*p,*q;//定义p,q为指向整型变量的指针变量p=&a;//将变量a的地址赋给p,这时见图1q=p;//将p的值赋给q,见图266&apa&pp变量的地址&aa变量的地址图1的说明:将a变量的地址赋给指针p,意味着让指针p指向a图1866&apa图2的说明:当着执行q=p;之后,p中所存的a变量的地址值,也就被放到q变量中,意味着让指针q也指向a图2&aq&p&qq=p;指针赋值9§10.2指针变量指针变量的赋值:方法1:例、pointer_1=&i;pointer_2=&j;注意,指针变量中只能存放地址,不能将一个非地址类型的数据(如常数等)赋给一个指针变量,如:pointer_1=100;(错误)方法2:也可以在定义指针变量的同时指定其初值,如、inta;int*p=&a;10§10.2指针变量指针变量的引用有两个运算符可以引用指针变量:(1)&:取地址运算符。如pointer_1=&i;(2)*:指针运算符。用于访问指针变量所指向变量如果定义:inti,j;int*pointer_1;pointer_1=&i;指针变量pointer_1指向变量i,现在,对变量i、j有两种访问方式:(1)直接访问。如i=100;j=i。(2)通过指针变量间接访问。如:*pointer_1=100;j=*pointer_1;11§10.2指针变量说明:定义指针变量时,还未规定它指向哪一个变量,此时不能用*运算符访问指针。只有在程序中用赋值语句具体规定其指向变量后,才能用*运算符访问所指向的变量.inta;int*p;(未规定指向哪个变量)*p=100;这种错误称为访问悬挂指针(suspendedpointer)12§10.2指针变量[例1]输入a和b两个整数,按先大后小的顺序输出a和b13§10.2指针变量1410.3指针变量作为函数的参数[例2]输入a和b两整数,按先大后小顺序输出a和b。151610.3指针变量作为函数的参数程序执行过程的说明1、执行pointer_1=&a;pointer_2=&b后,pointer_1和pointer_2分别指向a和b.2、调用函数swap(pointer_1,pointer_2),生成两个形参p1和p2。实参pointer_1的值传送给形参p1,因此p1也指向a。同理,p2指向b。1710.3指针变量作为函数的参数3、在swap()函数内,把*p1和*p2的值进行交换,*p1是变量a,*p2是变量b,即把a和b的值进行交换。4、函数swap()调用结束后,形参p1、p2被释放,main中得到的a和b是已经被交换的值。1810.3指针变量作为函数的参数intswap(int*p1,int*p2){int*p;*p=*p1;*p1=*p2;*p2=*p;}使用指针变量,应注意避免指针悬挂。1910.3指针变量作为函数的参数函数swap()的形参是指针变量,有两种调用方式:swap(pointer_1,pointer_2);swap(&a,&b);均把变量a和b的地址传送给形参,均能实现交换a和b的值。只有函数swap()知道变量a和b的地址,才能改变其值(交换)。如果swap()设计为下面形式,不能实现a和b的值交换intswap(intx,inty)/*该函数交换形参的值*/{intt;t=x;x=y;y=t;}该函数交换形参的值,不能实现实参值的交换,因为在C语言中,实参和形参之间使用“传值法”,数据只能单向由实参传到形参。形参值的变化不影响实参2010.3指针变量作为函数的参数分析:下面的程序是否能达到交换的目的?intswap(int*p1,int*p2)/*交换形参的值*/{int*p;p=p1;p1=p2;p2=p;}main(){inta,b;int*pointer_1,*pointer_2;scanf(%d,%d,&a,&b);pointer_1=&a;pointer_2=&b;if(ab)swap(pointer_1,pointer_2);printf(\n%d,%d\n,*pointer_1,*pointer_2);}2110.3指针变量作为函数的参数小结:1、指针变量作为函数参数,可以使函数通过指针变量返回其所指向的变量值,从而实现主调函数和被调函数之间的数据双向传递2、以指针变量作函数的参数,实参和形参之间使用“地址值传递法”,而且:“地址值”也只能单向由实参传到形参。形参值的变化不影响实参,即不能改变实参指针变量本身的值。但可以改变实参指针变量所指向的变量的值2210.3指针变量作为函数的参数[例3]输入a、b、c三个整数,按大小顺序输出232410.3指针变量作为函数的参数3.区分:*运算符在不同场合的作用,编译器能够根据上下文环境判别*的作用。inta,b,c,*p;(*表示定义指针)。p=&a;*p=100;(*表示指针运算符)。c=a*b;(*表示乘法运算符)。4.区分*运算符的以下用法:inta;int*p=&a;/*定义指针变量时指定初值,是为p指定初值*/。*p=100;/*给指针p所指向的变量赋值,这里是给变量a赋值。25§10.4数组的指针变量指针变量可以指向数组和数组元素,当指针指向数组后,对数组元素的访问,既可以使用数组下标,也可以使用指针。并且用指针访问数组元素,程序的效率更高(用下标访问数组元素程序更清晰)例如inta[10];/*元素为整型*/floatb[10];/*元素为实型*/int*p;/*可以指向数组a的元素*/float*pf;/*可以指向数组b的元素*/因此,以下语句均使指针p指向数组a:p=&a[0];p=a;/*把数组a的起始地址赋给p,不是把数组的全部元素赋给p*/。26§10.4数组的指针变量p+1指向下一个元素a[1],注意不是将p值简单加1。如果数组元素是整型,p+1表示p的地址加2;如果数组元素是实型,p+1表示p的地址加4;如果数组元素是字符型,p+1表示p的地址加1。p+i指向元素a[i]。可以使用*(p+i)访问元素a[i]。通过指针引用数组元素27§10.4数组的指针变量[例4]输出整型数组的全部元素整型访问各元素有三种方法:1、下标法(常用,很直观)main(){inta[10];inti;for(i=0;i10;i++)scanf(%d,&a[i]);printf(\n);for(i=0;i10;i++)printf(%d,a[i]);}28§10.4数组的指针变量2、用数组名(指针法)计算数组元素的地址(效率与下标法相同,不常用)main(){inta[10];inti;for(i=0;i10;i++)scanf(%d,&a[i]);printf(\n);for(i=0;i10;i++)printf(%d,*(a+i));}29§10.4数组的指针变量3、用指针变量访问各元素(常用,效率高)30§10.4数组的指针变量使用指针指向数组,应注意以下问题:1、若指针p指向数组a,虽然p+i与a+i、*(p+i)与*(a+i)意义相同,但仍应注意p与a的区别(a代表数组的首地址,是不变的;p是一个指针变量,可以指向数组中的任何元素),例、inta[10];*p;for(p=a;a(p+10);a++)printf(%d,*a);是否正确?31§10.4数组的指针变量32§10.4数组的指针变量2、指针变量可以指向数组中的任何元素,注意指针变量的当前值。因此:使用指针时,应特别注意避免指针访问越界例如:本例中第二次for循环,p已经越过数组的范围,但编译器不能发现该问题。避免指针访问越界是程序员自己的责任33§10.4数组的指针变量3、指针使用的几个细节。设指针p指向数组a(p=a),则:①p++(或p+=1),则:*p=?②*p++表示什么意义?③*(p++)与*(++p)的分别表示什么意义?④(*p)++表示什么意义?34§10.4数组的指针变量答案:①p++(或p+=1),p指向下一个元素。②*p++,相当于*(p++)。因为,*和++同优先级,++是右结合运算符。③*(p++)与*(++p)的作用不同。*(p++):先取*p,再使p加1。*(++p):先使p加1,再取*p。④(*p)++表示,p指向的元素值加1。小结:如果p当前指向数组a的第i个元素,则:*(p--)相当于a[i--],先取*p,再使p减1。(*p)--相当于a[i]--,先取*p,再使*p减1。*(++p)相当于a[++i],先使p加1,再取*p。*(--p)相当于a[--i],先使p减1,再取*p。35§10.4数组的指针变量数组名和指针变量作函数参数[例]将数组a中n个元素按相反顺序存放36§10.4数组的指针变量voidinv(intx[],intn)/*形参是数组*/{intt,i,j,m=(n-1)/2;for(i=0;i=m;i++){j=n-1-i;t=x[i];x[i]=x[j];x[j]=t;}}main(){staticinti,a[10]={3,7,9,11,0,6,7,5,4,2};printf(theoriginalarray:\n);for(i=0;i10;i++)printf(%d,a[i]);printf(\n);inv(a,10);printf(thearrayhasbeeninverted:\n);for(i=0;i10;i++)printf(%d,a[i]);printf(\n);}37§10.4数组的指针变量函数inv()可以用指针作形参,运行情况与用数组作形参相同。voidinv(int*x,intn){int*p,t,*i,*j,m=(n-1)/2;i