配色: 字号:
C程序课件第10章指针二
2012-04-24 | 阅:  转:  |  分享 
  
第十章指针10.1地址和指针的概念10.2变量的指针和指向变量的指针变量10.3数组的指针和指向数组的指针变量10
.4字符串的指针和指向字符串的指针变量四、字符串的指针和指向字符串的指针变量五、函数的指针和指向函数的指针变量六、
返回指针值的函数七、指针数组和指向指针的指针八、有关指针的数据类型和指针运算的小结#include
voidmain(){ intmax(int,int); intmin(int,int); intadd(int
,int); inta,b; printf(“Enteraandb:\n”); scanf(“%d,%d”,&a
,&b); printf(“Max=”); process(a,b,max); printf(“Min=”); pro
cess(a,b,min); printf(“Add=”); process(a,b,add);}max(intx,
inty){ if(x>y)returnx; elsereturny;}min(intx,inty)
{ if(xrn(x+y); }process(intx,inty,int(fun)()){ intresult; r
esult=(fun)(x,y); printf(“%d\n”,result);}一个函数可以带回一个整型值、字
符值、实型值,也可以带回指针型的数据,即地址。在C语言中允许一个函数的返回值是一个指针(即地址),这种返回指针值的函数称为指针型函
数。其概念与以前类似,只是带回的值的类型是指针而已。定义指针型函数的一般形式为:类型说明符函数名(参数表
)其中函数名之前加了“”号表明这是一个指针型函数,即返回值是一个指针。类型说明符表示了返回的指针值所指向的数据类型。如:
inta(intx,inty) { ...... /函数体/ }a是函数名,调用它以后能得到一
个指向整型数据的指针(地址)。x、y是函数a的形参,为整型。应该特别注意的是函数指针变量和指针型函数这两者在写法和意义
上的区别。如int(p)()和intp()是两个完全不同的量。int(p)()是一个变量说明,说明p是一个指向函数入口的
指针变量,该函数的返回值是整型量,(p)的两边的括号不能少。intp()则不是变量说明而是函数说明,说明p是一个指针型函数
,其返回值是一个指向整型量的指针,p两边没有括号。作为函数说明,在括号内最好写入形式参数,这样便于与变量说明区别。对于指针型函数
定义,intp()只是函数头部分,一般还应该有函数体部分。#includemain(){ inti
; charday_name(intn); printf("InputDayNo:\n"); scanf("%d
",&i); printf("DayNo:%2d-->%s\n",i,day_name(i));}charday_na
me(intn){ staticcharname[]={"Illegalday","Monday", "Tue
sday","Wednesday","Thursday", "Friday","Saturday","Sunday"}; r
eturn((n<1||n>7)?name[0]:name[n]);}本程序是通过指针函数,输入一个1-7之
间的整数,输出对应的星期名。程序中定义了一个指针型函数day_name,它的返回值指向一个字符串。该函数中定义了一个静
态指针数组name。name数组初始化赋值为八个字符串,分别表示各个星期名及出错提示。形参n表示与星期名所对应的整数。在主函数中
,把输入的整数i作为实参,在printf语句中调用day_name函数并把i值传送给形参n。day_name函数中的return
语句包含一个条件表达式,n值若大于7或小于1则把name[0]指针返回主函数输出出错提示字符串“Illegalday”。否则
返回主函数输出对应的星期名。例EX10_25有若干个学生的成绩(每个学生有4门课程),要求在用户输入学生序号后,能
输出该学生的全部成绩。(用指针函数来实现)#includefloatsearch(float(poin
ter)[4],intn){ floatpt; pt=(pointer+n); return(pt);}void
main(){ score[][4]={{60,70,80,90},{56,89,67,88}, {34,78,90,6
6}}; floatsearch(float(pointer)[4],intn); floatp; int
i,m; printf(“Enterthenumberofstudent:”); scanf(“%d”,&m);
printf(“\nThescoresofNo.%dare:\n”,m); p=search(score,m);
for(i=0;i<4;i++) printf(“%5.2f\t”,(p+i)); printf(“\n”);}例E
X10_26对上例中的学生,找出其中有不及格课程的学生及其学生号。#includefloatsea
rch(float(pointer)[4]){ floatpt; inti; pt=(pointer+1);
for(i=0;i<4;i++) if((pointer+i)<60)pt=pointer; return(pt)
;}voidmain(){ floatscore[][4]={{60,70,80,90},{56,89,67,88},
{34,78,90,66}}; floatp; inti,j; for(i=0;i<3;i++
) { p=search(score+i); if(p==(score+i)) { printf(“No.%dsc
ore:”,i); for(j=0;j<4;j++) printf(“%5.2f\t”,(p+j)); p
rintf(“\n”); } }}1、指针数组的概念指针数组的说明与使用一个数组的元素值为指针则是指
针数组。指针数组是一组有序的指针的集合。指针数组的所有元素都必须是具有相同存储类型和指向相同数据类型的指针变量。一维指针数组的定
义形式为:类型说明符数组名[数组长度]其中类型说明符为指针值所指向的变量的类型。例如:intp[3]
表示p是一个指针数组,它有三个数组元素,每个元素值都是一个指针,指向整型变量。由于[]比优先级高,因此p先与[3]结合,形成
p[3]形式,这显然是数组形式,然后再与结合,表示为指针类型,因此形成指针数组的形式。注意:不要写成int(p)[
3]的形式,它是指向一维数组的指针变量(P229最后一段说明)。通常可用一个指针数组来指向一个二维数组。指针数组中的每
个元素被赋予二维数组每一行的首地址,因此也可理解为指向一个一维数组。它比较适合于用来指向若干个字符串,使字符串处理更加方便灵活。
每个字符串都是存放在一个一维字符数组中的,如下所示:\0ngisedretupmoCCo
mputerdesign\0NARTROFFORTRAN\0llaWtaerGGreat
Wall\0CISABBASIC\0emwolloFFollowme字符串字符串的存储形
式Computerdesignname[4]FORTRANname[3]GreatWallname[2]BASI
Cname[1]Followmename[0]name指针数组字符串可以分别定义一些字符串,然后用指针数组中
的元素分别指向各字符串(上图),由此可以方便地对各字符串进行处理。如对字符串排序,不必改动字符串的位置,只需改动指针数组中各元素的
指向(即改变各元素的值,即各字符串的首地址)。这样,各字符串的长度可以不同,而且移动指针变量的值(地址)要比移动字符串所花时间少得
多。例10_27将若干字符串按字母顺序(由小到大)输出。#include#includeg.h>voidsort(charname[],intn){ chartemp; inti,j,k; f
or(i=0;ik],name[j])>0)k=j; if(k!=i) { temp=name[i];name[i]=name[k
]; name[k]=temp; } }}voidprint(charname[],intn){ i
nti; for(i=0;i{ voidsort(charname[],intn); voidprint(charname[],int
n); charname[]={“Followme”,“BASIC”, “GreatWall”,“FORTRA
N”, “Computerdesign”}; intn=5; printf(“Thestringsbefore
sort:\n”); print(name,n); sort(name,n); printf(“\nThestring
saftersorted:\n”); print(name,n);}排序操作的执行过程是移动了指向原字符串(数
组)的指针,而没有改变字符串的存储单元,简化了操作过程。Computerdesignname[4]FORTRANnam
e[3]GreatWallname[2]BASICname[1]Followmename[0]name指针数组
字符串Print函数也可以改写为以下形式:voidprint(charname[],intn){ inti=0;
charp; p=name[0]; while(i\n”,p); }}例EX10_27_2输出数组中各元素的值。#includeinta[3]
[3]={1,2,3,4,5,6,7,8,9};intpa[3]={a[0],a[1],a[2]};intp=a[0]
;main(){ inti; for(i=0;i<3;i++) printf("%d,%d,%d\n",a[i][2-i
],a[i], ((a+i)+i)); for(i=0;i<3;i++) printf("%d,%d,%d\n",
pa[i],p[i],(p+i));}本例程序中,pa是一个指针数组,三个元素分别指向二维数组a的各行。然后用循环语
句输出指定的数组元素。其中a[i]表示i行0列元素值;((a+i)+i)表示i行i列的元素值;pa[i]表示i行0列元素值
;由于p与a[0]相同,故p[i]表示0行i列的值;(p+i)表示0行i列的值。读者可仔细领会元素值的各种不同的表示方法。应该
注意指针数组和二维数组指针变量的区别。这两者虽然都可用来表示二维数组,但是其表示方法和意义是不同的。例EX10_27_3将
若干个国家按字母排序。#include#includevoidsort(char
name[],intn){ charp; inti,j,k; for(i=0;i for(j=i+1;j0)k=j; if(k
!=i) { p=name[i];name[i]=name[k]; name[k]=p; } }}void
print(charname[],intn){ inti; for(i=0;in",name[i]);}main(){ voidsort(charname[],intn); voidprin
t(charname[],intn); charname[]={"CHINA","AMERICA", "AUST
RALIA","FRANCE", "GERMAN"}; intn=5; sort(name,n); print(nam
e,n);}例EX10_27_4指针数组作指针型函数的参数#includecharday_n
ame(charname[],intn){ charpp1,pp2; pp1=name; pp2=(name
+n); return((n<1||n>7)?pp1:pp2);}main(){ staticcharname[]
={"Illegalday", "Monday","Tuesday", "Wednesday","Thursday",
"Friday","Saturday","Sunday"}; charps; inti; printf("inp
utDayNo:\n"); scanf("%d",&i); ps=day_name(name,i); printf("D
ayNo:%2d-->%s\n",i,ps);}Computerdesignname[4]FORTRANname[
3]GreatWallname[2]BASICname[1]Followmename[0]指针数组字符串
2、指向指针的指针在掌握了指针数组的概念的基础上,下面介绍指向指针数据的指针变量,简称为指向指针的指针。如下图所示,
p为指向指针的指针。namep定义一个指向指针数据的指针变量的一般形式为: 类型说明符指针变
量名如:charp;其中p为指向指针的指针变量。P的前面有两个号,运算符的结合性是从右到左,因此p相当于
(p),显然p是指针变量的定义形式。如果没有最前面的,那么是定义了一个指向字符数据的指针变量。现在它的前面又有一个号,表
示指针变量p是指向一个字符指针的变量(即指向字符型数据的指针变量)的。p就是p所指向的另一个指针变量,如果有: p
=name+3;printf(“%d\n”,p); printf(“%s\n”,p);则第一个printf函
数输出name[3]的值(它是一个地址),第二个printf函数则输出字符串“FORTRAN”。例EX10_28指向指针的
指针变量的简单应用。#includevoidmain(){ charname[]={“Follow
me”,“BASIC”, “GreatWall”,“FORTRAN”, “Computerdesign”}
; charp;inti=0; for(i=0;i<5;i++) { p=name+i; printf(“%
d\t\t”,p); printf(“%s\n”,p); }}本章要点10.5函数的指针和指向函数的
指针变量10.6返回指针值的函数10.7指针数组和指向指针的指针10.8有关指针的数据类型和指针运算的小结
1、字符串的表示形式在C程序中,可以用两种方法访问一个字符串。(1)用字符数组存放一个字符串,然后输出该字符串。例EX1
0_16字符数组的应用#includevoidmain(){ charstring[]=“Ilo
veChina!”; printf(“%s\n”,string);}(2)用字符指针指向一个字符串和数组的
属性一样,string也是数组名,它代表字符数组的首地址(P251图10.31)。string[4]代表数组中序号为4的元素(v)
,实际上string[4]就是(string+4),string+4是一个地址,它指向字符“v”。可以不定义字符数组,而定义一
个字符指针。用字符指针指向字符串中的字符。例EX10_16_2字符指针的应用#includevoid
main(){ charstring=“IloveChina!”; printf(“%s\n”,string);}
C语言对字符串常量是按字符数组处理的,在内存开辟了一个字符数组用来存放字符串常量。程序在定义字符指针变量string
时把字符串首地址(即存放字符串的字符数组的首地址)赋给string(P252图10.32)。注意string是一个指针,而不是字符
变量。语句: charstring=“IloveChina!”;等价于下面两行: charstring;
string=“IloveChina!”;对字符串中字符的存取,可以用下标法,也可以用指针法。(3)字符指针
变量的应用例EX10_17输出字符串中第n个字符后的所有字符。#includemain(){
charps="thisisabook"; intn=10; ps=ps+n; printf("%s\n",p
s);}例EX10_17_2在输入的字符串中查找有无‘k’字符。#includemain(){
charst[20],ps; inti; printf("inputastring:\n"); ps=st; s
canf("%s",ps); for(i=0;ps[i]!=''\0'';i++) if(ps[i]==''k'') { prin
tf("thereisa''k''inthestring\n"); printf(“The‘k’inthest
ringof%d character\n”,i+1); break; } if(ps[i]==''\0'')
printf("Thereisno''k''inthestring\n");}例EX10_18将字符串a复制为
字符串b。要求把一个字符串的内容复制到另一个字符串中,并且不能使用strcpy函数。#includevoid
main(){ chara[]=“Iamaboy.”,b[20]; inti; for(i=0;(a+i)!=
‘\0’;i++) (b+i)=(a+i); (b+i)=‘\0’; printf(“Stringais:%
s\n”,a); printf(“Stringbis:”); for(i=0;b[i]!=‘\0’;i++) pr
intf(“%c”,b[i]); printf(“\n”);}例EX10_19用指针变量来处理例EX10_18问题。
#includevoidmain(){ chara[]=“Iamaboy.”,b[20],p1,
p2; inti; p1=a;p2=b; for(;p1!=‘\0’;p1++,p2++) p2=p1;
p2=‘\0’; printf(“Stringais:%s\n”,a); printf(“Stringbis
:%s\n”,b);}也可以把第6—8行简化为以下形式: {while((p2++=p1++)!=`\0'');}
即把指针的移动和赋值合并在一个语句中。进一步分析还可发现`\0''的ASCⅡ码为0,对于while语句只看表达式的值为非0就循环,为
0则结束循环,因此也可省去“!=`\0''”这一判断部分,而写为以下形式: {while(p2++=p1++);}表达式
的意义可解释为,源字符向目标字符赋值,移动指针,若所赋值为非0则循环,否则结束循环。这样使程序更加简洁。在下面的程序中将会应用这一
点。2、字符串指针作为函数参数将一个字符串从一个函数传递到另一个函数,可以用地址传递的办法,即用字符数组名作
参数或用指向字符串的指针变量作参数。在被调用的函数中可以改变字符串的内容,在主调函数中可以得到改变了的字符串。例EX10_20
用函数调用实现字符串的复制,方法一,用字符数组作参数。#includevoidcopy_string(
charfrom[],charto[]){ inti=0; while(from[i]!=‘\0’) { to[i]
=from[i];i++; } to[i]=‘\0’;}voidmain(){ chara[]=“Iamate
acher.”; charb[]=“youareastudent.”; printf(“Stringais:%
s\nStringbis:%s\n”,a,b); copy_string(a,b); printf(“Stringa
is:%s\nStringbis:%s\n”,a,b);}例EX10_20_2用函数调用实现字符串的复制,
方法二,形参用字符指针变量。#includevoidcopy_string(charfrom,cha
rto){ for(;from!=‘\0’;from++,to++) to=from; to=‘\0’;}
voidmain(){ chara=“Iamateacher.”; charb=“youareastud
ent.”; printf(“Stringais:%s\nStringbis:%s\n”,a,b); copy
_string(a,b); printf(“Stringais:%s\nStringbis:%s\n”,a,b)
;}归纳起来,作为函数的参数,有以下几种情况:数组名字符指针变量字符指针变量数组名数组名数组名字符指
针变量字符指针变量形参实参3、对使用字符串指针变量与字符数组的讨论用字符数组和字符指针变量都可实现字符串
的存储和运算。但是两者是有区别的。在使用时应注意以下几个问题:(1)字符数组由若干个元素组成,每个元素中放一个字符,并以‘\
0’作为串的结束。而字符指针变量中存放的是地址(字符串的首地址),决不是将字符串放到字符指针变量中。(2)对字符数组作初始
化赋值,必须采用外部类型或静态类型,如: staticcharst[]={“CLanguage”};而对字符串指针变量则
无此限制,如: charps="CLanguage";(3)对字符串指针方式 charps="CLang
uage";可以写为: charps;ps="CLanguage";而对数组方式: staticcharst[
]={"CLanguage"};不能写为: charst[20];st={"CLanguage"};而只能对字符数组的
各元素逐个赋值。(4)如果定义了一个字符数组,在编译时为它分配内存单元,它有确定的地址。而定义一个字符指针变量时,给指针变
量分配内存单元,在其中可以放一个地址值,也就是说,该指针变量可以指向一个字符数组,但如果未对它赋予一个地址值,则它并未具体指向一个
确定的字符数组。对数组方式: charstr[10]; scanf(“%s”,str);是成立的,而对
指针方式: charp;scanf(“%s”,p);是不成立的,因为p并未指向一个具体的字符数组。必须写成以下的形式:
charp,str[10];p=str; scanf(“%s”,p);(5)指针变量的值是可以改变的(例E
X10_17)。需要说明,若定义了一个指针变量,并使它指向一个字符串,就可以用下标形式引用指针变量所指的字符串中的字符(例EX10
_17_2)。(6)用指针变量指向一个格式字符串,可以用它代替printf函数中的格式字符串。如: charforma
t;format=“a=%d,b=%d\n”; printf(format,a,b);相当于: printf(“a=%d
,b=%d\n”,a,b);从以上几点可以看出字符串指针变量与字符数组在使用时的区别,同时也可看出使用指针变量更加方便。
在C语言中规定,一个函数总是占用一段连续的内存区,而函数名就是该函数所占内存区的首地址。我们可以把函数的这个首地址(或称
入口地址)赋予一个指针变量,使该指针变量指向该函数。然后通过指针变量就可以找到并调用这个函数。我们把这种指向函数的指针变量称为“
函数指针变量”。1、用函数指针调用函数可以用指针变量指向整型变量、字符串、数组,当然也可以指向一个函数。一个
函数在编译时被分配给一个入口地址。这个入口地址就称为函数的指针。可以用一个指针变量指向函数,然后通过该指针变量调用此函数。
函数指针变量定义的一般形式为:类型说明符(指针变量名)();其中“类型说明符”表示被指函数的返回值的
类型。“(指针变量名)”表示“”后面的变量是定义的指针变量。最后的空括号表示指针变量所指的是一个函数。例如:int
(pf)();表示pf是一个指向函数入口的指针变量,该函数的返回值(函数值)是整型。下面通过例子来说明用指针形
式实现对函数调用的方法。例EX10_23求a和b中的大者。先写出用一般方法的程序。#include>intmax(intx,inty){ if(x>y)returnx; elsereturny;}v
oidmain(){ intmax(intx,inty); inta,b,c; printf("inputtw
onumbers:\n"); scanf("%d,%d",&a,&b); c=max(a,b); printf("a=%d
,b=%d,max=%d\n",a,b,c);}主函数中“c=max(a,b);”包括了一次函数调用(调用max函数
)。每一个函数都占用一段内存单元,它们有一个起始地址。因此,可以用一个指针变量指向一个函数,通过指针变量来访问它指向的函数。改写m
ain函数如下:voidmain(){ intmax(intx,inty); int(p)(); /定义一个指向函数的指针变量p/ inta,b,c; p=max; /将函数max的首地址赋予指针变量p/ printf("inputtwonumbers:\n"); scanf("%d,%d",&a,&b); c=(p)(a,b); /通过指针变量调用该指针指向的函数/ printf("a=%d,b=%d,max=%d\n",a,b,c);}说明:(1)指向函数的指针变量的一般定义形式为:数据类型(指针变量名)()这里的“数据类型”是指函数返回值的类型。(2)函数的调用可以通过函数名调用,也可以通过函数指针调用(即用指向函数的指针变量调用)。(3)(p)()表示定义一个指向函数的指针变量,它不是固定指向哪一个函数的,而只是表示定义了这样一个类型的变量,它是专门用来存放函数的入口地址的。在程序中把哪一个函数的地址赋给它,它就指向哪一个函数。在一个程序中,一个指针变量可以先后指向不同的函数。(4)在给函数指针变量赋值时,只需给出函数名而不必给出参数,如:p=max;因为将函数入口地址赋给p,而不牵涉到实参与形参的结合问题。(5)用函数指针变量调用函数时,只需将(p)代替函数名即可(p为指针变量名),在(p)之后的括弧中根据需要写上实参。如:c=(p)(a,b);(6)对指向函数的指针变量,指针运算是无效的。2、用指向函数的指针作函数参数函数指针变量常用的用途之一是把指针作为参数传递到其他函数。这个问题是C语言应用的一个比较深入的部分,这里只作简单介绍,以便今后进一步理解和掌握打下一点基础。例EX10_24设一个函数process,在调用它的时候,每次实现不同的功能。输入a和b两个数,第一次调用它时找出两个数中的大者,第二次调用时找出两个数中的小者,第三次求这两个数的和。
献花(0)
+1
(本文系紫霄书屋首藏)