《新编C语言程序设计教程》课件第8章_第1页
《新编C语言程序设计教程》课件第8章_第2页
《新编C语言程序设计教程》课件第8章_第3页
《新编C语言程序设计教程》课件第8章_第4页
《新编C语言程序设计教程》课件第8章_第5页
已阅读5页,还剩93页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第8章数组类型8.1一维数组8.2二维数组与多维数组8.3字符数组与字符串8.4重命名类型8.5程序设计举例8.1一维数组8.1.1一维数组的定义形式:存储类别类型标识符数组名[常量];类型标识符描述的是数组分量的类型,是定义数组类型的基类型,可以是任何类型。数组名代表数组所占存储空间的首地址。常量表示数组的大小(长度),即数组中分量的个数。与PASCAL语言不同,以上实际定义的是数组量,而非数组类型,数组类型隐含其中。提到数组,可能是指数组量,也可能是指数组类型,注意根据上下文区分。例如,定义数组,描述下列数据:(1)100个整数:intnum[100];(2)1000个学生C语言课程的成绩:floatccj[1000];(3)一年中每月的天数:intmonth[12];(4)100种商品的价格:floatprice[100];(5)500个字符类型的数据:charch[500];

说明:

(1)数组名命名规则和变量名命名规则相同,都遵循标识符命名规则。

(2)数组的长度可以用符号常量描述,但不能用变量描述,C语言不提供动态数组。

(3)数组以线性方式将数组分量依次存储,所占空间等于各分量所占空间之和,即数组分量个数乘以基类型数据所占空间。数组名代表存放数组的首地址。8.1.2一维数组的引用

下标变量的形式为:数组名[下标表达式]

例如,对以上定义的num数组、ccj数组:

num数组的100个分量为num[0]、num[1]、…、num[i]、…、num[99],每个分量存放一个整数,num[i]相当于一个int型变量。

ccj数组的1000个分量为ccj[0]、ccj[1]、…、ccj[i]、…、ccj[999],每个分量对应一个学生的成绩,ccj[i]相当于一个float型变量。

说明:

(1)下标的取值范围从0到数组长度减1。

(2)下标变量相当于基类型变量,能进行基类型量的一切运算操作。

(3)下标往往对应于循环控制变量,通过循环、通过下标的变化完成对数组所有分量的操作,即完成对整个数组的操作。

(4)下标往往对应特定的含义。

(5)对于下标出界,C语言不进行语法检查,务请小心。(6)如果希望下标为i的分量对应第i个数据,可将定义的数组大小增1。例如:intnum[101];

floatccj[1001];

100个整数用num数组的分量num[1]、num[2]、…、num[100]描述,num[i]对应于第i个整数。

1000个学生的C语言成绩用ccj数组的分量ccj[1]、ccj[2]、…、ccj[1000]描述,ccj[i]对应于第i个学生的成绩。下标为0的分量未使用。8.1.3一维数组的初始化数组的初始化可以在执行时进行,也可以在编译阶段进行。执行时初始化可通过赋值运算或赋值语句、或输入函数进行,但只能对数组分量进行,要占用运行时间。例如:输入数据给数组num、ccj。for(i=0;i<101;i++)scanf("%d",&num[i]);for(i=0;i<1001;i++)scanf("%f",&ccj[i]);对静态存储数组和外部存储数组,数组的初始化可以在编译阶段进行,即在程序运行之前初始化,节约运行时间。初始化形式:存储类别类型数组名[常量]={常量1,常量2,…,常量n};各分量依次初始化为常量1、常量2、…、常量n。注意初始化数据必须用花括号括起。例如:①staticintmonth[12]={31,29,31,30,31,30,31,31,30,31,30,31};则month[0]=31,month[1]=29,month[2]=31,…,month[12]=31。②staticcharch[5]={'a','e','i','o','u'};则ch[0]='a',ch[1]='e',ch[2]='i',ch[3]='o',ch[4]='u'。说明:

(1)对静态存储数组和外部存储数组,默认初值为0。

(2)可以只给一部分数组分量初始化。例如:staticinta[50]={70,75,60,80,90};相当于a[0]=70,a[1]=75,a[2]=60,a[3]=80,a[4]=90,没有给定初值的分量取默认初值。

(3)若对数组中所有分量给定了初值,则定义数组时可以不给出数组长度。数组的长度为给出的初值个数。例如:staticfloatx[ ]={1.5,2.5,3.5,4.5,5.5};给了数组5个初值,则数组长度为5。

(4)若仅给数组部分分量初值,则不能省略数组长度。例8–1

