C语言教材第7章.docx
- 文档编号:10550651
- 上传时间:2023-02-21
- 格式:DOCX
- 页数:33
- 大小:44.58KB
C语言教材第7章.docx
《C语言教材第7章.docx》由会员分享,可在线阅读,更多相关《C语言教材第7章.docx(33页珍藏版)》请在冰豆网上搜索。
C语言教材第7章
第七章数组
本章要点
了解数组的概念,掌握一维数组和二维数组的定义方法、初始化方法及数组元素的引用方法,正确理解字符数组的概念,掌握字符数组的初始化方法及引用方法。
能初步使用字符串处理函数,能用数组处理一些复杂的问题,例如排序等问题。
第一节概述
什么是数组?
为什么要使用数组?
先来分析一个计算机科学中应用最普遍的排序问题。
例如要对两个数进行从小到大的排序。
根据此前学过的知识,我们知道程序中定义三个变量用一个if语句就可以实现,程序段如下:
if(a>b)
{t=a;a=b;b=t;}
如果对三个数进行排序,定义四个变量用三个if语句实现,程序段如下:
if(a>b)
{t=a;a=b;b=t;}
if(a>c)
{t=a;a=c;c=t;}
if(b>c)
{t=b;b=c;c=t;}
如果对四个数进行排序,定义五个变量用六个if语句实现,程序段如下:
if(a>b)
{t=a;a=b;b=t;}
if(a>c)
{t=a;a=c;c=t;}
if(a>d)
{t=a;a=d;d=t;}
if(b>c)
{t=b;b=c;c=t;}
if(b>d)
{t=b;b=d;d=t;}
if(c>d)
{t=c;c=d;d=t;}
如果要对1000、10000或是更多的数进行排序,怎么办?
很明显,用此前所学过的基本类型(整型、字符型、浮点型)定义变量实现起来很麻烦,而用下面讲到的数组实现起来却很简单。
数组与之后要提到的结构体、共用体和枚举类型都称为构造类型。
数组的定义:
一组具有相同类型的数据的有序集合,例如一个班学生的学习成绩。
从这个定义中可以看出数组的两个特点:
①数组中的数据具有相同类型;②数组中的数据是有序的(此处的“有序”指的是数据之间的相对顺序,并非指数值的大小顺序)。
第二节一维数组
一、一维数组的定义
一维数组的定义方式为:
类型说明符数组名[常量表达式];
例如:
intarray[10];
定义了一个整型数组,数组的名称是array,数组的大小是10,即该数组有10个元素。
说明:
(1)“类型说明符”可以是之前所学过的基本类型中的任何一种。
例如定义如下数组:
charname[12];/*定义一个字符型数组name*/
longdigits[30];/*定义一个长整型数组digits*/
floatnum[100];/*定义一个单精度浮点型数组num*/
(2)数组名命名规则和变量名命名规则相同,都遵循标识符命名规则。
(3)常量表达式表示数组中元素个数,即数组的长度。
常量表达式中可以包括常量和符号常量,不能包含变量。
也就是说,在定义数组时必须确定其大小,不允许对数组的大小作动态定义。
请分析以下几个例子中数组定义是否正确。
①inta[10],b[20];
②#defineNUM30
floatf[2*NUM+1];
③intn=10;
intarr[n];
④intn;
scanf("%d",&n);
intaa[n];
第一个例子中定义了两个整型数组a和b,a数组长度是10,b数组长度是20;第二个例子中定义了一个符号常量NUM,浮点型数组f的长度是61;这两种定义方式是正确的。
第三个例子中n虽然赋值为10,但n是变量,只不过进行了初始化;第四个例子是在程序中临时输入数组的大小,这两种定义方式都是用变量定义数组的大小,所以是错误的。
(4)数组所占内存空间的大小取决于数组的类型和数组的长度。
例如有如下定义:
intb[10];
编译程序将为数组b开辟一块连续的存储单元存放数组元素,数组名b表示存储单元的首地址。
在VC6.0环境下,每个int类型的数据占用4个字节的空间,所以该数组总共占用40个字节的空间。
二、一维数组元素的引用
数组和简单变量一样,必须遵循“先定义,后使用”的原则。
定义了一个一维数组以后,就可以像使用简单变量一样使用数组中的每一个元素。
C语言规定:
只能逐个引用数组元素而不能一次引用整个数组。
数组元素的引用采用数组名加下标的方式,形式为:
数组名[下标]
说明:
(1)下标可以是整型常量或整型表达式,例如:
array[0]=array[2]+array[4]-array[2*4]
(2)注意定义数组时用到的“数组名[常量表达式]”和引用数组元素时用到的“数组名[下标]”的区别。
例如:
inti=10;inta[i];/*用变量定义数组,是错误的*/
a[i]=a[i-2]+a[i-1];/*程序中用变量或表达式作为下标引用数组元素,是正确的*/
(3)引用数组元素时,下标的范围是0~[数组长度-1]。
例如在数组array中,数组的10个元素分别是:
array[0],array[1],array[2],array[3],array[4],array[5],array[6],array[7],array8],array[9]。
请注意:
array[9]是数组中的最后一个元素,即第十个元素,在数组中不存在array[10]这个元素。
出于执行速度的考虑,C并不检查数组下标是否越界。
例如,如果在程序中出现了如下代码:
printf("%d\n",array[10]);
array[20]=790;
编译器不会发现这样的错误,程序能通过编译并运行,第一个输出语句输出了其它某个位置上的数据,而第二个赋值语句则会把数据放在可能由其它数据使用的位置上,因而会造成其它某个变量值被修改,造成程序结果的不可预料甚至使程序崩溃。
因此,在使用数组时一定要注意数组下标不能越界。
数组的优势要得到发挥,必须与之前学过的循环结构结合起来使用,下面先看一个简单的例子。
例7.1一维数组元素的引用。
#include
voidmain()
{
inti,a[10];
for(i=0;i<=9;i++)/*a[0]~a[9]赋值为0~9*/
a[i]=i;
for(i=9;i>=0;i--)/*将a[9]~a[0]的值输出*/
printf("%d",a[i]);
printf("\n");
}
程序运行结果:
9876543210
请想一想,如果不用数组来实现该程序的功能,应该怎么编写程序呢?
与这个程序比较,是否可以看出使用数组的优势呢?
三、一维数组的初始化
数组元素和变量一样,可以在定义时赋初值,称为数组的初始化。
一维数组初始化的格式为:
类型说明符数组名[常量表达式]={常量列表};
常量列表中的各个常量值之间用逗号隔开,初始化方法有以下几种:
(1)对数组中所有元素赋初值,例如:
inta[10]={2,4,6,8,10,12,14,16,18,20};
经过上面的定义和初始化之后:
a[0]=2,a[1]=4,a[2]=6,a[3]=8,a[4]=10,a[5]=12,a[6]=14,a[7]=16,a[8]=18,a[9]=20。
注意,如果常量列表中数值数目大于数组长度,编译器会提示错误信息“toomanyinitializers(初始化太多)”。
(2)对数组中的部分元素赋初值,例如:
inta[10]={2,4,6,8,10,12,14};
经过上面的定义和初始化之后:
a[0]=2,a[1]=4,a[2]=6,a[3]=8,a[4]=10,a[5]=12,a[6]=14,a[7]=0,a[8]=0,a[9]=0。
也就是说,如果只对数组中的部分元素赋初值,那么没有赋初值的元素系统自动将其值设置为0。
(3)如果想使一个数组中全部元素值为0,可以写成:
inta[10]={0,0,0,0,0,0,0,0,0,0};
或inta[10]={0};
请注意,如果想使一个数组中全部元素值为除0以外的其它值,则不能写成后一种形式。
即如果定义:
inta[10]={1,1,1,1,1,1,1,1,1,1};
不能写成:
inta[10]={1};
后一种形式下,系统认为只有a[0]=1,而其它9个元素的值为0。
(4)给数组中所有元素赋初值时可以不用指定数组的长度,编译器会根据常量列表中数值数目来确定数组的大小。
例如inta[10]={2,4,6,8,10,12,14,16,18,20};
可写成:
inta[]={2,4,6,8,10,12,14,16,18,20};
例7.2一维数组的初始化。
#include
voidmain()
{inta[5]={2,4,6,8,10};
intb[5]={3,5,7};
intc[]={1,2,3,4,5};
intd[5]={0};
inte[5]={8};
inti,f[5];
for(i=0;i<5;i++)printf("%d",a[i]);printf("\n");
for(i=0;i<5;i++)printf("%d",b[i]);printf("\n");
for(i=0;i<5;i++)printf("%d",c[i]);printf("\n");
for(i=0;i<5;i++)printf("%d",d[i]);printf("\n");
for(i=0;i<5;i++)printf("%d",e[i]);printf("\n");
for(i=0;i<5;i++)printf("%d",f[i]);printf("\n");
}
程序运行结果:
246810
35700
12345
00000
80000
-858993460-858993460-858993460-858993460-858993460(该行输出可能有所不同)
看最后一行输出结果,是不是莫名其妙?
数组f没有进行初始化,与变量相似,在对数组进行初始化之前,数组中各个元素的值是不确定的,输出结果也就无法确定。
四、一维数组程序举例
在学习了一维数组的相关知识后,我们再回头看看本章开始所提出的排序问题。
排序是计算机程序设计中的一种重要操作,计算机科学家研究了很多种排序方法,其中冒泡排序法是一种效率较高的排序方法。
例7.3对N个数用冒泡排序(BubbleSort)进行由小到大的排序。
假定对N个数,a0,a1,…aN-1进行排序,其基本思想如下:
将a0与a1进行比较,如果a0大于a1,则a0与a1进行交换,然后比较a1与a2,如果a1大于a2,则a1与a2进行交换。
依次类推,直到aN-2与aN-1进行过比较为止,完成第一趟排序,需要进行N-1次两两比较,其结果是aN-1是N个数中的最大者。
然后进行第二趟排序,将前N-1个数(a0与aN-2)进行同样操作,需要进行N-2次两两比较,其结果是aN-2是N个数中的次大者。
同理进行第三、第四……第N-1趟排序,在第i趟排序中需进行N-i次两两比较。
程序代码如下:
#include
#defineN10/*定义字符常量N*/
voidmain()
{
inti,j,a[N],temp;
printf("Pleaseinput%dnumbers:
\n",N);
for(i=0;i scanf("%d",&a[i]); for(i=0;i for(j=0;j<(N-1)-i;j++)/*内层循环,实现在每一趟排序中进行(N-1)-i次比较*/ if(a[j]>a[j+1]) { temp=a[j]; a[j]=a[j+1]; a[j+1]=temp; } printf("Theresultofsortingis: \n"); for(i=0;i printf("%d",a[i]); printf("\n"); } 程序运行结果: Pleaseinput10numbers: 8978675645342312-30-56↙(↙表示回车键,下同) Theresultofsortingis: -56-301223344556677889 在该程序中,定义了一个符号常量N,其作用有两点: ①使得整个程序中数组的大小能够保持一致;②该程序具有通用性,无论要排序的数的个数是多少,在程序中只需要修改符号常量N的值即可,而不需要修改其它涉及到数组大小的地方。 在进行程序设计时注意符号常量的使用通常会减轻程序员的工作量。 例7.4求Fibonacci数列的前40个数。 Fibonacci数列问题在前面已经分析过: F1=1n=1 F2=1n=2 Fn=Fn-1+Fn-2n≥3 程序如下: #include #defineN40 voidmain() { inti; longf[N]={1,1};/*定义长整型数组f,初始化前两个值都为1*/ for(i=2;i f[i]=f[i-2]+f[i-1]; for(i=0;i { if(i%4==0)printf("\n");/*控制每行输出四个数*/ printf("%16ld",f[i]); } printf("\n"); } 程序运行结果: 1123 581321 345589144 233377610987 1597258441816765 10946177112865746368 75025121393196418317811 514229832040134********309 35245785702887922746514930352 241578173908816963245986102334155 在该程序中,同样定义了一个符号常量N,通过对N值的设定,可以求Fibonacci数列的前任意个数。 但请注意,N值不可超出46,即N≤46,否则超出长整型范围(-2147483648-2147483647),结果将出现负数(如果您对二进制补码有所了解的话就能知道原因)。 有兴趣的读者可上机验证。 第三节二维数组 之前所讨论的数组只有一个下标,称之为一维数组。 但有时用一维数组存储数据并不是很合适。 例如要存储如下一个3行4列矩阵中的元素: 用一维数组存储,可以定义一个长度为12的一维数组,但这样无法区分矩阵的行和列;另一种方法,定义3个一维数组,每个数组的长度为4,这样能够明显看出矩阵的行列数,但试想一下,如果要存储的不是3行,而是30、300或更多行,这样定义数组合适吗? 显然是不合适的。 于是您可能想到: 能否定义一个数组,在这个数组里可以同时定义行数和列数呢? 答案是肯定的,您所想的就是在C语言里所允许构造的二维数组。 一、二维数组的定义 二维数组的定义方式为: 类型说明符数组名[常量表达式1][常量表达式2]; 其中“常量表达式1”表示第一维下标的长度(行数),“常量表达式2”表示第二维下标的长度(列数)。 例如: inta[3][4]; 定义了一个3行4列的整型二维数组。 可以这样理解该二维数组: a是一个包含了3个元素(a[0]、a[1]、a[2])的一维数组,每个元素又是包含了4个int型数据的数组。 如图7-1所示: 图7-1 二维数组的长度=常量表达式1×常量表达式2。 上面定义的a数组长度是3×4,即12,所占内存空间是12个int型所占的空间(即12×4=60字节)。 用二维视图表示数组便于直观地想象,实际上数组在物理存储上是顺序存放的。 如上述定义的a数组,在内存中先存放第一行元素a[0][0]、a[0][1]、a[0][2]和a[0][3],再存放第二行元素a[1][0]、a[1][1]、a[1][2]和a[1][3],依次类推。 C语言允许构造多维数组,其定义方式和二维数组类似,例如定义如下: intb[3][4][5]; 请根据二维数组的知识推出该三位数组的长度、所包含的元素及在内存中存放顺序。 二、二维数组元素的引用 二维数组元素的引用格式为: 数组名[行下标][列下标] 下标可以是整型常量或整型表达式。 例如: a[1][2]、b[3-1][2*2-1] 可以像使用简单变量一样使用二维数组中的元素。 例7.5二维数组元素的引用。 #include voidmain() { inti,j,a[3][4]; for(i=0;i<3;i++)/*用一个双重循环对二维数组各个元素赋值*/ for(j=0;j<4;j++) a[i][j]=i*2+j; for(i=0;i<3;i++)/*将二维数组输出*/ { for(j=0;j<4;j++) printf("%d",a[i][j]); printf("\n"); } } 程序运行结果: 0123 2345 4567 同样需要注意的是,如果下标越界,编译器并不会发现该错误。 所以在引用二维数组元素时,请确保下标必须在已定义范围内。 例如上例中数组a[3][4],可用的行下标最大值为2,列下标最大值为3,即最后一个元素是a[2][3]。 三、二维数组的初始化 二维数组初始化的方法分为两种: 分行赋初值和连续赋初值。 (1)分行赋初值。 例如: inta[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; 根据前面对数组a的理解,二维数组a是由三个一维数组构成的,{1,2,3,4}是对a[0]进行赋值,即给二维数组的第一行元素赋初值,{5,6,7,8}是对a[1]进行赋值,即给二维数组的第二行元素赋初值,依次进行赋值。 可以只对部分元素赋初值,例如: inta[3][4]={{1,2,3},{5,6,7,8},{9,10}}; 没有被赋初值的元素系统默认为0。 所以上述定义等价于: inta[3][4]={{1,2,3,0},{5,6,7,8},{9,10,0,0}}; 如果某行初值的个数大于列数,编译器同样会提示错误信息“toomanyinitializers”,该行的数值不会影响到下一行赋值。 无论是对所有元素赋初值还是对部分元素赋初值,该方法下都可以省略第一维的长度,因为内层花括号的个数可以确定第一维长度,但两种情况下第二维的长度都不能省略。 (2)连续赋初值。 例如: inta[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}; 这种方式省略了内层花括号,按顺序对数组元素依次赋值。 如果花括号内初值个数小于数组长度,按先后顺序逐行赋值后,没有赋值的元素初始化默认为0。 例如: inta[3][4]={1,2,3,4,5,6,7}; 等价于: inta[3][4]={1,2,3,4,5,6,7,0,0,0,0,0}; 该方法下如果对全部元素赋初值,也可省略第一维的长度,系统根据初值个数和第二维的长度来确定第一维长度,同样第二维的长度不能省略。 上述两种初始化的方法推荐第一种,比较直观,易于数据检查。 四、二维数组程序举例 例7.6求一个4×4矩阵主对角线上元素之和。 例如有如下矩阵a: 主对角线上的元素分别是a[0][0]、a[1][1]、a[2][2]、a[3][3],即8、5、6、9。 程序如下: #include #defineN4 voidmain() { inti,j,a[N][N],sum=0; printf("PleaseinputNarrayelements: \n"); for(i=0;i { for(j=0;j scanf("%d",&a[i][j]); } printf("Thearrayis: \n"); for(i=0;i { for(j=0;j printf("%d",a[i][j]); printf("\n"); } for(i=0;i sum+=a[i][i]; printf("Thesumofmaindiagonalelementsis%d\n",sum); } 程序运行结果: PleaseinputNarrayelements: 8645753119645389↙ Thearrayis: 8645 7531 1964 5389 Thesumofmaindiagonalelementsis28 请思考: 如果要输出副对角线上的元素a[0][3]、a[1][2]、a[2][1]、a[3][0]之和,程序应如何修改? 例7.7统计3个学生,每个学生4门课程的考试成绩,要求输出每个学生的总成绩,每个学生的平均成绩及每门课程的平均成绩。 程序如下: #include"stdio.h" voidmain() { floats[3][4],sum=0; floatt[3],sa[3],ca[4]; inti,j; for(i=0;i<3;i++)/*输入三个学生的4门课程考试成绩*/ for(j=0;j<4;j++) scanf("%f",&s[i][j]); for(i=0;i<3;i++) { t[i]=0; for(j=0;j<4;j++) t[i]+=s[i][j];/*t[i]存放第i个学生的4门课程成绩*/ printf("Thesumofstudent%dis: %-6.2f\n",i,t[i]); sa[i]=t[i]/4;/*a[i]存放第i个学生的4门课程平均成绩*/ } printf("\n"); for(i=0;i<3;i++) printf("Theaverageofstudent%dis: %-6.2f\n",i,sa[i]); printf("\n"); for(i=0;i<4;i++) { ca[i]=0; for(j=0;j<3;j++) ca[i]+=s[j][i];/*计算每门课程的总成绩*/ printf("Theaverageofcourse%dis: %-6.2f\n",i,ca[i]/3); } } 程序运行结果: 67707169878380
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C语言教材 第7章 语言 教材