第九章数组9.1数组的基本概念9.2数组的存储顺序9.3数组的赋值方式9.3数组的输出9.4数组的运算9.5数组的动态分配9.1数组的基本概念数组是一个集合,它的元素必须是标量,其标量元素可以属于任何的固有数据类型,派生数据类型,甚至是结构,但数组最关键的一个特征是:数组的所有标量元素必须属于同一个数据类型,并且具有同样的种别参数。这个特征决定了数组是一种功能强大的数据结构,因为存在大量的实际问题,需要用同一个计算过程来处理大规模的同种类型的数据在FORTRAN的早期版本里面,数组是作为数据的一种属性加以描述的,所使用的关键词为DIMENSION。这个规则一直被保留下来,因此任何数据对象只要是具有DIMENSION属性,就一定为数组。下一页上一页停止放映一、数组的结构数组的结构可以抽象地理解为多维离散空间的点的集合,即这些点都有相同的维度,在每一维上的坐标取值都是离散的标量。数组的结构是由维度,和每个维度的取值数目决定的。其中:一个数组的维度(行或列)的数目称为该数组的秩(rank)。FORTRAN标准要求数组的秩至少可以达到7。每个维度的坐标数目称为数组在该维度的宽度。在描述每个维度的宽度时,可以使用下标范围的形式。例如:REALA(2,0:24,10)下一页上一页停止放映一个数组的秩和每个维度的宽度就决定了该数组的形状;数组的形状可以用类似于向量的形式表示,即括号当中的一串标量数值,用逗号相隔,每个数值表示相应的维度的宽度。例如:REALA(2,25,10)表示以实型数值为元素的数组A,含有3维,每个维度的宽度分别是2,25,10。每一维的大小都由一个下界和一个上界来指定,之间以冒号分开,即下界:上界。维界表达式是整型的数学表达式,维界值可以是正、负或零,但维上界必须大于维下界的值。维长=上界-下界+1。声明数组时下界可以省略,此时维下界为默认值1。例如:REALB(0:9,-1:1,4:5,9)下一页上一页停止放映一个数组的所有维度的宽度的乘积,称为该数组的尺度,也就是该数组的元素的数目。例如:A数组的元素的数目=2*25*10=500B数组的元素的数目=(9-0+1)*(1+1+1)*(5-4+1)*(9-1+1)=10*3*2*9=540下一页上一页停止放映二、数组的定义F77中用类型说明语句、DIMENSION语句和COMMON语句F90中还可以用类型属性说明、POINTER语句、ALLOCATABLE语句。例如下面都是合法的数组声明:REALA(10,2,3)!类型说明DIMENSIONA(10,2,3)!DIMENSI0N语句ALLOCATABLEB(:,:)!ALLOCATABLE语句POINTERC(:,:,:)!POINTER语句REAL,DIMENSION(2,5)::D!类型说明中的DIMENSION属性REAL,ALLOCATABLE::E(:,:,:)!类型说明中的ALLOCATABLE属性REAL,POINTER::F(:,:)!类型说明中的POINTER属性F77注意:在同一个程序单元中,一个数组只能定义一次。下一页上一页停止放映三、数组引用1、数组名-代表数组中所有元素;2、数组元素-代表数组中某一个元素;3、数组片段-代表数组中若干个元素,它们可以相连或分离。下一页上一页停止放映数组元素数组元素的引用很简单,直接用下标给出该元素在每一个维度上的坐标即可。【例】声明1维数组X如下:F90:INTEGER,DIMENSION(25)::XF77:DIMENSIONX(25)INTEGERX那么对X的元素的引用例子为:X(3),X(12),X(24)下一页上一页停止放映声明3维数组A如下:F90:REAL,DIMENSION(2,25,10)::AF77:DIMENSIONA(2,25,10)INTEGERA那么对A的元素的引用例子为:A(1,12,5),A(2,22,8),A(1,17,10)这里的(1,12,5)等称为下标列。下一页上一页停止放映数组片断数组最灵活的功能体现在能够以数组的任意部分为对象作运算,把一个数组的任意指定部分作为一个新的数组,称为数组片断,而其所属的数组称为该数组片断的父数组。数组片断的引用,首先是一个父数组变量名称,然后是下标列,不过这里的下标列里面,必需至少包含一个下标是用下标三元组,或者是下标向量来表示的,否则这个引用就成了对数组元素的引用。下一页上一页停止放映1〉三元下标三元下标用三个值分别代表数组片段的下界,上界和步长。其一般形式为:[下界]:[上界][:步长]如果省略下界,缺省值为数组相应维的下界;如果省略上界,缺省值为数组相应维的上界;如果省略步长,缺省值为1。如果下标都省略了则缺省片段为这个维的全长。下一页上一页停止放映【例】下面是引用了一个数组片断:INTEGER,DIMENSION(25)::X…X(10:16)=78首先定义了1维整型数组X,其宽度为25,然后引用了X的一个片断,由X的第10个坐标到第16个坐标这7个元素组成,在这个引用当中,X所指定的这7个元素都被赋值为78。注意:这里的坐标引用(10:16)为一个省略了第3项的下标三元组。下一页上一页停止放映例:REALA(10)A(1:5:2)=3.0!把元素A(1),A(3),A(5)置为3.0A(:5:2)=3.O!把元素A(1),A(3),A(5)置为3.0,因为缺省下界为1A(2::3)=3.O!把元素A(2),A(5),A(8)置为3.0,因为上界缺省值为10A(7:9)=3.0!把元素A(7),A(8),A(9)置为3.0,因为缺省步长为1A(:)=3.0!和A=3.0相同,将A的所有元素置为3.0对于—个多维数组的数组片段,它的每一维都可以用三元下标来声明。如果要在一个语句或过程中引用这个数组片段,则引用下标要和声明时的下标个数一样多。注意,三元下标只能算一个下标。下一页上一页停止放映例:REALA(5,9)A(1:4:3,6:8:2)=3.0数组A是二维数组,数组片段是形状为二维数组。上面括号内第一个三元组表示第一维下标变化范围,第二个三元组表示第二维下标变化范围。其元素选取法是先把第二维下标定在下界值上,而后遍历第一维下标,选中元素为A(1,6),A(4,6);再把第二维下标增一步长,再遍历第一维下标,选中元素为A(1,8),A(4,8),如此重复直至全部选完。这种选取关系相当于把第二维作外层DO循环变量,第一维作内层循环变量的变化。这四个元素按先后次序保持一定的形状,上式等价于:(1,6)(1,8)(4,6)(4,8)AAAA下一页上一页停止放映2〉向量下标三元下标以上升或下降的顺序指定数组元素,而向量下标可以以任何顺序来指定数组元素。向量下标是一个一维整数数组(即向量),它可以从整个数组中选择片段。例:REALA(10),B(5,5)INTEGERI(4),J(3)I=(/5,3,8,2/)!定义向量IJ=(/3,1,5/)!定义向量JA(I)=3.O!设置元素A(5),A(3),A(8),A(2)的值B(2,J)=3.O!设置元素B(2,3),B(2,1)和B(2,5)的值下一页上一页停止放映例:INTEGER::a(4)=(/0,1,2,3/),b(3)=(/1,4,3/)则a(b)与a同类型,与b同形状,取值为(/0,3,2/)。a(b)可以不是数组片段,而是更大的数组。如上面b为(/2,3,2,3,2,3/)时,a(b)为(/1,2,1,2,1,2/)。例:CHARACTER(1)::symbol(0:1)=(/'F','M'/)INTEGER::bit(100)若bit的元素列为0001101100111...,则symbol(bit)是用{F,M}字符构成的100字节的字符型数组FFFMMFMMFFMMM...。下一页上一页停止放映向量下标的值应该在定义的边界之内,向量下标可以有多个重复的值,此数组片段称为多对一数组片段。例:REALA(3,3),B(4)INTEGERK(4)K=(/3,1,1,2/)!K矢量有重复值A=5.0!设置A的所有元素B=A(3,K)!数组片段B由下列元素组成:A(3,3),A(3,1),A(3,1),A(3,2)因为在B(4)或A(3,K)中有重复的元素A(3,1),所以它是多对一数组片段。一个多对一数组片段不能出现在赋值语句的左端。下一页上一页停止放映四、数组类型1〉显式形状(Explicit-shape)数组这种数组指定了所有特征:固定的秩、每一维的长度和形状。其中下界是可以忽略的。它的一般形式是:([下界:]上界[,[下界:]上界]…)例:INTEGERM(10,10,10),K(-3:6,4:13,0:9)维界可以是常数或变量。在过程(函数和子程序)中,数组的上界和下界可以由变量或表达式指定。使用变量或表达式的数组是自动数组和可调数组。下一页上一页停止放映2〉自动(Automatic)数组自动数组是显形数组的一种,它是过程中的局域变量,自动数组必须在过程中加以声明,并且它的上下界是不定的表达式。在调用过程时,上下界通过变量或表达式求出。过程中其后的变量或表达式值的变化不会对数组的上下界产生影响。例:SUBROUTINEEXAMPLE(N,R1,R2)DIMENSIONA(N,5),B(10*N)……N=IFIX(R1)+IFIX(R2)此例中的A和B都是自动数组。子程序被调用时,数组A和B的上界通过传入的变量N来确定,而以后N的值的变化对A和B的大小不会有影响。下一页上一页停止放映3〉可调(Adjustable)数组可调数组也是显形数组的一种,它是过程的一个哑元,至少有一个维界不是常数,这个维界当过程被调用时才被确定。其维界表达式中的变量是哑元,或者是通过COMMON语句中传递的常量。注意:多维可调数组的维界表达式必须与调用时的维界相符。下一页上一页停止放映FUNCTIONTHE_SUM(A,M,N)DIMENSIONA(M,N)SUMX=0.0DOJ=1,NDOI=1,MSUMX=SUMX+A(I,J)ENDDOENDDOTHE_SUM=SUMXENDFUNCTION例:DIMENSIONA1(10,35),A2(3,56)……SUM1=THE_SUM(A1,10,35)SUM2=THE_SUM(A2,3,56)END其中哑元M,N控制着可调数组的大小。下一页上一页停止放映例:DIMENSIONARRAY(9,5)L=9M=5CALLSUB(ARRAY,L,M)ENDSUBROUTINESUB(X,I,J)DIMENSIONX(-I/2:I/2,J)X(I/2,J)=999J=1I=2END下例说明了可调数组的维界X(-4:4,5)在调用过程时被确定后,过程内部对维界参数的赋值不会改变维界值。下一页上一页停止放映4〉假定形状(Assumed-shape)数组这种数组是在过程中的哑元,它从实际传递过来的数组获得形状参数。假定形状数组的秩由冒号的个数决定。它的一般形式是:([下界]:[,[下界]:]...)如果不指定下界,则默认值为1。上界值=过程调用时实参数组对应维的长度+下界值-1。注意:它与可调数组的区别在于,可调数组属于显型数组(必须指定上界)的范围,而假定形状数组的上界是不能指定的。下一页上一页停止放映主程序REALX(4,7,9)CALLASSUMED(X)例:子程序SUBROUTINEASSUMED(A)REALA(:,:,:)此时数组A的秩为3,但每一维的长度待定。当过程被调用时A将从传递到过程的数组获得形状。于是A获得了数组维界(4,7,9),实际数组和假定形状数组的值必须相同。如果上面过程中数组声明了下界A(3:,0:,-2:),以实元X(4,7,9)调用过程时,数组A的实际维界是A(3:6,0:6,-2:6)。下一页上一页停止放映例:INTERFACESUBROUTINESUB(M)INTEGERM(:,1:,5:)ENDSUBROUTINEENDINTE