求10个数的最大值与最小值,10个数用数组描述。程序如下:/*程序8-1,求10个数的最大值与最小值*/main( ){floata[10];/*存放10个数的数组*/inti;floatmax=−1e20,min=1e20;for(i=0;i<=9;i++)/*输入10个数到数组*/scanf("%f",&a[i]);for(i=0;i<=9;i++)/*求最大值与最小值*/{if(a[i]>max)max=a[i];

if(a[i]<min)min=a[i];

}for(i=0;i<=9;i++)/*输出数组中的10个数*/printf("%8.2f",&a[i]);printf("\n最大值=%f,最小值=%f",max,min);}

例8–2

求某班50个学生C语言课程的平均成绩及每个学生与平均成绩之差。算法提示:

(1)50个学生C语言课程的成绩及每个学生与平均成绩之差都是大量类型相同的数据,可分别用一个一维数组作整体描述。

(2)下标为0的分量没有使用,同时用下标对应学号。

(3)数组的整体操作转化成对数组分量进行,其实就是将对50个学生的成绩处理转化成对每个学生进行。/*程序8-2,求C语言课程的平均成绩及每个学生与平均成绩之差*/main( ){floatccj[51];/*C语言成绩数组*/inti;floattcj=0.0;/*总成绩*/floatav,cav[51];/*平均成绩av,与平均成绩之差数组cav*//*输入学生成绩*/for(i=1;i<=50;i++){printf("请输入第%d个学生成绩:",i);

scanf("%f",&ccj[i]);

}/*求总成绩、平均成绩*/for(i=1;i<=50;i++)tcj+=ccj[i];av=tcj/50;/*求与平均成绩之差*/for(i=1;i<=50;i++)cav[i]=ccj[i] −av;/*输出*/printf("C语言课程的平均成绩=%5.2f\n",av);for(i=1;i<=50;i++)printf("第%d个学生与平均成绩之差=%5.2\n",i,cav[i]);}

例8-3

用一维数组求Fibonacci数列前20项,要求每行输出5个数。/*程序8-3,求Fibonacci数列前20项*/main(){staticinta[20]={1,1};/*存放Fibonacci数列前20项的数组*/inti;for(i=2;i<20;i++)

f[i]=f[i-1]+f[i-2];printf(″Fibonacci数列前20项如下:\n″);for(i=2;i<20;i++)

{printf(″%8d″,f[i]);

if(i%5==0)printf(″\n″);/*if语句用来控制换行*/}}/*程序8-3,求Fibonacci数列前20项*/main(){staticinta[20]={1,1};/*存放Fibonacci数列前20项的数组*/inti;

for(i=2;i<20;i++)

f[i]=f[i-1]+f[i-2];

printf(″Fibonacci数列前20项如下:\n″);

for(i=2;i<20;i++)

{printf(″%8d″,f[i]);

if(i%5==0)printf(″\n″);/*if语句用来控制换行*/}}运行结果:Fibonacci数列前20项如下:

112358132134558914423337761098715972584418167658.1.4一维数组作函数参数

数组作函数参数有数组元素作函数参数和整个数组作函数参数两种情况。数组元素作函数参数只能是作函数的实参,与基类型变量作函数一样处理。整个数组作函数参数,此时实参与形参都应用数组名或后介绍的指针量,而且基类型应该一致。整个数组作函数参数,传递的是数组的首地址,即将实参数组的首地址传递给形参数组,形参数组与实参数组共享存储单元。在函数中改变了形参数组的值,实参数组将同时改变,因而数据是双向传递的。例8-4

将例8-2中求C语言课程平均成绩改用函数实现。函数如下:floatavf(xcj)/*求C语言课程平均成绩*/floatxcj[51];{inti;

floatsum=0.0,tav;

for(i=1;i<=50;i++)

sum+=xcj[i];

tav=sum/50;

return(tav);}

主函数中调用函数avf()来求平均成绩:av=avf(ccj);此时,实参数组为ccj,对应的形参数组为xcj,调用时将实参数组ccj首地址传递给形参数组xcj。请注意本例中数组的第一个分量ccj[0]、xcj[0]无意义。对形参数组可以不指定数组大小,在定义数组时数组名后跟空的中括号。在函数中另设一个参数,传递数组元素的个数。如此在函数中实现变相动态数组。

例8-5

将上例中函数延伸考虑为求n个学生C语言课程平均成绩。函数如下:floatavf(xcj,n)/*求n个学生C语言课程平均成绩*/floatxcj[],n;{inti;

floatsum=0.0,tav;

for(i=1;i<=n;i++)

sum+=xcj[i];

tav=sum/n;

return(tav);}

例8-2求50个学生C语言课程平均成绩可用如下函数调用:

