




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第8章指针地址和指针的概念
指向变量的指针变量
指针与数组字符串的指针和指向字符串的指针变量指针数组指向指针的指针函数指针返回指针的函数main()函数的返回指和参数8.1.地址和指针的概念内存单元的编号也叫做内存地址,通常把这个地址称为指针。即变量的指针就是变量的地址。对于一个内存单元来说,单元的地址即为指针,其中存放的数据是该内存单元的内容。内存单元的地址和内存单元的内容是两个不同的概念。指针变量是一个地址变量,当一个指针变量中存放了一个地址时,该指针变量就指向该地址的存储空间。(a)变量的地址装入指针变量中
(b)指针变量指向变量有了指针变量以后,对一般变量的访问既可以通过变量名进行,也可以通过指针变量进行。通过变量名或其地址(如a或&a)访问变量的方式叫直接访问方式;通过指针变量(如p)访问它指向的变量(如a)的方式叫间接访问方式。8.2.1指向变量的指针变量的定义指针变量也是一个变量,所以和其他变量一样必须先定义后使用。定义指向变量的指针变量的一般格式如下:类型标识符*变量名;例如:int*p1,*p2;float*q;在指针变量定义中,指针变量名前的“*”号仅是一个符号,并不是指针运算符,表示定义的是指针变量;类型标识符表示该指针变量所指向的变量的数据类型,并不是指针变量自身的数据类型,所有指针变量都是存放变量地址的。8.2指向变量的指针变量8.2.2指针运算符2.取内容运算符“*”取内容运算符“*”是单目运算符,其结合性为从右到左,功能是取指针变量所指向的存储区域内存放的值。取内容运算符“*”是优先级最高的运算符之一。1.取地址运算符“&”取地址运算符“&”是单目运算符,其结合性为从右到左,功能是取变量的地址。取地址运算符“&”是优先级最高的运算符之一。【例8.1】指针变量的应用。#include<stdio.h>voidmain(){inta=3,*p;intb=5,*q=&b;intc;printf("a=%d,b=%d\n",a,b);p=&a;*q=9;printf("a=%d,b=%d\n",a,b);printf("*p=%d,*&a=%d\n",*p,*&a);(*p)++;printf("(*p)++=%d\n",a);}程序运行结果:a=3,b=5a=3,b=9*p=3,*&a=3(*p)++=4使用指针运算符时应注意以下几点:⑴指针“*”运算符和指针定义中的指针标识符“*”不是一回事。在指针变量定义中,“*”是类型标识符,表示定义的变量是指针类型的变量。而表达式中出现的“*”则是一个指针运算符,表示取指针变量所指向变量的值。⑵对于语句“*p=&a,(*p)++;”表示使指针变量p所指向的存储单元的值自增,相当于a++。*p两边的括号是必须的,如果没有括号,成为*p++,而"++"和"*"是优先级相同的运算符,按从右到左的结合方向结合等价于*(p++)。p=&x;x=*p;p=&*p;x=*&x;
/*表示取整型变量x的内存地址,并赋值给指针变量p*//*表示取指针变量p所指向的变量的值,并赋值给整型变量x*//*按优先级&*p等价&(*p),*p就是变量x,再执行&x,即取变量x的地址,并将变量x的地址赋值给指针变量p。因此,&*p等价于&x*//*按优先级*&x等价于*(&x),&x就是取变量x的地址,再执行*运算相当于取变量x的值,并赋值给整型变量x。因此*&x等价于x*/【例8.2】按从大到小的顺序输出两个整型变量的值。#include<stdio.h>voidmain(){inta=5,b=9;intp,*pa,*pb;printf("%d,%d\n",a,b);pa=&a;pb=&b;if(*pa<*pb){p=*pa;*pa=*pb;*pb=p;}printf("%d,%d\n",*pa,*pb);getch();}程序运行结果:5,99,58.2.3指针变量的初始化指针变量初始化的一般格式如下:类型说明符*指针变量名=初始地址例如:intk,*p=&k;floatx,*s=&x;对于外部或静态指针变量在声明中若不带初始化项,指针变量被初始化为NULL,它的值为整数0。NULL由stdio.h定义为0,它也等同于‘\0’,意为空指针(定义一个指针变量后,没有使其指向一个确定的地址,这个变量称为空指针)。例如:#defineNULL0int*p=NULL;8.2.4指针变量的运算指针变量的运算是指指针变量所持有的地址为运算对象进行的运算,所以指针变量的运算实际上就是地址的运算。1.单个指针变量的算术运算单个指针变量的算术运算,包括+、一、++、--运算符。C语言的地址运算规则规定:一个地址加上或减去一个整数n,其运算结果仍然是一个地址,它是以运算对象的地址为基点向后或向前偏移n*基类型数据所占字节数的大小地址。即其运算结果应该是该指针变量当前指向位置的后方或前方第n*基类型数据所占字节数的大小地址。例如:inta,b,c,d,&p;p=&b;p++;
/*定义了4个整型变量,一个指针变量*//*指针变量p指向b*//*或p=p+1,通过++运算,指针变量向后偏移一个整型变量所占的字节数,假定本例中开辟的空间是连续的,则指向了下一个变量c*/2.两个指针变量之间的算数运算两个指针变量之间的运算只能在同一种指针类型中进行,主要包括+、-运算符。“-”运算所得的差是两个指针变量之间相差的元素个数。正数表示被减数指针变量指在减数指针变量的后面,负数表示被减数指针变量指在减数指针变量的前面。对于两个指针变量之间的"+"运算,是毫无意义的。floata,b,*p1,*p2,*p3;intn,c[10],*q1,*q2;p1=&a;p2=&b;q1=&c[1];q2=&c[7];n=q2-q1;p3=p1+p2;p3=q1;
/*定义了2个单精度的变量a,b,三个指针变量*//*定义了1个整型变量,1个整型数组,2个整型变量*//*p1和p2指向两个不同变量a,b*//*q1和q2指向同一个数组的不同数组元素c[1]和c[7]*//*相差元素的个数,为6个整型变量所占字节数的大小计6*4=24*//*毫无意义*//*不正确,指针的类型不同*/3.指针变量的关系运算基于类型相同的两个指针变量之间的关系运算,表示它们指向的地址之间的关系。假如数据存放在一段连续的存储空间内,那么指向后面的存储单元的指针变量的值大于指向前面存储单元的指针变量的值。指向同一存储单元的两个指针变量的值相等。两个指针之间可以进行大于、大于等于、小于、小于等于、等于、不等于(>,>=,<,<=,==,!=)的比较运算。在程序中,判断空指针变量可以与整数比较。设p为指针变量,若有p==0成立,表示p为空指针,它不指向任何变量;若p!=0成立,表明p不是空指针。【例8.3】分析下面程序的运行结果。#include"stdio.h"#include"conio.h"voidmain(){inta=3,*p1;charch='A',*p2;floatx,y,*p3,*p4;p1=&a;p2=&ch;p3=&x;p4=p3+1;printf("%d,%c\n",a,ch);*p1=*p1+6;*p2=*p2+5;printf("%d,%c\n",a,ch);if(p3<p4)printf("OK!\n");elseprintf("NOT!\n");}运行结果:3,A9,FOK!8.2.5指针变量作为函数参数如果形参作为指针变量,相对应的实参必须是变量的指针。在这种情况下,数据传送是地址的传递方式。
【例8.4】用函数调用的方法求一个整数m的平方。#include"stdio.h"voidsquare(int*pn){*pn=*pn**pn;}voidmain(){intn;printf("请输入数据n:");scanf("%d",&n);printf("输入的数据是:%d\n",n);square(&n);printf("输入数的平方据是:%d\n",n);}程序的运行结果:请输入数据n:5↙输入的数据是:5输入数的平方据是:25用地址传递方式把变量n的地址传递给square()函数。函数square()用指向int类型的指针pn作为形参,在函数square()内形参pn的值改变,同时也影响到了main()函数内实参n的值的改变。#include"stdio.h"voidswap(int*q1,int*q2){intt;t=*q1;*q1=*q2;*q2=t;}voidmain(){inta,b,*pa=&a,*pb=&b;printf("请输入数据a,b:");scanf("%d,%d",&a,&b);printf("比较前的两个数是:%d,%d\n",a,b);if(a<b)swap(pa,pb);printf("比较后的两个数是:%d,%d\n",*pa,*pb);}【例8.5】输入两个整数a,b,按从大到小的顺序输出。程序的运行结果为:请输入数据a,b:15,20比较前的两个数是:15,20比较后的两个数是:20,15【例8.6】输入3个数,输出其中的最大整数和最小整数。#include"stdio.h"voidmax_min(int*p1,int*p2,int*p3){intmax,min;max=min=*p1;if(max<*p2)max=*p2;if(max<*p3)max=*p3;if(min>*p2)min=*p2;if(min>*p3)min=*p3;*p1=max;*p3=min;}voidmain(){inta,b,c;printf("请输入a,b,c:");scanf("%d,%d,%d",&a,&b,&c);max_min(&a,&b,&c);printf("max=%d,min=%d\n",a,c);}程序运行结果:请输入a,b,c:2,5,9↙max=9,min=28.2.6程序实例【例8.7】调用自定义的函数getint读入一正整数,并将其输出。在输入过程中,可用退格键,而空格或回车键表示结束输入。#include"stdio.h"#include"conio.h"voidgetint(int*pintnum){inti,ch,finish=0;intbuf[10],count=10;*pintnum=0;while(!finish){ch=getch();switch(ch){case'':case'\r':finish=1;break;case'\b':if(count>0){printf("\b\b");--count;}break;default:if('0'<=ch&&ch<='9'){printf("%c",ch);buf[count]=ch;--count;}}}for(i=0;i<count;i++)*pintnum=10*(*pintnum)+(buf[i]-'0');}main(){intdata;getint(&data);printf("\n%d",data)}8.3指针与数组C语言规定数组名代表数组的起始地址,一个数组包含若干个元素,每个数组元素都在内存中占用存储空间,都有相应的地址,指针变量可以指向数组或数组元素。8.3.1
一维数组和指针8.3指针与数组1.指针指向一维数组数组名代表数组的起始地址,也是数组第一个元素的地址。例如:inta[10];
a代表该数组的起始地址,是一个常量,也等价于&a[0]。a+i代表元素a[i]的地址,即a+i代表元素&a[i]。
对于数组元素的访问,除了前面讲述的下标表示法之外(例如要访问第5个元素,则用a[4]表示),也可以用地址法表示。例如,a[0]等于*a,a[i]等于*(a+i)。等价于:p=a;例如:inta[10];int*p=a;也可在定义指针变量的同时赋值。例如:inta[10],*p;p=&a[0];2.指向数组元素的指针变量的使用【例8.8】输出数组a中的全部元素。方法一#include<stdio.h>voidmain(){inta[10]={3,6,1,8,2,7,0,4,2,5},i,*p;p=a;for(i=0;i<10;i++){printf("%3d",*p);p++;}}方法二#include<stdio.h>voidmain(){inta[10]={3,6,1,8,2,7,0,4,2,5},*p;for(p=a;p<a+10;p++){printf("%3d",*p);p++;}}
利用指向数组元素的指针变量,并对其进行适当的加减运算,即可处理整个数组。
例如:inta[10],*p;
则存取数组a中的第i个元素,使用指针可以表示如下:*(p+i);用地址法编写的程序。#include<stdio.h>voidmain(){inta[10]={3,6,1,8,2,7,0,4,2,5},i;for(i=0;i<10;i++)printf("%3d",*(a+i));}对指针变量进行的运算大致可分为如下几种:①指针运算符*与++、--的优先级相同,结合方向为从右到左。②p++使指针p指向下一个元素。p--同理。③p1-p2(pl和p2指向同一数组),得到pl和p2指向元素的下标差值。④p+j(p指向数组的某一元素),得到在当前地址基础上向后偏移j个元素的地址。p-j同理。⑤*p++等价于先得到p所指向变量的值(即*p),然后使p=p+l,即使p指向下一个元素。*p--同理。⑥*++p等价于先执行p=p+l,再取*p的值。*--p同理。⑦++(*p),先取*p的值加1存人p所指向地址,再取*p的值。--(*p)同理。对指针与数组元素的关系(设inta[10],*p=a;)归纳如下:①&a[j],a+j,p+j等价,代表a数组第j个元素的地址。②a[j],*(a+j),p[j],*(p+j)等价,代表a数组第j个元素的值。③*(p++)等价于a[j++]、*(p--)等价于a[j--]、*(++p)等价于a[++j]、*(--p)等价于a[--j]。【例8.9】分析下面程序的运行结果。#include<stdio.h>voidmain(){inta[]={5,15,25,35,45,55,65,75,85,95},m,*p;p=a;m=*p++;/*e1行*/printf("m=%d\n",m);m=*++p;/*e2行*/printf("m=%d\n",m);m=++(*p);/*e3行*/printf("m=%d\n",m);m=(*p)++;/*e4行*/printf("m=%d\n",m);}执行el行时,先取出p所指向的元素的值,即a[0]的值5,赋值给m后,再执行++运算,使p指向下一个元素a[1]。执行e2行时,p先执行++运算,使p指向下一个元素a[2],取出p所指向的元素的值,即a[2]的值25,再赋值给m。执行e3行时,先取出p所指向的元素的值,即a[2]的值25,再执行++运算将a[2]加1,即a[2]为26后赋值给m,p仍然指向a[2]。执行e4行时,先取出p所指向的元素的值,即a[2]的值26,赋值给m后,再执行++运算,使p所指向的元素的值a[2]加1,即a[2]为27,p仍然指向a[2]不变。使用指针变量是应该注意以下几问题:①不要使用没有赋值的指针变量,使用指针之前一定要对它正确的赋值。②使用指针变量访问数组元素时,要随时检查指针的变化范围和指针当前的值,使指针的指向不能超过数组的上下界。【例8.10】输入几个学生的成绩球平均成绩。#include"stdio.h"voidmain(){inta[10],*p=a,j;for(j=0;j<10;j++)scanf("&d",p++);for(j=0;j<10;j++)printf("%3d",*p++);printf("\n");}#include"stdio.h"voidmain(){inta[10],*p=a,j;for(j=0;j<10;j++)scanf("&d",p++);p=a;for(j=0;j<10;j++)printf("%3d",*p++);printf("\n");}③无论传递数组的首地址的函数参数用数组名还是指针,其实质都是指针,在函数被调用时,该指针通过参数传递均指向数组。方法一:实参用指针变量,形参用数组名。#include"stdio.h"#defineN5floataver(floatp[])/*定义aver()函数用于计算平均成绩,形参用数组名*/{inti;floatav,s=0;for(i=0;i<N;i++)s+=p[i];/*利用下标法取数组元素的值*/av=s/N;return(av);}voidmain(){floatscore[N],av,*p=score;inti;printf("请输入5个学生的成绩!");for(i=0;i<N;i++)scanf("&f",&score[i]);av=aver(p);/*调用aver()函数时,实参用指针变量*/printf("这5个学生的平均成绩是%5.2f",av);}方法二:实参用数组名,形参用指针变量。#include"stdio.h"#defineN5floataver(float*pa)/*定义aver()函数用于计算平均成绩,形参用指针变量*/{inti;floatav,s=0;for(i=0;i<N;i++)s+=*pa++;/*利用指针变量取数组元素的值*/av=s/N;return(av);}voidmain(){floatscore[N],av;inti;printf("请输入5个学生的成绩!");for(i=0;i<N;i++)scanf("&f",&score[i]);av=aver(score);/*调用aver()函数时,实参用数组名*/printf("这5个学生的平均成绩是%5.2f",av);}方法三:实参用指针变量,形参也用指针变量。#include"stdio.h"#defineN5floataver(float*pa)/*定义aver()函数用于计算平均成绩,形参用指针变量*/{inti;floatav,s=0;for(i=0;i<N;i++)s+=*pa++;/*利用指针变量取数组元素的值*/av=s/N;return(av);}voidmain(){floatscore[N],av,*p=score;inti;printf("!");for(i=0;i<N;i++)scanf("&f",&score[i]);av=aver(p);/*调用aver()函数时,实参用指针变量*/printf("%5.2f",av);}【例8.11】输入n个数,对其中的正数统计个数并求和,程序最后输出原始数据和统计结果。#defineN5voidmain(){inta[N],*p;intcount=0,sum=0;printf("%d!",N);for(p=a;p<a+N;p++)/*使指针指向下一个元素*/{scanf("%d",p);if(*p>0){sum+=*p;count++;}}p=a;/*使指针指向数组的首地址*/while(p<a+N)printf("%-3d",*p++);/*利用指针指向打印数组的元素*/printf("\n");printf("count=%d\n",count);printf("sum=%d\n",sum);}1.二维数组地址的表示方法8.3.2二维数组和指针例如:inta[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};2.二维数组的指针变量二维数组指针变量说明的一般形式为:类型标识符(*指针变量名)[长度];其中:“类型说明符”为所指向数组的数据类型。“*”表示其后的变量是指针类型。“长度”表示二维数组分解为多个一维数组时,一维数组的长度,也就是二维数组的列数。应注意“(*指针变量名)“两边的括号不可少,缺少括号则表示是指针数组,意义就完全不同了。【例8.12】用指向数组元素的指针变量输出数组元素的值,并统计其中的正数。
#include"stdio.h"voidmain(){inta[][4]={{1,-2,3,4},{11,-22,33,44},{-55,66,0,-89}};intcount=0,*p;for(p=a[0];p<a[0]+12;p++){if((p-a[0])%4==0)printf("\n");printf("%4d",*p);if(*p>0)count++;}printf("\ncount=%d\n",count);}程序运行结果
1-23411-223344-55660-88count=7【例8.13】查看某个学生某一门课程的成绩。#include"stdio.h"#defineN3/*N表示学生数*/#defineM4/*M表示课程数*/voidmain(){intscore[N][M]={{67,80,74,58},{77,80,84,90},{87,81,75,69}};inti,j;printf("请输入待查学生的学号%d和课程号%d");scanf("%d,%d",&i,&j);printf("第%d个学生的第%d课程的成绩是%d\n",i-1,j-1,*(*(score+i-1)+j-1));}程序的运行结果:请输入待查学生的学号和课程号:2,1↙第2个学生的第1课程的成绩是778.3.3程序实例#include<stdio.h>voidsort(inta[],intn){inti,j,temp;for(i=0;i<n;i++){for(j=n-1;j>i;j--)if(a[j-1]>a[j]){temp=a[j-1];a[j-1]=a[j];a[j]=temp;}}}
voidprint(inta[],intn){inti;for(i=0;i<n;i++)printf("%d",a[i]);printf("\n");}main(){inti,n,a[100];scanf("%d",&n);for(i=0;i<n;i++)scanf("%d",&a[i]);sort(a,n);print(a,n);}【例8.14】用冒泡排序法对数组进行排序。8.4字符串的指针和指向字符串的指针变量C语言中没有专门针对字符串变量的运算,对字符串的操作要通过字符数组和指针来完成。字符串在内存中的起始地址称为字符串的指针,可以定义一个字符指针变量指向一个字符串。8.4.1字符串的指针1.字符数组把字符串的各字符(包括结束标志‘\0’)依次保存在字符数组中,利用下标变量或数组名对数组进行操作。输出时用“%s”格式进行整体输出。2.字符指针也可以直接定义指向字符串的指针变量,利用该指针变量对字符串进行操作。【例8.15】字符数组应用举例。#include"stdio.h"voidmain(){charstr[]="Cprogram.";printf("%s\n",str);}程序运行结果:Cprogram.【例8.16】字符指针应用举例。#include"stdio.h"voidmain(){char*ps="Cprogram.";printf("%s\n",ps);}8.4字符串的指针和指向字符串的指针变量#include"stdio.h"voidmain(){charst[50],*ps;inti;printf("请输入一个字符串:");ps=st;scanf("%s",ps);for(i=0;ps[i]!='\0';i++)if(ps[i]=='k')break;if(ps[i]=='\0')printf("thereisno'k'inthestring.\n");elseprintf("thereisa'k'inthestring.\n");}【例8.17】在字符串中查找有无某字符。
程序的运行结果:请输入一个字符串:efgkabc↙thereisno'k'inthestring.请输入一个字符串:abcxyz↙thereisno'k'inthestring.在使用时应注意以下几个问题:①字符串指针变量本身是一个变量,用于存放字符串的首地址。而字符串本身是存放在以该首地址为首的一块连续的内存空间中,并以'\0'作为字符串的结束标志。字符数组是由若干个数组元素组成的,它可用来存放整个字符串。②对字符数组作初始化赋值,必须采用外部类型或静态类型,而对字符串指针变量则无此限制。staticcharst[]={"CLanguage"};char*ps="CLanguage";③对字符串指针方式char*ps=“CLanguage”;可以写为:char*ps;*ps="CLanguage";而对数组方式:staticcharst[]={"CLanguage"};不能写成:staticcharst[20];或st[]={"CLanguage"};【例8.18】对字符数据使用冒泡排序法进行排序,用字符数组和字符指针实现。#include<stdio.h>#include<string.h>voidmain(){inti,j,n;chart;staticchars[50];char*item=s;/*定义字符指针item,并把字符数组的首地址赋给item*/printf("请输入一个字符串:");gets(item);n=strlen(s);/*求字符串的长度*/for(i=1;i<n;i++)for(j=n-1;j>=i;j--){if(item[j-1]>item[j]){t=item[j-1];item[j-1]=item[j];item[j]=t;}}item=s;/*指针复位*/printf("\n排序后的字符串为:%S",item);}运行结果:请输入一个字符串:Cprogram排序后的字符串为:Cagmoprr8.4.2字符串作为函数参数将一个字符串从一个函数传递到另一个函数,一方面可以用字符数组名做参数,另一方面可以用指向字符串的指针变量做参数,这样,在被调函数中若改变了字符串的内容,则主调函数中相应的字符串的内容也随之改变。【例8.19】编写程序,把一个字符串的内容复制到另一个宇符串中,要求不能使用strcpy()函数。#include<stdio.h>voidcpystr(char*ps,char*pd)/*形参pss指向源字符串,而pds指向目标字符串*/{while((*pd=*ps)!='\0')/*将ps指向的字符串赋值到pd指向的存储单元中并判断是否结束*/{pd++;/*pd值加1,指向下一个字符*/ps++;/*ps值加1,指向下一个字符*/}}voidmain(){char*pa="CHINA",b[10],*pb;pb=b;cpystr(pa,pb);/*以指针变量pa、pb为实参,调用cpystr()函数*/printf("stringa=%s\nstringb=%s\n",pa,pb);}程序的运行结果:
stringa=CHINAstringb=CHINA【例7.20】编写程序,将输入字符串中的大写字母转换为小写字母。#include<stdio.h>#include<string.h>voidchan(char*p){inti,n;n=strlen(p);for(i=0;i<=n;i++)if(*(p+i)>64&&*(p+i)<92)*(p+i)=*(p+i)+32;}voidmain(){charstr[]="AbcDeF";puts(str);chan(str);puts(str);}程序的运行结果:AbcDeFabcdef8.5指针数组
指针数组是一个数组,该数组是指针变量的集合,即它的每一个元素都是一个指针变量,这些指针变量具有相同的数据类型。指针数组的定义格式为:类型标识*指针数组名[数组长度];例如:int*a[10];
对指向字符串的指针数组在说明赋初值时,是把存放字符串的首地址赋给指针数组的对应元素。例如:char*a[5]={"BASIC","FORTRAN","FOXBASE","PASCAL","COBOL"};定义了a是指针数组,它有5个元素分别存放了字符串"BASIC","FORTRAN","FOXBASE","PASCAL","COBOL"的起始地址。【例8.21】利用指针数组输出另一个一维数组中的各元素#include<stdio.h>voidmain(){inti;inta[5]={2,4,6,8,10};int*p[5];for(i=0;i<5;i++)p[i]=a+i;for(i=0;i<5;i++)printf("%d",*p[i]);}程序的运行结果:246810【例8.22】用0~6分别代表星期日至星期六,当输人其中的任意一个数字时,请输出对应的星期名。#include<stdio.h>voidmain(){char*weekname[7]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};intweek;printf("请输入0~6的数字:");scanf("%d",&week);if(week>=0&&week<7)printf("weekNO:%d-->%s",week,weekname[week]);elseprintf("inputerror!!\n");}程序运行结果:请输入0~6的数字:5↙weekNO:5-->Friday8.6指向指针的指针程序运行结果:x=10
指向指针的指针变量中存放的是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量。指向指针的指针变量的一般格式为:类型标识符**变量名;例如:int**pp;
表示pp是一个指针变量,它指向另一个指针变量,而这个指针变量指向一个整型量。【例8.23】指向指针的指针演示。#include<stdio.h>voidmain(){intx,*p,**pp;x=10;p=&x;pp=&p;printf("x=%d\n",**pp);}【例8.24】通过指针变量输出指针数组中数组元素的地址和数组元素所指向的数组。
#include<stdio.h>voidmain(){char*p[4]={"BASIC","DBASE","C","FORTRAN"};char**q;inti;for(i=0;i<4;i++){q=p+i;printf("%o",*q);printf("%s\n",*q);}}程序运行结果:634BASIC642DBASE640C650FORTRAN8.6.2指向指针的指针的应用现有5个国家的国名:"CHINA","AMERICA","AUSTRALIA","FRANCE","GERMAN",现要对这些国名按字母顺序排列后输出。思考:排序后排序前GERMAN\0GERMAN\0FRANCE\0FRANCE\0CHIAN\0AUSTRALIA\0AUSTRALIA\0AMERICA\0AMERICA\0nameCHINA\0name二维字符数组来存放字符串每个字符串不论其实际长度是多少均需占据10个字节,存储空间占据较多,在排序时字符串的存储位置作了交换,因此程序执行效率较低。
把所有的字符串存放在一个数组中,把这些字符数组的首地址放在一个指针数组中,当需要交换两个字符串时,只需要交换指针数组相应两元素的内容(地址)即可,而不必交换字符串本身,【例8.25】用指针数组处理字符串。voidsort(char*name[],intn){char*temp;inti,j;for(i=0;i<n-1;i++)for(j=n-1;j>i;j--)if(strcmp(name[j-1],name[j])>0){temp=name[j-1];name[j-1]=name[j];name[j]=temp;}}voidprint(char*name[],intn){inti,j;for(i=0;i<n;i++)printf("%s\n",name[i]);}main(){char*progname[]={"CHINA","AMERICA","AUSTRALIA","FRANCE","GERMAN"};sort(progname,5);print(progname,5);}指针可以指向一个变量,同样也可以指向一个函数。一个函数在编译时,其代码在内存中占用一段连续的内存单元,这片连续的内存单元有一个人口地址,这个地址是执行该函数的起始地址,也称为该函数的指针。可以用一个指针变量指向一个函数,然后通过该指针变量调用此函数。8.7.1函数的指针和指向函数的指针变量8.7函数的指针
一个函数在编译时被分配给一个入口地址,这个函数的入口地址就是函数的指针。C语言规定函数名代表函数的入口地址。
在C语言中规定,一个函数总是占用一段连续的内存区,而函数名就是该函数所占内存区的首地址。
可以把函数的这个首地址(或称入口地址)赋予一个指针变量,使该指针变量指向该函数,然后通过指针变量就可以找到并调用这个函数。把这种指向函数的指针变量称为指向函数的指针变量。使用指向函数的指针变量有以下3个步骤:⑴定义指向函数的指针变量类型说明符(*指针变量)();例如:int(*pf)();
表示pf是一个指向函数入口的指针变量,该函数的返回值(函数值)是整型。⑵将定义后的指针变量指向函数例如:
int(*p)();…p=fun;…intfun(intx,inty){return(x+y);}⑶用指向函数的指针变量调用函数调用函数的格式为:(*指针变量)(实参表)在上述程序段中,通过指向函数的指针变量fun()函数的格式为“s=(*p)(a,b);”【例8.26】演示函数指针的使用方法。#include<stdio.h>intmax(inta,intb)/*定义max()函数用于求两个数的较大数*/{if(a>b)return(a);elsereturn(b);}voidmain(){int(*pmax)(int,int);intx,y,z;pmax=max;printf("请输入两个数:");scanf("%d,%d",&x,&y);z=(*pmax)(x,y);/*通过函数指针调用max()*/printf("max=%d\n",z);}程序的运行结果:请输入两个数:15,30↙max=30指向函数的指针变量的性质与普通指针变量相同,唯一的区别是:普通指针变量指向的是内存的数据存储区;而指向函数的指针变量指向的是内存的程序代码区。8.7.2函数的指针作为函数参数
当函数在两个函数之间传递时,调用函数的实参应该是被调传递函数的函数名,而被调函数的形参应该是接收函数地址的指向函数的指针变量。【例8.27】任意输入两个整数,求它们的和、差。#include<stdio.h>intadd(intx,inty)/*定义add()函数用于计算两个数的和*/{return(x+y);}intsub(intx,inty)/*定义sub()函数用于计算两个数的差*/{return(x-y);}intfun(int(*p)(int,int),intx,inty)/*定义fun()函数用于调用相应的函数*/{intz;z=(*p)(x,y);return(z);}voidmain(){inta,b;printf("请输入两个数:");scanf("%d,%d",&a,&b);printf("%d+%d=%d\n",a,b,fun(add,a,b));printf("%d-%d=%d\n",a,b,fun(sub,a,b));}程序的运行结果:请输入两个数:126↙12+6=1812-6=68.7.3函数指针的应用【例8.28】设有一个函数general,调用它时,因为参数的不同实现不同的功能,输入a,b两个数,第一次调用general时,找出a和b中大者,第二次调用general时找出其中小者,第三次调用general时求a,b之和。#include<stdio.h>intmax(intx,inty){return(x>y)?x:y;}intmin(intx,inty){return(x<y)?x:y;}intadd(intx,inty){returnx+y;}voidgeneral(intx,inty,int(*fun)()){intresult;result=(*fun)(x,y);printf("%d\n",result);}main(){inta,b;printf("Entera,andb:");scanf("%d%d",&a,&b);printf("max=");general(a,b,max);printf("min=");general(a,b,min);printf("sum=");general(a,b,add);}运行结果如下:Enteraandb:-38↙max=8min=-3sum=5【例8.29】指向函数的指针数组的应用。#include"stdio.h"voidfun1(int);voidfun2(int);voidfun3(int);voidmain(){void(*f[3])(int)={fun1,fun2,fun3};intchoice;printf("Enteranumberbetween0and2,3toend:");scanf("%d",&choice);while(choice>=0&&choice<3){(*f[choice])(choice);printf("Enteranumberbetween0and2,3toend:");scanf("%d",&choice);}printf("Youentered3toend\n");}voidfun1(inta){printf("Youentered%dsofun1wascalled\n\n",a);}voidfun2(intb){printf("Youentered%dsofun2wascalled\n\n",b);}voidfun3(intc){printf("Youentered%dsofun3wascalled\n\n",c);}运行结果如下:Enteranumberbetween0and2,3toend:0Youentered0sofun1wascal
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年滨州滨城区事业单位招聘人员考试真题
- 社会工作者的角色与作用在精神障碍患者家庭中的实践探索
- 社交媒体在推广老年人听力保健中的作用
- 2025年皮革化学品:浸水助剂合作协议书
- 科技创新园区的空间设计策略分析
- 生产设备的绿色技术创新与实践报告
- 20以内乘法除法口算题目汇编1000道可打印
- 100以内乘法除法口算练习手册1000道可打印
- 铜修饰COF复合材料的制备及其光电催化二氧化碳还原的研究
- 中枢兴奋药项目绩效评估报告
- 硬质合金混合及成形
- 高蛋白干酒糟饲料DDGS简介(课堂PPT)
- 60万吨年磷石膏综合利用项目资金申请报告模板定制
- 硅酸盐水泥熟料矿物组成及配料计算概述(共101页).ppt
- 口腔诊所器材清单
- 急诊与灾难医学第二版配套课件 02 急性发热
- 部编版四年级道德与法治下册4《买东西的学问》第1课时课件
- 外研版英语(新标准)八年级下册教案(全册)
- 教师听课评分表
- 项目章程模板范文
- 泰山产业领军人才工程系统
评论
0/150
提交评论