数组在程序中的表现如下:
!声明数组
real a(10) !下标从1到10的一维数组
integer b(-5:8) !下标从-5到8的一维数组
dimension iArray(4) !根据i~n规则确定为是整型或实型数组
character*8, dimension(2:5) :: sa !类型声明形式
integer indices(3)
!赋初值
data a /10*3/ !赋成10个3
data b(-3), b(0), b(3) /1, 2, 3/ !把选中的三个元素分别赋成1,2,3
data (iArray(i),i=1,4) /4*2/ !把所有元素赋为2
!数组的存取
print *, "input 10 elements:"
read *, (a(i), i=1,10) !读入数组a的所有元素
a(1) = a(1) + 2
a(2:4) = 5 !把a(2)、a(3)和a(4)都设为5。a(2:4)等价于a(2:4:1)
print *, (a(i), i=1,5) !打印前5个值
!三元下标
b(:) = 8 !打b中的所有元素都设为8
b(1:6:2) = 7 !把b(1)、b(3)、b(5)设为7,三元下标(起始:终止:增量)
b(:-3) = 3 !把b(-5)、b(-4)、b(-3)设为3.默认起始为数组开头。
b(6::2) = 9 !把b(6)和b(8)设为9,默认终止为数组末尾
print *, b
!向量下标
indices = (/3, 8, 6/)
a(indices) = 13 !把a(3)、a(8)、a(6)设为13
print *, a
多维数组:
integer :: a(10, 5) = 77 !大小为10x5的数组,所有的元素值都为77
a(:,2:3) = 8 !把每行的2,3列都设为8
print *, ((a(i,j), i=1,10), j=1,5)
上面看到的数组都是显式形状(explicit-shape)数组,此外还有别的类型的数组:
自动(automatic)数组根据过程哑元(函数参数)来确定数组的形状与大小:
subroutine automatic_array(N)
integer a(N)
a(:) = 8
print *, a
end
调用方式:
call automatic_array(8)
可调(adjustable)数组根据传入的哑元数组以及维度信息来确定数组的大小:
subroutine adjustable_array(A, N)
integer A(N)
print *, A
end
调用方式:
integer a(8)
call adjustable_array(a, 8) !传入的形状必须与原数组形状一样。
假定形状(assumed-shape)数组可以先假定数组的维度,传入的数组必须有相同的维度。假定形状数组必须定义在interface里:
interface
!假定形状(assumed-shape)数组
subroutine assumed_shape_array(A)
integer A(:,:) !假定是个二维数组
end subroutine
end interface
调用方式:
integer a(2,3)
call assumed_shape_array(a) !a必须是二维,否则编译出错
假定大小(assumed-size)数组先假定数组指定维度的大小,传入的数组必须有相同的维度大小,否则在运行时可能会出现错误:
subroutine assumed_size_array(A)
integer A(2,2,*)
print *, A(:,:,1)
end
调用方式:
integer a(2,2,3)
call assumed_size_array(a)
数组的赋值可以用下面这种便利的方式:
integer a(6)
integer b(8)
a = (/1,2,3,4,5,6/) !长度必须一样,否则编译会出错
print *, a
a = (/3,2,3,4,7,8/) !可以多次对数组进行赋值
print *, a
a = [4,8,9,2,1,5] !方括号与(/.../)方式等价
print *, a
b = (/1,2,a(1:4),8,9/) !数组方式
print *, b
b = (/(i*2,i=1,4),a(3:6)/) !隐do方式
print *, b
Fortran中的多维数组在内存中是按列存储的,与C语言按行存储不同。
Fortran90对元素的处理是并行的,哪怕不是在并行计算机上,操作在形式上也是并行的。看下面的例子:
integer :: a(9) = (/(i,i=1,9)/)
a(2:9) = a(1:8) !并行方式
print *, a ! 1 1 2 3 4 5 6 7 8
a = (/(i,i=1,9)/)
do i=2,9
a(i) = a(i-1) !串行方式
end do
print *, a ! 1 1 1 1 1 1 1 1 1
reshape函数可以把一维数组转换成多维数组的格式,从而能够将其赋给一个多维数组变量。它的格式为:
结果=RESHAPE(源,形状[,补充][,顺序])
源是用来转变的一维数组;形状是一个一维整型数组,各元素表示结果数组的各个维
度的大小;补充是和源一样类型的一维数组,当源比结果数组小时,其元素用来补充缺少的元素;顺序也是一维数组,其元素为1到n的一个排列,其中n为形状数
组的大小,默认情况下顺序数组的元素为(1,2,...,n),表示源数组中的元素先填充顺序为n的维度,最后填充顺序为1的维度。下面是一个例子:
integer b(2,3)
b = reshape((/1,2,3,4,5,6/), (/2,3/))
print *, b
b = reshape((/1,2,3/), (/2,3/), (/8,9/))
print *, b !1,2,3,8,9,0。补充数组的元素仍不够的情况下补0
b = reshape((/1,2,3,4,5/), (/2,3/), (/8,9/), (/2,1/))
print *, b !1,4,2,5,3,8。顺序2,1说明先填满第一个维度(即行),再来填第二个维度(即列)。
where语句可以用来进行带条件的数组赋值,它的形式为
WHERE(屏蔽表达式) 赋值语句 或
[构造名:]WHERE(屏蔽表达式1)
[块]
[ELSEWHERE(屏蔽表达式2) [构造名]
[块]]
[ELSEWHERE [构造名]
[块]]
END WHERE [构造名]
下面是where的一个例子:
integer A(5), B(5), C(5)
A = (/1,2,3,4,5/)
B = (/3,3,3,3,3/)
C = (/0,0,0,0,0/)
where (A >= B) C = A
print *, C ! 0,0,3,4,5
where (A < B)
C = -1
elsewhere (A == B)
C = 0
elsewhere
C = 1
end where
print *, C ! -1,-1,0,1,1
forall语句是Fortran95对where语句的推广,它的一般形式为:
FORALL(循环三元下标[,循环三元下标]…[,屏蔽表达式]) 赋值语句 或
[构造名:]FORALL(循环三元下标[,循环三元下标]…[,屏蔽表达式])
[块]
END FORALL [构造名]
下面是forall的一个例子:
integer A(5, 5)
A = reshape((/(i,i=1,25)/), (/5,5/))
forall(i=2:3,j=1:5:2) A(i,j) = 0
print *, A
Fortran中可以直接以数组(或数组片段)为对象进行运算。当两个数组相容(即形状相同)时,所有的算术运算符(+,-,*,/,**)、逻辑运算符(如.AND.,.OR.,.NOT.)和所有关系运算符(如.LT.,.EQ.,.GT.),还有很多内在函数都可以接受数组名称作为参数并对数组元素逐一运算。比如:
integer A(2,3), B(2,3), C(2,3)
logical P(2,3), Q(2,3), R(2,3)
real X(2,2), Y(2,2)
!算术运算
A = reshape((/(i,i=1,6)/), (/2,3/))
B = 2
C = A + B
print *, C
C = A - B
print *, C
C = A * B
print *, C
C = A / B
print *, C
!比较运算
P = A < B
print *, P
Q = A > B
print *, Q
!逻辑运算
R = P .and. Q
print *, R
R = P .or. Q
print *, R
R = .not. P
print *, R
!基本内在函数
X = reshape((/1.,2.,3.,4./), (/2,2/))
Y = cos(X)
print *, Y
Y = sin(X)
print *, Y
Y = sqrt(X)
print *, Y
可以接受数组为参数的内在函数(即库函数)称为基本内在函数。F90数组运算内在函数表:
函数名称
描述
ALL(mask[,dim])
判断全部数组值在指定维上是否都满足mask的条件
ANY(mask[,dim])
判断是否有数组值在指定维上满足mask的条件
COUNT(mask[,dim])
统计在指定维上满足mask的条件的元素个数
CSHIFT(array,shift[,dim])
进行指定维上的循环替换
DOT_PRODUCT(vector_a,vector_b)
进行两个向量的点乘
EOSHIFT(array,shift[,boundary][,dim])
在指定维上替换掉数组末端,复制边界值到数组末尾
LBOUND(array[,dim])
返回指定维上的下界
MATMUL(matrix_a,matrix_b)
进行两个矩阵(二维数组)的乘积
MAXLOC(array[,dim][,mask])
返回数组的全部元素或指定维元素当满足mask条件的最大值的位置
MAXVAL(array[,dim][,mask])
返回在指定维上满足mask条件的最大值
MERGE(tsource,fsource,mask)
按mask条件组合两个数组
MINLOC(array[,dim][,mask])
返回数组的全部元素或指定维元素当满足mask条件的最小值的位置
MINVAL(array[,dim][,mask])
返回在指定维上满足mask条件的最小值
PACK(array,mask[,vector])
使用mask条件把一个数组压缩至vector大小的向量
PRODUCT(array[,dim][,mask])
返回在指定维上满足mask条件的元素的乘积
RESHAPE(source,shape[,pad][,order])
使用顺序order和补充pad数组元素来改变数组形状
SHAPE(source)
返回数组的形状
SIZE(array[,dim])
返回数组在指定维上的长度
SPREAD(source,dim,ncopies)
通过增加一维来复制数组
SUM(array[,dim][,mask])
返回在指定维上满足mask条件的元素的和
TRANSPOSE(matrix)
转置二维数组
UBOUND(array[,dim])
返回指定维上的上界
UNPACK(vector,mask,field)
把向量在mask条件下填充field的元素解压至数组
数组可以是静态的,也可以是动态的。静态数组的存储空间直到程序退出才会释放,而动态数组(F90)可以在运行时进行分配和释放。动态数组有两种:自动数组和可分配数组,前面已经介绍过了。
对于allocable的数组,可以用allocate来分配一块内存:
ALLOCATE(数组名[维界符][,数组名[(维界符[,维界符...])]] ...[,STAT=状态值])。
STAT用来接受返回值,如果不设置STAT的话,如果分配出错,程序会中止。下面是个例子:
INTEGER, ALLOCATABLE :: A(:),B(:)
INTEGER ERR_MESSAGE
ALLOCATE(A(10:25),B(SIZE(A)),STAT=ERR_MESSAGE)
IF(ERR_MESSAGE.NE.0) PRINT *,'ALLOCATION ERROR'
dellocate用来释放内存:
DEALLOCATE(数组名[,数组名]...[,STAT=状态值])
ALLOCATED(数组名)可以判断一个数组是否已被分配。