av=avf(ccj,50);最后请注意一点,C语言编译系统对形参数组大小不作检查。如果形参数组小于实参数组,这时形参数组得到实参数组的部分值。如果希望形参数组得到实参数组的全部值,则应指定形参数组不小于实参数组。8.2二维数组与多维数组8.2.1二维数组的定义

形式:存储类别类型标识符数组名[常量1][常量2];

n维数组的定义形式:存储类别类型标识符数组名[常量1][常量2]…[常量n];类型标识符描述的同样是数组分量的类型,是定义数组类型的基类型,它可以是任何类型。数组名代表数组所占存储空间的首地址。常量分别表示数组相应维的大小,数组分量个数等于常量1、常量2、…、常量n之积。(1)上述100个班,每班50个学生一门课程的成绩,定义如下二维数组描述:

floatcj[100][50];/*第一维对应班级,第二维对应学生*/(2)1000个学生,30门课程的成绩,定义如下二维数组描述:

floatacj[1000][30];/*第一维对应学生,第二维对应课程*/(3)上述某高校社会实践调查数据,定义如下三维数组描述:intb[3][2][3];/*第一维对应年级,第二维对应性别,第三维对应交通工具*/

说明:

(1)二维数组相当于用一张表格描述数据,第一维对应表格的行,第二维对应表格的列。

(2)二维数组以线性代数中的矩阵作为典型数学背景,矩阵在程序中用二维数组描述。

(3)二维数组还可看成由一维数组拓展而来,相当于一个基类型为一维数组的一维数组。例如,二维数组cj相当于基类型为floatx[50]、具有100个分量的一维数组。(4)对于多维数组,同样可看成由低维数组拓展而来。

(5)多维数组同样将数组各分量依次连续存储,即按下标1、下标2、…、下标n存储,所占空间等于各分量所占空间之和,即数组分量个数乘以基类型数据所占空间。对于二维数组,也就是按行、按列存储。数组名代表存放数组的首地址。8.2.2二维数组的引用二维数组下标变量的形式为:数组名[下标表达式1][下标表达式2]多维数组下标变量的形式为:数组名[下标表达式1][下标表达式2] … [下标表达式n]例如,以上定义的acj数组的3000个分量为:acj[0][0]、acj[0][1]、…、acj[0][29]acj[1][0]、acj[1][1]、…、acj[1][29],

acj[999][0]、acj[999][1]、…、acj[999][29]…

说明:

(1)每个下标的取值范围从0到数组长度减1,下标变量同样相当于基类型变量。

(2)对于多维数组整体操作的完成需用多重循环,一个下标对应于一重循环控制变量。二维数组的整体操作用两重循环完成,外重循环对应下标1,内重循环对应下标2。

(3)其它类似于一维数组处理。8.2.3二维数组的初始化

初始化形式:存储类别类型数组名[下标1][下标2]={常量1,常量2,…,常量n};例如:staticinta[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};初始化的结果是:a[0][0]=1,a[0][1]=2,a[0][2]=3,a[0][3]=4,a[1][0]=5,a[1][1]=6,a[1][2]=7,a[1][3]=8,a[2][0]=9,a[2][1]=10,a[2][2]=11,a[2][3]=12

说明:

(1)二维数组的初始化可以分行进行。例如,上面的a数组初始化还可以表示为:

staticinta[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};而定义4行3列的b数组可以表示为:

staticintb[4][3]={{1,2,3},{4,5,6},{7,8,9},{10,11,12}};(2)可以只对数组中部分分量进行初始化。例如:staticinta[3][4]={{1,2},{5},{9}};初始化的结果是:

a[0][0]=1,a[0][1]=2,a[1][0]=5,a[2][0]=9,其它分量初值取默认值,为0。(3)如果对二维数组中全部元素初始化,则定义数组时第一维的长度可以省略,但第二维的长度不能省略。例如:

staticinta[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};可以写成

staticinta[][4]={1,2,3,4,5,6,7,8,9,10,11,12};但不能写成

staticinta[][]={1,2,3,4,5,6,7,8,9,10,11,12};因为两个维数都省略时,可以理解为1*12、12*1、3*4、4*3、2*6、6*2等多种形式,会发生混淆,故只能省略第一个维数。(4)如果对二维数组按行进行初始化, 则定义数组时第一维的长度也可以省略。例如:

staticinta[][4]={{1,2},{5},{9}};二维数组与多维数组作函数参数跟一维数组作函数参数类同处理,但对形参数组,只有第一维的大小可以省略,第二维及其它高维的大小均不能省略。

例8-6

