
第6章数组在前面介绍的程序中,所使用的变量均为标量类型的变量。但是当在一个程序中用到大量数据时,使用标量类型的变量则不甚方便。此时,可以在程序中使用一种组合类型的数据数组。数组就是一组具有相同类型的有序变量的集合。数组中的变量称为数组的元素,数组元素的个数称为数组的长度。数组按其逻辑结构不同,可以分为一维数组、二维数组和多维数组等。这里的维,就是维度、方向的意思。数组中存储的数据可以是整型的,也可以是实型的、字符型的,还可以是其他类型的不过存储在同一个数组中的数据必须具有相同的类型,不同类型的数据只能存储于不同的数组中,而且数组必须先定义后使用,数组的大小由需要存储的数据多少来确定。本章主要介绍一维数组和二维数组的使用方法,并且只涉及整型和实型数据在数组中的存储和处理。批量字符型数据的存储和处理需要使用字符数组,将在第8章中专门讲述。品家6.1一维数组告-维数组的所有元素看作一行,相当于数学中的向量。在程序中使用数组时,也必须先定义后使用。6.1.1一维数组的定义一维数组定义的一般形式为类型说明符数组名【数组长度];其中,数组长度一般是一个正整数,也可以是整型常量的表达式。例如:int al1ol;该语句定义了一个数组名为a的一维数组,该数组包含了10个int型的数组元素,即a[0],a[1],a[2],...,a[9]。一维数组的元素,不但在名称上是有序的,在内存中的存储也是连续且有序的两点说明:(1)在C89标准中,不允许定义变长数组,即在表示数组长度的表达式中,不能包含变量名。而在C99标准中,则允许定义变长数组。例如:int n;scanf("%d",&n);int a[nl;该语句组在C89标准中是错误的,而在C99标准中则是正确的。(2)不能对数组元素进行越界引用

例如:int a[10];a[10]=200;是错误的,因为在数组a中不存在a[10]这个元素。6.1.2一维数组的引用在程序中,一般不能将一维数组作为一个整体操作,而只能针对数组中的元素进行操作。当在程序中引用数组元素时,数组元素的下标可以是整型的常量、变量或表达式。例如:int a[10],i=2;a[0]=10;a[i]=100;//等价于a【2]=100;a[i*2+1]-1000;//等价于a【5]=1000;通常可以利用数组元素的有序性特点,通过循环来处理数组中的元素【例6.1】从键盘输入10个整数存入一个一维数组中,然后按逆序输出。编程思路:(1)要输入一个整数并存人数组元素a[0]中,可用以下语句实现:1=0;scanf("%d",&a[il);/*可以用整型变量作为数组元素的下标*(2)用一个循环控制变量i的值从0变到9,即可输入10个整数并存人数组a中:for(i=0;i=0;i--)printf("odn,a[i]);源程序:#includeint main (void){int a[10],i;//定义数组及变量printf("请输人1o个整数:n");for(i=0;i=0;i--)语printf("d",alij);言printf("In"):程return 0;库设此程序只是实现了数组元系的读序输出,数组中数据的存储顺序并未发生改变计新6.1.3一维数组的初始化思可以在定义一维数组的同时给数组元素赋初值,称为数组的初始化。一维数组的初始路80

化有下面几种形式。(1)给全部数组元素赋初值。例如:inta[6]=(1,3,5,7,9,0}(2)给部分数组元素赋初值。例如:int a[6]=(3,6,9];int f[6]=(0];此时,未经赋值的数组元素,系统自动将其赋值为0。(3)在初始化一维数组时,可以不指定数组的长度例如:inta[1-(2,6,8,9,0,1]i此时,系统可以按照初值的个数来确定数组的长度。需要注意,inta[];是错误的,因为此时无法确定数组a的长度,从而无法为它分配内存空间。a6.1.4一维数组应用举例【例6.2】斐波那契数列的变化规律是:前两项都是1,从第三项开始的每一项等于其前面两项之和。试用一维数组编写程序,求出斐波那契数列的前40项。编程思路:(1)定义一个一维数组f[40],用于存储数列的前40项。(2)将前两项存人f[0]和f[1]中,即f[0]=1,f[1]=]。(3)按照数列的规律,求得第i项并存人f[]中,即f[]-f[i-2]+f[i-1],其中,i的取值为2~39。(4)最后输出所有的项。源程序:#inciude <stdio.hyint main(void)/将前两项存入[0]和f[1中(long int f[40]={1,1);int i;for(i=2;i<=39;i++)f[i]=f[i-2]+f[i-1];/求得第i项并存人f[i]中//输出数据for(i=0;i<=39;i++)printf("%201d",f[i);//每个数据占20列,以使数据排列整齐return 0;第程序中使用语句printf("%20ld"fil):输出,是为了使得输出的数据排列整齐。若直接6使用语句printf("%ld",fii);输出,则数据排列显得杂乱。幸【例6.3】编写程序实现:从键盘输人年份和月份,求出该月份的天数并输出。编程思路:数(1)将每个月的天数存人数组mon中,mon[i存储i月份的天数,二月份天数暂取28。(2)根据年份判断,若是年,则修正二月份的天数为29。组81

(3)根据月份m的值,输出数组元素mon[m]的值,即对应的月份天数。源程序:#include int main(void)[int Y,m;intmon[13]=(0,31,28,31,3031,30,3131,30,31,30,31);//每个月的天数printf("请输人年份和月份(用空格分隔):")scanf("%d%d",&y,&m);if((y%4==0)&&(y%100!=0)11(y%400==0))//若是闰年则修正二月份的天数mon[2]=29;printf("该月份的天数=%d\n",mon[ml);return o;请对比该程序与例4.11中源程序的不同之处,体会使用数组的优势。【例6.4】从键盘输入10个整数,求出其中的最大数并输出。编程思路:可采用打播台的方法来求最大数。(1)定义一个数组a[10],用于存储输人的10个数;(2)定义一个变量max,用于存储当前的最大数;(3)首先将a[o的值赋给max(其实可以取数组中的任意一个元素,为便于编程通常取a[0]);(4)取数组中的下一个元素a[i]与max比较。若a[i]的值大于max,则将a[i]的值赋给max(a[i是当前的最大数),否则max保持不变;(5)循环执行第(4)步,直至9次比较完成,此时max的值就是10个数中的最大数。源程序:#include int main(void)(inta[io]rmax,i;printf("请输人10个整数(用空格分隔):\n");for(i=0;imax)max=a[i];c1语printf("max=%dln",max);言return 0;程库想一想如何求出一批数中的第二大数?设【例6.5】从键盘输入10个数,用选择法按降序排序并输出计编程思路:新思排序问题可以理解为反复求最大值(或最小值)的问题。路(1)定义一个数组a[10],用于存储要排序的10个数。82

(2)首先找出10个数中的最大数,并置入a[01中。方法是依次将a[0]与其余9个数比较,并将较大者存人a[0]中,其实就是例6.4的插台法。将a[0]与a[1]相比较,并将较大者置人a[0]中。if(a[0]<a[1])(t=a[o];a[0]=a[1];a[1j=t;将a[0]与a[2]相比较,并将较大者置人a[0]中。if(a[0]<a[2])(t=a[0];a[0]=a[2];a[2]j=t;1将a[0]与a[9]相比较,并将较大者置入a[0]中。if(a[0]<a[9])(t=a[o];a[0]=a[9];a[9]=t;以上9条if语句,可以归纳为如下一个单重循环:i=0;for(j=i+l;j<=9;j++)if(a[i]<a[jl)(t=a[i];a[i]=a[j];a[j]=t;1(3)再找出其余9个数中的最大数,并置人a[1]中。可用如下一个单重循环实现。i=1;for(j=i+1:j<=9;j++)if(a[i]<a[j])(t=a[il;a[i]=a[j];a[j]=t;(4)以此类推,直至找出剩余2个数中的最大数,并置人a[8]中,最小数置人a[9]中第可用如下一个单重循环实现。6i=8;章for(j=i+l;j<=9;j++)if(a[i]<a[j])数(t=a[i];a[i]=a[j];a[j]=t;组183

至此,排序完成。(5)显然,上述9个单重循环可以合并为如下的双重循环。for(i=0;iintmain(void){int a[lo],i,j,t;版社printf("请输人10个整数(用空格分隔):n");for(i=0;ia[k])k=j;库1设t=a[i];a【i]=a[k];a[k]=t;/ /将10个数中的最大数与a[0】的值互换计(2)同样地,要找出剩余9个数中的最大数,并置人数组元素a[1]中,可用如下程序新思段实现。路1=1;84

k=i;/ /k保存9个数中最大数的下标for(j=i+1;ja[k])k=j;1t=a[i];a[i]=a[k];a[k]=t;/ /将9个数中的最大数与a[1]的值互换(3)以此类推,直至找出剩余2个数中的最大数,并置人数组元素a[8]中,可用如下程序段实现。i=8;k=i;//k保存2个数中最大数的下标for(j=i+l;ja[k])k=ji//将2个数中的最大数与a【8]的值互换t=a[il;a[i]=a[k]ia[k]=t;至此完成排序,总共需要9个单重循环。(4)而上述9个单重循环可以合并为如下的一个双重循环。for(i=-0;ia[k])k=j;//将本轮最大数a[k]与a[i]互换t=a[ilia[i]=alk]ia[k]=t;完整的源程序:#includeint main(void)(inta[io],t,i,i,k;printf("请输人10个整数(用空格分隔):In");for(i=0;ia[k])k=j;1第//将本轮最大数a[k]与a[i]互换t=a[ilia[i]=a[k]a[k]=t,6章printf("排序后的结果为:In")for(i=0;i<=9;i++)1/数据之间用逗号分隔printf("%d,",a[ij);数printf("In");return 0;组85

本程序还可以进一步改进,可以在数据交换之前首先进行判断。如果与i的值相等(说明ak就是a[il),则不需要交换;只有k与i的值不相等时,才需要交换。从而最大限度地减少数据交换的次数,提高程序的运行效率。相应的源代码如下:/增加判断语句if(kl=i)//将本轮最大数a【k]与a[i]互换(t=a[i];a[i]=a[k];a[k]=t;]【例6.7】从键盘输人10个数,用冒泡法按升序排序并输出。编程思路:冒泡法总是将相邻的两个数进行比较,若是升序排序,则将较大数后移;若是降序排序,则将较小数后移。(1)首先找出10个数中的最大数,并置人a[9]中。将a[0]与a[1]比较,如果a[0]>a[1],则将二者五互换。if(a[0]>a[1])(t=a[0];a[o]=a[l];a[1]=t;将a[1]与a[2]比较,如果a[1]>a[2],则将二者互换。if (a[1]>a[2])(t=a[1];a[1]=a[2];a[2]=t;....将a[8]与a[9]比较,如果a[8]>a[9],则将二者互换if(a[8]>a[9])(t=a[8];a[8]=a[9];a[9]=t;以上9条if语句,可以归纳为如下一个单重循环:for(j-0:ja[j+l])(t=a[j]l;a[j]=a[j+i];ca[j+1]-t;语言(2)再找出其余9个数中的最大数,并置人a[8]中,可用如下一个单重循环实现。程for(j=0;ja[j+l])设(t=aj]l;计a[j]=a[j+i];新a[j+1]=t;思路(3)以此类推,直至找出剩余两个数中的最大数,并置人a[1]中,最小数置入a[0]中,86

可用如下一个单重循环实现。for(j=0;ja[j+l])(t=alj];a[j]=a[j+1];a[j+1]=t;1至此,排序完成(4)显然,上述9个单重循环可以合并为如下的双重循环。//共9趟,每一趟将一个最大数沉到最底部for(i=0;ia[j+])(t=alj];a[j]=a[j+1];a[j+1]=t;/1完整的源程序:#include int main(void){int a[io],t,i,j,k;printf("请输人10个整数(用空格分隔):In");for(i=0;ia[j+li)(t=a[l;a[J]=a[j+1] ;a[j+1]=t;YAprintf("升序排序后的结果:1n");for(i=0:i<=9;i++)1/数据之间用逗号分隔printf("sd,",a[ij);printf("In");return O;第6【例6.8】编程序实现输人任意一个日期的年、月、日的值,求出从这一年的1月1章日到这一天总共有多少天。数编程思路:(1)首先求出从这一年的第一天到上月末的总天数,然后加上该日期中的日数即可。(2)到上月末的天数,可以通过循环累加的方式求得,即将从一月份到上个月的天数组87

累加求和。源程序:#include int main(void)Iint Y,m,d,days,i;1ntmon[13]={031,28,31,30,31,30,3131,30,31,30,31]://每个月的天数printf("请输人年、月、日(用空格分隔):\n");scanf("gd&d%d",&y,&m&d);if((y%4==0)&&(y%100!=0)1|(%400==0))//若是国年则修正二月份的天数mon[21=29;days=0;for(i=l;i设int main(void)计fint n,i,新printf("请输人整数的总个数:")思scanf("&d",&n);路88