您好,欢迎访问三七文档
《C程序设计》课程讲义第1页共10页第10章指针第10章指针【计划课时】授课12课时+上机8课时10.1地址和指针的概念1.地址如果在程序中定义了一个“实体”(变量、数组、函数……),编译时系统就要给这些实体分配内存单元。分配规则:存储类型registerautoataticextern决定存储区域(动态存储区/静态存储区/寄存器组……)数据类型charintfloatdouble等决定占用的内存长度(字节数)和存储方式(ASCII码、补码等)而内存单元是以字节为单位,每个字节都有一个编号(即“地址”)。如果将内存比作一个旅馆,内存单元就好比“床位”,而实体则好比“旅客”。这些“旅客”(实体)中,有单人型(char)、夫妇型(int)、家庭型(float,long,double等),还有团体型(数组等)。每个“实体”占用的内存单元是不同的。如:chara;intb;floatc;intd[3];intmax()这些“实体”在内存中占用存储单元的情况可用下图表示(假定从内存单元地址1000开始):&a=1000a字符型变量a占1个字节&b=10011002b整型变量b占2个字节&c=1003100410051006c单实型变量c占4个字节d=100710081009101010111012d[0]整型数组d占6个字节d[1]d[2]max=1013max()函数max()入口地址《C程序设计》课程讲义第2页共10页第10章指针通常我们关心的不是具体的地址值,而是每个实体的“起始地址”。实体地址表示法1:直接访问(实体名)·普通变量a,b,c——&a,&b,&c·数组d[3]——d(数组名)&d[0],&d[1],&d[2]对二维数组,可用单下标法表示每行首地址。如对charx[3][4],可用x[0]、x[1]、x[2]分别表示第一、二、三行的首地址。·函数max()——max(函数名)入口地址&取地址运算符(适用于普通变量或数组元素)实体地址表示法2:间接访问(指针)适合于地址运算(加减等)【说明】字符串是一种特殊的实体,存放在内存用户区的常量区(参见第四章第五节)。2.指针(pointer)实体地址的一种表示法(便于编程处理)。指针是一种特殊的数据类型——存放的是某个实体的地址值。【变量的“指针”】变量的地址10.2变量的指针和指向变量的指针变量10.2.1指针变量P202存放“指针”(地址值)的特殊变量。通常在C语言中,所谓“指针”就是指“指针变量”。从现在开始,我们使用“指针”来表示“指针变量”。为什么要用指针变量?C程序中访问(读写)一个变量有两种方式:直接访问:利用实体名访问变量。访问变量的过程如下:变量(实体)名→定义时分配的地址→变量值好比“先坐再买票”看电影,来一个观众,分配一个空位给他去坐,并且还要在纸上记一个某人坐在哪里。这种方式对用户来说很方便(“直接就座”),但对系统来说,“找某人”就极不方便(间接:查名字→座号)间接访问:通过“指针”访问变量好比先买票(票上座号——指针),再按号入座看电影。这种方式对用户来说属于“间接就座”,便对系统查找来说就很直接,且便于处理。尤其对于数组(团体),可通过指针简单自加或自减,对整个数组进行处理。指针变量定义方法:类型标识符*变量名如int*a;char*b;float*c;此处,指针变量a,b,c分别指向某个未确定的整型变量、字符变量和实型变量。但指针变量a,b,c本身是整数(地址)。(编程测试可以发现在PC机上指针变量取值范围为-32767~32767,超出该范围编译就会出错,以此推算PC机地址长度为16位即2个字节)。以下程序亦可证实这一点:《C程序设计》课程讲义第3页共10页第10章指针main(){char*a;longint*b;double*c;printf(%d,%d,%d\n,sizeof(a),sizeof(b),sizeof(c));}结果:2,2,2【注意】数组名是常量,不能自加、自减或重新赋值,指针变量则可以。如chara[10],*b,x=5;a++;或a=100;a=x;×(编译出错)b++;或b=100;b=x;√(编译不出错)b=x实际上不行,见P256。指针变量可以通过变量说明语句或赋值语句进行初始化。可以把指针变量初始化为0、NULL或某个地址。具有NULL或0值的指针不指向任何地址(空值指针,见P256)。NULL是在stdio.h中定义的符号常量。值0是唯一能够直接赋给指针变量的整数值。10.2.2.指针变量的运算与引用P204a.与指针有关的运算符&取地址运算符(变量名前加一个&,表示该变量的地址)*指针运算符(“间接访问”运算符)*放在某个指针变量前,表示该指针变量所指向的变量。(注意与乘号“*”的区别)简单记忆:·如果p被定义成指向普通变量的指针变量,则*p代表该变量的值。如int*p,a=5;p=&a;则*p代表变量a的值(5)。·如果p被定义成指向某个数组的指针变量,则*p代表该数组中某个元素的值。如int*p,a[3]={1,2,3};p=a;则*p代表数组a中某个元素。【例】main(){int*p,a[12]={1,2,3,4,5};clrscr();p=a;for(;*p5;p++)printf(%d,*p);}结果:1234·如果p被定义成指向某个字符数组或某个字符串的指针变量,则*p代表某个字符。如int*p,a[3]=”abcd”;p=a;*p代表a中的某个字符【例】main(){char*p,a[12]=abcde;p=a;for(;*p;p++)printf(%c,*p);}main(){char*p;p=abcde;for(;*p;p++)printf(%c,*p);}《C程序设计》课程讲义第4页共10页第10章指针结果:abcde结果:abcde&与*组合使用时:若inta,*p;p=&a;则&*p=&a=p;*&a=a=*p&和*可以看作互相“抵消”。【例一】main(){inta=5,*p;p=&a;printf(“%d,%d,%d\n”,p,*p,a)}结果(按右图):2000,5,5【例二】以下程序的运行结果是什么?main(){inta,b=10,*p;p=&b;a=*p+3;printf(a=%d,b=%d\n,a,b);}结果:a=13,b=10【例三】main(){floatx,y;int*p;x=3.14;p=&x;y=*p;printf(y=%f\n,y);}结果:y=-2621.000000(把int*p改为float*p后,结果正确y=3.140000)b.指针变量的算术运算只有加、减两种p+5p++p-1p--注意加减运算是以实体为单位而不是以字节为单位。此外,两个指针变量可以相减。即:如果两个指针变量指向同一数组时,两个指针变量值之差是两个指针之间的元素个数。P256但两个指针变量相加并无实际意义。c.指针的逻辑比较P256指针变量指向同一个对象(如数组)的不同单元地址时,才可以进行比较。地址在前者为小。《C程序设计》课程讲义第5页共10页第10章指针实例:#includestdio.h#includestring.hfun(char*w,intn){chart,*s1,*s2;s1=w;s2=w+n-1;while(s1s2){t=*s1++;*s1=*s2--;*s2=t;}}main(){char*p;p=1234567;fun(p,strlen(p));puts(p);}结果:1711717【注意】对*s1++,因*与++同级,且自右至左结合,所以等价于*(p++),执行时是先做*s1,后做s1++。P215p=NULL表示指针变量为空值(不指向任何变量)。任何指针变量或地址都可以与NULL作相等或不相等的比较。如if(p==NULL)……【注意】在指针p指向某个实体的地址之前,不可对*p进行赋值。否则可能发生意想不到的错误(p随便指向某个单元)。典型错误:1、指针变量定义后,未指向具体存储单元就使用(此时指针变量所指单元是任意的)2、指针变量定义后,虽指向具体存储单元但未赋值就参加运算(此时其值是任意的)【例一】分析以下句子的错误int*p,*q;q=p;p指向?(错误类型1)inta=20,*p,*q=&a;*p=*q;p指向?(错误类型1)inta,*p,*q;q=&a;*p=*q;*q=?(错误类型2)【例二】若有定义char*p,ch;则不能正确赋值的语句组是。(01-1-06考题)A)p=&chB)p=(char*)malloc(1);scanf(“%c”,p);*p=getchar();C)*p=getchar();D)p=&ch;p=&ch;*p=getchar();答案:C(指针p未指向任何变量就赋值)【例三】如果有定义语句char*a,b[30];试判断以下各句哪些是正确的?《C程序设计》课程讲义第6页共10页第10章指针A)a=”abcde”;B)b=”abcde”;×C)scanf(“%s”,a);×D)scanf(“%s”,b);【例四】若有说明:int*p,m=5,n;试判断以下各句哪些是正确的?《试题汇编》【9.13】A)p=&n;scanf(“%d”,&p);B)p=&n;scanf(“%d”,*p);C)scanf(“%d”,&n);*p=n;D)p=&n;*p=m;答案:D【例五】若有说明:int*p1,*p2,m=5,n;试判断以下各句哪些是正确的?A)p1=&m;p2=&p1;×(p2应为**p2)B)p1=&m;p2=&n;*p1=*p2;×(*p2=?)C)p1=&m;*p2=*p1;×(p2指向?)D)p1=&m;p2=p1;10.2.3指针变量作为函数参数【例一】main(){voidswap(int,int);inta=5,b=3,*p1,*p2;clrscr();p1=&a,p2=&b;swap(*p1,*p2);printf(a=%d,b=%d\n,a,b);}voidswap(intx,inty){x=x-y;y=10;printf(x=%d,y=%d\n,,x,y);}结果:x=2,y=10a=5,b=3main(){voidswap(int*,int*);inta=5,b=3,*p1,*p2;clrscr();p1=&a,p2=&b;swap(p1,p2);printf(a=%d,b=%d\n,a,b);}voidswap(int*x,int*y){*x=*x-*y;*y=10;printf(x=%d,y=%d\n,*x,*y);}结果:x=2,y=10a=2,b=10【例二】P207例10.3地址传递【例三】以下程序的运行结果是什么?#includestdio.hfun(int*i){staticinta=1;*i+=a++;第一次调用fun(&k)后,k=*i=1,a=2;第二次调用fun(&k)后,k=*i=3,a=3;《C程序设计》课程讲义第7页共10页第10章指针}main(){intk=0;fun(&k);fun(&k);printf(%d\n,k);}结果:3【讨论】如果fun()函数中没有static,结果呢?(2)为了实现:在被调函数中改变实体值,然后在主调函数中使用这些改变了的实体值主要技术要点在于:主调函数的实参和被调函数对应的形参都必须用地址表示——地址传递用于作实参的地址可以是:·&变量名&数组元素名(很少使用)·数组名·指针变量名对应的形参则为:·数组定义·指针定义10.3指针与数组10.3.1指向数组元素的指针数组名对一维数组inta[10]:数组名a代表数组首地址(数组第一个元素a[0]的地址)即:a=&a[0]a+i=&a[i]*a=a[0]*(a+i)=a[i]对二维数组inta[10][10]:数组名a代表数组首行地址(数组第0行的行地址),即:a=a[0]a+i和*(a+i)均表示第i行的行地址a[i]+j和*(a+i)+j均表
本文标题:第10章指针
链接地址:https://www.777doc.com/doc-2241681 .html