从键盘输入50个学生8门课程成绩,求每个学生的总成绩与平均成绩。/*程序8-6,求总成绩及平均成绩*/main(){floatcj[51][9];

inti,j;

floattcj[51],acj[51];

voidtcjf();

voidacjf();

for(i=1;i<=50;i++)/*输入成绩*/{printf(″请输入第%d个学生8门课程成绩:″,i);

for(j=1;j<=8;j++)

scanf(″%f″,&cj[i][j]);

}tcjf(cj,tcj);/*调用函数tcjf()求总成绩*/acjf(tcj,acj);/*调用函数acjf()求平均成绩*/printf(″所求学生总成绩与平均成绩如下:\n″);/*输出处理结果*/for(i=1;i<=50;i++)

printf(″第%d个学生总成绩=%6.2f,平均成绩=%5.2f\n″,tcj[i],acj[i]);}voidtcjf(xcj,xtcj)/*求总成绩函数*/floatxcj[51][9],xtcj[51];{inti,j;

for(i=1;i<=50;i++)

for(xtcj[i]=0.0,j=1;j<=8;j++)

xtcj[i]+=xcj[i][j];

}voidacjf(xtcj,xacj)/*求平均成绩*/floatxtcj[51],xacj[51];{inti;

for(i=1;i<=50;i++)

xacj[i]=xtcj[i]/8;}例8-7

编写程序,计算两个3×4的整数矩阵之和。算法提示:(1)两个3×4的矩阵用两个二维数组a、b描述。(2)和亦是一个3×4的矩阵,同样用一个二维数组c描述。

(3)和矩阵元素等于矩阵对应元素之和。/*程序8-7,求两个3×4的矩阵之和*/main(){inta[3][4],b[3][4];

inti,j;

intc[3][4];

for(i=0;i<3;i++)/*输入矩阵a*/for(j=0;j<4;j++)

scanf(″%d″,&a[i][j]);

for(i=0;i<3;i++)/*输入矩阵b*/for(j=0;j<4;j++)

scanf(″%d″,&b[i][j]);

for(i=0;i<3;i++)/*计算矩阵c*/ for(j=0;j<4;j++) c[i][j]=a[i][j]+b[i][j];printf("所求和矩阵为:\n");for(i=0;i<3;i++)/*输出矩阵c*/{for(j=0;j<4;j++)printf("%6d",c[i][j]);

printf("\n");

}}输入数据:111111111111 222222222222运行结果:所求和矩阵为:

3333333333338.3字符数组与字符串8.3.1字符数组1.字符数组的定义

字符数组的定义和上面讲述的数组定义形式完全一样,只是字符数组的基类型为特定的字符类型。例如:

charch1[10],ch2[3][4],ch3[2][3][4];

定义了一个一维字符数组ch1,含有10个元素;定义了一个二维字符数组ch2,含有12个元素;定义了一个三维字符数组ch3,含有24个元素。2.字符数组的引用字符数组的引用通过字符数组的下标变量进行。字符数组的下标变量相当于字符类型的变量。

3.字符数组的初始化对于字符数组的初始化,最易理解的方式是将字符一一赋给字符数组分量,或整体作为字串处理。如果只给字符数组的一部分分量初始化,那么没有给出值的字符数组分量取默认初值空格字符。例如:①staticcharcity[8]={'c','h','a','n','g','s','h','a'};②charcity[8];city[0]='c',city[1]='h',city[2]='a',city[3]='n',city[4]='g';city[5]='s',city[6]='h',

city[7]='a';8.3.2字符串

注意:

(1)字符串数据用双引号表示,而字符数据用单引号表示。

(2)字符串的长度可以根据串中字符的个数临时确定,而字符数组的长度必须事先给定。

(3)对于字符串,系统在串尾加'\0'作为其结束标志,而字符数组并不要求最后一个字符是'\0'。(4)用字符数组来处理字符串时,字符数组的长度应比要处理的字符串长度大1,以存放串尾结束符'\0'。例如:

staticcharcity[9]={'c','h','a','n','g','s','h','a','\0'};用字符串描述为:

staticcharcity[9]={''changsha''}或 ''changsha'';以上两条语句可分别理解为用字符数组来处理字符串,用字符串对字符数组初始化。

(5)千万不能在程序中给字符数组赋值。例如:

city=''changsha'';/*绝对错误*/1.输入/输出输入/输出分别用scanf( )、printf( )函数完成,采用“%s”格式。输入、输出参数用字符数组名。例如,有如下程序:

main( ){charcomp[9];

scanf("%s",comp);/*本身就是地址,不需加地址运算符*/printf("COMP=%s",comp);}输入数据:CHINAONE

运行结果:COMP=CHINAONE

说明:

(1)输入字符串数据时不需用界定符。

(2)输入多个字符串数据时,以空格分隔数据。如果字符串数据本身包含有空格字符,需使用gets()函数。

(3)输出时先找到存放字符串的字符数组的首地址,遇串尾结束符'\0'结束。输出字符不包括串尾结束符'\0'。

