1 / 37

第五章 数 组

第五章 数 组. Fortran 90 数组的特点: *** 可以逐个元素对数组进行操作,也可以对数组整体、数组段直接进行操作; *** Fortran 90 提供了针对数组操作的构造块和函数; *** Fortran 90 提供了动态数组,以有效利用内存; *** Fortran 90 数组具有隐式循环和数组赋值的功能。. 第一节 数组声明. 数组声明实例 REAL , DIMENSION(15) ::X !下界缺省值为 1

Télécharger la présentation

第五章 数 组

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第五章 数 组 Fortran 90数组的特点: *** 可以逐个元素对数组进行操作,也可以对数组整体、数组段直接进行操作; *** Fortran 90提供了针对数组操作的构造块和函数; *** Fortran 90提供了动态数组,以有效利用内存; *** Fortran 90 数组具有隐式循环和数组赋值的功能。

  2. 第一节 数组声明 数组声明实例 • REAL,DIMENSION(15) ::X !下界缺省值为1 • REAL,DIMENSION(1:5,1:3) ::Y • REAL,DIMENSION(-4:0,1:3) ::Z (1)维(rank) —代表下标个数。X为一维数组,Y和Z为二维数组。 (2)界(bounds) — X下界1、上界15,Y下界1和1,上界5和3,Z下界-4和1、上界0和3。 (3)度(extent) —维上的元素个数。X度为15,Y和Z度为5和3。 (4)大小(size) —总的元素个数,或特定维上的元素个数。X、Y和Z的大小为15。 (5)形状(shape) —由维和度决定。X的形状为(/15/),Y和Z形状为(/5,3/)。 (6)一致的(conformable) —形状相同的数组是一致的或兼容的,一致的数组才能相互赋值,这里Y和Z 形状相同。

  3. 数组声明的一般形式: • TYPE,DIMENSION( [dl:],du[[dl:] du]…) ::Arr • TYPE [::] Arr( [dl:], du[[dl:] du]…) TYPE代表数据类型,dl 和du 分别为维的下界和上界,Arr 为数组变量。 下列都是合法的数组声明: • INTEGER, PARAMETER ::lda=5 • REAL,DIMENSION(100) ::R • REAL,DIMENSION(1:10,1:10) ::S • REAL ::T(10,10) • REAL,DIMENSION(-10: -1) ::X • INTEGER,PARAMETER ::lda=5 • REAL,DIMENSION(0:lda-1) ::Y • REAL,DIMENSION(1+lda*lda,10) ::Z 表明: (1)上、下界可以任意规定; (2)缺省下界为1; (3)可省略 DIMENSION 属性,如 T ; (4)数组大小可以为0; (5) Fortran 77数组声明分2步:先数组类型,再数组维数及大小。

  4. 例 5-1 一维数组的使用,从保存有学生学号、姓名和成绩三列数据的文件中读取全部数据,并在屏幕上显示 PROGRAM Main IMPLICIT NONE INTEGER,PARAMETER :: MAX = 100 ! 最大行数 CHARACTER(20) NO(MAX),NAME(MAX) ! 学号、姓名 REAL MARK(MAX) ! 成绩 INTEGER IO,I,N ! N 代表实际行数 OPEN (1,FILE = ‘DATA.TXT’) READ(1,*,IOSTAT = IO) (NO(I),NAME(I),MARK(I),I=1,MAX) IF(IO<0)THEN ! 遭遇文件尾 N=I-1 ELSE N=MAX END IF PRINT*,N WRITE(*,‘(2A,F4.1)’) (NO(I),NAME(I),MARK(I),I=1,N) CLOSE(1) END PROGRAM

  5. 例5-2 二维数组的使用,从保存有学生学号、姓名和成绩三列数据的文件中读取全部数据,并在屏幕上显示 • PROGRAM Main • IMPLICIT NONE • INTEGER,PARAMETER :: MAX = 100 !最大行数 • CHARACTER(20) Stud(MAX,3) !学号、姓名、成绩,共3列 • INTEGER IO,I,J,N • OPEN (1,FILE = ‘DATA.TXT’) • READ(1,*,IOSTAT = IO) ((Stud(I,J),J=1,3),I=1,MAX) • IF(IO<0)THEN • N=I-1 • ELSE • N=MAX • END IF • PRINT*,N • PRINT*,((Stud(I,J),J=1,3),I=1,N) • CLOSE(1) • END PROGRAM

  6. 第二节 数组存储 1. 自由存储 • 不规定数组在内存中如何存储,便于编写可移植的程序,编译器可以自由地实现存储优化。例如:在分布式计算环境中,一个大的数组可以被存储到100 个处理器中,每个存储数组中的部分元素。在 High Performance Fortran 中,自由存储被广泛应用。 2. 列主存储 • 先存储第一列,然后是第二列、第三列,直到最后一列,称为列主存储。例如:向另一个语言编写的例程传递数组、数组构造、数组输入/输出、系统提供的一些数组函数(TRANSFER,RESHAPE,PACK,UNPACK和MERGE)时,需要明确给出数组的存储方式 —列主存储。

  7. 第三节 数组操作 1. 数组赋初值 (1) 使用 DATA 的一般形式为: • INTEGER A(5) • DATA A/1, 2, 3, 4, 5/! A(1), A(2), A(3), A(4), A(5)的值分别为1, 2, 3, 4, 5 (2) 使用乘号(*) • DATA A /5 *3/! A(1), A(2), A(3), A(4), A(5)的值都为3 乘号“*” 表示数据的重复, 重复的次数写在前面。 (3) 使用隐式循环 • DATA (A(I), I=2,4) /2, 3, 4/ !A(2),A(3),A(4)的值分别为2,3,4 隐式循环可用来设置数组的初值,也可以认为是 DO 循环的简略形式,在隐式循环中,同样可以设置循环变量的增量(或步长)。例如: • DATA (A(I), I=1, 5, 2) /1, 3, 5/ !A(1),A(3),A(5)的值分别为1,3,5

  8. 隐式循环也可以嵌套使用,例如: • INTEGER B(2,2),I,J • DATA ((B(I,J),J=1,2 ) /1,2,3,4/ (4) 省略 DATA Fortran 90可以省略 DATA 关键字,直接给数组设置初值。例如: • INTEGER :: A(5)=(/1,2,3,4,5/) 省略 DATA ,仍可使用隐式循环,所赋初值的个数要与数组元素的个数相等。 • INTEGER I • INTEGER ::A(5)=(/1,(2,I=2,4),5/) !A(2),A(3),A(4)的值为2,A(1)和A(5)的值分别为1,5 隐式循环可以给数组赋初值,也可以用来输出数组。例如: • PRINT *,((B(I,J),I=1,2),J=1,2)

  9. 2. 数组整体操作 Fortran 90 可以对数组进行整体操作,操作简化,举例说明如下: • A=5 其中,A是任意维数及大小的数组,该语句将数组A 所有元素的值设为5。 • A=(/1,2,3/) 其中,A(1)=1,A(2)=2,A(3)=3,所提供的数据个数必须跟数组 A 的大小一样。 • A=B 其中,A 和 B 是形状完全相同的数组,数组 A 相应位置元素的值设置成同数组 B。 • A=B+C • A=B-C • A=B*C • A=B/C 其中,A、B 和 C 是3个形状完全相同的数组,数组 B 和 C 相应位置元素的值相加、相减、相乘和相除,得到的结果再赋给数组 A 对应元素。 • A=Sin(B) 其中,数组 A 的每一个元素为数组 B 相应元素的 Sin 值,数组 B 须是实型。 • A=B>C 其中,A、B 和 C 是3个形状完全相同的数组,不过 A 为逻辑型数组,B 和 C 为同类型的数值型数组。

  10. 3. 数组段操作 Fortran 90除针对整个数组进行操作外,还能对数组段进行操作。 数组段的下标三元组形式为: • [<bound1>] : [<bound2>] :[<stride>] 数组段起始于下标 bound1 ,终止于下标 bound2,步长为 stride。例如: • A(:) !整个数组; • A(m:n:k) !A(m)~A(n),步长为k • A(m:) !A(m)~A(上界),步长1; • A(:n) !A(下界)~A(n),步长1; • A(::2) !A(下界)~A(上界),步长2; • A(m:m) !一个元素的数组段 数组段的操作语法类似于隐式循环,如: • A(3:5) =5 其中,将A(3)、A(4)、A(5)的值设置为5,其他值不变。

  11. A(3:) =5 其中,将A(3)以后所有元素的值设为5,其他值不变。 • A(3:5) = (/3,4,5/) 其中,将A(3) 、A(4)、 A(5) 的值分别设为 3、4、5,其他值不变。 • A(1:3) = B(4:6) 其中,设置A(1) = B(4)、 A(2) = B(5)、 A(3) = B(6)。 • A(1:10) = A(10:1:-1) 其中,A(1:10)翻转,即将A(1)设为A(10),A(2)设为A(9),依次类推。 • A(:) = B(:,2) 其中,假设 A 和 B 分别声明为 INTEGER A(5)、 INTEGER B(5,2),这里将二维数组B第2列的 5 个元素的值赋给一维数组 A 的5个元素,注意必须保持元素个数的一致。

  12. 4. 数组输出 数组元素、数组整体和数组段都可以表控输出(PRINT*),对3×3矩阵假设有下列输出语句: • PRINT*,‘Array element =’,a(3,2) • PRINT*,‘Array section =’,a(:,1) • PRINT*,‘Sub – array =’,a(:2,:2) • PRINT*,‘Whole Array =’,a • PRINT*,‘Array Transp“d =’,TRANSPOSE(a) 输出结果为: • Array element = 6 • Array section = 1 2 3 • Sub – array =1 2 4 5 • Whole Array =1 2 3 4 5 6 7 8 9 • Array Transosed =1 4 7 2 5 8 3 6 9

  13. 5. WHERE构造 关于WHERE的说明:WHERE用来取出部分数组内容进行操作,WHERE的操作是按照逻辑判断,使用满足条件的部分数组元素。 关于WHERE的实例:使用 WHERE 构造计算应上交的所得税,每年收入3万元以下,所得税为10%;收入为3万元到5万元之间,所得税为12%;收入5万元以上,所得税为15% 例5-3 WHERE 构造的使用 • PROGRAM Main • IMPLICIT NONE • REAL :: income(10)=(/25000,30000,50000,40000,& 35000,60000,27000,45000,20000,70000/) • REAL :: tax(10) = 0 • INTEGER I • CALL Proc_Where;PRINT*,tax • CALL Proc_IF;PRINT*,tax • CONTAINS

  14. SUBROUTINE Proc_Where ! Where构造 • WHERE(income<30000.0) • tax = income*0.1 • ELSEWHERE(income<50000.0) • tax = income*0.12 • ELSEWHERE • tax = income*0.15 • END WHERE • END SUBROUTINE • SUBROUTINE Proc_IF ! IF构造 • DO I = 1,10 • IF(income(I)<30000.0)THEN • tax(I)=income(I)*0.1 • ELSE IF(income(I)<50000.0)THEN • tax(I)=income(I)*0.12 • ELSE • tax(I)=income(I)*0.15 • END IF • END DO • END SUBROUTINE • END PROGRAM

  15. WHERE 构造的程序代码比较精简,其语法格式为: • WHERE(logical-expr1) • block1 • ELSEWHERE(logical-expr2) • block2 • ELSEWHERE(logical-expr3) • block3 • … • ELSEWHERE • blockE • END WHERE 如果只有一条执行语句,那么可以将这条执行语句写在 WHERE后面,并省略 END WHERE,例如: • WHERE(income>50000) income = 50000 此时,WHERE 构造转化为 WHERE语句,WHERE语句和 IF 语句在构造形式上是相同的,但省去了循环语句,结构精简。 • WHERE(logical-expr) 执行语句

  16. WHERE 构造也可以被命名,例如: • name:WHERE(income>50000) • income = 50000 • END WHERE name WHERE 构造也可以嵌套使用,例如: • WHERE(income<50000.0) • WHERE(income<30000.0) • tax = income*0.1 • ELSEWHERE • tax = income*0.12 • END WHERE • ELSEWHERE • tax = income*0.15 • END WHERE

  17. 6. FORALL 构造 FORALL构造,通过隐式循环来使用数组,功能强大,属于 Fortran 95 新添功能,举例说明如下:例 5-4 FORALL 构造的使用 • PROGRAM Main • IMPLICIT NONE • INTEGERI,J,A(5,5) • CALL Proc_1 • WRITE(*,‘(5I)’)((A(I,J),J=1,5),I=1,5) • CALL Proc_2 • WRITE(*,‘(5I)’)((A(I,J),J=1,5),I=1,5) • CONTAINS • SUBROUTINE Proc_1 • FORALL(I=1:5,J=1:5) • A(I,J)=I*J • END FORALL • END SUBROUTINE • !Proc_1采用FORALL来实现;Proc_2采用DO循环来实现 • SUBROUTINE Proc_2 • DO I = 1,5 • DO J = 1,5 • A(I,J) = I*J • END DO • END SUBROUTINE • END PROGRAM

  18. 例5-5 FORALL 语句的使用 • PROGRAM Main • IMPLICIT NONE • INTEGER I,J • INTEGER,PARAMETER :: N=5 • INTEGER A(N,N) • CALL Proc_1 • WRITE(*,‘(5I)’)((A(I,J),J=1,N),I=1,N) • CALL Proc_2 • WRITE(*,‘(5I)’)((A(I,J),J=1,N),I=1,N) • CONTAINS • SUBROUTINE Proc_1 • FORALL(I=1:N,J=1:N,I<J)A(I,J)=1 !上三角 • FORALL(I=1:N,J=1:N,I==J)A(I,J)=2 !对角线 • FORALL(I=1:N,J=1:N,I>J)A(I,J)=3 !下三角 • END SUBROUTINE !内部例程Proc_1采用FORALL来实现

  19. SUBROUTINE Proc_2 • DO I = 1,N • DO J =1,N • IF(I<J) A(I,J)=1 !上三角 • IF(I==J) A(I,J)=2 !对角线 • IF(I>J) A(I,J)=3 !下三角 • END DO • END DO • END SUBROUTINE • END PROGRAM !内部例程Proc_2采用DO循环结合IF语句来实现 FORALL 语句的一般形式为: • FORALL(循环表达式1,[循环表达式2]…,[条件判别式]) 执行语句 FORALL 构造的一般形式为: • [name:] FORALL (循环表达式1, [循环表达式2]…,[条件判别式]) • FORALL 语句块 • END FORALL [name]

  20. 关于FORALL的说明如下: (1)循环表达式,相当于 DO 循环中的表达式1、表达式2和表达式3,循环表达式的数量和数组维数相对应; (2)条件判别式,逻辑表达式,若省略该项(缺省),则条件为真,条件判断式可使用循环表达式中的循环变量; (3)FORALL 语句块,要被赋值的变量须是数组元素或数组段,且须引用出现在循环表达式中的所有循环变量(或数组下标),赋值表达式不能是字符表达式; (4)Name规定FORALL 构造的名字; (5)FORALL 可以嵌套,可以在 FORALL 构造中使用 WHERE,但 WHERE构造中不能使用 FORALL ,FORALL 的嵌套及 FORALL中使用 WHERE的例子详见课本68页的程序代码段。

  21. 7. 矢量下标 数组段中的元素次序未必是线性的,例如: • INTEGER,DIMENSION(5) :: V=(/1,4,8,12,10/) • INTEGER,DIMENSION(3) :: W=(/1,2,2/) • A(V) = 3.5 A(V) 标识一个非规则数组段:A(1) 、A(4) 、A(8) 、A(12) 和A(10),将 3.5 赋给上列5个元素。 • C(1:3,1) = A(W) 将数组段C(1:3,1) 设为A(1) 、A(2) 、A(2),即将A(1) 、A(2) 、A(2) 的值赋给数组段C(1:3,1) 。 对矢量下标的说明: (1)矢量下标可用在赋值操作符(=)的任何一边,为保持并行计算环境下数组操作的完整性,赋值操作符左边的数组下标必须是唯一的,那么对A(W)赋值是非法的,因为A(W)放在“=”左边,A(2)被赋值2次。 (2)矢量下标的效率非常的低,不应轻易使用。

  22. 8. 数组标准函数 Fortran 90 提供了许多针对数组操作的标准函数,假设有下列数组声明: REAL,DIMENSION(-10:10,23,14:28) ::A 说明如下: (1) LBOUND(SOURCE[,DIM]) —返回指定维的数组下界,如: • LBOUND(A) = (/-10,1,14/) (数组) • LBOUND(A,1) = -10 (标量) (2) UBOUND(SOURCE[,DIM]) —返回指定维的数组上界,如: • LBOUND(A) = (/10,23,28/) (数组) • LBOUND(A,1) = 10 (标量) (3) SHAPE(SOURCE) —返回数组形状,如: • SHAPE(A) = (/21,23,15/) (数组) • SHAPE((/4/)) = (/1/) (数组) (4) SIZE(SOURCE[,DIM]) —返回数组(或指定维)的元素个数,如: • SIZE(A,1) = 21 • SIZE(A) = 7245

  23. (5) RESHAPE(SOURCE,SHAPE) —改变数组形状,如: • B = RESHAPE((/1,2,3,4/),(/2,2/)) ! INTEGER :: B(2,2) 将一维数组A(4)改成二维数组B(2,2), 存放顺序为B(1,1),B(2,1),B(1,2),B(2,2) (6) ALL(X) —相当于逻辑“与”操作,当逻辑数组 X 中的所有元素为真时,该函数返回真;否则,返回假。 (7) ANY(X) —相当于逻辑“或”操作,当逻辑数组 X 中的任何元素为真时,该函数返回真;否则,返回假。 (8) SUM(X) —返回数值型数组所有元素的和,如下列代码段所示: • INTEGER,DIMENSION(5,5)::A • REAL X(3),Y(3) • … • IF(ANY(A>0)) A=1 • IF(ANY(A == 0)) A=-1 • Dot = SUM(X*Y)

  24. 第四节 数组参数 作为例程参数使用的数组有固定形状、假定大小和假定形状数组3种形式,不管是哪一种形式的数组参数,其传递均采取引用方式传递。 1. 固定形状数组 固定形状数组,其维具有明确的上、下界,其形状规定采取如下形式: • ([dl:] du[,[dl:] du]…) 其中:dl 和 du 分别代表下、上界,若下界省略,其缺省值为1,维的上、下界取整数。 说明: 假设至少有一维的界由非常量表达式表示,这样的数组称为大小可调数组,其实际大小待例程调用时方能确定。非常量表达式中的变量,要么是虚参,要么是公用区中的变量。 实例:例5-6。

  25. 例5-6 固定形状数组,数组可调大小 • PROGRAM MAIN • IMPLICIT NONE • REAL,DIMENSION(3,2)::A1=(/1.0,2.0,3.0,4.0,5.0,6.0/) • PRINT*,THE_SUM(A1,3,2) • CONTAINS • FUNCTION THE_SUM(A,M,N) • INTEGER M,N,I,J • REAL A(M,N),THE_SUM,SUMX ! A为可调大小数组 • 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 • END PROGRAM *** 函数THE_SUM 中的虚参数组A为可调大小数组,运行时,可调大小数组A的大小由与虚参M和N对应的实参决定。

  26. 2. 假定形状数组 假定形状数组,不明确规定维的上界,其形状规定形式为: • ([dl]:[,[dl]:]…) 下界 dl 若省略,缺省值为1。 例5-7 假定形状数组参数的使用 • PROGRAM Main • IMPLICIT NONE • REAL,DIMENSION(3:5,2:3)::A1=(/1.0,2.0,3.0,4.0,5.0,6.0/) • PRINT*,THE_SUM(A1) • CONTAINS • FUNCTION THE_SUM(A) • REAL A(-1:,:),THE_SUM,SUMX !A为假定形状数组 • INTEGER I,J • SUMX=0.0 • DO J=1,UBOUND(A,2) • DO I= -1,UBOUND(A,1) • SUMX=SUMX+A(I,J) • END DO • END DO • THE_SUM=SUMX • END FUNCTION • END PROGRAM

  27. 假定形状数组虚参采取和实参数组的形状相同,或者说,实参假定形状数组虚参采取和实参数组的形状相同,或者说,实参 数组将形状传递给虚参数组,然后两者按列主方式逐个元素进 行对应,在例 5-7 中,实参数组和虚参数组的对应关系为: • A1:A1(3,2), A1(4,2), A1(5,2), A1(3,3), A1(4,3), A1(5,3) • A: A(-1,1), A(0,1), A(1,1), A(-1,2), A(0,2), A(1,2) 程序中采用 UBOUND 函数,直接获取对应后的虚参数组上界。 若外部例程采用假定形状数组参数,则须在调用程序中建立其接口块,例如: • INTERFACE • FUNCTION THE_SUM(A) • REAL A(-1:,:) • END FUNCTION • END INTERFACE

  28. 3. 假定大小数组 假定大小:是指虚参数组和实参数组的大小相同。假定大小数组的形状规定为: • ([expli-shape-spec,]…[dl:]*) 其中:expli-shape-spec 代表固定形状规定,dl 指最后一维的下界,缺省值为1,*指最后一维的上界。具体见实例5-8:假定大小虚参数组的使用。 • PROGRAM Main • IMPLICIT NONE • REAL,DIMENSION(3,2) ::A1=(/1.0,2.0,3.0,4.0,5.0,6.0/) • INTEGER ::ROW=3,COL=2 !使用代表行、列数的参数,来对数组中的各元素进行循环 • PRINT*,THE_SUM(A1,ROW,COL) • CONTAINS • FUNCTION THE_SUM(A,M,N) • INTEGER I,J,M,N • REAL A(M,*),THE_SUM,SUMX !A为假定大小数组 • 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 • END PROGRAM

  29. 第五节 动态数组 动态数组:有时数组的实际大小事先无法确定,为适应可能的情况,通常声明一个超大的数组,这无疑会浪费内存空间。因此定义动态数组,程序执行时,决定数组的实际大小和为数组动态分配内存空间,当不需要时,将动态分配给数组的内存释放掉,从而高效地利用资源。 Fortran 90 支持动态数组,Fortran 77不支持动态数组。 动态数组的使用一般要经历3个步骤: (1) 声明动态数组,规定数组的维数,但不给出维的大小和上、下界。 如:REAL,DIMENSION(:),ALLOCATABLE ::X。 (2) 给动态数组分配内存。如:ALLOCATE( X(N) )。 (3) 将分配的内存释放掉。如:DEALLOCATE( X )。 实例:动态数组的使用,例5-9,5-10

  30. 例5-9 动态数组的使用之一,根据输入的学生人数,动态设置数组的大小。 • PROGRAM Main • IMPLICIT NONE • INTEGER Students ! 学生人数 • REAL,ALLOCATABLE::Mark(:) ! 声明动态数组,学生成绩 • INTEGER I • WRITE(*,’(A)’,ADVANCE=‘NO’) ‘How many students:’ • READ*,Students • ALLOCATE(Mark(Students)) ! 动态分配内存 • DO I=1,Students • WRITE(*,”(‘No.’,I,‘’‘s mark:’)”,ADVANCE=‘NO’)I • READ*,Mark(I) • END DO • PRINT*,Mark • DEALLOCATE(Mark) ! 释放内存 • END PROGRAM *** 动态数组大小的设置可以使用变量,一般数组大小要使用常量。

  31. 例 5-10 动态数组的使用之二 • PROGRAM Main • IMPLICIT NONE • CHARACTER(20),DIMENSION(:,:),ALLOCATABLE::X,OldX • CHARACTER(20),DIMENSION(3)::A • INTEGER IOI,J,N • OPEN (1,FILE=‘DATA.TXT’) • CALL Proc_1 • CALL Proc_2 • CLOSE(1) • CONTAINS • SUBROUTINE Proc_1 • !先确定文件记录数 N,再重读文件中的数据 • N=0 • DO • READ(1,*,IOSTAT = IO) !将变量列表置空 • IF(IO<0)EXIT • N=N+1 • END DO • ALLOCATE(X(N,3)) !动态分配内存 • REWIND(1) !定位文件指针到文件头 • READ(1,*)((X(I,J),J=1,3),I=1,N) • PRINT*,N • PRINT*,((X(I,J),J=1,3),I=1,N) • DEALLOCATE(X) !释放内存 • END SUBROUTINE !例程 Proc_1 是先确定文件行数(或记录数),再为动态数组分配适当大小的存储单元。

  32. SOBROUTINE Proc_2 • !在读文件的过程中,动态分配内存和释放内存 • ALLOCATE(X(0,3)) !可分配 0 大小的内存 • N=0 • REWIND(1) • DO • READ(1,*,IOSTAT = IO)(A(I),I=1,3) • IF(IO<0)EXIT • N=N+1 • ALLOCATE(OldX(N-1,3)) • OldX=X !数组整体赋值 • DEALLOCATE(X) • ALLOCATE(X(N,3)) • X(:N-1,:) = OldX • X(N,:) = A(:) • DEALLOCATE(OldX) • END DO • PRINT*,N • PRINT*,((X(I,J),J=1,3),I=1,N)) • DEALLOCATE(X) !释放内存 • END SUBROUTINE • END PROGRAM 例程 Proc_2 是在确定文件行数的过程中,边分配边释放,直至最后一行。

  33. 注意事项: (1)Fortran 90 的动态数组与其他语言(如 Visual Basic)不同,要增加动态数组的大小,必须将原来的动态数组释放掉,再重新指定动态数组的大小。 (2)计算机的内存是有限的,用户不可能无休止地请求分配内存,所以 ALLOCATE 分配内存并不总是成功的。 (3)为检查内存配置是否成功,Fortran 90提供了可选状态参数 STAT,例如: • ALLOCATE(X(SIZE),STAT=ERROR) ERROR 为事先声明好的整形变量,如果 ERROR 等于0,则表示内存配置成功,否则内存配置失败。 (4)与动态分配内存有关的函数还有 ALLOCATED,用来检查一个动态数组是否已配置内存,其返回值为逻辑真或者假。例如: • IF(.NOT. ALLOCATED(X)) ALLOCATE(X(0,3)) (5)动态数组不能作为例程虚参来使用。

  34. 第六节 数组型函数 Fortran 90 中函数可以返回一个值(标量),也可以返回多个值(矢量) —数组,例 5-11 所示。 例 5-11 函数的返回值为二维字符数组。 • MODULE Mod • IMPLICIT NONE • CONTAINS • FUNCTION FileRow(FileName) !返回文件中的数据行数 • CHARACTER(10),INTENT(IN)::FileName • INTEGER FileRow • INTEGER N,IO • OPEN(1,FILE=FileName) • N=0 • DO • READ(1,*,IOSTAT=IO) !将变量列表置空 • IF(IO<0)EXIT • N=N+1 • END DO • FileRow=N • CLOSE(1) • END FUCTION

  35. FUCTION FileData(FileName,N) !返回二维字符数组 • CHARACTER(10),INTENT(IN)::FileName • INTEGER,INTENT(IN)::N !文件中的行数 • CHARACTER(10),DIMENSION(N,3)::FileData,X !二维字符数组 • INTEGER I,J • OPEN(1,FILE=FileName) • READ(1,*)((X(I,J),J=1,3),I=1,N) !数组隐式循环 • FileData=X !数组整体赋值 • CLOSE(1) • END FUNCTION • END MODULE • PROGRAM Main • USE Mod • IMPLICIT NONE • CHARACTER(10),DIMENSION(:,:),ALLOCATABLE::X !声明动态数组X • INTEGER N,I,J • N=FileRow(‘Data.txt’) !数据行数,依据函数 FileRow 返回的行数动态分配大小 • ALLOCATE(X(N,3)) • X=FileData(‘Data.txt’,N) !二维字符数组,函数 FileData 返回的数组直接赋给动态数组 X • PRINT*,N • WRITE(*,’(3A)’) ((X(I,J),J=1,3),I=1,N) • DEALLOCATE(X) ! 动态数组X释放 • END PROGRAM

  36. 小 结 (1) Fortran 90 的数组声明形式为 : TYPE,DIMENSION([dl:]du[,[dl:]du]…)::Arr 或 TYPE [::] Arr([dl:]du[,[dl:]du]…) (2) Fortran 90 中,一些场合下数组按列主方式存储,在另一些场合下并不规定数组按何种方式存储。 (3) * 数组赋初值一般使用 DATA 语句,其中还可以使用隐式循环; * Fortran 90 允许对数组元素、数组段及数组整体进行操作; * Fortran 90 的 WHERE构造相当于 DO 循环内嵌 IF 块,WHERE 语句形式上类似于 IF 语句; * Fortran 95 的 FORALL 构造相当于隐式循环结合隐式 IF 语句,是对数组元素进行操作,FORALL 构造允许内嵌; * 一维矢量可以作为数组下标,用来规定一个数组段,该数组段中的元素依次可以是非线性的; * Fortran 90 提供了许多有关数组操作的标准函数。 (4) Fortran 90 有三种形式的数组参数:固定形状数组、假定形状数组和假定大小数组。 固定形状数组包括可调大小数组;假定形状数组和实参数组的形状保持一致,若外部例程含有假定形状数组参数,须在调用程序中建立接口块;假定大小数组和实参数组的元素个数保持相同。

  37. (5) 动态数组的使用要经历声明、分配和释放三个步骤。 声明时,动态数组须是延迟形状数组,具有 ALLOCATABLE 属性;分配和释放分别使用 ALLOCATE 和 DEALLOCATE 语句;若要增加动态数组的大小,须将原来的动态数组释放掉,再重新指定大小。 (6) Fortran 90 的函数返回值,既可以是标量,也可以是矢量(数组)。

More Related