_fortran-第七章 过程
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Fortran 提供了一个特定机制,使得可以在构建 最终的程序前容易地独立开发和调试子任务。 可以把每个子任务作为独立的程序单元来编码, 该独立程序单元被称为外部过程( external procedure) ,每个外部过程都可以独立于程序 中的其它子任务(过程)来进行编译、调试。 Fortran 中有两种外部过程:子程序 ( subroutine) 和函数子程序( function subprogram)(或者就叫函数, function)
7.1 子程序
SUBROUTINE 语句标志着子程序的开始,定义了子 程序名和相关参数表。子程序名必须遵循标准的 Fortran 命名规则由字母和数字组成,最大长度可以 到31 个字符,但第一个字符必须是字母。参数表含 有一系列变量和/或数组,这些变量、数组的值将从 调用程序传递给子程序。这些变量被称为形参 (dummy agument ,形式参数),子程序实际上没有 为它们真正分配任何内存空间。对从调用程序单元传 递来的实际参数(实参)来说它们仅仅是占位符。
每个子程序是一个独立的程序单元,它开始于 SUBROUTINE 语句,结束于END SUBROUTINE 语句。 当程序调用子程序时,调用程序的执行暂时被 挂起,子程序执行部分开始运行。当运行到子 程序的RETURN 语句或END SUBROUTINE 语 句时,调用程序又开始运行调用子程序语句下 面的程序代码。 任何可执行程序单元都可以调用子程序,包括 另一个子程序。(但是,子程序不能调用它自 身,除非它被定义为递归类型(recursive) )。
Fortran95/2003程序设计
第七章 过程
本章学习目标: • 学习Fortran 语言中的过程如何帮助实现好的程序设 计 • 了解子程序与函数的不同 • 掌握创建和调用子程序 • 理解并学会使用INTENT 属性 • 理解使用地址传递方案实现变量传递 • 理解显式结构的形参数组、不定结构的形参数组和不 定大小的形参数组之间的区别 • 理解为什么不再使用不定大小的数组 • 掌握在过程之间使用模块实现共享数据 • 理解显式接口,以及为什么在模块内部定义过程更好 • 能创建并且调用用户自定义函数 • 掌握如何把Fortran 过程调用参数传递给其他过程。
节介绍)
(3) 用星号(*)来声明形参数组的长度,定义 不定大小的形参数组(assumed-size dummy array) 。不会进行越界检测。
如果数组datal 和data2 的长度大于或等于比 nvals ,则正常,否则出错。是早期版本的一个过
渡行为,不再使用。
例7-4 子程序数组越界
7.1.5 传递字符变量给子程序
7.3 模块过程(module procedures) 除了数据之外,模块还可以含有完整的子程序 和函数,它们被称为模块过程(module procedure)
7.3.1 使用模块创建显式接口 既然任何子程序和函数可以独立编译和调用, 那么为什么还要费周折放到模块中呢?
在模块内编译并通过use关联的子程序称为有显式接口 ( explicit interface) ,该子程序在任何时候使用时, Fortran 编译器清楚地知道过程的每个参数的所有细 节,并通过检测接口来确保正确使用该子程序。 反之,不在模块内的子程序称为隐式接口(implicit interface) ,编译器在编译调用该子程序时,不知道其 任何信息,不对该子程序的参数个数、类型、intent等 信息进行检查。
使用use后模块对于该子程序是可见的,但是对 于调用该子程序的程序是不可见的,除非该程 序也use了该模块。 例7-6 生成随机数
一个简单的随机数生成算法:
ni 是一个非负整数,上式生成一系列数据, 它们取值在[0 ,134455]之间。现设计一个 随机数发生器,它将输出一个范围为[0.0, 1.0] 的实数。
EXTERNAL 属性 EXTERNAL 语句
例7-9 函数作为参数传递给过程。
7.5.2 子程序作为参数传递 子程序也可以作为调用参数传递给过程,也必 须用EXTERNAL 语句声明。
例7-10 子程序作为参数传递给过程。
字符变量作为子程序的形参时,用*来声明字 符变量的长度。因为没有给形参分配内存,所 以在编译时无需知道字符参数的长度。
7.1.6 子程序中错误处理
不是最佳处理方式,因为一旦停止,将 丢失调用该子程序之前的数据信息。
永远不要在子程序中使用STOP 语句。如果在一 个子程序中可能存在错误条件,那么应该对错误 进行检测,并设置错误标志,返回给调用程序。
例7-7 模块中的子程序
7.4 Fortran 函数子程序
Fortran 函数( function) 是这样一个过程,它的结 果是单个数值、逻辑值、字符串或、数组。
函数名必须至少出现在赋值语句的左侧一次。 当返回调用程序单元时,赋给函数名的值是 函数的返回值。
必须为函数指定一个类型。如果使用IMPLICIT NONE语句,那么在函数和调用程序中都应该 声明函数类型。如果没有使用IMPLICIT NONE 语句,除非它们用类型声明语句说明,否则函 数的缺省类型将会遵循Fortran 语言的标准规 则来确定。
例7-8 计算f(x)=ax^2+bx+c
7.5 过程作为参数传递给其他过程 函数和子程序都可以被当作调用参数来传递。 7.5.1 用户自定义函数作为参数传递
Fun1, fun 2 是两个用户函数 只有被声明为外部量(extemal) 时,用户自定义 函数才可以当作调用参数传递。当参数表中的 某个名字被声明为外部变量,相当于告诉编译 器在参数表中传递的是独立的己编译函数,而 不是变量。用EXTERNAL 属性或者EXTERNAL 语句可以声明函数为外部:
子程序通过在一个单独的CALL 语句中引入子程 序名来进行调用,并且可以通过调用参数来返回 多个结果。 函数通过在表达式中引入函数名来进行调用,它 的结果是单个数值,该值用来为表达式赋值。
在实际编程时,把一个大程序任务分解为若 干个子过程,可以获得很多好处:独立测试组 件、复用子过程,隔离无意的副作用。
确保在函数子程序自身和调用它的程序中声明 函数类型。
7.4.1 函数的副作用
函数使用参数传递模式,函数获取的是指向参 数位置的指针,它可能会有意或无意地修改了 其中的内容。修改了它的参数表值的函数会产 生副作用(side effect) 。
函数应该永远不修改自身的输入值,如果需要 一个过程生成多个输出值,那么应该把过程写 成为子程序而不是函数。为了确保函数的参数 不被无意识地修改,应该总是用INTENT(IN) 属性声明输入参数。
7.1.3 Fortran 中的变量传递:地址传递方案
主程序和子程序之间用地址传递(pass-by-reference) 方 案来进行通信。主程序传递一个指针来指向实参表中 各个参数的存储位置,子程序查找调用程序所指向的 内存位置,获得形参值。
参数列表中的值与子程序的调用参数在个数、 类型、次序方面都必须完全匹配。如果存在不 匹配, Fortran 程序不能识别这种现象,会在没 有任何提示的情况下错用这些参数,产生错误 结果。 例7-3 调用子程序形参不匹配示例
子程序中的RETURN 语句是可选的。当运行到 END SUBROUTINE 语句时,程序会自动返回 到调用程序。只有需要在子程序结束之前返回 到调用程序时,才需要用到RETURN 语句。 例7-1 用直角三角形两直角边计算斜边。 例7-2 数据排序
7.1.2 INTENT 属性 子程序的形参可以与一个INTENT 属性联合 使用。INTENT 属性与类型声明语句联合使 用,来声明每个形参的类型, 告诉编译器如 何使用形参。
7.2 用模块共享数据
模块(module) 是一个独立编译的程序单元,它 包含了程序单元间共享的数据的定义和初始值。 如果程序单元中使用了包含模块名的USE 语句, 那么在那个程序单元中可以使用模块中定义的 数据。
SAVE 语句使得模块中的数据能够被所有的引 用修改保存。
USE 语句必须出现在程序单元中的其他语句之前。 例7-5 使用模块示例。
7.1.4 传递数组给子程序 通过内存位置指针将参数传递给子程序,如果 参数是个数组,那么指针指向的就是数组中的 第一个值。为此,子程序既需要知道数组的地 址,也需要知道数组的大小。
有3 种可能的方式来指明形参数组的大小: (1)把数组的大小作为形参传递。
(2) 把子程序中的所有形参数组声明为不定结 构的形参数组( assumed-shape dummy array) ,以创建一个子程序的显式接口。(7.3