(4)如果字符数组中包含多个'\0',则输出遇到第一个'\0'时结束。

(5)如果字符数组长度大于字符串实际长度,也只输出到'\0'结束。2.字符串处理函数

puts()与gets()函数包含在头文件stdio.h中,字符串处理函数包含在头文件string.h中,用#include"string.h"指明。在以下函数中,参数str、str1、str2为字符数组或指向字符的指针。

(1)字符串输出函数puts(str):输出指定字符串。参数可以为字符串常量。

(2)字符串输入函数gets(str):从键盘输入字符串至字符数组str中,输入的字符串可以包含空格。函数的返回值是字符数组str的首地址。

(3)字符串复制函数strcpy(str1,str2):将str2的值复制到str1中,实际上完成字符串的赋值操作。要求str1的长度大于str2的长度,第二个参数可以是字符串常量。(4)字符串连接函数strcat(str1,str2):将str2的值连接到str1中原有值的后面。注意str1必须足够大,以便能容纳两个字符数组中的所有值。连接完成后,两个字符串并成一个字符串,第一个字符串后面的原结束符自动取消。

(5)字符串比较函数strcmp(str1,str2):比较str1和str2,若两者相同,则返回函数值为0;若str1大于str2,则返回函数值为一个正整数;若str1小于str2,则返回函数值为一个负整数。两个参数可以是字符串常量。字符串比较规则与其它语言相同,将两个字符串中的字符从左至右依次比较,如果全部字符相同,则认为相等;若出现不同字符,则以第一个不同字符比较结果为准。(6)strlen(str):函数的返回值为字符串的实际长度。(7)strlwr(str):将字符串中大写字母转换成小写字母。(8)strupr(str):将字符串中小写字母转换成大写字母。8.3.3字符串数组对于多个字符串的处理需用字符串数组描述,字符串数组相当于二维字符数组。例如:

(1)100个城市名:

charcity[100][17];/*假定城市名不超过16个字符*/100个城市名分别用city[0]、city[1]、…、city[99]描述,city[i]相当于一个字符数组。(2)1000本书名:

charbook[1000][31];/*假定书名不超过30个字符*/1000本书名分别用book[0]、book[1]、…、book[999]描述,book[i]相当于一个字符数组。例8-8

用字符数组输出下面的图案。***********程序如下:/*程序8-8,用字符数组输出图案*/main(){staticcharch[3][5]={"***","*****","***"};

puts(ch[0]);

printf("\n");

puts(ch[1]);

printf("\n");

puts(ch[2]);

printf("\n");

}

例8-9输入一行字符,统计数字字符、字母字符及其它字符的个数。算法提示:

(1)一行字符用一维字符数组line描述。数字字符、字母字符及其它字符的个数用大小为3的一维整型数组num描述。

