c语言 大学 第5章课后答案.docx
《c语言 大学 第5章课后答案.docx》由会员分享,可在线阅读,更多相关《c语言 大学 第5章课后答案.docx(38页珍藏版)》请在冰豆网上搜索。
c语言大学第5章课后答案
第5章数组
大家在前面的章节中已经碰到过这样的例子:
求两个整数中的较小的那个,或者求三个整数中的最小数。
那么大家想一下,如果题目中要求大家找出10个整数中的最小数呢,甚至100个整数中的最小数呢?
在计算机应用领域中,也常常遇到这类处理大量数据的问题,其特点也是:
数据量很大,数据之间存在一定的内在关系。
那么,对于这样的一组数据,计算机如果用前面讲过的简单变量来处理就很不方便,甚至不能处理。
考虑上面的求出10个整数中的最小数,先要设10个变量a1,a2,a3……a10,然后这10个变量之间又要相互比较,求出最小数。
显然是非常麻烦,要是成千上万个数据,是不是还要设一万个变量呢?
为了解决这一问题,C语言引入了一个重要的数据结构——数组,它是具有相同数据类型的变量集合,这些变量具有相同的名字,但用不同的下标表明数据的位置,我们称这些变量为数组元素。
将数组与循环结合起来,可以有效地处理大批量的数据,大大提高了工作效率,十分方便。
本章介绍在C语言中怎样定义和使用数组,包括一维数组,二维数组和字符串。
5.1一维数组
5.1.1一维数组的定义和引用
例5-1要求从键盘中输入10个互不相同的整数,求其中的最小数并输出。
10#include"stdio.h"
20main()
30{
40inta[10];/*定义数组a*/
50inti,min;/*定义变量i和min*/
60for(i=0;i<=9;i++)/*循环10次*/
70scanf("%d",&a[i]);/*从键盘输入数给数组元素赋值*/
80for(i=0;i<=9;i++)/*循环10次*/
90printf("%d\t",a[i]);/*输出数组元素的值*/
100min=a[0];/*给min变量赋初值*/
110for(i=1;i<=9;i++)/*循环9次*/
120if(min>a[i])
130min=a[i];/*比较min与数组中的每个数的大小,将较小的赋给min*/
140printf("Theminis%d\n",min);/*输出最小值*/
150}
该程序的流程图如图5-1所示。
图5-1例5-1的流程图
运行结果:
4512893564715679
4512893564715679
Theminis3
程序说明:
(1)行号为40的语句“inta[10];”是数组的定义。
表示定义一个名为a的数组,其中这个数组里包含10个元素,均为整型。
(2)行号为70,90,100,120和130的语句都是对该数组的引用。
1.一维数组的定义
在C语言中使用数组必须先进行定义。
一维数组的定义方式为:
类型说明符数组名[常量表达式];
其中:
(1)类型说明符是任一种基本数据类型或构造数据类型,即int、float、char等这些基本数据类型。
从这里可以看出,数组是建立在基本数据类型的基础之上的,因此数组为构造类型。
在上面的例子中int表示数组元素为整型数据。
(2)数组名是用户定义的数组标识符。
对于数组元素来说,具有一个共同的名字,即数组名,用标识符表示,上面例子中a为一维数组名。
(3)方括号中的常量表达式表示数据元素的个数,也称为数组的长度。
例如:
floatb[10],c[20];定义实型数组b,有10个元素,实型数组c,有20个元素。
charch[20];定义字符数组ch,有20个元素。
对于数组定义应注意以下几点:
(1)数组的类型实际上是指数组元素的取值类型。
对于同一个数组,其所有元素的数据类型都是相同的。
(2)数组名不能与其它变量名相同。
例如:
main()
{
inta;
floata[10];
……
}
是错误的。
(3)方括号中常量表达式表示数组元素的个数,如a[5]表示数组a有5个元素。
但是其下标从0开始计算。
因此5个元素分别为a[0],a[1],a[2],a[3],a[4]。
(4)不能在方括号中用变量来表示元素的个数,但是可以是符号常数或常量表达式。
例如:
#defineD5
main()
{
inta[3+5],b[4+D];/*合法的定义*/
……
}
但是下述说明方式是错误的。
main()
{
intn=10;
inta[n];/*不合法的定义,n为变量*/
……
}
2.一维数组元素的存储
每个数组元素都占用内存中的一个存储单元,每个元素都是一个变量,可以像以前讲过的普通变量一样使用,只不过数组元素是通过数组名和方括号“[]”里的下标来确定的。
系统为数组元素在内存中分配连续的存储单元。
例如:
定义语句inta[15];说明了以下几个问题:
(1)数组名为a。
(2)数组元素的数据类型为int整型数据。
(3)数组元素的下标值从0开始。
数组元素的个数为15个,它们是:
a[0]、a[1]、a[2]....a[13]、a[14]
(4)数组名a是数组存储区的首地址,即存放数组第一个元素的地址。
a&a[0];因此数组名是一个地址常量。
不能对数组名进行赋值和进行运算。
这个例子中数据元素的存储形式如图5-2所示。
a[0]
a[1]
a[2]
a[3]
……
a[12]
a[13]
a[14]
内存地址内存数组元素
2000
2002
2004
2006
……
2026
20282030
图5-2一维数组的存储形式
3.一维数组元素的引用
数组的引用就是对数组元素(数据)的读取操作。
数组的引用与变量的引用类似,数组的引用也是先定义后引用。
与变量不同的是不能对数组整体进行(读取)操作,只能对数组的元素进行操作。
一维数组的引用格式:
数组名[下标]
其中:
(1)下标可以是常量或常量表达式,如a[3]、a[3+2]。
(2)下标也可以是变量或变量表达式,如a[i],a[i+j],a[i++]。
(3)下标如果是表达式,首先计算表达式,计算的最终结果为下标值。
(4)引用时,下标值若不是整型,C系统会自动取整,a[5.3]相当于a[5]。
(5)下标值从0开始。
而不是从1开始。
(5)数组的引用下标不能越限,即引用时的下标不能超过或等于定义时的下标值。
如inta[10];a[10]=4;是错误的。
例5-2有等差数列an=3n,要求输出an的所有值,并求出数列的和。
n为0到9的整数。
#include"stdio.h"
main()
{
inta[10];/*定义数组a*/
intn,sum=0;/*定义变量n和sum*/
for(n=0;n<=9;n++)/*循环10次*/
{
a[n]=3*n;/*给数组元素赋值*/
printf("a[%d]=%d\t",n,a[n]);/*输出数组元素*/
sum+=a[n];/*将数组元素作累加*/
}
printf("sum=%d\n",sum);/*输出累加和*/
}
运行结果:
a[0]=0a[1]=3a[2]=6a[3]=9a[4]=12a[5]=15a[6]=18a[7]=21a[8]=24a[9]=27
sum=135
5.1.2一维数组的初始化
与一般变量的初始化一样,数组的初始化就是在定义数组的同时,给其数组元素赋初值。
数组初始化是在编译阶段进行的。
这样将减少运行时间,提高效率。
初始化赋值的一般形式为:
类型说明符数组名[常量表达式]={数值1,数值2……数值n};
其中在{}中的各数据值即为各元素的初值,各值之间用逗号间隔。
例如:
inta[3]={0,1,2};相当于a[0]=0;a[1]=1;a[2]=2;C语言对数组的初始化有以下几点规定:
(1)可以只给部分元素赋初值。
当{}中值的个数少于元素个数时,只给前面部分元素赋值。
例如:
inta[10]={0,1,2,3,4};相当于只给a[0],a[1],a[2],a[3],a[4]赋初值,而后5个元素自动赋0值。
(2)只能给元素逐个赋值,不能给数组整体赋值。
例如给十个元素全部赋1值,只能写为:
inta[10]={1,1,1,1,1,1,1,1,1,1};而不能写为:
inta[10]=1;
(3)如给全部元素赋值,则在数组说明中,可以不给出数组元素的个数。
例如:
inta[5]={1,2,3,4,5};可写为:
inta[]={1,2,3,4,5};
(4)花括号{}中数值的个数多于数组元素的个数是语法错误。
5.1.3一维数组应用举例
例5-3兔子问题(它是中世纪最杰出的数学家Fibonacci提出的):
如果一对兔子每月能生一对小兔(一雄一雌),而每对小兔在出生后的第三个月里,又能开始生一对小兔,假定在不发生死亡的情况下,由一对出生的小兔开始,2年后有多少对兔子?
这就是著名的斐波纳契数列。
根据题意,以f[n]表示n个月以后兔子的总对数,其规律为f[n]=f[n-2]+f[n-1],如此构成的数列
f[1]=1,f[2]=1,f[3]=2,f[4]=3,f[5]=5,……,f[n]=f[n-2]+f[n-1],……
根据上述题目的要求,可以写成下面的程序。
流程图如图5-3所示。
#include"stdio.h"
main()
{intn,f[25];/*定义变量*/
f[1]=f[2]=1;/*赋初值*/
for(n=3;n<=24;n++)
f[n]=f[n-1]+f[n-2];/*计算f[n]的值*/
for(n=1;n<=24;n++)
{if((n-1)%4==0)
printf("\n");/*每输出四个数后换行*/
printf("%10d",f[n]);/*输出数列中所有的值*/
}
}
运行结果:
1123
581321
345589144
233377610987
1597258441816765
10946177112865746368
图5-3例5-3的流程图
很多数列的问题都可以类似于上述的斐波纳契数列的计算方法,用数组来进行存储和计算。
例5-4任意给n个数,按由小到大对其排序,并输出结果。
采用“冒泡”排序法。
“冒泡”排序法的思路:
将相邻两个数比较,将小的数调到前头(或将大的数调到后面)。
若有5个数,分别是7,6,10,4,2,依次将其放入数组a中。
我们看一下冒泡排序法的处理过程:
(1)第一趟(如图5-4所示),经过4次比较。
第1次:
将第1个数a[0]和第2个数a[1]进行比较,将较小的数调到前面,也就是说,若后面的数小,就将两数交换,否则不交换。
级7和6对调位置。
结果如图5-4(b)所示。
第2次:
将第2个数a[1]和第3个数a[2]进行比较,将较小的调到前面。
也就是7和10比较,这次比较不用对调位置。
结果如图5-4(c)所示。
第3次:
将第3个数a[2]和第4个数a[3]进行比较,将较小的调到前面。
也就是10和4比较后对调位置。
结果如图5-4(d)所示。
第4次:
将第4个数a[3]和第5个数a[4]进行比较,将较小的调到前面。
也就是10和2比较后对调位置。
结果如图5-4(e)所示。
第1次第2次第3次第4次第一趟结果
a[0]
a[1]
a[2]
a[3]
a[4]
(a)(b)(c)(d)(e)
图5-4冒泡排序第一趟过程
如此进行共4次,结果得到6-7-4-2-10的顺序,最大的数10成为最下面的一个数.最大的数位置“沉底”,最小的数2向上“浮起”一个位置(冒第一个泡)。
这四次处理过程都是类似的,都是“相邻两数比较,若后面的数小,则两数交换,否则不交换”;所不同的是“比较的两个数,他们的位置不同”,先是a[0]和a[1]比较,再是a[1]和a[2]比较,再是a[2]和a[3]比较,最后是a[3]和a[4]比较,大家会发现一个规律,每次比较位置往后移了一位,所以我们可以用一个变量i控制,每次都是a[i]和a[i+1]比较,而每次比较完后i+1,总共比较4次,这样我们就可以用一个循环来实现,即:
for(i=0;i<4;i++)
if(a[i]>a[i+1])
{
temp=a[i];a[i]=a[i+1];a[i+1]=temp;
}
(2)第二趟(如图5-5所示),经过3次比较。
经过第一趟后最大数10已经沉到底了,第二趟就对余下的四个数(6-7-4-2)按上述的方法,经过三次比较,得到次大的数。
次大的数7“沉底”,最小数2又向上“浮起”一个位置(冒第二个泡),结果得到:
6-4-2-7的顺序。
第1次第2次第3次第二趟结果
a[0]
a[1]
a[2]
a[3]
(a)(b)(c)(d)
图5-5冒泡排序第二趟过程
这趟比较的代码跟第一趟几乎一样,不一样的是比较的次数不一样,那就是循环次数不一样,这趟循环3次。
用循环语句实现如下:
for(i=0;i<3;i++)
if(a[i]>a[i+1])
{
temp=a[i];a[i]=a[i+1];a[i+1]=temp;
}
(3)第三趟(如图5-6所示),经过2次比较。
对余下的三个数(6-4-2)按上述方法,经过两次比较,得到第三大数6“沉底”,最小数2又“浮起”一个位置(冒第三个泡)。
第1次第2次第三趟结果
a[0]
a[1]
a[2]
(a)(b)(c)
图5-6冒泡排序第三趟过程
这趟比较代码同上类似,循环次数变成2次。
(3)第四趟(如图5-7所示),经过1次比较。
对余下的三个数(4-2)按上述方法,经过1次比较,得到第四大数4“沉底”,最小数2又“浮起”一个位置(冒第四个泡)。
第1次第四趟结果
a[0]
a[1]
(a)(b)
图5-7冒泡排序第四趟过程
最后得到5个数的排序结果:
2-4-6-7-10(从小到大)。
从上面的四趟处理过程中可以看出,每一趟都很类似,都是“最大的数位置下沉,最小数向上浮起一个位置”;所不同的是“每趟比较的次数不同”,第一趟4次,第二趟3次,第三趟2次,第四趟1次,所以我们引入“趟次”循环变量j,一共需要4趟,故j从1到4,二每趟比较的次数都是5-j。
因此,我们可以用两个for循环来实现,“趟次”循环变量j作为外层循环控制变量,每趟里面的次数作为内循环:
for(j=1;j<=4;j++)/*j是趟次循环变量(外循环变量)*/
for(i=0;i<5-j;i++)/*i是每趟中两两比较的次数变量(内循环变量)*/
if(a[i]>a[i+1])
{
temp=a[i];a[i]=a[i+1];a[i+1]=temp;
}/*比较相邻两数大小,将较小的数放在前面*/
也就是说“冒泡”排序最重要的是在确定趟数和每趟的次数。
我们来分析一下:
其一,需要比较的趟数——5个数需要冒4个泡,即比较4趟,所以n个数要比较(n-1)趟。
其二,每趟比较次数——五个数排序,第一趟比较4次,第二趟比较3次,第三趟比较2次,第四趟比较1次,得出规律“n个数排序,第j趟要比较n-j次”。
综上所述,n个数需要进行n-1趟比较,在第j趟的比较中要进行n-j次两两比较。
所以任意n个数进行排序,程序如下:
#include"stdio.h"
#defineN10/*定义符号常量,对几个数排序,N的值就是几*/
main()
{inta[N];
inti,j,t;
printf("input10numbers:
\n");
for(i=0;iscanf("%d",&a[i]);
printf("\n");
for(j=1;jfor(i=0;iif(a[i]>a[i+1])/*比较相邻两数大小,将较小的数放在前面*/
{t=a[i];
a[i]=a[i+1];
a[i+1]=t;
}
printf("thesortednumbers:
\n");
for(i=0;iprintf("%d\t",a[i]);
}
运行结果:
input10numbers:
102348796520
thesortednumbers:
234567891020
5.2二维数组
5.2.1二维数组的定义和引用
前面介绍的数组只有一个下标,称为一维数组,其数组元素也称为单下标变量。
在实际问题中有很多量是二维的或多维的,比如最常见的矩阵就是二维的,因此C语言允许构造多维数组。
多维数组元素有多个下标,以标识它在数组中的位置,所以也称为多下标变量。
本小节只介绍二维数组,多维数组可由二维数组类推而得到。
1.二维数组的定义
二维数组定义的一般形式是:
类型说明符数组名[常量表达式1][常量表达式2];
其中常量表达式1表示第一维下标的长度,常量表达式2表示第二维下标的长度。
说明:
(1)类型说明符、数组名的说明同一维数组的说明。
(2)下标为整型常量或整型常量表达式。
(3)数组元素个数为:
常量表达式1常量表达式2。
(4)下标值从0开始。
例如:
intx[2][3];x是二维数组名,这个二维数组共有6个元素(2×3=6),它们是:
x[0][0],x[0][1],x[0][2],x[1][0],x[1][1],x[1][2]。
其全部元素数值均为整型的。
2.二维数组的存储
二维数组在概念上是二维的,比如说矩阵,但是存储器单元是按一维线性排列的。
如何在一维存储器中存放二维数组,可有两种方式:
一种是按行排列,即放完一行之后顺次放入第二行。
另一种是按列排列,即放完一列之后再顺次放入第二列。
在C语言中,二维数组是按行排列的。
如:
intx[2][3];先放第一行,即x[0][0],x[0][1],x[0][2],再放第二行,即x[1][0],x[1][1],x[1][2]。
如图5-8所示。
x[0][0]
x[0][1]
x[0][2]
x[1][0]
x[1][1]
x[1][2]
图5-8二维数组的存储
3.二维数组的引用
同一维数组一样,二维数组也要先定义、后引用;不能对一个二维数组的整体进行引用,只能对具体的数组元素进行引用。
其引用的格式为:
数组名[下标1][下标2]
说明:
(1)下标可以是常量(大于等于0)、常量表达式、变量或变量表达式。
(2)数组中要特别注意下标越限。
因为有的程序编译系统不检查数组下标越限问题,所以程序设计者应特别注意。
例如:
a[3][4],表示a数组第三行四列的元素。
下标变量和数组说明在形式中有些相似,但这两者具有完全不同的含义。
数组说明的方括号中给出的是某一维的长度,即可取下标的最大值;而数组元素中的下标是该元素在数组中的位置标识。
前者只能是常量,后者可以是常量,变量或表达式。
5.2.2二维数组的初始化
二维数组的初始化即定义数组的同时对其元素赋值,初始化有两种方法。
(1)把初始化值括在一对大括号内,例如二维数组intx[2][3]={1,2,3,4,5,6};初始化结果是:
x[0][0]=1,x[0][1]=2,x[0][2]=3,x[1][0]=4,x[1][1]=5,x[1][2]=6。
(2)把多维数组分解成多个一维数组,也就是把二维数组可看作是一种特殊的一维数组,该数组的每一个元素又是一个一维数组。
例:
intx[2][3];可把数组x看成是具有两个元素的一维数组,其元素是x[0]和x[1]。
而每个元素x[0]、x[1]又都是具有三个元素的一维数组,其元素是:
x[0][0]、x[0][1]、x[0][2]、x[1][0]、x[1][1]、x[1][2]。
x:
x[0]:
x[0][0],x[0][1],x[0][2];
x[1]:
x[1][0],x[1][1],x[1][2]。
因此,上例二维数组的初始化可分解成多个一维数组的初始化:
intx[2][3]={{1,2,3},{4,5,6}};
对于二维数组初始化赋值还有以下几点说明:
(1)可以只对部分元素赋初值,未赋初值的元素自动取0值。
例如:
intx[2][2]={{1},{2}};是对每一行的第一列元素赋值,未赋值的元素取0值。
赋值后各元素的值为:
x[0][0]=1,x[0][1]=0,x[1][0]=2,x[1][1]=0。
(2)如对全部元素赋初值,则第一维的长度可以不给出。
例如二维数组x的初始化过程:
intx[2][3]={1,2,3,4,5,6};也可写成:
intx[][3]={1,2,3,4,5,6};即第一下标值省略,但第二下标值不能省略。
5.2.3二维数组应用举例
例5-5一个学习小组有5个人,每个人有三门课的考试成绩。
求全组分科的平均成绩和总平均成绩。
学生的成绩表如表5-1所示。
表5-1学生成绩表
课程
张
王
李
赵
周
Math
80
61
59
85
76
C语言
75
63
67
89
72
英语
90
72
74
80
82
分析:
可设一个二维数组a[5][3]存放五个人三门课的成绩。
再设一个一维数组v[3]存放所求得各分科平均成绩,设变量average为全组总平均成绩。
流程图如图5-9所示。
图5-9例5-5流程图
代码如下:
#include"stdio.h"
main()
{
inti,j,s=0,average,v[3];
inta[5][3]={{80,75,90},{61,63,72},{59,67,74},{85,89,80},{76,72,82}};/*初始化*/
for(i=0;i<3;i++)
{
for(j=0;j<5;j++)
s=s+a[j][i];/*各科的分数累加*/
v[i]=s/5;/*各科平均分*/
s=0;
}
average=(v[0]+v[1]+v[2])/3;/*总平均分*/
printf("math:
%d\nclanguag:
%d\nenglish:
%d\n",v[0],v[1],v[2]);
printf("total:
%d\n",average);
}
例5-6编写一个程序实现34的矩阵的转置。
矩阵转置是把矩阵的行和列互换,如:
1234
5678
9101112
转置后变成43的矩阵:
159
2610
3711
4812
程序如下:
#include"stdio.h"
main()
{