数组字符串指针及其应.ppt
程序设计-2005年秋,1,第7讲数组、字符串、指针及其应用(Part II),周水庚2005年10月26日,程序设计-2005年秋,2,数组的基本概念一维数组多维数组字符数组和字符串指针和数组,提要,程序设计-2005年秋,3,数组,定义形式类型说明符 数组名常量表达式;类型说明符 数组名常量表达式常量表达式;引用形式数组名下标数组名下标下标,程序设计-2005年秋,4,数组的基本概念一维数组多维数组字符数组和字符串指针和数组,提要,程序设计-2005年秋,5,字符数组,字符数组定义形式与其他数组定义形式一样 char 字符数组名元素个数;如:char s5;表示数组s有5个元素,每个元素能存放一个字符,整个数组最多可存放5个字符当存于字符数组中的字符列最后有ASCII码值为0(记为0)时,称该数组中的字符列为字符串。并称字符0为字符串结束标志符,程序设计-2005年秋,6,字符数组初始化,字符数组除可以与普通数组一样初始化外,也可利用字符串常量给字符数组初始化。用字符串常量对字符数组初始化时,系统会在字符列未尾添加一个字符串结束符如:char a_str=I am happy!;或简写为 char a_str=I am happy!;数组a_str有12个元素,其中a_str11的值是字符串的结束标志符0如:char str_list30=I am happy!,I am learning c language.;字符数组str_list0和字符数组str_list1各可存储30个字符,现分别存储有11个有效字符的字符串和有25个有效字符的字符串,程序设计-2005年秋,7,字符串,称最后有字符串结束符的字符序列为字符串字符数组中存储的字符序列本身并不要求最后要有字符0。但当字符数组内存储的内容需要作为字符串时,就必须要有标志符 0当字符数组内存储的是字符串时,可用”%s”格式输出,若是普通的字符序列,则它不能用格式”%s”,而只能用格式”%c”char s1=student;char s2=s,t,u,d,e,n,t;则 printf(“%s”,s1);是正确的而 printf(“%s”,s2);是错误的实际上字符数组s1有8个元素;s2只有7个元素,程序设计-2005年秋,8,字符串与字符数组,文字信息可作为字符串来处理,而字符串又以字符数组的形式来组织存储字符数组需预先指定长度以保证能存放足够长的文字信息但限定长度对使用是不方便的。例如定义的字符数组:char str120可存储120个字符,如用它来接受输入或组织输出,每次必须键入120个字符,或总得输出120个字符。显然是不合理的,因为通常输入输出的字符个数均小于120为能使存于字符数组中的字符串的实际长度可长可短,且其长度可随时测定,两个长度不相等的字符串能按字典顺序比较,C语言为字符串规定了一个字符串结束标志符0,程序设计-2005年秋,9,字符串常量,字符串常量的书写形式为:字符序列其中字符序列可由零个或多个字符组成,如字符串常量”I am a student.”含15个有效字符字符串常量”不含任何有效字符,其长度为0,习惯称为空字符串在字符串常量的书写形式中,双引号“只充当字符串的界限符,不是字符串的一部分如果字符串要包含字符“,则可经过转义序列(如”)来实现,其它转义序列(如n,t)也可以作为单个字符出现在字符串常量中。如 tThis is a string.n,程序设计-2005年秋,10,字符串常量串接规则,通常字符串写在一行内。如果一个字符串常量在一行内写不下时,可用字符串常量的串接规则把字符串分成连续多行形式书写字符串常量串接规则有两条在键入字符 之后紧接键入回车键。如“I am a st(回车换行符)ring.“就是字符串常量 I am a string.“连续两个紧接的字符串常量相当于一个字符串常量。如 I am a string.“也是字符串常量 I am a string.,程序设计-2005年秋,11,字符串输入输出,字符串的输入输出可以有两种方式用格式“%c”,结合循环结构逐个字符输入或输出用格式“%s”,将字符串整体地输入或输出例如:char s=C language;用第一种方法输出 for(i=0;si;+i)printf(%c,si);用第二种方法输出 printf(%s,s);,程序设计-2005年秋,12,字符串注意点-1,1-字符串与存储字符串的字符数组有区别字符串的有效字符是指从所指位置的第一个字符开始至字符串结束标志符之前的那些字符。如:char str50=Pas0cal Cobol Fortran C;printf(%sn,str);将只输出 Pas而实际上,数组str在字符串结束符之后还存有其它许多字符,程序设计-2005年秋,13,字符串注意点-2&3,用“%s”格式输出字符串时,不包括字符串结束标志符对应的输出项是字符串或字符串名。字符数组名可作为字符串名在调用scanf()为字符数组输入字符串时,输入项是数组名,不要加地址运算符 用“%s”格式输入字符串时,掠过前导的空白类字符,只能输入一串不含空白类字符的字符序列,遇空白类字符,或输入了格式指定的字符个数,就结束输入若要输入一串包括空格符在内的一行字符,要用字符行输入函数gets(),程序设计-2005年秋,14,字符串注意点-4,若用”%c”格式结合循环输入字符序列,若程序又想将输入的字符序列构成字符串,则程序必须用赋值语句在字符列之后存入字符串结束标志符如:char s20;int k;for(k=0;k 5;k+)scanf(”%c”,程序设计-2005年秋,15,常用字符串处理函数,求字符串长度函数 strlen()函数调用strlen(str)返回str中的有效字符(不包括0)个数字符串拷贝函数strcpy()函数调用strcpy(str1,str2)将字符串str2复制拷贝到字符数组str1。限定字符数组str1要定义得足够大,以便能容纳被拷贝的str2的全部内容。限制:str1不能是字符串常量,程序设计-2005年秋,16,常用字符串处理函数(续),字符串拷贝函数strncpy()函数调用strncpy(str1,str2,n)的作用是将str2中的前n个字符拷贝到str1(并附加0)其中n是整型表达式,指明欲拷贝的字符个数。如果str2中的字符个数不多于n,则函数调用strncpy(str1,str2,n)等价于strcpy(str1,str2)。限制:str1不能是字符串常量,程序设计-2005年秋,17,常用字符串处理函数(续),字符串连接函数 strcat()函数调用strcat(str1,str2)将str2内容拷贝接在字符数组str1中的字符串的后面限制str1不能是字符串常量。该函数调用返回str1的开始地址。注意,字符串连接前,str1和str2都各自有0,连接后,str1中原来的0 在拷贝时被覆盖掉,而在新的字符串有效字符之后再保留一个0例如char str130=Beijing;char str230=Shanghai;strcat(str1,str2);printf(%sn,str1);将输出 BeijingShanghai,程序设计-2005年秋,18,常用字符串处理函数(续),字符串比较函数 strcmp()函数调用strcmp(str1,str2)比较两个字符串的大小,对两个字符串自左至右逐对字符相比较(按字符的ASCII代码值的大小),直至出现不同的字符或遇到0字符为止。如直至0字符,全部字符都相同,则认为相等,函数返回0值若出现不同的字符,则以这第一个不相同的字符比较结果为准,若str1的那个不相同字符小于str2的相应字符,函数返回一个负整数;反之,返回一个正整数注意,对字符串不允许施行相等“=”和不相等“!=”运算,必须类似于本函数那样,通过逐个字符比较来实现,程序设计-2005年秋,19,常用字符串处理函数(续),字符串大写英文字符转换成小写英文字符函数strlwr()函数调用strlwr(str)将存于字符数组str的字符串内的大写英文字符转换成小写英文字符。限制str不能是字符串常量字符串小写字母转换成大写字母函数 strupr()函数调用 strupr(str)将存于字符数组str的字符串内的小写英文字符转换成大写英文字符。同样限制str不能是字符串常量,程序设计-2005年秋,20,常用字符串处理函数(续),字符串输出函数 puts()函数调用puts(str)将str的字符串输出到终端,并将str中的0字符转换成换行符n。即输出字符串内容后,并换行。所以puts(str)相当于printf(”%sn”,str)字符串输入函数 gets()函数调用gets(str)从终端输入字符序列到字符数组str,字符序列以回车符作为结束,并将输入时的回车符转换成0字符存储。该函数调用返回str的存储开始地址,程序设计-2005年秋,21,字符数组和字符串应用样例-1,#include char s1100,s2100,s3100;void main()printf(输入字符序列s1n);scanf(%s,s1);while(getchar()!=n);printf(s1=%sn,s1);strcpy(s2,s1);strncpy(s3,s1,5);printf(从s1拷贝的s2=%sn,s2);printf(从s1只拷贝5个字符的s3=%sn,s3);strcat(s1,s3);printf(接上s3的s1=%sn,s1);printf(输入字符行到s1n);gets(s1);printf(s1=%sn,s1);strcpy(s2,s1);strncpy(s3,s1,5);puts(s2);puts(s3);strcat(s1,s3);puts(s1);,程序示例:说明上述库函数的应用,程序设计-2005年秋,22,字符数组和字符串应用样例-2,输入字符行,统计各英文字母出现的次数程序设计分析程序需要一个存储字符行的数组,还需要52个英文字母计数器,统计52个英文字母的出现次数顺序扫视输入的字符行中的字符,直至遇字符串结束符结束。当程序发现当前字符是英文字母时,对应英文字母的计数器增1,否则掠过当前字符用数组count52实现52个计数器,并设大写英文字符顺序对应前26个计数器(count0-count25),小写英文字符顺序对应后26个计数器(count26-count51),程序设计-2005年秋,23,字符数组和字符串应用样例-2(续),#include void main()char buf120;int i,count52;printf(Enter letter line.n);gets(buf);for(i=0;i=A,输入字符行,统计各英文字母出现的次数,程序设计-2005年秋,24,字符数组和字符串应用样例-3,输入字符行,统计其中单词个数。约定单词由英文字母组成,其它字符只是用来分隔单词程序设计分析 设置单词计数器等初值;输入一行字符(如用gets()函数);顺序扫视输入的字符行(如用for语句)判定当前字符是否是字母;if(现在正在单词中)if(当前字符不是字母)设置当前状态不在单词中的标志;else if(当前字符是字母)设置当前状态在单词中的标志;单词计数器增;/*状态有不是单词变为单词时,进行统计*/,程序设计-2005年秋,25,字符数组和字符串应用样例-3(续),#include void main()char c,line120;int i,words,inword,letter;words=0;inword=0;/*预置状态不在单词中*/printf(Input a line.n);gets(line);for(i=0;linei;i+)c=linei;letter=(c=a,输入字符行,统计其中单词个数。约定单词由英文字母组成,其它字符只是用来分隔单词,程序设计-2005年秋,26,字符数组和字符串应用样例-4,#include#include#define MAXLINE 256void main()int len,max;char line MAXLINE,save MAXLINE;max=0;for(;)printf(“输入字符行(回车结束).n);gets(line);if(len=strlen(line)=0)break;if(len max)max=len;strcpy(save,line);if(max 0)printf(“最长行是:n%sn,save);,读入一串字符行,以空行(即只键入回车符的行)结束,输出其中最长的行,程序设计-2005年秋,27,字符数组和字符串应用样例-5,描绘图像 r()=sin(2)程序设计分析用字符在显示屏上描绘 r=r()图像的一般方法当变化时,r()描绘出一个封闭平面图,用一个二维字符数组代表图像r()的画面,可定义为 char canvas 2480;普通显示屏在25mm(一英寸)见方的区域上纵向 5.5 行,横向约10列。按这个比例设定X、Y的比例。约定屏幕左上角的字符位置对应canvas00,图像坐标系的原点位于 canvas1240取0到360范围内的值,步长为1。对于具体函数,应充分利用函数图像对称性:X 轴对称、Y 轴对称、关于原点中心对称等,程序设计-2005年秋,28,字符数组和字符串应用样例-5(续),描绘图像 r()=sin(2)(续)程序设计分析(续)描绘图像程序的算法结构 置画面数组为全空白符;for(seta=0;seta 360;seta+)alpha=seta/180.0*pi;r=r(seta)*scale;x=r*cos(alpha);y=r*sin(alpha);i=12-(int)(0.55*y);/*屏幕的行号递增方向与图像 Y 轴的方向相反*/j=40+x;canvasij=*;,程序设计-2005年秋,29,字符数组和字符串应用样例-5(续),#include#include#define SCALE 20.0#define MID 12#define PI 3.14159#define RATE 0.55void main()char canvas2*MID80;double r,alpha,x,y;int i,j,seta;for(i=0;i 2*MID;i+)for(j=0;j 80;j+)canvasij=;,描绘图像 r()=sin(2)(续)对于本题,scale 可定义为20。以下程序利用图像关于X 轴、Y轴及关于直线Y=X的对称性,for(i=0;i2*MID;i+)canvasi79=0;for(seta=0;seta45;seta+)alpha=seta/180.0*PI;r=sin(2*alpha)*SCALE;x=r*cos(alpha);y=r*sin(alpha);i=(int)(RATE*y);j=(int)(x);,程序设计-2005年秋,30,字符数组和字符串应用样例-5(续),canvasMID+i40+j=/*X 轴对称*/canvasMID+i40-j=/*中心对称*/canvasMID-i40-j=/*Y轴对称*/canvasMID-i40+j=*;/*本身图像点*/i=(int)(RATE*x);/*关于直线X=Y 对称*/j=(int)(y);canvasMID+i40+j=/*X 轴对称*/canvasMID+i40-j=/*中心对称*/canvasMID-i40-j=/*Y轴对称*/canvasMID-i40+j=*;/*本身图像点*/for(i=0;i 2*MID;i+)puts(canvasi);,描绘图像 r()=sin(2)(续)对于本题,scale 可定义为20。以下程序利用图像关于X 轴、Y轴及关于直线Y=X的对称性,程序设计-2005年秋,31,数组的基本概念一维数组多维数组字符数组和字符串指针和数组,提要,程序设计-2005年秋,32,指针和数组,指向数组元素的指针当指针变量指向数组的元素时,就可用指针引用数组的元素设有以下变量定义int a100,*p;赋值运算 p=&a0使p指向a0表示&a0还有更简洁的方法,即数组名a让指针指向数组元素,不仅为引用数组元素提供了一种新的途径,更主要的是指向数组元素的指针所具有的运算能力,特别适宜描述对数组元素的成批处理,比用下标引用数组元素更灵活和简洁,程序设计-2005年秋,33,指向数组元素的指针,对指向数组元素的指针允许作有限的运算设有以下代码 int*p,*q,a100;p=当两个指针指向同一个数组的元素时,这两个指针可以作关系比较(,=,!=)若两指针p和q指向同一个数组的元素,则p=q为真表示p,q指向数组的同一个元素;若pq为真,表示p所指向的数组元素的下标小于q所指向的数组元素的下标。如对上述代码pq为真,程序设计-2005年秋,34,指向数组元素的指针(续),对指向数组元素的指针允许作有限的运算(续)指向数组元素的指针可与整数进行加减运算由数组元素在内存中顺序连续存放的规定,以及地址运算规则,表达式a+1为a1 的地址,a+2为a2的地址。一般地,表达式a+i为 ai 的地址。把这个结论应用于指向数组元素的指针,同样地成立若p的值为a0的地址,则表达式p+i的值为ai的地址。或者说,p+i的值为指向ai的指针值。若p指向数组元素a10,则p+n就表示指向数组元素a10+n,这里n是任意的整数表达式C语言约定,当指针变量指向数组a的元素时,不论数组元素的类型是什么,指针和整数n进行加减运算时,总是根据所指元素的数据存储字节长度sizeof a0,对n放大,保证加减n,使指针值向前或向后移动n个元素位置,程序设计-2005年秋,35,指向数组元素的指针(续),对指向数组元素的指针允许作有限的运算(续)当两个指针指向同一个数组的元素时,允许两个指针作减法运算。其绝对值等于两指针所指数组元素之间相差的元素个数利用运算符*可引用指针所指对象,*(a+i)表示引用a+i所指向的数组元素ai。这样*(a+i)就是ai。对于指向数组元素的指针变量p,若p指向a10,*(p+i)表示引用p+i所指向的数组元素a10+i与用数组名和下标引用数组元素的标记法相一致,指向数组元素的指针变量也可带下标引用数组的元素,即*(p+i)也可写成pi若p=&a10,则pi引用的是a10+i,p-2引用的是a8,程序设计-2005年秋,36,int a8;a 0 int*p=a+1;1 p a+i i p+i(=a+i+1)7 指向数组元素的指针与数组元素位置之间的关系,指向数组元素的指针(续),程序设计-2005年秋,37,指向数组元素的指针(续),引用数组元素有以下三种形式用数组元素的下标引用数组元素,如a5利用数组名表达式的值是数组首元素指针的约定,以指针表达式引用表达式所指的元素,如*(a+i)=ai利用指向数组元素的指针变量,用它构成指向数组元素的指针表达式,并用该表达式引用数组元素。如*(p+i)或pi注:用数组名a表达数组元素指针与用指向数组元素的指针p来表达数组元素的指针,在实际应用上有区别p是变量,其值可改变,如p+;数组名a只代表数组a的首元素的指针,是不可改变的,程序只能把它作为常量使用,程序设计-2005年秋,38,指向数组元素的指针样例-1,以下代码利用指针遍历数组,输入生成一个数组和将已知数组复制到另一个数组int a100,b100,*p,*q;for(p=a;p a+100;)scanf(”%d”,p+);for(p=a,q=b;p a+100;)*q+=*p+;,程序设计-2005年秋,39,指向数组元素的指针样例-2,#include int a=1,2,3,4;void main()int j,*p;for(j=0;j 4;j+)printf(”a%dt=%dt”,j,aj);printf(”n”);for(p=a;p=,下面是说明引用数组元素各种不同方法的示意程序,for(p=a,j=0;p+j=0;j-)printf(”p-%dt=%dt”,j,p-j);printf(”n”);,程序设计-2005年秋,40,指向字符串的指针,为字符串常量提供存储空间有两种方法把字符串常量存放在一个字符数组中例如,char s=I am a string.;由编译系统将字符串常量与程序中出现的其他常量一起存放在常量存储区中例如,char*cp1,*cp2=I am a string;cp1=”Another string”;程序为了能访问存于常量存储区中的字符串常量,可用一个字符指针指向它的第一个字符当字符串常量出现在表达式中时,系统将字符串常量放入常量存储区,而把表达式转换成该字符串常量存储单元的第一个字符的字符指针,程序设计-2005年秋,41,指向字符串的指针(续),系统预定义许多用于字符串处理的库函数,程序可以用字符串常量或指向某字符串的指针调用这些库函数如调用库函数strlen()求一字符串常量的长度 strlen(I am a string.)该函数调用的结果是14,表示此字符串常量由14个有效字符组成如s是一个字符数组,其中已存有字符串;cp是一个字符指针变量,它指向某个字符串的首字符,则代码:printf(“%sn”,s);输出存于字符数组s中的字符串代码:printf(%sn,cp);输出字符指针变量cp所指向的字符串,程序设计-2005年秋,42,指向字符串的指针示例-1,将一个已知字符串复制到一个字符数组,设from为已知字符串的首字符指针,to为存储复制字符串的字符数组首元素的指针若用下标引用数组元素标记法,完成复制的代码可写成 k=0;while(tok=fromk)!=0)k+;如采用字符指针描述有 while(*to+=*from+)!=0);由于字符串结束符0的值为0,上述测试当前复制字符不是字符串结束符的代码中,“!=0”是多余的,字符串复制更简洁写法是 while(*to+=*from+);,程序设计-2005年秋,43,指向字符串的指针示例-2,将字符串s中的某种字符去掉,设要去掉的字符与字符变量c中的字符相同采用一边考察字符一边复制引入两个字符指针p和q,p指向当前正考察的字符,q指向下一个用于存储复制字符的位置若p所指字符与c不相同,则将它复制到新字符串否则,该字符不被复制每复制一个字符q才增1,p是每考察一个字符就增1 for(p=q=s;*p;p+)if(*p!=c)*q+=*p;/*复制*/*q=0;/*重新构成字符串*/,程序设计-2005年秋,44,指向数组的指针,如果有一个二维数组,且指针变量所指的是二维数组中的一整行,则指针变量另有一些很有意义的性质设二维数组为int a34=1,2,3,4,5,6,7,8,9,10,11,12;这里,数组a有3行4列。按行来看数组a,数组a有三个元素,分别为a0,a1,a2。它们又分别是一个一维数组,各有4个元素例如,a0所代表的一维数组为 a00、a01、a02、a03,程序设计-2005年秋,45,指向数组的指针(续),二维数组,且指针变量指的是二维数组中一整行(性质续)与一维数组名可看作数组的第一个元素(下标为 0)的地址的约定相一致,二维数组名a可以看作a的首元素a0的地址,即表示二维数组第一行的首地址。一般地,a+i可以看作数组a的元素ai的地址,即二维数组第i+1行的首地址因二维数组a能用a0,a1,a2分别表示其中的一维数组,所以a0能表示用a0表示的一维数组的首元素a00的地址;a1能表示用a1表示的一维数组的首元素a10的地址一般地,ai能表示用ai表示的一维数组的首元素ai0的地址,程序设计-2005年秋,46,指向数组的指针(续),二维数组,且指针变量指的是二维数组中一整行(性质续)由于数组的开始地址与数组首元素的地址相同,a+i与ai应有相同的值,但它们的意义不同,a+i表示用ai表示的一维数组的首地址,ai表示用ai表示的一维数组的首元素ai0的地址另外,因ai可写成*(a+i),所以a+i 与*(a+i)也有不同意义,而值相等。ai或*(a+i)表示二维数组a的元素ai0的地址,即&ai0根据地址运算规则,ai+j即代表数组a的元素aij的地址,即&aij。因ai与*(a+i)等价,所以*(a+i)+j也与&aij等价,程序设计-2005年秋,47,指向数组的指针(续),二维数组,且指针变量指的是二维数组中一整行(性质续)数组元素aij有以下三种等价表示形式:*(ai+j)、*(*(a+i)+j)、(*(a+i)ja00,等价表示形式有:*a0 和*a数组元素aij的地址也有三种等价表示形式ai+j、*(a+i)+j、定义为一个指针数组p,即p有四个元素,每个元素是一个指向整型变量的指针,程序设计-2005年秋,48,指向数组的指针(续),二维数组,且指针变量指的是二维数组中一整行(性质续)定义:int(*p)4;中的p不同于指向整型变量的指针。指向整型变量的指针变量指向整型数组的某个元素时,指针增减1运算,表示指针指向数组的下一个或前一个元素p是一个指向由四个整型元素组成的数组,对p作增减1运算,就表示向前进或向后退四个整型元素如有变量定义:int a34,(*p)4;p=a;使p指向二维数组a的第1行p+1的指针值为指向二维数组a的第二行若p=a,则p+i指向二维数组a的第i+1行,与a+i一样同二维数组元素的地址计算规则相对应,*p+j指向a0j;*(p+i)+j,或者pi+j指向数组a的元素aij,程序设计-2005年秋,49,指向数组的指针示例,说明指向数组元素的指针和指向数组的指针区别的示意程序,#include void main()int a34=1,3,5,7,9,11,13,15,17,19,21,23;int i,*ip,(*p)4;p=a+1;ip=p0;for(i=1;i=4;ip+=2,i+)printf(%dt,*ip);printf(n);,p=a;for(i=0;i 2;p+,i+)printf(%dt,*(*(p+i)+1);printf(n);程序运行后,将输出 9 13 17 21 3 19,程序设计-2005年秋,50,a 0 1 2 3 p-1a+0 a0 a+1 a1 a+2 a2+0+1+2+3 p1或*(p+1),指向数组的指针,二维数组名和指向数组的指针与数组元素位置之间的关系,int a34;,int(*p)4=a+1,p+1,程序设计-2005年秋,51,指针数组,当数组元素类型为某种指针类型时,该数组就称为指针数组指针数组的定义形式为 类型说明符*数组名常量表达式;其中常量表达式是一个整型的,是数组的长度说明,用于指明数组元素的个数;类型说明符指明指针数组的元素指针能指向的对象的类型。数组名之前的“*”是必需的,由于它出现在数组名之前,使该数组成为指针数组例如,int*p10;定义指针数组p的每个元素都能指向int型数据的指针变量,有十个元素:p0、p1、p9。和一般的数组定义一样,数组名p也可作为p0的地址,程序设计-2005年秋,52,指针数组(续),在指针数组的定义形式中,由于“”比“*”的优先级高,使数组名先与“”结合,形成数组,然后再与数组名之前的“*”结合,表示数组元素是指针类型的注意,在“*”与数组名之外不能加上圆括号,否则变成指向数组的指针变量如,int(*q)10;是定义指向由10个int型元素组成的数组的指针引入指针数组的主要目的是便于统一管理同类的指针如利用指针数组能实现对一组独立的变量以数组的形式对它们作统一处理,程序设计-2005年秋,53,指针数组(续),如有以下定义 int a,b,c,d,e,f;int*apt=/*其中*aptk可写成*(apt+k)*/下面的两个程序实现将一组独立的变量输入它们的值,排序后输出。前一个程序排序时交换变量的值,后一个程序排序时交换它们的指针,程序设计-2005年秋,54,指针数组示例-1,排序时交换变量值,#include#define N sizeof ap/sizeof ap0int a,b,c,d,e,f;void main()int*ap=/*scanf(“%d”,*(apt+k)*/,for(k=1;k*apj+1)t=*apj;/*交换变量的值*/*apj=*apj+1;*apj+1=t;for(k=0;k N;k+)printf(“%dt”,*apk);printf(“nn”);,程序设计-2005年秋,55,指针数组示例-2,排序时不交换变量的值,而是交换它们的指针,#include#define N sizeof ap/sizeof ap0int a,b,c,d,e,f;void main()int*ap=,for(k=1;k*apj+1)t=apj;/*交换变量的指针*/apj=apj+1;apj+1=t;for(k=0;k N;k+)printf(“%dt”,*apk);printf(“nn”);,程序设计-2005年秋,56,指针数组示例-3,从文件输入字符行,对输入的字符行排序后输出到另一文件中。设文件字符行的行数不超过500行,每行字符不超过80个字符,#include#include#define LINES 500#define Nline 80FILE*fp;char rfname40,wfname40;char linesLINESNline+1;char*lptrLINES;void main()int n,i,j;char*t;printf(输入文件名?n);scanf(%s%*c,rfname);if(fp=fopen(rfname,r)=NULL)printf(不能打开输入文件%sn,rfname);return;,程序设计-2005年秋,57,指针数组示例-3(续),n=0;while(n 0)t=lptri;lptri=lptri+1;lptri+1=t;printf(输出文件名?n);scanf(%s%*c,wfname);fp=fopen(wfname,”w”);,从文件输入字符行,对输入字符行排序后输出到另一文件(续),for(i=0;i n;i+)fprintf(fp,%s,lptri);fclose(fp);printf(nnn);for(i=0;i n;i+)printf(%s,lptri);printf(nnn);,程序设计-2005年秋,58,指针数组(续),当指针数组的元素分别指向两维数组各行首元素时,也可用指针数组引用两维数组的元素以下代码说明指针数组引用两维数组元素的方法 int a1020,i;int*b10;for(i=0;i 10;i+)bi=/*bi指向数组元素ai0*/则表达式aij与表达式bij引用同一个元素,即从指针数组方向来看,因bi指向元素ai0,*(bi+j)或bij引用元素aij,程序设计-2005年秋,59,指针数组(续),当指针数组的元素指向不同的一维指针数组的元素时,也可通过指针数组,把它们当作两维数组那样来引用如以下代码所示 char w0=“Sunday”,w1=“Monday”,w2=“Tuesday”,w3=“Wednesday”,w4=“Thursday”,w5=“Friday”,w6=“Saturday”;char*wName=w0,w1,w2,w3,w4,w5,w6;则语句 for(i=0;i=6;i+)printf(“%sn”,wNamei);输出星期英文名称。wName24引用字符w24,其值为d,程序设计-2005年秋,60,指针数组程序例,#include#define N 8int pN*(N+1)/2,i,j,*ptN;void main()for(pt0=p,i=1;i N;i+)pti=pti-1+i;for(i=0;i N;i+)pti0=ptii=1;for(j=1;j i;j+)ptij=pti-1j-1+pti-1j;for(i=0;i N;i+)printf(%*c,40-2*i,);for(j=0;j=i;j+)printf(%4d,ptij);printf(n);,以下例子程序把一维数组分割成不等长的段,从指针数组方向来看,把它当作两维数组来处理,程序产生如下形式的二项式的系数三角形 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 1 7 21 35 35 21 7 1,程序设计-2005年秋,61,多级指针,当指针变量pp所指变量ip又是一种指针时,pp是一种指向指针的指针,称指针变量pp是一种多级指针定义指向指针变量的指针变量的一般形式为 类型说明符*变量名;首先定义变量为指针变量,其次是该变量能指向一种指针对象,最后是被指向的指针对象能指向的对象的类型例如,int*pp,*ip,i;ip=定义说明pp是指向指针的指针变量;它能指向的是这样一种指针对象,该指针对象是能指向int型的指针变量。如上述代码让pp指向指针变量ip,ip指向整型变量i,程序设计-2005年秋,62,多级指针(续),多级指针与指针数组有密切的关系若有指针数组char*lines=“ADA”,“ALGOL”,“C”,“C+”,“FORTRAN”,“PASCAL”;则lines指针数组的每个元素分别指向以上字符串常量的首字符。在这里数组名lines可以作为它的首元素lines0的指针,lines+k是元素linesk的指针linesk也是指针,表达式lines+k的值是一种指针的指针如有必要还可引入指针变量cp,让它指向数组lines的某元素,如cp=,程序设计-2005年秋,63,多级指针(续),对于指向字符指针的指针变量的定义 char*cp;为了定义这样的cp,它的前面有两个*号由于*自右向左结合,首先是“*cp”表示cp是指针变量,再有*cp表示cp能指向的是某种指针类型,最后“char*cp”表示指针变量cp能指向字符指针数据对象如果有赋值cp=&lines1,让它指向数组元素lines1,则*cp的表示引用lines1,它也是一个指针,指向字符串“ALGOL”的首字符。如再引用指针*cp所指内容,有*cp表示引用lines10,其值是字符A,程序设计-2005年秋,64,多级指针示例,下面代码实现顺序输出指针数组lines各元素所指字符串 for(cp=lines;cp lines+6;cp+)printf(”%sn”,*cp);下面代码是采用”%c”格式,逐一输出字符串字符,实现顺序输出指针数组lines各元素所指的字符串 for(i=0;i 6;i+)/*设i 和j是int类型*/for(j=0;linesij!=0;j+)printf(”%c”,linesij);printf(”n”);,程序设计-2005年秋,65,多级指针示例(续),设有数组a和指针数组pt有以下代码所示的关系 int a=2,4,6,8,10;int*pt=上例说明指针的指针与指针数组有密切关系,指向指针数组元素的指针即为指针的指针,如以上程序中的指针变量p上述代码首先让它指向指针数组的首元素,然后循环让它顺序遍历指向指针数组的各元素,表记*p能引用p所指的数组元素,*p能引用p所指数组元素所指的变量。程序中用*p访问数组a的元素,程序设计-2005年秋,66,本讲小结,字符数组和字符串字符数组、字符串、字符串处理函数指针和数组指向数组元素的指针、指向字符串的指针指向数组的指针、指针数组、多级指针,程序设计-2005年秋,67,第四章结束(小结),数组的基本概念一维数组多维数组字符数组和字符串指针和数组,