《《C语言程序设计》第5章指针.ppt》由会员分享,可在线阅读,更多相关《《C语言程序设计》第5章指针.ppt(45页珍藏版)》请在三一办公上搜索。
1、第五章 指 针Pointer,5.1 指针的基本概念,指针是C语言的重要特征,是C语言访问内存数据和程序的灵活和有效的手段。,C语言的指针支持:函数的地址调用;动态分配内存;数组的地址引用。,内存、地址、指针(Memory,Address,Pointer),内存存放了计算机正在运行的程序和程序正在使用的数据。内存的基本单元是字节(Byte)。,为了访问内存单元,CPU给每个内存单元一个编号,该编号称为该内存单元的地址。,变量是程序中可以改变的量,当说明变量时,系统将为其在内存中开辟相应得内存单元。由此确定变量的地址及内存中的表示方式。,2000H,2001H,2002H,2003H,int a
2、=0;,a的内存单元,a的地址&a,如果有一变量p,其内容存放了a的地址&a,通过p也可实现对a的访问,p称为指针,并指向a。,00H,20H,0,0,p,指针的说明,指针是特殊类型的变量,其内容是变量的地址。在使用前必须说明,说明某标识符是指针类型,并可指向某种类型的对象。,指针的说明格式:type*pname1,*pnamen;,标识符命名的指针变量名。,指针标志。,指针指向对象的类型。,int*p,*q;/*p、q是指向整型变量的指针。*/,float*pfValue,*pf;/*pfValue和pf是指向浮点型的指针。*/,指针对变量的引用,定义指针的目的是通过指针引用内存对象,指针的
3、引用应按如下步骤进行:,说明指针,int a=0,*p;,指针指向对象,p=,通过指针引用对象,*p=*p+2;,4.指针操作的两种运算符:,取地址运算&a表示取变量a地址的运算。,间接运算*p表示取指针p指向变量内容的运算。,int a,*p;,2000H,a,p,p=/*p指向a。*/,2000H,*p=2;,2,举例:,#include void main(void)int x,*p;x=55;p=,2000H,x,p,2000H,55,65,关于指针的说明:,指针必须指向对象后,才能引用。,int*p;*p=2;/*Error!*/,&和*为互补运算。,int a,*p;p=则:&*p
4、 p*&a a,【例5-1】,/*example 5-1 指针访问简单变量示例*/#include void main(void)int a,b,*p1,*p2;p1=,5。指针的运算,指针是特殊类型的变量,其内容是变量的地址,因此指针的运算及结果一定要符合地址逻辑。,五种算术运算,int a,b,*p1,*p2;p1=,a,2000H,b,2400H,p1,p2,2000H,2400H,p1+;/*含义指向a后的整型单元*/,2002H,2002H,p1-;/*指向a前的整型单元*/,p1+n;/*指向a后的第n个整型单元*/,p1-n;/*指向a前的第n个整型单元*/,p2-p1;/*a和
5、b之间差的单元数*/,结果200H,p n 相当于:p的实际内容 nsizeof(*p);,六种关系运算,比较两个同类型变量之间的地址关系。,p1p2;,指针赋值运算,#include void main(void)int a,b,*p1,*p2;a=2;b=3;p1=,差别,a,&a 2000H,b,&b 2400H,p1,p2,2,3,2000H,2400H,5.2 指针与数值型数组,数组是同类型的变量的集合,各元素按下标的特定顺序占据一段连续的内存,各元素的地址也连续,指针对数组元素非常方便。,指针与一维数组,通过指针引用数组元素可以分以下三个步骤:,说明指针和数组,int*p,a10;
6、,指针指向数组,p=a;/*指向数组的首地址*/p=/*指向数组的首地址*/,通过指针引用数组元素,当指针指向数组的首地址时,则下标为i的元素地址为:p+i 或a+i,引用数组元素可以有三种方法:,下标法:a i 指针法:*(p+i)数组名法:*(a+i),注意:数组名是地址常量,不能改变!,a=p;/*Error!*/,/*example 5-2 通过指针访问数组元素*/#include void main(void)double dArray10,dAvge,*dPointer;int i;dAvge=0;dPointer=dArray;/*指针指向数组*/for(i=0;i10;i+)s
7、canf(%lf,dPointer+i);/*dPointer+i为下标为i的元素地址*/dAvge+=*(dPointer+i);/*累加各个元素的值*/dAvge/=10;printf(The avgerage of array is:%lfn,dAvge);,【例5-2】有一个具有10个元素的双精度数组,通过指针求其所有元素的平均值。,/*example 5-3 通过指针求数组元素最大值及其位置*/#include void main(void)int iArray10,*ipCur;/*ipCur遍历访问数组的指针*/int*ipPos;/*ipPos最大元素地址*/int i;ipC
8、ur=iArray;/*指针指向数组*/for(i=0;i10;i+)scanf(%d,ipCur+);/*ipCur为下标为i的数组元素的地址*/ipPos=iArray;/*指向数组首地址*/*设下标为0的元素为最大值*/ipCur=iArray+1;,【例5-3】通过指针求数组的最大值及其位置。,for(i=1;i*ipPos)ipPos=ipCur;/*ipPos保存最大元素的地址*/ipCur+;/*指向下一元素*/printf(The max is%dn,*ipPos);printf(The position is%dn,ipPos-iArray);,举例:打印数组中的奇数。,#i
9、nclude void main(void)int i,a 10;for(i=0;i10;i+)scanf(“%d”,数组元素法。,循环输入。,循环判断,满足条件输出。,数组名法。,a+i,*(a+i),指针法。,*p;,p=a;,p+,*(p+i),结果是否正确?,p=a;*p=*,注意指针在运算时的变化。,2.指针与二维数组,如下说明数组int a34=1,2,3,4,5,6,7,8,9,10,11,12;,其二维结构如下:,行,列,为了便于索引,C语言将数组分为两级管理。,a0,a1,a2,将a理解为一维数组,数组有三个元素,它们分别为a0、a1,a2。各个元素又是一个有四个元素的一维数
10、组。,从地址的角度看:a 为a0 第一行的首地址a+1 为a1 第二行的首地址a+2 为a2 第三行的首地址,a+1 地址一次加一行。,i行j列数组元素的地址可以由a i+j得到。,数组名地址的两级管理,a,a0,a1,a2,a00 a01 a02 a03,a10 a11 a12 a13,a20 a21 a22 a23,等价地址及其管理方式,数组名是数组的地址,而且是常量,*运算不改变其值!,以下三种地址等价:,a+i,*(a+i),a i,加法按行递增,加法按列递增,(a+1)+1,*(a+1)+1,差别?,数组名表示数组元素,a i j,(*(a+i)j,*(*(a+i)+j),*(a i
11、+j),指针与二维数组,int*p,a34;p=a;aij*(p+4*i+j)等价!,a00,a,a01,a02,a0,a10,a11,a12,a1,a20,a21,a22,a2,a+1,a1+2,/*example 5-4 求二维数组最小值及其位置*/#include void main(void)int a34,i,j;int iMinRow,iMinCol;/*iMinRow最小值的行,iMinCol最小值的列*/for(i=0;i3;i+)for(j=0;j4;j+)scanf(%d,ai+j);/*ai+j为i行j列元素的地址*/iMinRow=0;iMinCol=0;/*假定a00
12、为最小值*/for(i=0;i3;i+)for(j=0;j4;j+)if(*(*(a+i)+j)aiMinRowiMinCol)iMinRow=i;iMinCol=j;/*修正i和j为新的最小值下标*/printf(The min is a%d%d=%dn,iMinRow,iMinCol,aiMinRowiMinCol);,【例5-4】输入三行四列的整型数组,求最小值及其位置。,/*example 5-5 通过指针求二维数组元素的累加和*/#include void main(void)int i,j,a23,sum;int*p;p=(int*)a;/*p指向数组a,由于a加1加1行,转换为整
13、型指针*/for(i=0;i2;i+)for(j=0;j3;j+)scanf(“%d”,ai+j);/*ai+j为i行j列元素的地址*/sum=0;for(i=0;i2;i+)for(j=0;j3;j+)sum+=*(p+i*3+j);/*通过指针p表示aij*/printf(The sum of a=%dn,sum);,【例5-5】输入两行三列的整型数组,通过指针求所有元素的累加和。,举例:在数组a中查找输入的数,输出行列位置。,#include void main(void)int a34=1,2,3,4,5,6,7,8,9,10,11,12;int i,j,iS;int*p;p=a;sc
14、anf(“%d”,下标法。,*(a i+j),*(*(a+i)+j),*(p+4*i+j),【例5-6】输入3行4列的浮点型数组,通过指针求数组的平均值。,/*example 5-6 通过指针求二维数组的平均值*/#include void main(void)int i,j;float a34,fAvg;float(*p)4;p=a;/*指针指向数组*/fAvg=0;for(i=0;i3;i+)for(j=0;j4;j+)scanf(“%f”,pi+j);/*pi+j为i行j列元素的地址*/fAvg+=pij;/*pij表示aij*/fAvg/=12;printf(The average o
15、f a=%fn,fAvg);,5.3 指针与字符串(字符数组),字符串在内存中可以存储为两种形式:,字符数组字符串常量,可以使指针指向字符数组或字符串常量,通过指针引用字符数组或字符串的各个字符。,1.指针与字符数组:,char*chp,str=”Hello!”;/*说明字符指针和字符数组*/chp=str;/*指针指向字符数组*/putchar(*(chp+2);/*通过指针引用数组元素*/,2.指针与字符串:,char*strp;/*说明字符指针*/strp=“Hello!”;/*指针指向字符串*/puts(strp);/*通过指针引用字符串*/,说明指针时,可以同时赋初值,如:,char
16、*strp=“Hello!”;,赋值表示将字符串的地址赋给指针!,/*example 5-7 通过指针访问字符串常量*/#include void main(void)char*p;/*说明指向字符的指针p*/int iNumOfi;p=“This is a test string”;/*指针指向字符串常量*/iNumOfi=0;while(*p!=0)if(*p=i)iNumOfi+;p+;printf(In the string the number of i=%dn,iNumOfi);,【例5-7】统计字符串常量中的小写字母i的数量。,/*example 5-8 通过指针访问字符数组*/
17、#include void main(void)char str80,*chp;/*说明字符数组及指向字符的指针*/chp=str;/*指针指向字符数组*/gets(chp);while(*chp!=0)if(*chp=a,【例5-8】输入字符串,将其中小写字母转换成大写字符,其余的字符不变,输出结果。,举例:将字符串中的大写字母转化对应的小写字母。,#include void main(void)char*p,s80;p=s;gets(p);for(;*p!=0;p+)if(*p=A,举例:将无符号的八进制字符串转换为十进制整数。,#include void main(void)char*p
18、,s6;int i,n=0;p=s;gets(p);for(;*p!=0;p+)n=n*8+*p-0;printf(“%dn”,n);,p指向s数组。,输入字符串。,s,p,s,5,5,6,0,n=0*8+5-05,n=5*8+5-045,n=45*8+6-0366,思考题:将4位十六进值字符串转化为十进制字符串。,5.4 指 针 数 组和指向指针的指针,指针是存放其它数据对象地址的变量。因此,指针可以构成数组。每个数组元素为一个指针变量,且在内存中连续存放。,指针数组的说明,说明格式:type*数组名const exp;,int*p 4;,含义是在内存中开辟空间,并指明元素所指向的对象的类型
19、。,数组名p为数组的地址。,使用前必须让各元素指向对象。,int i,a34,*p3;for(i=0;i3;i+)p i=a i;*(p2+1)=2;/*通过指针数组引用数组元素a21*/,/*example 5-9 通过指针数组访问二维数组*/#include void main(void)int a34;int*p3;/*说明行数相同的指针数组*/int i,j;int iSumOfPosi,iCountOfPosi;for(i=0;i3;i+)pi=ai;/*指针数组元素指向对应的行*/for(j=0;j4;j+)scanf(%d,pi+j);iSumOfPosi=0;iCountOfP
20、osi=0;,【例5-9】统计3行4列整型二维数组中正数的个数,并求正数的累加和,输出结果。,for(i=0;i 0)iSumOfPosi+=*(pi+j);/*通过指针数组访问二维数组*/iCountOfPosi+;printf(The sum of posi-numb in array is%dn,iSumOfPosi);printf(The number of posi-numb in array is%dn,iCountOfPosi);,指针数组的应用举例,指针数组与多维数组,通过指针数组按数学方式输出数组的值。,#include void main()int i,j;int a34=
21、1,2,3,4,5,6,7,8,9,10,11,12;int*p3;p0=a0;p1=a1;p2=a2;for(i=0;i3;i+)for(j=0;j4;j+)printf(“%5d”,*(pi+j);printf(“n”);,p0,数组a的二维结构,p1,p2,a0,a1,a2,每输出一行,打印回车。,/*example 5-10 通过指针数组访问二维字符数组*/#include#include void main(void)char strName510,*strP5,*strTemp=NULL;int i,j;for(i=0;i 0)/*比较*/,【例5-10】对存放于二维字符数组中的五
22、个字符串按由小到大排序输出。,strTemp=strPi;strPi=strPj;strPj=strTemp;printf(The result after sort:n);for(i=0;i5;i+)puts(strPi);/*输出*/,指针数组与多字符串,通过指针数组构成的菜单,执行DOS命令。,#include void main(void)char*command=“dir”,“time”,“date”,ch;for(;)do printf(“1:directoryn”);printf(“2:set timen”);printf(“3:set daten”);printf(“4:qui
23、tn”);printf(nselection:”);ch=getchar();printf(“n”);while(ch4);if(ch=4)break;system(commandch-1);,内层循环输入选项,外层循环根据选项执行命令,执行系统命令函数,如:system(“dir”);,3-1 2,【例5-11】输入0到6的数字分别代表周日到周六,输出英文名称。,/*example 5-11 字符型指针数组与字符串常量*/#include void main(void)char*strDay7=“Sunday”,“Monday”,“Tuesday”,Wednesday,Thursday,Fr
24、iday,Saturday;int iDay;scanf(%d,指向指针的指针,如果指针变量的内容存放其它指针的地址,称该指针为指向指针的指针。,指向指针的指针的说明:,形式:type*p;,int*p;,p是一个指向整形指针的指针。,#include void main(void)int x,*p,*q;x=10;p=,p为指向整型的指针。,q为指向整型指针的指针。,x,p,q,2000H,3000H,10,2000H,3000H,指向指针的指针的应用,指向指针的指针一般用于多维数组和指针数组的操作。,多维数组,#include void main()int a34=1,2,3,4,5,6,
25、7,8,9,10,11,12,;int*arr3=a0,a1,a2;int i,j,*p;p=arr;for(i=0;i3;i+)for(j=0;i4;j+)printf(“%5d”,*(*(p+i)+j);printf(“n”);,ai,aij,arr,arr,p,p+1,【例5-12】指向指针的指针的简单应用。,/*example 5-12 通过指向指针的指针访问简单变量示例*/#include void main(void)int x,*p,*q;/*说明变量、指针、指向指针的指针*/x=20;p=/*引用指向的对象*/,/*example 5-13 通过指向指针的指针与指针数组访问二维
26、数组*/#include void main(void)int a34,*p3,*pp;/*说明二维数组及与其行数相同的指针数组*/int i,j;float iAvg;for(i=0;i3;i+)pi=ai;/*指针数组元素指向对应的行*/for(j=0;j4;j+)scanf(%d,pi+j);pp=p;/*pp指向指针数组*/iAvg=0;for(i=0;i3;i+)for(j=0;j4;j+)iAvg+=*(*(pp+i)+j);/*通过pp访问aij*/printf(The average of a is%fn,iAvg/12);,【例5-13】通过指向指针的指针与指针数组,求二维数
27、组的平均值。,用于处理多字符串,#include void main(void)char*name=“one”,“two”,“three”,“four”;char*p;int i;for(i=0;i4;i+)p=name+i;printf(“%sn”,*p);,p,name+i,指针的类型问题,通过指针可以访问基本类型的变量及数组,指针的类型是其指向数据的类型,该类型决定了指针逻辑加一时所加的物理字节数。,可以强制转换指针的类型,转换方式为:,(type*)p,#include void main()char a3,*p;int y;a0=0 x12;a1=0 x34;a2=0 x56;p=,
28、&a0,p,相邻单元转化为一个整型单元。,chp5ex2,*p,指向void类型的指针,void称为“空类型”,void不能说明变量。但可以用void说明指针。当用void说明指针时,指针称为指向空类型的指针,空类型指针加1,地址移动一个字节。也就是说void指向的类型是以物理字节为单位的内存。,5.5 程序代码风格,1.命名规范,标识符是C语言的命名机制,标识符可以对变量、数组、函数、结构类型、宏名等需要命名的数据命名。为了提高程序的可读性,命名一般的规则如下:,(1)宏名 宏名一般全部由大写字母构成,以示与其他数据名字的区别,(2)函数名 函数命名最好采用动词短语加名词短语,每个短语的首字
29、符用大写表示。主要目的是尽可能在名字中描述函数实现的功能。,(3)变量名 变量的名是程序中使用最多的名字,变量的命名应尽可能的做到“见名知意”,也就是在命名中尽可能体现变量在程序中的作用,同时变量的名字中最好能体现变量的类型。业界较为通行的是Windows程序员的规范,该规范是也称“匈牙利命名法”,是匈牙利人Charles Simonyi提出的命名方式。该方式以小写字母构成的前缀表示类型,以一个或多个名词短语表示变量的含义,每个名词短语的首字符为大写,表达式及语句风格,1.表达式,表达式要尽量简单易读,在程序中不要用过于复杂的表达式。,2.语句中的 风格在分支和循环的语句中,无论是否需要都加 包含其语句。,3.空行在语句中加入适当空行表示某个操作的结束,以增加程序的可读性。,4.注释在程序中加入注释对于提高程序的可读性、可调性、可维护性都是十分必要的,因此在程序关键算法、关键语句、关键位置都应该加必要的注释。,