2010-101《C语言程序设计实用教程》Powerpoint制作:耿祥义张跃平第8章数组2010-102主要内容及难点2010-103概述数组是相同类型的变量按顺序组成的一种复合数据类型,称这些相同类型的变量为数组的元素或单元,数组通过数组名加索引来使用数组的元素。本章不再叙述VC++6.0编译、链接、运行的过程。对于本章例子中的的C程序,在用VC++6.0时,要建立相应的工程,并将源文件加到工程中。2010-1048.1一维数组定义一维数组的格式如下:数组类型数组名[字面常量或符号常量或常量表达式];假设需要3个int型变量,可如下定义一个名字为boy、类型为int的一维数组:intboy[3];通过数组名加数组下标,来使用数组中的数据(下标从0开始排序)。数组boy是由3个int型变量所构成,它们称作数组boy的元素。数组boy可以使用下标运算访问它的元素(boy[0],boy[1],boy[2]),即操作属于它的变量。在定义一维数组的格式中◆数组类型:通过数组的类型说明是哪些相同类型的变量组成了这个数组。数组的类型可以是基本型如char,short,int,long,float和double,也可以是后面学习的指针类型、结构体类型和公用体类型。◆数组名:符合标识符规定即可◆数组的长度:数组包含的元素的个数称作数组的长度。◆字面常量、符号常量或常量表达式:定义数组中元素的个数,即数组的长度。不可以使用含有变量的表达式的值指定数组元素的个数。也不可以使用const常量(const常量是只读变量)来指定数组的大小。8.1.1一维数组的定义2010-1058.1.2一维数组的结构1.顺序结构:例如对于如下定义的一维数组:inta[5];操作系统将为数组a分配5个元素(5个变量),其类型都是int型,数组的元素在内存中是按顺序存储的,每个元素占4个字节。2.数组名是只读变量C语言将数组名看作是一个只读变量,数组名存放了数组的第一个元素的地址后,就再也不能改变这个只读变量中的地址、只可以读取其中的地址。程序可以对数组中的元素进行赋值操作,数组中的元素才是真正的变量。当我们如下定义数组:inta[5];后,完整的内存模型如图8.2所示,示意图中的箭头示意数组可以通过下标运算访问它的元素,用深色填充的区域表示的是只读变量a的内存。2010-1068.1.3一维数组的使用定义一维数组后,就可以使用数组名加下标运算访问数组中的元素,也称引用数组中的元素。在函数体中定义数组时,不要和语句有交叉。例子1(example8_1.c)使用循环语句为int型数组a的元素赋值,并输出了数组a中各个元素的地址(用十六进制)以及元素的值,同时也输出了a中的值(地址)。例子2(example8_2.c)将Fibonacci数列的前40项存放在一个一维数组中,然后倒序输出数组的元素的值。2010-1078.1.4怎样获取一维数组的长度数组占有的内存数量(单位是字节)就是它的各个元素占有的内存数量之和。由于数组各个元素占有内存空间的字节数量都是相同的,因此如果我们知道了数组占有的内存的数量,而且也知道数组的类型(类型决定了数组元素所占内存的数量),那么就可以知道数组的长度了。对于数组a,sizeof(a)就是数组所占内存的数量(单位是字节)比如,对于inta[]={1,2,3,4,5};数组的长度就是sizeof(a)/sizeof(int)。2010-1088.1.5一维数组的初始化在定义数组的同时可以把大括号括起的、用逗号分隔的若干个值指定为数组元素的初始值,即让数组元素依次取大括号中的值。1.大括号括起的若干个值的数量等于数组的长度。例如:inta[3]={1,2,3};该初始化相当于定义数组:inta[3];然后再进行赋值:a[0]=1;a[1]=2;a[2]=3;2.大括号括起的若干个值的数量小于数组的长度。那么,在大括号中没有对应值的数组元素的值默认被初始化为0。例如对于inta[4]={1,2,3};相当于a[0]的值为1,a[1]的值为2,a[2]的值为3,a[3]的值为0。3.初始化时省略数组的长度。例如:inta[]={1,2,3};等价于:inta[3]={1,2,3};4.大括号括起若干个值的数量不能大于数组的长度,例如:inta[3]={1,2,3,4};是错误的。例子3(example8_3.c)使用数组存放某月份的日期,并输出了该月的日历。2010-1098.1.6避免下标越界定义数组之后,数组名通过下标运算访问数组中的元素,但必须小心下标越界问题。在访问数组元素时,下标运算从0开始,最大的下标是数组长度减1。例如,对于shorta[3];可以如下对数组的元素进行赋值操作:a[0]=1;a[1]=2;a[2]=3;但千万避免如下的操作:a[3]=90;因为数组一共有3个元素,没有第4个元素。对a[3]=90;的操作,就是将数据90放入了操作系统为数组a分配的内存后面连续的2个字节中,此时这个内存是否被其它程序使用我们并不清楚,这是十分危险的。2010-10108.2数组名作参数数组名本质上是一个变量,它的值只能是地址,即该变量中只能存放地址。当在函数体中定义数组时,数组名是只读变量,该变量只可以存放地址,不可以再更改。但是,当数组名是函数的参数时,数组名就是一个变量(既可读也可写)。2010-10118.2.1一个重要的结论如果两个类型相同的数组的数组名的值相同,那么这两个数组的元素就完全相同。对于示意图中的数组a和b,a[0]和b[0]是相同的变量,依次a[1]和b[1]、a[2]和b[2]、a[3]和b[3]、a[4]和b4]都是相同的变量,也就是说,如果进行:b[0]=100;操作,那么a[0]和b[0]的值都是100。它们共用内存空间。2010-10128.2.2形参与数组对于形参为数组类型的函数原型:voidf(inta[]);也可以等价地写成:voidf(int[]);//省略数组的名字如果一个函数定义中形参是数组名,那么这个数组名就是一个变量的名字,该变量专门用来存放数组的首元素的地址。那么负责给形参传递值的实参的值也必须是一个地址,比如实参是其他的数组名。例子4(example8_4.c)main函数中有一个一维int型数组a,函数large的一个参数是数组类型,另一个是基本型。(1)执行main函数中的代码:inta[]={1,2,3,4,5};时(2)执行main函数中的代码:large(a,5);时(3)执行large函数中的代码:for(i=0;isize;i++){b[i]=100;}时重要结论:如果实参是数组名,那么当把实参传递给函数的同类型的形参后,那么该函数在函数体中对形参数组的元素的操作就等同对实参数组的元素的操作。2010-10138.3起泡法_1所谓对数组进行排序或排序数组就是想办法交换元素之间的值,以达到数组中的元素的值依次从小到大或从大到小排序。起泡法是数组排序的一种常用方法,算法被形象的比喻石头沉入水底的同时也向上冒起泡泡。我们假设int数组a中有6个元素,值依次是6,5,4,3,2,1。1.我们要做的第一件事就是把最大的数放到数组的最后(让最重的石头入水底)。执行图8.14的文本框中的循环语句。循环语句结束后,最大的数在数组的最后一个元素中(最重的石头沉入水底),数组a变成如图8.16所示。2010-10148.3起泡法_22.由于最大的数已经在数组的最后一个元素中,那么只要对数组除最后一个元素外,再实施上述同样的操作,就可以把第二大的数放入数组的倒数第二个元素中,依此类推,就可以把数组从小到大排序,即依次执行图8.17文本框中的循环语句。例子5(example8_5.c)用起泡法对数组进行排序。2010-10158.4二维数组定义二维数组和定义一维数组类似,包括数组名、数组的类型和数组含有的元素的个数,例如,假设需要3×4(12)个int型变量,可如下定义一个名字为girl、类型为int的二维数组:intgirl[3][4];那么数组girl是由12个int型变量所构成,称作数组girl的元素。数组girl可以使用双下标运算访问它的元素,即操作属于它的变量,例如:girl[0][0]=1;girl[0][1]=2;girl[0][2]=3;girl[0][3]=4;girl[1][0]=5;girl[1][1]=6;girl[1][2]=7;girl[1][3]=8;girl[2][0]=9;girl[2][1]=10;girl[2][2]=11;girl[2][3]=12;8.4.1二维数组的定义2010-10168.4.2二维数组的结构1.顺序结构一个二维数组是由一维数组所构成,例如对于:intgirl[3][4];二维数组girl是由3个一维数组所组成,这3个一维数组的数组名分别是:girl[0],girl[1]和girl[2],这3个一维数组都有4个元素。二维数组中的一维数组按索引顺序称作第0行,第1行…。定义二维数组时,第一对中括号中的常量值是二维数组包含的一维数组的数量,第二对中括号中的常量值是二维数组包含的一维数组的长度。二维数组的元素在内存中是按顺序排列的,而且是行优先,例如,对于二维数组:intgirl[3][4];排列顺序是第0行、第1行、第2行,内存示意图如图8.21。如果二维数组含有m×n个元素,那么在进行双下标运算时,第一个下标的索引从0至m-1,第二个下标的索引从0至n-1。2.数组名是只读变量当二维数组名不是函数的参数时,操作系统认为数组名是一个只读变量(当数组名做参数时,数组名是一个变量),但这个只读变量只能存放地址。二维数组名字的值是第0行首元素的地址。对于二维数组,单下标运算得到的是一维数组的名字,例如:girl[0],girl[1],girl[2]是三个一维数组的名字,双下标运算得到的是二维数组中的元素。2010-10178.4.3二维数组的初始化在定义二维数组的同时可以按行初始化,也可以逐个地对元素进行初始化。1.按行初始化。例如:inta[3][4]={{1,2,3,4},{5,6,7,8,},{9,10,11,12}};按行初始化实际上就是逐行地对二维数组中的一维数组进行初始化,因此遵守的是一维数组的初始化规则。对于inta[3][4]={{1,2,3,4},{5,6,7,8,}};那么a[2]行的元素的值都是0。对于inta[3][4]={{1,2,3,4},{5,6,7,8,},{9,10,11,12},{13,14,15,16}};这种初始化是错误的。2.逐个初始化。按二维数组元素的顺序,用大括号括起的若干个值依次初始化二维数组的元素的值。对于在大括号中没有对应值的二维数组元素的值默认被初始化为0。大括号括起若干个值的数量不能大于二数组中元素的个数。例如:inta[3][4]={1,2,3,4,5,6,7,8,,9,10,11,12};3.初始化时省略二数组的行数。例如:inta[][4]={{1,2,3,4},{5,6,7,8,},{9,10,11,12},{13,14,15,16}};等价于inta[4][4]={{1,2,3,4},{5,6,7,8,},{9,10,11,12},{13,14,15,16}};2010-10188.4.4二维数组的使用定义二维数组后,就可以使用数组名加双下标运算访问数组中的元素,也称引用数组中的元素。例子6(example8_6.c)使用二维数组计算矩阵的转置矩阵。例子7(example8_7.c)输出矩阵A中的最大值和最小值,并输出矩阵A的正对角元素之和。2010-10198.5const数组使用关键字const声明常量的格式:const类型名字=常量值;例如,声明一个基本类型常量MAX:constintMAX=100;有时候,我们不希望程序再更改数组元素的值,那么就可以用const声明定义一维数组:const类型数组名[常量]={初始值列表};或二维数组:const类型数组