(2)对line数组的分量依次判断,若是数字字符,则数字字符数加1;若是字母字符,则字母字符数加1;否则,其它字符的个数加1。程序如下:/*程序8-9,统计数字字符、字母字符及其它字符的个数*/main(){charline[81];/*假定一行不超过80个字符*/inti;

intnum[3]={0,0,0};

gets(line);/*读入一行字符*/for(i=0;line[i]!='\0';i++)if(line[i]>='0'&&line[i]<='9')num[0]++;

elseif((line[i]>='a'&&line[i]<='z')||(line[i]>='A'&&line[i]<='Z')num[1]++;

elsenum[2]++;

printf("数字字符数=%d字母字符数=%d其它字符数=%d",num[0],num[1],num[2]);}

例8-10

求80个字符串中的最大者。算法提示:

(1)80个字符串用二维字符数组str描述。

(2)字符串最大者的求法与求最大值的方法完全相同,但比较、赋值操作需用函数strcmp()、strcpy()完成。程序如下:/*程序8-10,求80个字符串中的最大者*/main(){charstr[80][21];/*假定字符串的最大长度不超过20个字符*/inti;

charmstr[21];/*存放最大者*/for(i=0;i<80;i++)gets(str[i]);

strcpy(mstr,str[0]);/*最大者初始化为第一个字符串*/for(i=1;i<80;i++)/*求最大者*/if(strcmp(str[i],mstr)>0)strcpy(mstr,str[i]);

printf("字符串中的最大者=%s",mstr);}8.4重命名类型8.4.1重命名类型的方法一般形式:

typedef已有类型新类型名;一旦重命名类型,就可以用新类型名来描述数据。习惯上新类型名用大写字母表示。例如:①typedefintinteger;/*重命名整型integer*/integeri,j;/*定义整型变量i、j*/②typedefintCOUNT;/*命名一计数类型COUNT*/COUNTn1,n2;/*定义计数型变量n1、n2*/③typedefintNUM[100];/*命名一整型数组类型NUM*/NUMn;/*定义NUM型数组n*/④typedefcharSTRING[81];/*命名一字符串类型STRING*/STRINGstr1,str2;/*定义STRING型变量str1、str2*/⑤typedefstruct{intday;

intmonth;

intyear;

}DATE;/*命名一结构体类型DATE*/DATEdate1,date2;/*定义DATE型变量date1、date2*/8.4.2重命名类型的作用重命名类型的作用如下:

(1)有利于加强数据描述的针对性,增加程序的可读性。如用上面的重命名类型COUNT来定义计数器变量,用途一目了然。(2)有利于程序的通用和移植。

C语言程序设计有时可能会依赖于具体的计算机。例如,整型数据在某种机器上可能占2字节内存单元,在另外一种机器上又可能占4字节的内存单元,若将程序从2字节的机器移植到4字节的机器,则要将所有int说明改成long说明,修改的部分可能较多,程序的移植性较差。在整型数占2字节的机器上,若用typedef重命名类型:typedefintinteger;,则可用integer定义变量。若要将程序移植到整型数占4字节的机器上,只要用long代替原来的int即可,这时可再用typedef重命名类型:typedeflonginteger;。

(3)有利于减少程序书写的工作量。若程序中有不少地方要用到同一种复杂数据类型,书写起来比较复杂,通过重命名类型,可减少重复劳动。8.4.3几点说明

(1)用typedef只能对已有类型增加一个名字,而不能定义一个新的类型。

(2)用typedef可以对各种已有类型增加新的类型名,但不能用来定义变量。

(3)重命名类型可以将数组类型与数组变量分离开来。

(4)重命名类型与编译预处理不同,它是在编译时处理的,实际上也并不是作简单的字符串替换。

(5)常将一些常用的重命名类型单独放在一个文件中,需要时用#include指令将它们包含至程序中。8.5程序设计举例

例8-11

求n个实数的和、积、最大值及最小值。本题的算法我们已很清楚,这里是在考察在用数组描述数据的情况下的实现。求和、积、最大值、最小值均用数组作参数的函数完成。引入数组后,最大值、最小值可用其下标来描述,先假定最大值、最小值是数组的第一个分量。程序如下:/*程序8-11,求n个数的和、积、最大值、最小值*/#defineN100main(){floata[N];

intn;

inti;

floatsf();/*函数申明*/floatmf();

floatmax();

floatmin();

scanf("%d",&n);/*输入n个数*/for(i=1;i<=n;i++)scanf("%f",&a[i]);printf("和=%8.3f\n",sf(a,n));/*输出结果*/printf("积=%8.3f\n",mf(a,n));printf("最大值=%8.3f\n",max(a,n));printf("最小值=%8.3f\n",min(a,n));}

floatsf(xa,xn)/*求和*/floatxa[];intxn;{inti;

floats=0;for(i=1;i<=xn;i++)s+=xa[i];

return(s);}

floatmf(xa,xn)/*求积*/floatxa[];intxn;{inti;

floatm=1;

for(i=1;i<=xn;i++)m*=xa[i];

return(m);}floatmax(xa,xn)/*求最大值*/floatxa[];intxn;{inti,k=1;/*k存放最大值下标*/for(i=2;i<=xn;i++)if(xa[i]>xa[k])k=i;

return(xa[k]);}

floatmax(xa,xn)/*求最小值*/floatxa[];intxn;{inti,k=1;/*k存放最小值下标*/for(i=2;i<=xn;i++)if(xa[i]<xa[k])k=i;

return(xa[k]);}

例8-12

