鬼驱人4:Fortran 语法备忘录 (中级)

来源:百度文库 编辑:九乡新闻网 时间:2024/04/27 22:27:13
转自:http://zhousicheng.googlepages.com/a_014
目录:
【主程序】【语句函数】【内在过程】【内部过程】【外部过程】
◆外部函数◆外部子程序◆EXTERNAL属性和哑过程◆INTENT属性◆OPTIONAL属性◆哑元改名◆关键字变元INTRINSIC属性◆类属过程◆过程接口 INTERFACE◆超载操作符◆自定义操作符◆超载赋值号
【模块】【块数据】【指针】
【主程序】
!-----------------------------------------------------------------------
[PROGRAM [程序名]]
[说明部分]
[可执行部分]
[CONTAINS
内部过程]
END [PROGRAM [程序名]]
!-----------------------------------------------------------------------
【语句函数】 f(x)=x**2+1
【内在过程】 max,abs,sin,char。。。。
【内部过程】 Contains
与宿主程序共享变量名, 外部过程FUNCTION, SUBROUTINE都可以有自己的内部过程。
通常没有说明语句。
没有哑元,无哑实结合。
使用内部过程的规则:在宿主中不要定义子程序名和函数名的类型,也不能指定它们是有EXTERNAL属性。宿主中的变量名和数组名等在内部过程中有效,有相同的数值。但同一名若在内部过程中又进行了类型声明,则此名被视为其过程中的独立变量,无相同的数值。内部过程中也可引用另一内部过程。
例:
!-----------------------------------------------------------------------
program internal
real a,b,c
call find
print *,c
contains
subroutine find
read *, a,b
c=sqrt(a**2+b**2)
end subroutine find
end
!-----------------------------------------------------------------------
【外部过程】
过程=函数&子程序
哑元调用方式:传址调用call by adress,即传递4字节的变量的内存地址。
◆外部函数
调用:函数名(实元表) 函数名()
如果没有结果名,则函数名就是结果名。
!-----------------------------------------------------------------------
[前缀] FUNCTION 函数名([哑元列表])[RESULT(结果名)]
[说明部分]
[可执行部分]
[CONTAINS
内部过程]
END [FUNCTION 函数名]
!-----------------------------------------------------------------------
◆外部子程序:
调用:
CALL 子程序名 [(哑元列表)]
哑元可以是变量名、数组名、过程名、指针名等均可作为哑元。它们之间用逗号隔开。
前缀是F90中新增的,它可以是:[类型说明] 或[关键词]。关键词:RECURSIVE(F90),PURE(F95),ELEMENTAL(F95)。RECURSIVE表示过程时可以直接或间接地调用自身,即递归调用,其过程是递归过程。
!-----------------------------------------------------------------------
[前缀] SUBROUTINE 子程序名[(哑元列表)]
[说明部分]
[可执行部分]
[CONTAINS
内部过程]
END [SUBROUTINE [子程序名]]
!-----------------------------------------------------------------------
一个有用的例子:互换数字
!-----------------------------------------------------------------------
SUBROUTINE swap(p,q)
INTEGER :: p,q,r
r=p;p=q;q=r
RETURN
END
!-----------------------------------------------------------------------
◆EXTERNAL属性和哑过程 (哑元为外部过程,即哑过程)
指定EXTERNAL语句或属性说明实元实际上是外部过程
类型定义语句: 类型,EXTERNAL :: 外部函数名[,外部函数名]…
或EXTERNAL语句:EXTERNAL [外部函数名][,子程序名][,块数据名]…
哑元也可以是一个过程,这时作为哑元的过程称为哑过程。(至少两层调用)
例如:
!-----------------------------------------------------------------------
Programm main
Real x,y
External Plus !外部过程名作实元,必须用External说明,或者具有External属性
x=1.0 ; y=2.0
Print,* Calculate(x,y,Plus) !调用Calculate函数,实元为外部过程Plus
End Program main
Real Function Plus(a,b) !(第二层被调用的外部函数)
Real, Intent(In) :: a,b
Plus=a+b
End Function Plus
Real Function Calculate (x,y,func)
Real, Intent(In) :: x,y
Real, External func !类型定义语句, 说明哑元时一个外部过程, 也可以直接用External说明
Calculate=func(x,y) !调用自定义的外部函数
End Function Calculate
!-----------------------------------------------------------------------
或者将 Real, External func 改为接口程序:
Interface
Real Function Plus(a,b) !Plus被接口块说明为一个哑元,即一个哑过程
Real, Intent(In) :: a,b
End Function Plus
End Interface
◆INTENT属性 (过程的哑元说明)
在类型定义语句中: 类型,INTENT(意图说明符) :: 哑元名表
或用INTENT语句 : INTENT(意图说明符) :: 哑元名表
意图说明符为以下字符串:
IN 指明哑元仅用于向过程提供数据,过程的执行期间哑元不能被重定义或成为未定义的,相联合的实元可以是常数、变量、数组以及它们的算术表达式。
OUT 指明哑元用于把过程中的数据传回调用过程的程序,与之相结合的实元只允许是变量,不得为常数。
INOUT 指明哑元既可以用于向过程提供数据,也可用于返回数据,与之相结合的实元只允许是变量。
◆OPTIONAL属性可选变元,部分哑元作哑实结合
内在函数PRESET用来反映它的自变量是否在程序执行部分中出现。PRESET(A)的值是一个逻辑值,以此来构造不同的算法。
例如,要求编一子程序,既能求四边形同长(A+B+C+D)的值,也能求三角形周长(A+B+C)的值。此时D就是可选择变元,并规定当D不出现时,置D值为零。子程序如下:
!-----------------------------------------------------------------------
SUBROUTINE SUM(S,A,B,C,D)
IMPLICIT NONE
REAL,INTENT(IN) :: A,B,C
REAL,INTENT(IN),OPTIONAL :: D
REAL,INTENT(OUT) :: S
REAL :: TEMP
IF(PRESET(D)) THEN
TEMP=D
ELSE
TEMP=0.
END IF
S=A+B+C+TEMP
END SUBROUTINE SUM
!-----------------------------------------------------------------------
◆哑元改名
例如,对于上面求边长的子程序,如调用时欲把哑元名A,B,C,D改为物理意义明确的名称UPPER,DOWN,LEFT,RIGHT,只需在主调程序中写入接口块,在接口块的哑元表中用新的哑元名即可:
!-----------------------------------------------------------------------
PROGRAM SUMMATION
INTERFACE
SUBROUTINE SUM(S,UPPER,DOWN,LEFT,RIGHT)
IMPLICIT NONE
REAL,INTENT(IN) :: UPPER,DOWN,LEFT
REAL,INTENT(IN),OPTIONAL :: RIGHT
REAL,INTENT(OUT) :: S
REAL :: TEMP
END SUBROUTINE SUM
END INTERFACE
READ *, UPPER,DOWN,LEFT,RIGHT
CALL SUBROUTINE SUM(S,UPPER,DOWN,LEFT,RIGHT)
……
END PROGRAM SUMMATION
!-----------------------------------------------------------------------
◆关键字变元
哑实结合:(哑元名=实元表达式)
例如: CALL TEST(1,10,D=1000,C=100)
同: CALL TEST(A=1,B=10,D=1000,C=100)
F90也允许在调用语句中,前面部分实元不用关键字变元,只从某一个变元开始用关键字变元。
主调程序中如采用关键字变元调用过程,就必须写出被调子程序的接口块。
!-----------------------------------------------------------------------
PROGRAM swap_pro !交换大小两个实数swap(a,b)
INTERFACE
SUBROUTINE swap(klein,gross)
IMPLICIT NONE
REAL,INTENT(out) :: klein,gross
END SUBROUTINE swap
END INTERFACE
READ *, klein,gross
CALL SUBROUTINE swap(klein,gross)
……
END PROGRAM swap_pro
!-----------------------------------------------------------------------
◆INTRINSIC属性
与EXTERNAL语句或属性说明的实元是外部过程相对应,INTRINSIC语句或属性用来说明实元实际上是内在过程。其一般形式为:
类型定义语句:类型,INTRINSIC :: 内在函数名[,内在函数名]…
或INTRINSIC语句:INTRINSIC 内在过程名[,内在过程名]…
内在过程名必须是内在过程的通用名或专用名。如果是专用名,则可以在其作用范围单元中作为一个过程的实元,但它必须出现在一个INTRINSIC语句中,或被该单元中的一个类型声明语句指明具有INTRINSIC属性。需要注意的是,一个内在过程名只能在INTRINSIC语句中出现一次,并且不能同时出现在INTRINSIC语句和EXTERNAL语句中。
例:
!-----------------------------------------------------------------------
PROGRAM MAIN
REAL F
REAL,INTRINSIC :: ALOG !说明Alog是内部函数,可以作实元
F=CALCULATE(0.0,1.0,ALOG) !使用内在函数ALOG作实元

