2012-07-26 11:10:04
原文: 第五章: 数组 数组类型与定义
两种变量:标量+数组. 标量维数为0, 数组维数>=1.
数组的定义
类型相同的一组标量数据的有序集合
数组元素类型必须相同, 这些元素按某种确定方式排列
- 一维数组:向量(列向量或行向量)
- 二维数组:矩阵
数组的维数
- 数组的维数(dimension):最小为1, 最大为7
- 数组的维长(extent):某一维中元素的个数, 可以为0
- 维长由 维下界:维上界 指定, 等于维上界-维下界+1
- 维下界省略时为默认值1
- 维上界必须大于维下界的值
- 维界值可以是正、负、零或任何整型表达式
- 数组的大小(size):所有元素的个数, 等于各维长的乘积, 可以为0
- 数组的形状(shape):取决于维数与每一维的维长, 可由函数shape得到
例
- 数组
A(10,3,2)
的维数为3, 维长分别为10、3、2, 大小为10×3×2=60, 形状为10乘3乘2, 或表示成(10,3,2), shape(A)的结果是一维数组, 其元素为10, 3, 2. - 数组
B(2,2,0)
的第三维维长为0, 因而大小为0, 不能用于存储任何数据. - 数组
C(2, 0:9, -3:-1, int(-sqrt(45./3.)):int(5/2))
为4维数组, 大小为2×10×3×6.
数组声明
声明时数组的维数必须指定的, 大小和形状是否需要指定视数组的形式而定
real A(10,2,3)
类型说明dimension A(10,2,3)
dimension语句allocatable B(:,:)
allocatable语句pointer C(:,:,:)
pointer语句real, dimension(2,5):: D
类型说明中的dimension属性real, allocatable:: E(:,:,:)
类型说明中的allocatable属性real, pointer:: F(:,:)
类型说明中的pointer属性
数组的引用
- 数组名 :数组中所有元素, 无下标
- 数组元素:数组中某个元素, 指定所有下标
-
数组片段:数组中若干元素, 不需连续或遵循某个规则, 指定部分下标列表, 本身也是数组
- 引用时数组的下标必须用逗号隔开
- 引用下标的个数要和声明的数组的维数一致
- 下标是整型表达式, 可正、可负、也可为0, 但必须在引用的数组的维界之内
例
real A(3,3), B(3,3), C(89), R
B(2,2)=4.5; R=7.O; C(int(R)*2+1)=2.O
!给元素B(2,2)和C(15)赋值A(1,2)=B(int(C(15)), int(sqrt(R)))
!元素A(1,2)和元素B(2,2)的值相同real A(2,3,4)
, 则A(1,2,3)是数组元素, 而A(1:2,2,2),A(1,1,4:2:-1),A(1,2:3,(/2,4/))
都是数组片段
数组的下标列表有两种:三元下标和向量下标.
三元下标[下界]:[上界][:步长]
用三个值分别代表数组片段的下界, 上界和步长, 以上升或下降的顺序指定数组元素.
- 若省略下(上)界, 缺省值为数组相应维的下(上)维界
- 若上下界全省略, 缺省片段为这个维的全长
- 三元下标的值可以不在数组的边界以内
- 三元下标只能算一个下标
- 对多维数组的数组片段, 每一维都可以用三元下标来声明
- 在语句或过程中引用数组片段时, 引用下标的个数必须与声明时的相同
- 若省略步长, 缺省值为1.
- 步长不能是0. 当步长为负值时, 数组子片段从上界开始递减至下界
例
real A(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.0real B(10)
- 数组片段
B(9:2:-2)
是由元素B(9), B(7), B(5)和B(3)组成的数组. - 数组片段
B(3:15:6)
是由B(3)和B(9)组成的数组. real A(5,9)
则A(1:4:3,6:8:2)=3.0
等价于A(1,6)=3.0; A(1,8)=3.0; A(4,6)=3.0; A(4,8)=3.0
向量下标
利用一个一维整数数组(即向量)来指定数组元素
- 向量下标的值应该在定义的边界之内
- 向量下标可以有多个重复的值, 此时数组片段称为多对一数组片段
例
real A(10), B(5,5)
integer I(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….real A(3,3), B(4)
integer K(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), 所以它是多对一数组片段. 一个多对一数组片段不能出现在赋值语句的左端
数组类型
-
显式形状(Explicit-shape)数组:指定了维数和每一维的维长, 维下界是可省略,
Array([维下界:]维上界[,[维下界:]维上界]…)
例:
integer M(10,10,10), K(-3:6,4:13,0:9)
- 维界可以是常数或变量.
- 在过程(函数和子程序)中, 数组的上界和下界可以由变量或表达式指定.
- 使用变量或表达式的数组是自动数组和可调数组.
-
自动(Automatic)数组
- 显形数组的一种, 它是过程中的局域变量
- 自动数组必须在过程中加以声明, 并且它的上下界是不定的表达式.
- 在调用过程时, 上下界通过变量或表达式求出.
- 过程中其后的变量或表达式值的变化不会对数组的上下界产生影响.
例
# Language: fortran subroutine example(N,R1,R2) dimension A(N,5), B(10*N) …… N=IFIX(R1)+IFIX(R2) …… end
此例中的A和B都是自动数组. 子程序被调用时, 数组A和B的上界通过传入的变量N来确定, 而以后N的值的变化对A和B的大小不会有影响.
例
# Language: fortran subroutine sub1(M, N) integer M, N, lower common/bound/lower …… integer auto_array1(N) integer auto_array2(lower:N) integer auto_array3(20,N*M/2) …… end subroutine
-
可调(Adjustable)数组
- 可调数组也是显形数组的一种, 它是过程的一个哑元, 至少有一个维界不是常数, 这个维界当过程被调用时才被确定.
- 其维界表达式中的变量是哑元, 或者是通过COMMON语句中传递的常量.
- 注意多维可调数组的维界表达式必须与调用时的维界相符.
例
# Language: fortran dimension A1(10,35), A2(3,56) …… sum1=the_sum(A1, 10, 35) sum2=the_sum(A2, 3, 56) end function the_sum(A, M, N) dimension A(M, N) sumx=0.0 do j=1,N do i=1,m sumx=sumx+A(i,j) end do end do the_sum=sumx end function
其中哑元M,N控制着可调数组的大小.
例
# Language: fortran dimension Array(9,5) L=9 M=5 call sub(Array,L,M) end subroutine sub(X,i,j) dimension X(-i/2:i/2,j) X(i/2,j)=999 j=1 i=2 end
可调数组的维界X(-4:4,5)在调用过程时被确定后, 过程内部对维界参数的赋值不会改变维界值.
-
假定形状(Assumed-shape)数组
- 这种数组是在过程中的哑元, 它从实际传递过来的数组获得形状参数. 假定形状数组的秩由冒号的个数决定.
- 它的一般形式是:([下界]:[,[下界]:]…). 如果不指定下界, 则默认值为1. 上界值=过程调用时实参数组对应维的长度+下界值-1.
- 注意它与可调数组的区别在于,可调数组属于显型数组(必须指定上界)的范围, 而假定形状数组的上界是不能指定的.
例
# Language: fortran subroutine assumed(a) real a(:,:,:) end
此时数组a的秩为3, 但每一维的长度待定. 当过程被调用时a将从传递到过程的数组获得形状
real x(4,7,9)
call assumed(x)
于是a获得了数组维界(4,7,9), 实际数组和假定形状数组的值必须相同. 如果上面过程中数组声明了a(3:,0:,-2:), 以哑元x(4,7,9)调用过程时, 数组a的实际维界是a(3:6,0:6,-2:6).应用假定形状数组为哑元的过程时必须有显式的接口INTERFACE语句.
例
# Language: fortran interface subroutine sub(m) integer m(:,1:,5:) end subroutine end interface integer L(20,5:25,10) call sub(L)
在此例中数组M的维界是(1:20,1:21,5:14).
-
假定大小(Assumed-size)数组
- 这种数组是在过程中的哑元, 它从实际传递过来的数组获得数组大小.
- 除了最后一维的上界以外, 其它所有特征(秩, 长度和维界)都必须指定.
- 声明一个假定大小数组时, 最后一个的上界用星号表示. 它的一般形式是:([显型维界,][显型维界,]…[下界:]).
例
# Language: fortran subroutine assume(a) real a(2,2,*) end
假定大小数组的秩和形状可以和实际传入的数组不同, 传入的数组只确定它的大小. 实际数组的元素按列传递给假定大小数组, 假定大小数组也按列接收. 接受的过程中假定大小数组的最后一维的长度会改变来接受所有传递进来的数组元素, 于是最终给出数组的大小. 如上例子中的assume子程序, 如果以数组x为哑元来调用的话,
real x(7)
call assume(x)
则数组X的元素与数组A的对应顺序是:
X(1):A(1,1,1)
X(2):A(2,1,1)
X(3):A(1,2,1)
X(4):A(2,2,1)
X(5):A(1,1,2)
X(6):A(2,1,2)
X(7):A(1,2,2)其中数组A的最后一维没有必要成为完整的维, 所以数组A始终没有确定的形状. 因为假定大小数组没有形状, 所以这样的数组不能仅仅通过名称来向其它过程传递.
假定大小数组可以分解成确定的数组片段. 如上例中的数组A, 可分为三个片段:A(1:2,1:2,1)和A(1:2,1,2)以及A(1,2,2).
假定大小数组的秩是完全确定的维数+1. 上例中数组A的秩为3, 尽管A的第三维不是完整的.
-
延迟形状(Deferred-shape)数组
用来声明可分配数组, 维数由冒号确定, 但维长只有在分配数组才被确定.
例
real, allocatable:: A(:,:,:)
integer, allocatable, target:: K(:)
可分配数组可由下列方式声明:使用allocatable语句、dimension语句、target语句或在类型声明中使用allocatable属性. 如果迟形数组以dimension语句或target语句声明, 则在其它语句中必须给出allocatable属性.
在迟形数组的大小、形状和维界没有确定之前, 其任何部分都不能被引用, 可分配数组的大小、形状和维界在allocate语句执行时才被确定.
例
integer,allocatable:: A(:,:)
real,allocatable,target:: B(:,:), C(:)
allocate(A(2,3), C(5), B(size(C),12))