给定一个4×3的整数矩阵,求矩阵中最小值及最小值所在行的行号和列号。程序如下:/*程序8-12,求矩阵中最小值及其位置*/main(){inta[4][3];/*存放矩阵*/inti,j;

intmin,row,col;/*存放最小值及最小值所在行的行号、列号*/for(i=0;i<4;i++)/*输入矩阵*/for(j=0;j<3;j++)scanf("%d",&a[i][j]);row=0;col=0;min=a[0][0];/*初始化最小值及最小值所在行的行号、列号*/for(i=0;i<4;i++)/*求最小值及最小值所在行的行号、列号*/for(j=0;j<3;j++)if(a[i][j]<min){min=a[i][j];

row=i;col=j;

}printf("最小值为%d,处在%d行%d列",min,row,col);

例8-13

将n个实数由大到小排序。

n个实数用数组a描述。本例提供用选择排序方法与冒泡排序方法分别实现n个实数由大到小排序的函数。算法一:选择排序。选择排序需反复进行求最大值与交换两个数这两种基本操作。对a[0]、a[1]、…、a[n?1]由大到小排序:先求所有数的最大值,然后将最大值与a[0]进行交换;再求a[1]至a[n-1]这些数的最大值,然后将最大值与a[1]进行交换;再求a[2]至a[n-1]这些数的最大值,然后将最大值与a[2]进行交换……最后求a[n-2]与a[n-1]这些数的最大值,然后将最大值与a[n?2]进行交换。如此经过n-1轮处理完成排序。排序函数如下:voidsort1(a,n)/*选择排序函数*/floata[];intn;{intk,i,j;/*k最大值下标,i、j循环控制变量*/floatt;/*中间变量,用于两个数的交换*/for(i=0;i<n?1;i++){k=i;/*求最大值下标*/for(j=i+1;j<n;j++)if(a[j]>a[k])k=j;

t=a[i];a[i]=a[k];a[k]=t;/*进行交换*/}}

算法二:冒泡排序。冒泡排序需反复进行相邻两个数的比较与交换这两种基本操作。对相邻的两个数进行比较时,如果后面的数大于前面的数,将这两个数进行交换,大的数往前冒。将所有相邻的两个数比较一遍,称为一轮比较。如果一轮比较中无交换,则排序完成。有无交换用一标志变量描述,一轮比较用for循环完成,整个排序利用标志变量用条件循环控制。排序函数如下:voidsort2(a,n)/*冒泡排序函数*/floata[];intn;{inti;/*一轮比较的循环控制变量*/intflag;/*标志变量,为1有交换,为0无交换*/floatt;/*中间变量,用于两个数的交换*/do{flag=0;/*先假定无交换,已排好序*/for(i=0;i<n-2;i++)if(a[i+1]>a[i]){t=a[i];a[i]=a[i+1];a[i+1]=t;/*进行交换*/flag=1;/*有交换,标志变量的值改变为1*/}}while(flag);}

例8-14

筛法求2~1000之间的所有素数。算法提示:

(1)建立筛子,在这里正好利用数组作筛子,下标对应于数,相应下标变量的值标志是否在筛子中,为1表示在筛子中,为0表示已被筛去,不在筛子中。

(2)找每一轮筛选种子,筛选种子是完成一轮筛选后的下一个最小的素数,初值为2。

(3)对每一轮筛选种子,筛去其所有倍数,即将相应下标变量的值赋值为0。倍数初值为筛选种子的2倍。

(4)筛选完成,筛子中剩下的即为素数。程序如下:/*程序8-14,筛法求2~1000之间的所有素数*/main(){inta[1000]; /*筛子数组*/inti;

intminp,double; /*minp筛选种子,double倍数*/intn=0; /*素数个数,用于输出格式控制*/for(i=2;i<1000;i++) /*建立筛子*/a[i]=1;

minp=2; /*筛选种子初始化*/while(minp<500) /*完成整个筛选*/{double=2*minp; /*倍数初始化*/while(double<1000) /*完成一轮筛选*/{a[double]=0; /*筛去当前倍数*/double+=minp; /*计算下一个倍数*/}do /*计算下一轮筛选种子*/{minp++;

}while(a[minp]==0);}printf("2~1000之间的所有素数如下:\n");/*输出*/for(i=2;i<1000;i++)if(a[i]==1){printf("%6d",i);

n++;

if(n%5==0)printf("\n"); /*5个素数输出在一行*/}}

例8-15

求10~1000之间的回文数。算法提示:

(1)要判断一个数是不是回文数,先将其数字分离,用一数组a存放,然后将相应数字进行比较。

(2)引入一标志变量flag,为1表示是回文数,为0表示不是回文数。程序如下:/*程序8-15,求10~1000之间的回文数*/main(){inti,x;

inta[8],j;

intb,e;

intflag;

for(i=10;i<1000;i++){j=0;x=i; /*将数i的数字分离,用数组a存放*/while(x>0){a[j]=x%10;

x/=10;

j++;

}flag=1; /*先假定i为回文数*/b=0;e=j?1;

while(b<e&&flag) /*判断i是否为回文数*/if(a[b]!=a[e])flag=0; /*将对应位数字进行比较*/else{b++;e--;}if(flag)printf("%6d",i); /*i是回文数,输出*/}}

例8-16

从n个数据中查找指定数。

n个数据用一数组a描述,查找对象用x描述。算法一:将n个数据与查找对象依次比较,进行顺序查找,请读者编程实现。

算法二:比顺序查找进一步的是折半查找或称二分查找。折半查找要求n个数据已排好序,排序的目的就是为了快速查找。假定n个数据已经由小到大排好序。查找到的数据用其下标k表示,是否找到用一标志变量flag描述。查找问题转化成在区间[0,n-1]中找k。折半查找时先计算其中点d,如果a[d]=x,则k=d,找到;如果a[d]>x,则查找区间缩小为[0,d];如果a[d]<x,则查找区间缩小为[d,n-1]。要么找到,要么查找区间缩小一半,继续折半查找。折半查找函数如下:floatsearch(a,n,x) /*折半查找函数*/floata[],x;intn;{intk,flag;

intb=0,e=n?1,d;

flag=0; /*找到标志*/do{d=(b+e)/2;

if(a[d]==x){k=d;flag=1;}elseif(a[d]>x)e=d;

elseb=d;

}while(b<e&&!flag);

if(flag==0)k=-1; /*没找到*/return(k);}

例8-17

某班有50个学生,期终考试考了8门课程。求每个学生的总成绩及平均成绩,并按总成绩由高到低排序。算法提示:

(1)每个学生包括姓名和8门课程成绩,50个学生的数据分别用二维字符数组st、二维实型数组cj描述,通过第一个下标进行关联。

(2)50个学生的总成绩和平均成绩用二维实型数组tacj描述,同样通过第一个下标与其姓名、8门课程成绩进行关联。

(3)排序采用冒泡排序方法。

(4)整个程序由输入input()、计算总成绩及平均成绩count()、排序sort()、输出output()四个模块组成。

(5)使用外部数组完成数据传递。程序如下:/*程序8-17,成绩处理程序*/charst[51][12]; /*采用外部数组实现数据传递*/floatcj[51][9];floattacj[51][3];main(){voidinput(); /*函数申明*/voidcount();

voidsort();

voidoutput();

input(); /*调用输入函数*/count(); /*调用计算函数*/sort(); /*调用排序函数*/output(); /*调用输出函数*/}voidinput() /*输入函数*/{inti,j;

for(i=1;i<=50;i++){printf("请输入第%d个学生姓名,成绩:\n",i);

scanf("%s",st[i]);

for(j=1;j<=8;j++)scanf("%f",&cj[i][j]);

}}voidcount() /*计算函数*/{inti,j;

for(i=1;i<=50;i++){tacj[i][1]=0;

for(j=1;j<=8;j++)tacj[i][1]+=cj[i][j];

tacj[i][2]=tacj[i][1]/8;

}}voidsort() /*排序函数*/{inti,flag;

charts[12];

floatt;

do{flag=0;

for(i=1;i<=49;i++)if(tacj[i+1][1]>tacj[i][1]){strcpy(ts,st[i]);strcpy(st[I],st[i+1]);strcpy(st[i+1],st);/*交换姓名*/for(j=1;j<=8;j++) /*交换8门课程成绩*/{t=cj[i][j];cj[i][j]=cj[i+1][j];cj[i+1][j]=t;}t=tacj[i][1];tacj[i][1]=tacj[i+1][1];tacj[i+1][1]=t;/*交换总成绩*/t=tacj[i][2];tacj[i][2]=tacj[i+1][2];tacj[i+1][2]=t;/*交换平均成绩*/flag=1;

}}while(flag);}voidoutput()/*输出函数*/{inti;

printf("50个学生成绩处理结果如下:\n");

printf("姓名课程1课程2课程3课程4课程5课程6课程7课程8总成绩平均成绩名次\n");

for(i=1;i<=50;i++){printf("%8s",st[i]);

for(j=1;j<=8;j++)printf("%7.2f",cj[i][j]);

printf("%7.2f%7.2f%5d",tacj[i][1],tacj[i][2],i);

printf("\n");

}}

例8-18

用递归的方法计算n个数的最大公约数和最小公倍数。算法提示:

(1)定义外部数组a存放n个数,假定n不超过50。

(2)先计算头两个数的最大公约数和最小公倍数;再计算求出的最大公约数和最小公倍数与第3个数的最大公约数和最小公倍数;再计算与第4个数的最大公约数和最小公倍数……直至求出与最后一个数的最大公约数和最小公倍数即为所求。

(3)定义递归函数gysfn()计算n个数的最大公约数,递归函数gbsf()计算n个数的最小公倍数。其中都调用求两个数的最大公约数函数gysf2()。

(4)主函数中仅进行n个数的输入和计算结果的输出。程序如下:/*例8-18,用递归的方法计算n个数的最大公约数和最小公倍数*/intn,a[50]; /*数组a存放n个数*/intgysf2(); /*计算两个数的最大公约数*/intgysfn(); /*计算n个数的最大公约数*/intgbsf(); /*计算n个数的最小公倍数*/main(){inti;

clrscr();

printf("输入数的个数:");scanf("%d",&n);

for(i=0;i<n;i++){printf("输入第%d个数:",i);scanf("%d",&a[i]);}printf("\n\n");printf("最大公约数=%d\n",gys

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论