END PROGRAM
!-----------------------------------------------------------------------
注意这里必须用专用名ALOG,而不能用通用名LOG。
◆类属过程
允许用不同类型的实元与同一个哑元结合,如内在基本函数ABS(X),结合的实元可以是整型、实型与复型。
例如,要编写求两数之和的类属函数时,分别编写哑元是实型和整型的函数:
!-----------------------------------------------------------------------
FUNCTION SUM_REAL(A,B) RESULT(SUM_REAL_RESULT)
REAL :: A,B,SUM_REAL_RESULT
SUM_REAL_RESULT=A+B
END FUNCTION SUM_REAL
FUNCTION SUM_INTEGER(A,B) RESULT(SUM_INTEGER_RESULT)
INTEGER :: A,B,SUM_INTEGER_RESULT
SUM_INTEGER_RESULT=A+B
END FUNCTION SUM_INTEGER
!现在把这两个函数过程综合成一个类属函数,类属函数名取为MY_SUM,在主调程序应写明如下接口:
PROGRAM SUMMATION
INTERFACE MY_SUM
FUNCTION SUM_REAL(A,B) RESULT(SUM_REAL_RESULT)
REAL :: A,B,SUM_REAL_RESULT
END FUNCTION SUM_REAL
FUNCTION SUM_INTEGER(A,B) RESULT(SUM_INTEGER_RESULT)
INTEGER :: A,B,SUM_INTEGER_RESULT
END FUNCTION SUM_INTEGER
END INTERFACE
IMPLICIT NONE
REAL :: X,Y
INTEGER :: I,J
READ *, X,Y,I,J
PRINT *, MY_SUM(X,Y),MY_SUM(I,J)
END PROGRAM SUMMATION
!-----------------------------------------------------------------------
◆过程接口 INTERFACE
一个内部过程总是由程序单元中的语句来调用的。一般来讲,编译程序知道内部过程的一切情况,如知道该过程是一个函数或子程序、过程名、哑元的名字、变量类型和属性、函数结果的特性等等。这个信息的集合被称为过程的接口(interface)。
对于内部过程、内在过程和模块,过程接口对编译程序而言是己知的和显式给出的,故称显式接口。
如在调用一个外部过程或一个哑过程时,编译系统通常不知道该过程的各种情况,这种接口是隐式的。
用EXTERNAL语句来指明一个外部过程或哑过程,但此语句仅说明每一个外部名是一个外部过程名或哑过程名,并没有指明过程的接口,所以接口仍是隐式的。
为了全面准确地通知编译系统,在主调程序中有时需要加入接口块,以说明主调程序与被调程序的接口。接口块是F90中引进的新颖程序块,它显式指明了过程接口的机制。通过接口块可用为一个外部过程或哑过程指明一个显式的接口。这比EXTERNAL语句提供了更多的信息,也提高了程序的可读性。
过程接口确定过程被调用的形式,它由过程的特性、过程名、各哑元的名字和特性以及过程的类属标识符(可以省略)组成,一般它们都被写在一个过程的开头部分。此接口块被放在主调程序的说明部分中,通常还应写在类型说明语句之前,它的内容是被调用的过程中的说明部分,功能是通知编译系统,主调程序调用的过程中各种变元的类型、属性、性质等。
用法:
!-----------------------------------------------------------------------
INTERFACE [类属说明]
[接口体]…
[模块过程语句]…
END INTERFACE [类属说明]
!-----------------------------------------------------------------------
其中类属说明的形式为:
类属名 -> 类属过程
OPERATOR -> 超载操作符、自定义操作符
ASSIGNMENT(=) -> 超载赋值号
接口体的形式为:
函数语句
[说明部分]
函数END语句
子程序语句
[说明部分]
子程序END语句
模块过程语句的形式为:MODULE PROCEDURE 过程名表。
例:
!-----------------------------------------------------------------------
interface
subroutine swap(x,y)
real x,y
end subroutine
end interface
real a,b
read *,a,b
call swap(a,b)
end
subroutine swap(x,y)
real x,y
z=x;x=y;y=z
end subroutine
!-----------------------------------------------------------------------
凡遇下列情况之一时,主调程序必须有接口块:
1、如果外部过程具有以下特征:
过程的哑元有可选择属性。
过程的哑元是假定形数组、指针变量、目标变量。
函数过程的结果是数组或指针。
对于字符型函数过程的结果、其长度不是常数,也非假定长度(*)。
2、如果调用过程时出现:
实元是关键字变元。
用一个类属名调用。
用超载赋值号(对于子程序)。
用超载操作符(对于函数)。
3、如果过程前缀关键词是ELEMENTAL
◆超载操作符
超载操作符的形式仍是系统内部操作符,如+、-、*、/等,但通过编出恰当的过程,可以扩充这些操作符的功能。例如;‘+’本来用于对数值作算术操作,但经恰当的编程后‘+’也可用于字符型操作,这就像车辆超载一样,故称为超载操作符。定义超载操作符,需先编写一个实现此超载(扩充)功能的函数过程,再在主调程序中编写过程的接口,在接口语句后加上超载说明,其一般形式为:
INTERFACE OPERATOR(被超载使用的操作符号)
例如:要使‘+’超载能执行如下操作:把两个字符串的最后一个字母接起来。
!-----------------------------------------------------------------------
PROGRAM ADD_CHARACTER
IMPLICIT NONE
CHARACTER(LEN=10) :: A,B
INTEGER :: I,J
INTERFACE OPERATOR(+)
FUNCTION ADD(A,B) RESULT(ADD_RESULT)
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: A,B
CHARACTER(LEN=2) :: ADD_RESULT
END FUNCTION ADD
END INTERFACE
READ *, A,B
PRINT *, A+B,2+3
END PROGRAM ADD_CHARACTER
FUNCTION ADD(A,B) RESULT(ADD_RESULT)
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: A,B
CHARACTER(LEN=2) :: ADD_RESULT
ADD_RESULT=A(LEN_TRIM(A):LEN_TRIM(A))//B(LEN_TRIM(B):LEN_TRIM(B))
END FUNCTION ADD
!-----------------------------------------------------------------------
接口的作用是向编译系统提示,遇到操作符‘+’时,如果操作数不是数值,就不是原来意义的加法,操作含义要到 FUNCTION ADD中找。当主调程序有了上述接口块后,在下面执行部分中执行字符串操作CH1+CH2时,+号作超载用。
◆自定义操作符 .klein. .gross. .plus.
INTERFACE OPERATOR(.plus.) ! .plus. = +
MODULE PROCEDURE add
END INTERFACE
◆超载赋值号 INTERFACE ASSIGNMENT(=)
例:编一程序把逻辑量超载赋值给整型变量。先编一个实现这一功能的子程序,
!-----------------------------------------------------------------------
SUBROUTINE LOG_INT(I,L)
IMPLICIT NONE
LOGICAL, INTENT(IN) :: L
INTEGER, INTENT(OUT):: I
IF(L) I=1 !I=.True. 得到1
IF(.NOT.L) I=0 !I=.Falsh. 得到0
END SUBROUTINE LOG_INT
再在主程序内编写接口,
INTERFACE ASSIGNMENT(=)
SUBROUTINE LOG_INT(I,L)
IMPLICIT NONE
LOGICAL, INTENT(IN) :: L
INTEGER, INTENT(OUT):: I
END SUBROUTINE LOG_INT
END INTERFACE
!-----------------------------------------------------------------------
I=1 得到1
I=.True. 得到1
I=.Falsh. 得到0
【模块】 复制所有语句,共享所有变量
共享数据的2个方法:一个是哑实结合,一个就是数据共享
共享方式有:使用COMMON语句和EQUIVALENCE语句(F77),使用模块(F90)。另外,使用INCLUDE复制。
!-----------------------------------------------------------------------
COMMON [/[公共块名1]/]变量名表1[[,]/[公共块名2]/变量名表2]...
EQUIVALENCE (变量名表1),(变量名表2),… !仅限于同一程序单元
INCLUDE '文件名[/[NO]LIST]'
!-----------------------------------------------------------------------
例如:下面的COMMON语句段
COMMON/happy/we,you,they
COMMON/ /our,your,their
COMMON/happy/i,he,she
COMMON/angry/dog,cat,mouse
COMMON my,his,her
等价于语句段,
COMMON/happy/we,you,they,i,he,she
COMMON/angry/dog,cat,mouse
COMMON/ /our,your,their,my,his,her
!-----------------------------------------------------------------------
◆模块用途:
包含通常使用的过程
声明全局变量和派生类型
声明外部过程的接口块
初始化全局数据和全局可分配数组
封装数据和处理数据的过程
存储在公共块COMMON中的变量可以被摘录和保存到模块之中。
如果一个程序单元中,只使用模块中的部分变量或需要重新命名部分变量,可以指定这些变量具有ONLY属性。
模块用法:
!-----------------------------------------------------------------------
MODULE 模块名
类型说明部分
[CONTAINS
内部过程

[内部过程]]
END MODULE [模块名]
!-----------------------------------------------------------------------
例如:
MODULE MY_MODULE
REAL, PARAMETER :: Pi=3.141592654
CONTAINS
SUBROUTINE SWAP(X,Y)
REAL :: TEMP,X,Y
TEMP=X
X=Y
Y=TEMP
END SUBROUTINE SWAP
END MODULE MY_MODULE
该模块内有一内部过程SWAP,引用这个模块的外部过程都将包含有此内部过程。
◆使用模块:
USE 模块名1, 模块名2, … 模块名n
它包括两方面:模块定义时规定只有哪些内容允许共享、引用模块时只要求共享哪些内容。
1) 模块的PRIVATE属性:
当定义派生类型的TYPE块写在模块中时,可以限制该派生类型定义的使用范围,以及类型定义内各成员的使用范围。譬如规定模块内的该派生类型或派生类型内的成员只供本模块内引用,不许模块外程序单元引用。其形式是:
!-----------------------------------------------------------------------
TYPE,PRIVATE :: 派生类型名
成员1类型说明
……
成员n类型说明
END TYPE [派生类型名]
!-----------------------------------------------------------------------
使用PRIVATE专用特性后,可以禁止一切外部过程(包括主程序)访问派生类型的内部成员,而只是把派生定义类型作为一个整体黑箱使用。以后如果派生类型内部成员要改动,只需改写派生类型部分,引用模块的各程序单元可不必改动。
2) 模块内的变量改名:
如果需要对多个模块进行访问,而在不同的模块中可能用到了相同的名字,因此允许USE语句对被访问的实体重新命名,以解决局部实体和模块中访问实体之间的名字冲突问题。要重新命名时,USE语句具有下列形式:
!-----------------------------------------------------------------------
USE 模块名 [,改名列表]
!-----------------------------------------------------------------------
其中,改名列表的形式为:局部名1=>块中名1, 局部名2=>块中名2, …。其中,局部名是使用USE语句的程序单元中用的名字,块中名是待改的模块内部使用的变量名。
如模块中定义的变量名是A、B,程序单元中同名变量A、B与之共享,但若要在程序单元中把变量名改为C、D,则只需在单元内把引用语句写成:
USE模块名, C=>A, D=>B
即可,而无需修改模块。
3) ONLY选项:
可以规定只取模块中一部分变量与本程序单元中实体共享,即只需要使用模块中的部分实体,其它实体没有共享关系。这时可在USE语句中使用ONLY选项。这时USE语句具有下列形式:
!-----------------------------------------------------------------------
USE模块名, ONLY : [,仅用名列表]
!-----------------------------------------------------------------------
其中,仅用名列表的形式为:[局部名1=>]块中名1, [局部名2=>]块中名2, …。
模块应用:
1) 全局数据
如果数据是在整个可执行程序中都要用到的全局数据,可以把它们放在一个模块中统一说明,在需要这些数据的程序单元内使用USE语句导出它们即可。例如:
!-----------------------------------------------------------------------
MODULE DATA_MODULE
SAVE
REAL :: A(10), B, C(50,10)
INTEGER,PARAMETER :: I=10
COMPLEX D(I,I)
END MODULE DATA_MODULE
!-----------------------------------------------------------------------
如果要在程序单元中访问模块中定义的全部数据对象,可使用语句:
USE DATA_MODULE
如果只需访问其中的A和D,则可使用语句:
USE DATA_MODULE, ONLY : A,D
如果要避免名字冲突而改名的话,则可使用语句:
USE DATA_MODULE, ONLY : A_MODULE=>A, D_MODULE=>D
2) 过程共享
利用模块,还可以把整个可执行程序中都要用到的全局过程封装在一起,即把这些过程放在一个模块中统一说明,而在需要这些过程的程序单元内使用USE语句导出它们即可,这就是模块过程。使用的方式是,首先在模块中把待用的全局过程定义为模块的内部过程,即写在CONTAINS语句之后,在调用过程单元中写上USE语句以调用此模块,再写上接口块,接口块的实体是模块过程语句:
USE MODULE PROCEDURE 模块过程名表
例:
!-----------------------------------------------------------------------
PROGRAM CHANGE_KIND
USE Module1
INTERFACE DEFAULT
MODULE PROCEDURE Sub1, Sub2
END INTERFACE
integer(2) in
integer indef
indef = DEFAULT(in)
END PROGRAM
MODULE Module1
CONTAINS
FUNCTION Sub1(y)
REAL(8) y
sub1 = REAL(y)
END FUNCTION
FUNCTION Sub2(z)
INTEGER(2) z
sub2 = INT(z)
END FUNCTION
END MODULE
!-----------------------------------------------------------------------
3) 公用派生类型
模块还可用来封装一些派生类型,供其它程序单元公用。例如:
!-----------------------------------------------------------------------
MODULE SPARSE_MATRIX
TYPE NONEZERO
REAL A
INTEGER I,J
END TYPE
END MODULE SPARE_MATRIX
!-----------------------------------------------------------------------
定义了一个由实数和两个整数构成的数据类型,用以表示稀疏矩阵的非零元素。其中的实数表示元素的值,两个整数表示该元素的下标。于是,派生类型NONZERO就可被其他单元通过USE语句来共用。
4) 全局可分配数组
在许多程序中需要一些全局公用的可分配数组,它们的大小在程序执行前是不知道的,这时也可用模块来实现。例如:
!-----------------------------------------------------------------------
PROGRAM MAIN

