第8章指针-xg-zhan

上传人:无*** 文档编号:244553023 上传时间:2024-10-05 格式:PPT 页数:65 大小:1.03MB
返回 下载 相关 举报
第8章指针-xg-zhan_第1页
第1页 / 共65页
第8章指针-xg-zhan_第2页
第2页 / 共65页
第8章指针-xg-zhan_第3页
第3页 / 共65页
点击查看更多>>
资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,北京邮电大学出版社,*,第,8,章 指针,8.1,地址与指针,8.2,指针变量,8.3,指针与数组,8.4,指针与字符串,8.5,指针与函数,8.6,指针数组,8.7,多级指针,本章小结,习题参考答案,北京邮电大学出版社,8.1,地址与指针,地址,:,一般把存储器中的一个字节称为一个内存单元。计算机为每个内存单元进行编号,内存单元的编号也就是内存单元的地址,.,指针,:,通常也把这个地址称为指针。所以说指针本质上就是地址。,注,:内存单元的地址(即指针)和内存单元的内容是两个,不同,的概念。,指针变量,:在语言中,允许用一个变量来存放指针,这种变量称为指针变量。,北京邮电大学出版社,指针和指针变量:,一个指针是一个地址,是一个常量。而一个指针变量却可以被赋予不同的指针值,是变量。,但常把指针变量简称为指针。,引进指针的目的,就是为了能直接访问内存单元。,获取数据单元或代码的指针:,例如变量,a,,使用取地址运算符,&,,即,&,a,;,如一个函数,printf,(),,获取该函数的起始地址的方法是,直接使用函数名,即,printf,。,分类:,虽然指针本质上都是内存地址,为了避免被错误使用,分成不同类型,有整型指针、实型指针、字符型指针等等。定义时指明。不同类型的指针变量不可以直接进行赋值的。,指针变量中只能保存变量的地址,不能直接保存数据,图,8.2,具体描述了两者之间的区别。,北京邮电大学出版社,例:,假设,i,、,j,是整型变量,,f,是单精度型变量,,pointer1,是整型指针变量,,pointer2,是单精度型指针变量。,以下均为合法操作:,pointer1=,pointer1=,pointer2=,北京邮电大学出版社,以下操作使用不正确:,pointer1=j; /*,不允许保存整型数据*,/,pointer1= /* pointer1,不能保存不同类型数据的地址(指针)*,/,pointer2= /* 3.14,是常数,不能使用,&,来获取地址(指针)*,/,指针变量的值是可以是变量的地址,也可以是其它数据结构的地址,如:数组或一个函数的首地址。因为数组或函数都是连续存放的。也就找到了该数组或函数。,北京邮电大学出版社,8.2,指针变量,8.2.1,指针,变量,的定义:,先定义后使用:,类型说明符 *变量名,;,其中,*表示这是一个指针变量。,类型说明符表示本指针变量所指向的变量的数据类型。,而指针变量自身的类型就是指针型。,例如:,int,*p2; /*p2,是指向整型变量的指针变量*,/,float,*p3; /*p3,是指向浮点变量的指针变量*,/,char,*p4; /*p4,是指向字符变量的指针变量*,/,北京邮电大学出版社,8.2.2,指针变量的引用,两种与指针有关的运算符:,&,取地址运算符。,*,指针运算符(或称“间接访问”运算符)。,例如,:,int,x=10 ,*p, y;,p=&,x; /* &x,表示,x,的地址,赋给指针变量,p */,y,=*p; /* *p,表示取指针变量,p,所指向单元的内容,即变量,x,的值,因此,y=10 */,注意:在第一个语句中“*,p”,表示将,p,定义为一个指针变量,用以区别一般的变量,而第三个语句中的“*,p”,是使用指针变量,此时“*”是指针运算符,表示取出指针变量,p,所指向单元的内容。如图,8.3:,北京邮电大学出版社,8.2.3,指针变量的使用,指针变量的初始化方式有两种:,1,指针变量初始化的方法,int,a;,int,*p=,2,赋值语句的方法,int,a;,int,*p;,p=,不允许把一个数赋予指针变量,故下面的赋值是错误的:,int,*p;,p=1000;,被赋值的指针变量前不能再加“*”说明符,如写为*,p=&a,也是错误的。,例,:,int,i=200,x;,int,*,ip,;,ip,=,北京邮电大学出版社,x,=*,ip,;,*,ip,访问的是地址为,1800,的存储单元,等价于,x=i;,另外,,指针变量值是可以改变的,,即可以改变它们的指向,假设,char,i,j,*p1,*p2;,i=a;,j=b;,p1=,p2=,北京邮电大学出版社,北京邮电大学出版社,这时赋值表达式语句:,p2=p1;,就是使,p2,与,p1,指向同一对象,i,,此时的*,p2,就等价于,i,,而不是,j,,如图,8.6,所示:,北京邮电大学出版社,如果执行如下赋值表达式语句:,*,p2=*,p1;,实际上就是,j=i;,则表示把,p1,指向的内容赋给,p2,所指的区域,,此时就变成图,8.7,所示,北京邮电大学出版社,通过指针访问它所指向的一个变量是以间接访问的形式进行的,所以比直接访问一个变量要费时间,而且不直观。,例如*,p2=*p1;,实际上就是,j=i;,,前者不仅速度慢而且目的不明。但灵活性,使代码简洁和有效。,指针变量可出现在表达式中,。设,int,x,y,;*,px,=,例如,:,y=*px+5; /*,表示把,x,的内容加,5,并赋给,y */,(,y,=+*,px,; /*,px,的内容加上,1,之后赋给,y,,,+*,px,相当于,+(*,px,) */,y=*,px,+; /*,相当于,y=*,px,;,px,+ */,),北京邮电大学出版社,例,8.1,写出下列程序的运行结果,main(),int,a ,b ,p;,int,*p1, *p2;,a=10;,b=20;,p1=,p2=,if(a,b),p=*p1;*p1=*p2;*p2=p;,printf(%d,%dn, ,a,b,);,printf(%d,%dn,*p1, *p2);,运行结果:,20,,,10,20,,,10,北京邮电大学出版社,例,8.2,写出下列程序的运行结果。,main(),int,a,b,;,int,*p1, *p2,*p;,a=10;,b=20;,p1=,p2=,if(a,b),p=p1;p1=p2;p2=p;,printf(%d,%dn,a,b,);,printf(%d,%dn,*p1, *p2);,运行结果:,10,,,20,20,,,10,请读者自己思考本题与例题,8.1,的区别在哪儿?为什么结果不一样?,北京邮电大学出版社,8.3,指针与数组,8.3.1,通过指针访问一维数组,在,C,语言中,指针和数组有着非常紧密的联系,其原因在于凡是由数组下标完成的操作皆可用指针来实现。在数组中我们知道,可以通过数组的下标唯一确定数组中的某个元素,这种访问方式称为“下标法”。,例如:,int,a5=1,2,3,4,5 ,x , y;,x=a0 ; /*,通过下标将数组,a,中下标为,0,的元素赋给,x,,,x=1 */,y=a3 ; /*,通过下标将数组,a,中下标为,3,的元素赋给,y,,,y=4 */,由于数组中的每个元素都相当于相应类型的变量,指针变量可以指向一般的变量,因此指针变量也可以指向数组中的元素,也可以用“指针法”来访问数组中的元素。我们以前知道数组中的各个元素都是按顺序连续的存在内存中,因此,我们只要知道一个数组的首地址即第一个元素的地址,然后依次往下移动,就能找到该数组的所有元素。,北京邮电大学出版社,例,8.3,main(),int,a= 1,2,3,4,5,6;,int,x,y,*p;,p=,x=*(p+2);,y=*(p+5);,printf,(*p=%,d,x,=%,d,y,=%,dn,*,p,x,y,);,运行结果:,*,p=1 , x=3 ,y=6,程序中语句“,p=”,表示将数组,a,的首地址即,a0,的地址赋给指针变量,p,,即,p,就指向了该数组的首地址。,北京邮电大学出版社,在,C,语言中,获取数组的首地址有两种方法:,1,数组中第一个元素的地址,如:,&a0,。,2,数组名,数组名也代表数组的首地址。所以语句“,p=”,等价于“,p=a”,。,如例,8.3,对于指针变量,p,指向了数组的首地址,,p+1,就代表数组中元素,a1,的地址,,p+2,也代表元素,a2,的地址,依次类推,,,p+i,就代表,ai,的地址,同样,a+i,也代表,ai,的地址;因此对于数组的元素,ai,的值,同样可以用*,(,p+i,),或*(,a+i,)表示,这种访问数组元素的方法也称为指针法。如图,8.9,所示:,北京邮电大学出版社,对于数组元素的访问,下标法和指针法是等价的。设,a,是一个数组名,指针变量,p,指向了数组,a,的首地址,对于数组,a,元素的表示方法有,4,种:,1,下标法:,ai,或,pi,2,指针法:*,(,a+i,),或 *,(,p+i,),但是读者要注意,数组名和指针变量,p,本身并不完全等同;数组名代表一个地址常量,是数组的首地址,不能被用户改变它的值,不同于指针变量,指针变量的值是可以被改变的。因此语句:,p+,、,+p,、,p=p+1,都是正确的;而语句:,a+,、,+a,、,a=a+1,都是错误的。,例,8.4,输出数组,a,中的全部元素。,main(),int,a10,i;,for(i,=0;i10;i+),*(,a+i,)=i;,for(i,=0;i10;i+),printf(a%d,=%,dn,i,*(,a+i,);,北京邮电大学出版社,例,8.5,分析以下程序。,main(),int,a=1,2,3,4,5,*p;,p=a;,printf(%dn,*p);,printf(%dn,*(+p);,printf(%dn,*(p-);,p+=3;,printf(%dn%dn,*p,*(a+3);,运行结果:,1,2,2,4,4,北京邮电大学出版社,例,8.6,通过移动指针来访问数组中的所有元素。,main(),int,*p,i,a8;,p=a;,for(i,=0;i8;i+,p+),*p=i;,p=a;,for(i,=0;i8;i+,p+),printf(a%d,=%,dn,i,*p);,北京邮电大学出版社,8.3.2,通过指针访问二维数组,在,C,语言中,二维数组是按行优先的规律转换一维数组存放在内存中,因此,可以通过指针访问二维数组中的元素。若有:,int,a43 ,*p;,p=,则二维数组,a,的数据元素在内存中存储顺序及地址关系如图,8.10,所示:,北京邮电大学出版社,这里,,a,表示二维数组的首地址;,a0,表示,0,行的元素的起始地址,,a1,表示,1,行的元素的起始地址,,a2,表示,2,行的元素的起始地址,,a3,表示,3,行的元素的起始地址。因此,a,和,a0,是数组,a00,的地址,也是,0,行的地址。,a+1,和,a1,是数组元素,a10,的地址,也是,1,行的首地址。,由于,a,是二维数组,经过两次下标运算, ,之后才能访问到数组元素。所以根据,C,语言的地址计算方法,,a,要经过两次*操作才能访问到数组元素。这样就有,*,a,或,a0,就是数组元素,a00,的地址,*,a,就是元素,a00,,同样*,a0,也表示数组元素,a00,。,1,二维数组的指针,假设有如下数组定义语句:,int,array34;,(,1,)从二维数组角度看,数组名,array,代表数组的起始地址。,array+i,:行指针值,指向二维数组的第,i,行。,*,(,array+i,),:(列)指针值,指向第,i,行第,0,列(控制由行转为列,但仍为指针)。,*,(*(,array+i,),:数组元素,arrayi0,的值。,用,array,作指针访问数组元素,arrayij,的格式:,*,(*(,array+i,),j),北京邮电大学出版社,(,2,)从一维数组角度看,数组名,array,和第,1,维下标的每一个值,共同构成一组新的一维数组名,array0,、,array1,、,array2,,它们均由,4,个元素组成。,C,语言规定:数组名代表数组的起始地址,所以,arrayi,是第,i,行一维数组的地址,它指向该行的第,0,列元素,是一个以数组元素为单位进行控制的列指针:,arrayi+j,:(列)指针值,指向数组元素,arrayij,。,*,(,arrayi+j,),:数组元素,arrayij,的值。,如果有“,int,array34,*p=array0;”,,则,p+1,指向下一个元素,如图,8.12,所示。,北京邮电大学出版社,用,p,作指针访问数组元素,arrayij,的格式:,*,(p+(,*每行列数,+j),2,行指针变量(数组指针),指向由,n,个元素组成的一维数组的指针变量,(,1,)定义格式,数据类型 (*指针变量),n;,注意:“*指针变量”外的括号不能缺,否则成了指针数组,数组的每个元素都是一个指针变量。,(,2,)赋值,行指针变量 二维数组名 (或行指针变量),;,北京邮电大学出版社,例,8.7,使用行指针输出二维数组的任一元素。,main(),int,array34=1,2,3,4,5,6,7,8,9,10,11,12;,int,(*p)4, row,col,;,p=array;,printf(Input,row=);,scanf(%d,&row,);,printf(Input,col,=);,scanf(%d,&col,);,printf(array%1d%1d=%,dn,row,col,*(*(,p+row)+col,);,北京邮电大学出版社,例,8.8,使用列指针输出二维数组的任一元素。,main(),int,array34=1,2,3,4,5,6,7,8,9,10,11,12;,int,*p, row,col,; /*,定义一个,(,列,),指针变量,p*/,p=array0; /*,给,(,列,),指针变量,p,赋值*,/,printf(Input,row=);,scanf(%d,&row,);,printf(Input,col,=);,scanf(%d,&col,);,printf(array%1d%1d=%,dn,row,col,*(,p+(row,*4+col);,程序运行结果:,Input row=1,Input,col,=1,array11=6,北京邮电大学出版社,8.3.3,指针的基本运算,对于指针的运算有三种:指针与正整数的加减运算、两个指针的关系运算以及两个指针的减法运算。,指针与正整数的加减运算,当指针,p,指向数组中的元素时,,n,为一个正整数,则表达式:,p+n,表示:指针,p,所指向当前元素之后的第,n,个元素。而表达式,p-n,表示:指针,p,所指向当前元素之前的第,n,个元素。,最常见的指针加减运算为,p+,的含义是:指针加,1,,指向数组中的下一个元素;,p-,的含义是:指针减,1,,指向数组中的前一个元素。,由于指针,p,所指的具体对象不同,所以对指针与整数进行加减运算时,,C,语言会根据所指的不同对象计算出不同的放大因子,以保证正确操作实际的运算对象。对于字符型,放大因子为,1,;对于整型,放大因子为,2,;对于长整型,放大因子为,4,;对于双精度类型,放大因子为,8,。也就是说不同数据类型的放大因子等于该数据类型在内存所占的字节数。,北京邮电大学出版社,例,8.9,用指针进行字符串的复制,把字符串,str1,复制到字符串,str2,。,# include ,main(), char str180,str280,*p1,*p2;,printf(Enter,string 1:);,gets(str1);,p1=str1;,p2=str2;,while(*p2=*p1)!=0), p1+;,p2+;,printf(String,2:);,puts(str2);,北京邮电大学出版社,2,两个指针的关系运算,只有当两个指针指向同一个数组的元素时,才能进行关系运算。,当指针,p,和指针,q,指向同一数组时,则:,当,p,所指的元素在,q,所指的元素之前时,,pq;,当,p,和,q,指向同一元素时,,p=q,。,不允许两个指向不同数组的指针进行比较,因为这样的判断没有任何实际的意义。,北京邮电大学出版社,例,8.10,编写程序将一个字符串反序,# include,main(),char str50,*p,*,s,c,;,printf(Enter,string:);,gets(str,);,p=s=,str,;,while(*p),p+;,p-;,while(s,p),c=*s;,*s+=*p;,*p-=c;,puts(str,);,北京邮电大学出版社,两个指针的减法运算,两个指针变量之间的运算:只有指向同一数组的两个指针变量之间才能进行减法运算,否则运算毫无意义。,两指针变量相减:两指针变量相减所得之差是两个指针所指数组元素之间相差的元素个数。实际上是两个指针值,(,地址,),相减之差再除以该数组元素的长度,(,字节数,),。例如,pf1,和,pf2,是指向同一单精度型数组的两个指针变量,设,pf1,的值为,2010H,,,pf2,的值为,2000H,,而浮点数组每个元素占,4,个字节,所以,pf1-pf2,的结果为,(2000H-2010H)/4=4,,表示,pf1,和,pf2,之间相差,4,个元素。两个指针变量不能进行加法运算。例如,,pf1+pf2,是什么意思呢,?,毫无实际意义。,北京邮电大学出版社,例,8.11,用指针相减求字符串的长度,# include,main(),char str50,*p=,str,;,printf(Enter,string:);,gets(str,);,while(*p),p+;,printf(String,Length=%,dn,p-str,);,北京邮电大学出版社,8.4,指针与字符串,8.4.1,字符数组与字符指针,我们在前面详细讨论过字符数组与字符串,字符指针也可以指向一个字符串。可以用字符串常量对字符指针进行初始化。例如,有说明语句:,char *str1=”How are you!”;,此时字符指针指向的是一个字符串常量的首地址,即指向字符串的首地址。,这里要注意字符指针与字符数组的区别,例如,有说明语句:,char str2 =”How are you!”;,此时,,str2,是字符数组,它存放一个字符串。,字符指针,str1,与字符数组,str2,的区别是:,str1,是一个变量,可以改变,str1,的值,即,str1,可以指向不同内存单元,;str2,是一个数组名,数组名,str2,的值不能改变,也就是说,str2,的值也是一个内存单元的地址,但是地址不能被用户改变。,北京邮电大学出版社,例如:,char *,str,*,str1=”Hello!”;,char string100=”China”;,则下面语句是正确的:,str,+;,str,=”Computer”;,str,=str1;,strcpy(string,”ABCEFGH,”);,strcat(string,str,);,而下面语句是错误的:,string+; /*,不能对数组名进行,+,运算 *,/,string=”How do you do!”; /*,不能给数组名进行赋值操作 *,/,string=,str,; /*,不能给数组名进行赋值操作 *,/,北京邮电大学出版社,8.4.2,字符指针举例,在,C,语言中,如我们上节所讨论的,有两种方法访问一个字符串:,1,用字符数组存放一个字符串,然后输出该字符串。,例,8,12,写出下列程序的运行结果,main(),char string=”I love China!”;,printf(%sn,string,);,运行结果:,I love China!,说明:和前面介绍的数组属性一样,,string,是数组名,它代表字符数组的首地址。,2,用字符指针指向一个字符串。,可以不定义字符数组,而定义一个字符指针变量,用字符指针变量指向字符串中的字符。,北京邮电大学出版社,2,用字符指针指向一个字符串。,可以不定义字符数组,而定义一个字符指针变量,用字符指针变量指向字符串中的字符。,例,8.13,写出下列程序的运行结果,main(),char *string=”I love China!”;,printf(%sn,string,);,运行结果:,I love China!,例,8.14,在输入的字符串中查找有无,k,字符。,main(),char st20,*,ps,;,int,i;,printf(input,a string:n);,ps,=,st,;,scanf(%s,ps,);,for(i,=0;psi!=0;i+),if(psi,=k),printf(there,is a k in the stringn);,break;,if(psi,=0),printf(There,is no k in the stringn);,北京邮电大学出版社,例,8.15,将,s,所指字符串下标为偶数的字符删掉,,s,中剩余的字符形成的新串放在,t,所指的数组中。例如:当,s,所指字符串为,ABCDEFGHIJK,,在,t,中所指数组中的内容为:,BDGFHJ,#include ,#include ,void,fun(char,*,s,char,t),int,i,j,n,;,n=,strlen(s,);,for(i,=0,j=0;i,n;i,+),if(i%2!=0),tj,=,si;j,+;,tj,= 0;,main(),char s80,t80;,printf(nplease,enter string:);,scanf(%s,s,);,fun(s,t,);,printf(nthere,is :%,sn,t,);,北京邮电大学出版社,8.5,指针与函数,我们知道在函数之间可以传递一般变量的值,在函数之间同样可以传递地址(指针)。函数与指针之间有着密切的关系,它包含三种关系:指针作为函数的参数,函数的返回值为指针及指向函数的指针。,8.5.1,指针作函数的参数,变量的地址属性是变量的一个重要特性,知道了变量的地址就可以通过地址间接访问变量的数值,变量的地址在,C,语言中就是指针,通过地址间接访问变量的数值就是通过指针间接访问指针所指的内容。指针作函数的参数就是在函数间传递变量的地址。,在函数间传递变量地址时,函数间传递的不再是变量中的数据,而是变量的地址。此时,变量的地址在调用函数时作为实参,被调用函数使用指针变量作为形参接收传递的地址。这里实参的数据类型要与形参的指针所指的对象的数据类型一致。,北京邮电大学出版社,例,8,16,输入的两个整数按大小顺序输出。,swap(int,*p1,int *p2),int,temp;,temp=*p1;,*p1=*p2;,*p2=temp;,main(),int,a,b,;,int,*pointer_1,*pointer_2;,scanf(%d,%d,&a,&b,);,pointer_1=,if(a,b),swap(pointer_1,pointer_2);,printf(%d,%dn,a,b,);,运行结果:,5,7,7,5,北京邮电大学出版社,例,8.17,请注意,不能企图通过改变指针形参的值而使指针实参的值改变。,swap(int,*p1,int *p2),int,*p;,p=p1;,p1=p2;,p2=p;,main(),int,a,b,;,int,*pointer_1,*pointer_2;,scanf(%d,%d,&a,&b,);,pointer_1=,if(a,b),swap(pointer_1,pointer_2);,printf(%d,%dn,*pointer_1,*pointer_2);,运行结果:,5,9,5,9,北京邮电大学出版社,例,8.18,输入,a,、,b,、,c,三个整数,按大小顺序输出。,swap(int,*pt1,int *pt2),int,temp;,temp=*pt1;,*pt1=*pt2;,*pt2=temp;,exchange(int,*q1,int *q2,int *q3),if(*q1*q2)swap(q1,q2);,if(*q1*q3)swap(q1,q3);,if(*q2*q3)swap(q2,q3);,main(),int,a,b,c,*p1,*p2,*p3;,scanf(%d,%d,%d,&a,&b,&c,);,p1=,p2=,p3=,exchange(p1,p2,p3);,printf(%d,%d,%d,n,a,b,c,);,程序运行结果:,1,2,3,3,2,1,北京邮电大学出版社,8.5,指针与函数,8.5.2,数组名作函数的参数,数组名可以作函数的实参和形参。本质上也是地址传递。,例如:,main(),int,array10;,f(array,10);,f(int,arr,int,n);,北京邮电大学出版社,其中,array,为实参数组名,,arr,为形参数组名。在学习指针变量之后就更容易理解这个问题了。数组名就是数组的首地址,实参向形参传送数组名实际上就是传送数组的首地址,形参得到该地址后也指向同一数组。这就好象同一件物品有两个彼此不同的名称一样。如图,8.19,所示。,北京邮电大学出版社,同样,指针变量的值也是地址,数组名即为数组的首地址,当然也可作为函数的参数使用。,例,8,19,输入,10,个学生的成绩,求学生的平均成绩。,float,aver(float,*pa);,main(),float score10,av,*sp;,int,i;,sp=score;,printf(ninput,10 scores:n);,for(i,=0;i10;i+),scanf(%f,&scorei,);,av,=,aver(sp,);,printf(average,score is %5.2f,av);,float,aver(float,*pa),int,i;,float,av,s,=0;,for(i,=0;i10;i+) s=s+*pa+;,av,=s/10;,return,av,;,北京邮电大学出版社,例,8.20,利用函数从,10,个数中找出其中最大值和最小值。,本题要求不能改变数组元素的值,求出其中的最大值和最小值,而函数调用只能得到一个返回值,因此本题利用用全局变量在函数之间“传递”数据。程序如下:,int,max,min,; /*,全局变量*,/,void,max_min_value(int,array,int,n),int,*p,*,array_end,;,array_end,=,array+n,;,max=min=*array;,for(p,=array+1;pmax),max=*p;,else,if(*pmin),min=*p;,main(),int,i,number10;,printf(Enter,10 numbers:n);,for(i,=0;i10;i+),scanf(%d,&numberi,);,max_min_value(number,10);,printf(max,=%,d,min,=%,dn,max,min,);,程序运行结果:,Enter 10 integer numbers:,5 4 10 9 16 8 20 12 7 11,max=20,min=4,北京邮电大学出版社,例,8,21,将数组,a,中的,n,个整数按相反顺序存放。,求解此题的算法为:将,a0,与,an-1,对换,再,a1,与,an-2,对换,直到将,a(n-1/2),与,an-int(n-1)/2),对换。现用循环处理此问题,设两个“位置指示变量”,i,和,j,,,i,的初值为,0,(指向数组中开始的元素),,j,的初值为,n-1,(指向数组中最后的元素)。将,ai,与,aj,交换,然后使,i,的值加,1,(指向下一个元素),,j,的值减,1,(指向前一个元素),再将,ai,与,aj,交换,直到,i=(n-1)/2,为止。,北京邮电大学出版社,程序如下:,void,inv(int,x,int,n) /*,形参,x,是数组名*,/,int,temp,i,j,m,=(n-1)/2;,for(i,=0;i=,m;i,+),j=n-1-i;,temp=,xi,;,xi,=,xj,;,xj,=temp;,main(),int,i,a10=5,8,10,9,0,6,7,3,14,1;,printf(The,original array:n);,for(i,=0;i10;i+),printf(%d,ai,);,printf(n,);,inv(a,10);,printf(The,array has been inverted:n);,for(i,=0;i10;i+),printf(%d,ai,);,printf(n,);,程序运行结果:,The original array:,5,8,10,9,0,6,7,3,14,1,The array has been inverted:,1,14,3,7,6,0,9,10,8,5,北京邮电大学出版社,例,8,22,用实参为指针变量改写例题,8,21,。,void,inv(int,*,x,int,n),int,*,p,m,temp,*i,*j;,m=(n-1)/2;,i=x;,j=x+n-1;,p=,x+m,;,for(;i,=,p;i+,j,-),temp=*i;,*i=*j;,*j=temp;,main(),int,i,arr10=5,8,10,9,0,6,7,3,14,1,*p;,p=,arr,;,printf(The,original array:n);,for(i,=0;i10;i+,p+),printf(%d,*p);,printf(n,);,p=,arr,;,inv(p,10);,printf(The,array has been inverted:n);,for(p,=,arr;p,arr+10;p+),printf(%d,*p);,printf(n,);,注意:,main,函数中的指针变量,p,是有确定值的。即如果用指针变量作为实参,必须要使指针变量有确定值,指向一个已定义的数组。,北京邮电大学出版社,例,8.23,用选择法对,10,个整数排序。,main(),int,*p,i,a10=3,7,9,11,0,6,7,5,4,2;,printf(The,original array:n);,for(i,=0;i10;i+),printf(%d,ai,);,printf(n,);,p=a;,sort(p,10);,for(p,=,a,i,=0;i10;i+),printf(%d,*p);,p+;,printf(n,);,sort(int,x,int,n),int,i,j,k,t,;,for(i,=0;in-1;i+),k=i;,for(j,=i+1;j,xk,),k=j;,if(k,!=i),t=,xi;xi,=,xk;xk,=t;,程序运行结果:,The original array:,3,7,9,11,0,6,7,5,4,2,0 2 3 4 5 6 7 7 9 11,说明:函数,sort,用数组名作为形参,也可改为用指针变量,这时函数的首部可以改为:,sort(int,*,x,int,n),其他可一律不改。,北京邮电大学出版社,8.5.3,函数返回值是指针,函数的返回值可以是指针,返回指针的函数一般说明形式应该是:,数据类型 *函数名,(,参数列表,),“,数据类型”后面的*表示函数的返回值是一个指向该数据类型的指针。注意,此时说明的是函数,而不是指针变量。,例,8.24,使用函数求两个数的最大值。,#include ,int,*,max(int,*p1,int *p2),int,*p;,p=*p1*p2?p1:p2;,return (p);,北京邮电大学出版社,main(),int,a,b,*,pmax,;,printf(Enter,a b:);,scanf(%d%d,&a,&b,);,pmax,=,max(&a,&b,);,printf(max,=%,dn,*,pmax,);,程序运行结果:,Enter a b: 10 20 ,max=20,说明:函数,max,返回值的类型是整型指针,在函数,max,中使指针变量,p,指向大的数,8,,然后把,p,的值返回给函数,max,。在主函数中把函数,max,的值赋给,pmax,,最后输出,pmax,所指的值为,20,。,北京邮电大学出版社,8.5.4,指向函数的指针,在,C,语言中,指针的使用方法非常灵活,指向函数的指针就是一个在其它高级语言中非常罕见的功能。在定义一个函数后,编译系统就为每个函数确定了一个入口地址,当调用该函数的时候,系统就会从这个“入口地址”开始执行该函数。存放函数的入口地址的指针变量就是一个指向函数的指针。其定义方式为:,类型标识符(*指针变量)(),;,类型标识符为函数返回值的类型。特别值得注意的是,由于,C,语言中()的优先级比*高,因此,“*指针变量”外部必须用括号,否则指针变量首先与后面的()结合,就是前面介绍的“函数返回值是指针”。试比较下面两个说明语句:,int,(*pf)(); /*,定义一个指向函数的指针,该函数的返回值为整型数据*,/,int,*f(); /*,定义一个返回值为指针的函数,该指针指向一个整型数据*,/,和变量的指针一样,函数的指针也必须赋初值,才能指向具体的函数。由于函数名代表了该函数的入口地址,因此,一个简单的方法就是直接用函数名为函数指针赋值,即:,函数指针名,=,函数名,;,北京邮电大学出版社,例如:,double fun(); /*,函数原型声明*,/,double (*f)(); /*,函数指针说明*,/,f=fun; /*f,指向,fun,函数*,/,函数的指针经定义和初始化之后,在程序中就可以引用该指针,目的是调用被指针所指的函数,由此可见,使用函数的指针增加了函数的调用方式。,例,8.25,用指针调用函数,实现输出两个数中的较大数,#include,main(),int,max(int,int,);,int,(*pf)();,int,a,b,c,;,pf=max;,scanf(%d%d,&a,&b,);,c=(*,pf)(a,b,);,printf(a,=%,d,b,=%,d,max,=%,dn,a,b,c,);,北京邮电大学出版社,max(int,a,int,b),return (a,b?a:b,);,程序运行结果:,8 10,a=8,b=10,max=10,在该例中,语句,c=(*,pf)(a,b,),等价于,c=,max(a,b,),,因此当一个指针指向一个函数时,通过访问该指针,就可以访问它所指向的函数。,需要注意的是:一个函数指针可以先后指向不同的函数,将哪个函数的地址赋给它,它就指向哪个函数,使用该指针,就可以调用哪个函数,但是,必须用函数的地址为函数指针赋值。另外,如果有函数指针,(*pf)( ),,则,pf+,pf+n,pf,等运算是无意义的。,引用函数指针,除了增加函数的调用方式之外,还可以将其作为函数的参数,在函数中传递地址数据,这是,C,语言中一个比较深入的问题,可以参考其它的书籍。,北京邮电大学出版社,8.6,指针数组,8.6.1,指针数组,一个数组的元素都是指针则称为指针数组。指针数组是一组有序的指针的集合。指针数组的所有元素都必须是具有相同存储类型和指向相同数据类型的指针变量。,指针数组说明的一般形式为:,类型说明符 *数组名,数组长度,;,其中类型说明符为指针值所指向的变量的类型。,例如:,int,*pa3;,表示,pa,是一个指针数组,它有三个数组元素,每个元素值都是一个指针,指向整型变量。,注意:不要写成,int,(*pa)3;,这是一个指向一维数组的指针变量(该一维数组包括三个元素),在前面章节中已学过。,为什么要用指针数组呢?它比较适合于用来指向若干个字符串,使字符串处理更加方便灵活。这时指针数组的每个元素被赋予一个字符串的首地址。指向字符串的指针数组的初始化更为简单。,北京邮电大学出版社,例如:,char *name=Sunday,Monday,Tuesday,Wednesday,Thursday, Friday,Saturday;,完成这个初始化赋值之后,,name0,即指向字符串,Sunday,,,name1,指向,Monday,,,例,8.26,输入数字,0-6,,输出对应的星期几的英文名称。,# include ,char *week_day7=Sunday,Monday,Tuesday,Wednesday, Thursday,Friday,Saturday;,main(),int,day;,char *p,*,lookstr,();,printf(Enter,Day:);,scanf(%d,&day,);,p=,lookstr(week_day,day,);,printf(%sn,p,);,char *,lookstr(table,day),char *table;,int,day;,int,i;,for(i,=0;i!=,day&i,7;i+);,if (i=6),return(tableday,);,else,return(NULL,);,北京邮电大学出版社,8.6.2 main,函数的参数,指针数组的一个重要应用是作为,main,函数的形参。在我们以前的学习过程中,,main,函数的第一行全部写成了以下的形式:,main(),括号中为空,表示没有参数,实际上,main,函数是可以带参数的,其一般形式为:,main(int,argc,char,*,argv, ),其中形参,argc,表示命令行参数的个数,形参,argv,是指向命令行参数的指针数组。,北京邮电大学出版社,在操作系统下运行,C,程序时,可以以命令行参数形式向,main,函数传递参数。命令行参数的一般形式是:,运行文件名 参数,1,参数,2 ,参数,n,运行文件名和参数之间、各个参数之间要用一个空格分隔。,argc,表示命令行参数的个数(包括运行文件名),,argv,是指向命令行参数的指针数组,指针数组元素,argv0,指向的字符串是运行文件名,,argv1,指向的字符串是命令行中的参数,1,,,argv2,指向的字符串是命令行中的参数,2,,,等等。,例,8.27,下列文件的运行文件名为,TEST1,,使用命令行参数的运行情况。,#include ,main(int,argc,char,*,argv, ),int,k;,printf(argc,=%,dn,argc,);,for (k=0;k,argc;k,+),printf(%sn,*,argv,+);,运行该程序,设在操作系统提示符下输入的命令行参数为:,TEST1 IBM-PC COMPUTER,则执行该程序后,输出结果为:,argc,=3,TEST1,IBM-PC,COMPUTER,这样利用指针数组作为主函数,main,的形式参数,可以很方便地实现,main,函数与操作系统的通信。,北京邮电大学出版社,8.7,多级指针,一个指针可以指向任何一种数据类型,包括指向一个指针。当指针变量,p,中存放另一个指针,q,的地址时,则,p,称为指针型指针,也称为二级指针。定义形式 :,类型标识符 * * 指针变量名,;,由于指针变量的类型是被指针所指的变量的类型,因此上述定义中的类型标识符应为:该指针所指的指针变量所指的那个变量的类型。,为二级指针初始化的方式是用指针的地址为其赋值,例如:,int,x;,int,*p;,int,*q;,p= /*,指针变量,p,指向整型变量,x,。*,/,q=&p /*,二级指针,q,指向指针变量,p*/,此时就可以通过二级指针,q,来访问变量,x,,如要使变量,x,的值为,10,,可以使用如下几种方式:,x=10,*p=10,*q=10,以上三种方式都是等价的。我们可以从图,8.22,看出变量,x,、指针变量,p,、二级指针变量,q,的关系。,北京邮电大学出版社,例如,8.28,使用二级指针访问字符串,main(),char *,str,=,Beijing,shanghai,Guangzhou,Shenzhen,Wuhan,;,char *p;,int,i;,for(i,=0;i5;i+),p=,str+i,;,printf(%sn,*p);,程序运行结果为:,Beijing,shanghai,Guangzhou,Shenzhen,Wuhan,北京邮电大学出版社,例,8.29,int,a33=1,2,3,4,5,6,7,8,9;,int,*b=a0,a1,a2;,int,*p=b;,main(),int,i,j,;,for(i,=0;i3;i+),for(j,=0;j3;j+),printf(%d,%d,%dn,*(,bi+j,),*(*(,p+i)+j,),*(*(,a+i)+j,);,运行结果:,1,,,1,,,1,2,,,2,,,2,3,,,3,,,3,4,,,4,,,4,5,,,5,,,5,6,,,6,,,6,7,,,7,,,7,8,,,8,,,8,9,,,9,,,9,北京邮电大学出版社,本章小结,本章所涉及的指针是,C,语言中最重要的内容之一,也是学习,C,语言的重点和难点。在,C,语言中使用指针进行数据处理十分方便灵活和高效,而且在实际的编程过程中也大量使用指针。指针与变量、函数、数组、结构、文件等都有着密切的联系,因此,要学好指针必须从基本概念入手。,本章涉及的主要内容有:,1,指针的基本概念。包括:变量的地址和变量的值、指针变量的定义、指针变量的初始化、指针的赋值、指针的基本运算(取变量的地址,取指针指向的内容)、变量与指针的关系等。,2,指针与数组之间的关系。包括:数组名与地址的关系、使用指针操作数组元素、对于二维数组下标与指针之间的关系、行指针(数组指针)的概念和使用、指针的运算(指针加减一个整数,两个指针相减,指针的比较等)、使用指针操作字符串、动态数组。,北京邮电大学出版社,3,指针与函数之间的关系。包括:指针作为参数在函数之间传递、数组名作为函数的参数、函数的返回值是指针类型、指向函数的指针、指针数组与,main,函数的参数。,请读者注意分析有关指针的定义形式:,int,*p;,变量的指针,int,(*p),长度,;,行指针
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 管理文书 > 施工组织


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!