slide1 n.
Download
Skip this Video
Loading SlideShow in 5 Seconds..
第五章 数 组 PowerPoint Presentation
Download Presentation
第五章 数 组

Loading in 2 Seconds...

play fullscreen
1 / 37

第五章 数 组 - PowerPoint PPT Presentation


  • 97 Views
  • Uploaded on

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

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

第五章 数 组


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.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - 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 的函数返回值,既可以是标量,也可以是矢量(数组)。