CAIL CONFIGURE_ARRAYS !分配数组
CALL COMPUTE !用分配好的数组进行计算

END PROGRAM MAIN
MODULE WORK_ARRAYS
INTEGER N
REAL,ALLOATABLE,SAVE :: A(:),B(:,:),C(:,:,:)
END MODULE WORK_ARRAYS
SUBROUTINE CONFIGURE_ARRAYS
USE WORK_ARRAYS
READ *,N
ALLOCATE(A(N),B(N,N),C(N,N,2*N))
END SUBROUTINE CONFIGURE_ARRAYS
SUBROUTINE COMPUTE
USE WORK_ARRAYS

END SUBROUTINE COMPUTE
!-----------------------------------------------------------------------
5) 抽象数据类型和超载运算
可以用模块来自定义抽象数据类型,为此只需在模块中先定义派生类型,再随后定义可在这种类型值上进行的运算即可。例如:
!-----------------------------------------------------------------------
MODULE INTERVAL_ARITHMETIC
TYPE INTERVAL
REAL LOWER,UPPER
END TYPE INTERVAL
INTERFACE OPERATOR(+)
MODULE PROCEDURE COMB_INTERVALS
END INTERFACE
INTERFACE OPERATOR(*)
MODULE PROCEDURE INTERSECTION_INTERVALS
END INTERFACE
CONTAINS
FUNCTION COMB_INTERVALS(A,B)
TYPE(INTERVAL) COMB_INTERVALS,A,B
COMB_INTERVALS%LOWER=MIN(A&LOWER,B%LOWER)
COMB_INTERVALS%UPPER=MAX(A&UPPER,B%UPPER)
END FUNCTION
FUNCTION INTERSECTION_INTERVALS(A,B)
TYPE(INTERVAL) INTERSECTION_INTERVALS,A,B
INTERSECTION_INTERVALS%LOWER=MAX(A&LOWER,B%LOWER)
INTERSECTION_INTERVALS%UPPER=MIN(A&UPPER,B%UPPER)
END FUNCTION
END MODULE INTERVAL_ARITHMETIC
!-----------------------------------------------------------------------
模块中定义了派生类型INTERVAL,它表示一个实数区间,通过接口块说明定义的运算符‘+’和‘*’号,它们分别是求两个区间的并计和交集。
【块数据】--> 模块
!-----------------------------------------------------------------------
BLOCK DATA[块数据名]
[说明部分]
COMMON
DATA
END [BLOCK DATA[块数据名]]
!-----------------------------------------------------------------------
【指针】
◆用法1:指向变量
Integer, Target  ::  a
Integer, Pointer  ::  p
p=>a
p=3              !改变指针指向的变量
!-----------------------------------------------------------------------
用法2:指向一块内存
Allocate (p)     !给指针p分配一块内存空间
Deallocate (p)  !重新指定p之前最好将其释放
!-----------------------------------------------------------------------
◆查询:
Associated (pointer,[target])
检查针是否指向一个target,返回逻辑变量。
判断:
确保开始指针没有指向的函数null(),指向一块不能用的内存地址
Integer, Pointer  ::  p=>null()         !F95用法
或者用Nullify命令,设置指针为不能使用的内存地址
Nullify (pointer1, [pointer2,...])        !F90用法
32位机,一个pointer记录一个地址,占4字节
◆数组操作:
用法1:
Integer, Target  ::  a(5)=(/1,2,3,4,5/)
Integer, Pointer  ::  p(:)          !声明p为一个一维指针数组,大小未定
p=>a
p=>a(1:5:2)                          !p=>部分数组
p=>a(5:1:-1)
!-----------------------------------------------------------------------
用法2
Integer, Pointer  ::  p(:)
Allocate (p(3))                       !分配指针p内存空间,3个整数
p=(/1,2,3,4,5/)
!-----------------------------------------------------------------------
◆指针作为哑元需要添加接口程序:
求一维数组的最小值,函数名和变量均为指针
!-----------------------------------------------------------------------
Implicit none
Integer, target  ::  a(5)
Integer, Pointer  ::  p(:)
Interface
Function getbig(p)
Integer, Pointer  ::  p(:)
Integer, pointer ::  getbig
End Function
End Interface
a=(/1,2,3,4,5/)
p=>a
write (*,*) getbig(p)
stop
End
Function getbig(p)
Implicit none
Integer, Pointer  ::  p(:)
Integer, Pointer  ::  getbig
Integer  n,temp,i
n=size(p,1)
temp=0
do i=1,n
if (temptemp=p(i)
getbig=>p(i)
endif
end do
End Function
!-----------------------------------------------------------------------
用Module来封装函数,相当于写好了Interface:
!-----------------------------------------------------------------------
Module func
contains
Function getbig(p)
Implicit none
Integer, Pointer  ::  p(:)
Integer, Pointer  ::  getbig
Integer  n,temp,i
n=size(p,1)
temp=0
do i=1,n
if (temptemp=p(i)
getbig=>p(i)
endif
end do
End Function
end module
use func
Implicit none
Integer, target  ::  a(5)
Integer, Pointer  ::  p(:)
a=(/1,2,3,4,5/)
p=>a
write (*,*) getbig(p)
stop
End
!-----------------------------------------------------------------------
指针的应用:
◆指向多维数组:
integer, target  ::  matrix(100:100)
integer, pointer ::  p(:,:)
p=>matrix(10:20,10:20)
!-----------------------------------------------------------------------
指向Type类型:
type person
character*20 name
integer  number
real  old
end type
type(person)  ::  me,he,temp
type(person),pointer :: pme,phe,ptemp
pme=>me
phe=>he
ptemp=>pme
!-----------------------------------------------------------------------
◆指向Next
module k_module
type :: knoten
integer  ::  i
type (knoten), pointer  ::  next
end type knoten
type(knoten) punkt
end k_module
!-----------------------------------------------------------------------
第一行定义一个扩展类型knoten
第二行定义一个编号i,例如 punkt%i
第三行定义一个指针next,类型为knoten,例如:punkt%next指向一个地址。
指针punkt%next还没有指向的时候,是没有定义的,也就是说punkt%next%i不存在。
指针punkt%next只能指向一个knoten类型的地址,即变量punkt%next%i与punkt%next%next
例如:
!-----------------------------------------------------------------------
call k_module
implict none
type(knoten), target  ::  k(3)
tyep(knoten), pointer ::  p
integer :: i
p=>k(1)                                 !定义一个计数指针
k(1)%i=1
k(1)%next=>k(2)                    !定义k(1)%next指向k(2)
k(2)%i=2
k(1)%next=>k(2)
k(3)%i=3
nullify(k(3)%next)                    !定义k(3)的指针变量不再有指向!
!连续输出的方法:
i=1
do while (.true.)
write (*,*) p%i
if (.not. associated (p%next)) exit
p=>p%next
end do
stop
end
!-----------------------------------------------------------------------
循环运行过程:
p=>k(1)  输出p%i 即k(1)%i=1
p%next=k(2)
p%next%next=k(3)
p%next%next%i=k(3)%i=3
i=1, p=>k(1)%next   即k(2)  输出p%i 即k(2)%i=1
i=2, p=>k(2)%next   即k(3)  输出p%i 即k(3)%i=1
i=3, exit
数据结构为
k(1)=knoten(1,K(2))
k(2)=knoten(1,K(3))
k(3)=knoten(1,null())