fortran95教程6.docx

上传人:b****6 文档编号:5605563 上传时间:2022-12-28 格式:DOCX 页数:32 大小:43.98KB
下载 相关 举报
fortran95教程6.docx_第1页
第1页 / 共32页
fortran95教程6.docx_第2页
第2页 / 共32页
fortran95教程6.docx_第3页
第3页 / 共32页
fortran95教程6.docx_第4页
第4页 / 共32页
fortran95教程6.docx_第5页
第5页 / 共32页
点击查看更多>>
下载资源
资源描述

fortran95教程6.docx

《fortran95教程6.docx》由会员分享,可在线阅读,更多相关《fortran95教程6.docx(32页珍藏版)》请在冰豆网上搜索。

fortran95教程6.docx

fortran95教程6

第6章构造数据

固有数据类型只是描述了问题当中出现的基本数据形式,但在实际的计算当中,计算对象往往并不只是限于那些固有数据类型,而是一些数据结构。

例如:

线性数学问题里面的计算对象很少是单纯的标量,而是诸如行列式,向量这样的由

一系列标量组成的数据结构。

甚至在计算过程中,还需要以这种数据结构的某个特定部分作为计算对象,例如行

列式或向量的单独的行与列,或对角线,部分块等

又例如:

样品的属性值可以是多方面的,例如在测量一个导体样品的交流输运性质时,需要考虑的物理量包括电流,电压,相位等,如果以每个样品的属性值作为数据对象,那么这种数据对象就至少包括3个成员:

电流,电压,相位。

它们的取值的类型不同,精度要求也可能不同,这3个数值同样构成一个数据结构。

因此,进一步FORTRAN95需要以固有数据对象为基础,能够构造一定的数据结构,从而能够作到基于数据结构进行运算。

本章讨论的就是FORTRAN95构造数据结构的几种方式:

●   派生数据类型;

●   数据结构的子对象;

●   数据结构的成员;

●   数组;

●   指针。

特别的,我们首先讨论FORTRAN95关于数据对象的一个基本分类:

变量与常量。

它们是数据在程序当中的2种基本行为方式,是我们理解FORTRAN95语言范畴的关键。

6.1 数据的2种基本行为—变量与常量

首先我们给出几个抽象的基本概念,在这里只是给出大意而不作更加形式化的讨论,完全只是为了后面行文的方便。

读者不用深究它们的精确定义,只需要在后面行文当中遇到这些概念时,知道回到这里稍加体会即可。

●   数据对象:

计算过程当中,任何充当计算对象的数据内容,都称为数据对象,是最一般意义上

的数据个体,今后提到数据对象,我们可以理解为一个固有数据类型,一个属于某

固有数据类型的变量,一个常量,一个标量,一个数据结构,一个数据结构的成员

或子对象,表达式求值的结果,或函数引用的执行结果(即函数值)。

数据对象有数

据类型(固有的或派生的),可以有数据值。

可以是一个数据的集合,集合的元素

数目称为秩,每个数据对象有一个秩。

它可以是一个标量或是一个数组。

有名数

据对象的类型可以显式或隐式地规定。

●   子对象:

子对象是某些有名对象的一部分,可由程序的其他部分引用和独立地定义。

包括数据组的部分,字符串的部分(子串)和结构的部分(成员)。

作为子对象的来源的数据对象称为该子对象的父对象。

子对象只能用子对象描述符来引用。

变量的子对象是变量。

●   标量:

任何单一的数据对象,无论它是属于固有数据类型还是属于派生数据类型,就称为标量。

●   数组:

一个标量的集合,如果其中每一个元素都具有相同的数据类型,相同的种别参数,那么无论它们组织成什么形式,例如行,列,块,甚至更高维度,都把这种集合称为数组。

●派生数据类型:

一个标量的集合,如果其中元素的种别参数不同,或者数据类型不同,那么把这个

集合称为结构,或派生数据类型。

从程序运行这么一个动态过程的角度来看,特别是基于下面的基本计算模式:

输入数据

输出数据

数据可以有2种基本行为方式:

●数据对象在整个程序运行过程当中保持不变;

●数据对象在整个程序运行过程当中发生变化。

保持不变的称为常量,发生变化的称为变量。

FORTRAN95中常量与变量,标量与数组这些概念与早期的FORTRAN版本有微妙的差异。

请熟悉FORTRAN77的读者注意。

●   常量有两种,一种是字面常量,早期的FORTRAN版本称为常量;另一种是命名常量,早期的FORTRAN版本称为常数符号名,显然新的名称突出表达了该数据作为常量的特点,它与字面常量的最大差别在于有一个名字。

这个名字可以在它的定义作用域当中任意引用。

它们的共同点在于,它们的值在可执行程序执行期间是不变的。

●   字面常量是标量,根据它的字面的句法构成来表明其数据类型,种别参数以及值。

在一个可执行程序中,所有具有相同形式的字面常量具有相同的值。

命名常量则是一个与具有PARAMETBR属性的名字相结合的常量。

它的数据类型,种别参数和取值,都需要预先定义,而一旦定义之后,在其定义的作用域内都不会改变,而且这个名称也必须接受唯一解释的。

●   变量的值即使用DATA语句给以初始化也能在程序运行过程当中发生变化。

而FORTRAN95的变量包括了早期FORTRAN标准里面所谓的变量和数组。

具有DIMENSION属性的名字在FORTRAN95标准里面也称为变量,属于数组。

●   数组是标量的有序集合,它在FORTRAN95标准当中有许多新的扩充,将在后面作详细讨论。

在程序运行过程当中,对数据的使用首先必须是定义,然后才能是引用,所谓定义和引用的差别在于:

●   对于一个变量,当程序中确定其值时称为定义,而使用其值时称为引用,已经定义了的变量可以重定义或者回复为无定义。

例如,在程序单元中使用DATA语句使得一个变量具有初值,在程序执行过程中又可以对它赋值而得到重定义;如果该变量不具有SAVE属性的话,当该程序单元执行RETURN语句或END语句后,它就回复为无定义状态。

●   对于一个常量,它的值可以被引用但不能被重定义。

命名常量虽然出现的形式是一个名字,而不是一个具体的值,但它只是常量的一个便于引用的标记。

【例6-1】

X=0

N=X+1

在第一个语句当中,变量X被赋值为常量值0,这个语句的执行与X是否在此之前被定义为其他值无关,总之此时X得到一个定义,此后只要X没有被重定义,它就能用值0被程序引用。

在第二个语句当中,X被引用,并且在执行加1的运算之后,得到的值被赋值给N。

在第一个语句当中的X和在第二个语句当中的N都不是被引用,而是被定义,而在第二个语句当中的X属于被引用。

变量(variable)的句法形式(R601)为;

scalar-variable-name

array-variable-name

subobject

其中子对象(subobject)的句法形式(R602)为:

array-element

array-section

structure-component

substring

变量可以是任意的数据类型,在一定的上下文当中,变量也必须取一定的数据类型。

常量父对象的子对象不可能是变量。

6.2 数据的结构----派生数据类型

五个固有数据类型已经能够作到描述,或者近似描述整数,实数,复数,逻辑值,字符串这五类常用数据对象。

考虑一下FORTRAN建立这五种相对独立的数据类型的出发点,是有助于我们进一步理解语言的数据描述这个重要任务的。

首先考虑整数。

似乎整数是一切计算的基本出发点,这里是没有省略的余地的,想像一下,没有了整数,我们还能做什么计算呢?

别忘了Kronecker的名言:

“上帝创造了自然数,其余都是人造的”。

然后就是实数。

由于FORTRAN本质上只能表示有限位有理数,因此实际上也可以通过整数的除法来得到实型数据的近似表示,比方说用一个整数二元组(37,71)来表示37/71这个有理数,相应的也可以用来近似地表示实数,我们可以来衡量一下这样做的利弊:

●   好处就是可以不用建立实型数据类型,也就是不用引入小数点,减少了一个数据类型,也就简化了FORTRAN语言的实现;

●   但同时坏处就是把麻烦留给了程序作者,在处理涉及实数的问题时,肯定会因为不能直接表达实数而增加算法的复杂性,甚至在语言本身,也有可能不得不增加一些函数之类的语言成分,用来解决由此产生的一些问题。

所以FORTRAN的解决方案就是直接引入实数的有限有理小数表示(实际上一般的程序语言都是这样做的),对于语言本身来说,无非就是增加了对小数点的语义解释,增加了对浮点数值的多种存储模式(FORTRAN使用种别参数来进行分类)的建立等,由此而可以在语言当中自然的使用有限有理小数所表示的实数。

再来分析一下复数。

本质上复数就是一个实数的二元组,而且这个二元组与复数是一一对应的,因此可以很完美的通过运用二元实数组来代替复数,这也是大多数程序语言的处理方式。

但是FORTRAN的选择是建立一个独立的复型数据类型,尽管得为这个独立的数据类型定义相应的运算,但是由于FORTRAN主要就是面向科学计算的语言,因此FORTRAN能够直接写出复数,成为FORTRAN的一个优点,极大地方便了程序作者。

由此可见,建立一个数据类型的主要功能就是面向问题,以能够直接描述算法为目的。

那么我们是否有可能从实际问题当中归纳出一些数据类型,然后可以期望这些数据类型就可以满足任何问题的需要呢?

显然是不可能的。

一方面,程序语言必须能够精确描述任何需要用它来解决的问题当中出现的数据;另一方面我们不可能给每一个新问题当中出现的独特的数据结构形式规定一种相应的数据类型,唯一的解决方法,就是在FORTRAN里面约定一种语法机制,可以依据这种语法机制来描述与问题要求相适应的数据类型。

反过来只要是依据这个语法机制构造出来的语言结构都能被FORTRAN编译器辨认为一种数据类型,从而知道按照什么存储模式来存储该数据,也知道应该对该种数据施加什么运算。

 

这就是FORTRAN从90版标准以来设置派生数据类型的出发点。

鉴于固有数据类型被认为是真实世界最基本的数据类型,任何的数据对象,或者就是属于某种固有数据类型,或者就是可以由一系列固有数据描述,因此构造派生数据类型的基本思想就是认为一个派生数据等于一系列成员的集合,这个集合构成一种数据结构,而每一个成员或者仍然属于一个派生数据类型,或者就是属于某种固有数据类型。

这样对一个派生数据类型的描述,就归结到对它的成员的描述,另外再加上给出该数据类型的名称,并可选择性地描述其他属性。

这样得到的所谓派生数据类型,和五种固有数据类型不同的地方主要在于:

●   每一种固有数据类型都拥有一个特定的名称,用来作为数据声明的关键词;而派生数据类型则需要程序作者自己首先定义一个名称,然后才能在后面作为关键词进行声明。

●   每一种固有数据类型都已经定义好了自己的常量书写方式;而派生数据类型则依据其成员的常量形式来确定自己的常量的形式。

●   每一种固有数据类型都已经定义好了自己的特定的运算;而派生数据类型则需要程序作者自己预先依据实际问题的需要来定义好相应的运算。

●   每一种固有数据类型都已经定义好了自己的取值范围以及相应的多种存储模式;而派生数据类型,则完全依据其成员的取值范围与存储模式,来确定自己的取值范围和存储方式。

●   派生数据类型可以在数据类型的定义里,就给出该数据类型的默认初始值,使得今后属于该类型的数据对象都一定取该初始值;而固有数据类型的定义里面不含有定义初始值的部分,要想显式地给出变量初始值,得需要使用数据类型声明语句或者DATA语句。

●   固有类型的名称是全局性的,在任何环境总是可访问的,而派生类型只可在其定义的作用域内访问它们。

FORTRAN定义的数组同样是数据对象的集合,不过派生数据类型与数组的差别在于组成数组的各个成员必须是相同的数据类型,而派生数据类型的特点就在于它的成员可以是属于不同的数据类型。

派生数据类型的成员可以仍然是某个派生数据类型,但数组的成员就不能是数组。

要想让数组的成员为数组只能通过间接的方式,即取数组的唯一成员为一个派生数据类型,然后该派生数据类型的成员取为数组。

对于这样构造出来的与具体问题密切相关的派生数据类型,由于其所具有的内部结构个性太强,显然我们需要定义一些与这种结构相关的特征属性,可以用来描述这种个性:

●   正是由于一个已经定义好的派生数据类型具有完全个性化的内部结构,因此如果一个派生数据类型是定义在一个模块内部的话,自然的问题就是这个派生数据类型的面向模块外部的可访问性如何控制。

在默认情形下,一个在模块内部定义的派生数据类型可以被模块外部的任意程序单元访问,这个默认状态等价于使用PUBLIC语句。

反之,也可以通过使用PRIVATE语句来阻止模块外程序单元的访问。

不过,由于一个模块包含许多不同层次的数据对象,因此PRIVATE的作用对象必须是精确指定的,这里分为以下几种情况:

·每一个对象都可以单独地通过使用属性PUBLIC或PRIVATE来指定其可访问性。

·对于一个派生数据类型,可以在定义类型的语句当中设置可选的PUBLIC或PRIVATE描述符。

·使用单独的针对类型名称的PRIVATE语句或在类型定义当中使用PRIVATE描述符,可以把对该类型访问控制在本模块之内。

·在类型定义的内部使用单独的PRIVATE语句,可以只控制该派生类型的特定的组元的模块可访问性,而不影响整个类型的默认下的可访问性。

●   组成一个派生类型的各个成员可以按照一定的顺序进行存储,这是通过在派生类型的定义当中运用SEQUENCE语句得到的。

一个派生类型的定义当中,成员的叙述上的顺序并不表示它们具有相应的存储上的顺序,只有在定义当中设置一个SEQUENCE语句,才能对这些成员的存储进行排序。

从而可以进一步对这些成员应用COMMON语句或EQUIVALENCE语句。

●   一个派生数据类型的取值范围显然就是它的所有成员的取值范围的组合,使用集合论语言就是各成员值集的乘积。

FORTRAN规定了一个语法机制来给派生数据类型构造值的形式,例如用来定义命名常量,这样就可以在类型声明语句或PARAMETER语句当中使用其命名常量。

这种语法机制称为派生数据类型的结构构造器。

至此我们可以看到FORTRAN语言对派生数据类型的定义,不是以某种真实世界的自然的数据集合为依据,而是提供一种描述方式,并且在语言当中约定,只有运用这种方式进行描述,就可以成立为一种数据类型。

而对于通过这种方式成立的数据类型,同样包含四个方面的基本属性:

● 拥有名称,以备引用;

● 取值在一定的集合上;

● 可以施加的运算;

● 常量的写法。

下面就从这四个方面来说明派生数据类型。

6.2.1 派生数据类型的构造

给出一个派生数据类型的名称,同时意味着要给出该派生数据类型的完整定义或着说描述。

一个完整的派生数据类型的句法形式(R422)为:

TYPE[[,access-specification]:

:

]type-name

 [private-sequence-statement]…

component-definition-statement

 [component-definition-statement]…

ENDTYPE[type-name]

其中:

·可选的访问说明(access-specification)为关键词PUBLIC或PRIVATE。

·类型名称(type-name)需要由程序作者自己给出,最好是有意义的英文词汇或缩写。

·私用序列语句(private-sequence-statement)为PRIVATE语句和SEQUENCE语句。

每一条成员定义语句(component-definition-statement)(R425)包含一个数据对象的类型说明(R502),其句法形式为:

type-specification[[,component-attribute-list]:

:

]component-declaration-list

其中:

·类型说明(type-specification)表示一个固有数据类型,或者是一个已经定义过的派生数据类型,不过如果这个描述符后面带有POINTER属性,由于指针的赋值特性,那么该成员就可以表示任意可访问的派生类型,包括正在被定义的派生类型自身。

·成员属性(component-attribute)(R426)只能是POINTER或DIMENSION,即对于指针性质的成员,使用可选的属性POINTER;而对于数组成员,使用可选的属性DIMENSION,后面还可以再加上数组描述。

POINTER和DIMENSION这两个属性可以同时出现。

·成员声明(component-declaration)给出成员的名称。

成员声明(R428)的句法形式为:

 

component-name[(component-array-specification)]&

[*character-length][component-initialization]

其中:

·成员数组说明(component-array-specification)是可选项,放置在括号当中。

如果该数组具有指针属性,那么它的形状未定,否则就是显形状。

在显形状的描述当中,数组的界都必须是标量整型常量表达式。

如果在这里没有指出数组的界,那么一定要在后面的DIMENSION属性里说明。

·字符长度参数(character-length)是一个可选的标量整型字面常量,它必须以星号开头。

当然这个参数只能用于修饰字符型成员。

成员初始化(component-initialization)(R429)取下面2种形式之一:

=initialization-expression

=>NULL()

其中:

·初始化表达式(initialization-expression)用来说明非指针成员的默认初始值。

·=>NULL()即把成员作为指针赋值为不带变元的固有函数NULL的结果,表示指针成员的未结合或空置这2种初始结合状态。

初始化指针状态的用处在于,很多情形下,要设置一个指针,都必须首先要求该指针具有确定的结合状态。

构造了一个派生数据类型之后,要使用这个派生类型,自然需要声明属于该类型的变量,对于派生类型来说,变量的声明采用如下句法形式:

TYPE(type-name)[,attribute-list:

]entity-list

注意这个TYPE语句和定义派生类型的TYPE语句在句法上有差别:

声明变量时,TYPE后面必须接括号里面的变量所属派生类型名称;而定义派生类型时,后接不带括号的派生类型名称。

构造了一个派生数据类型之后,经常需要引用其中的成员,引用的句法形式为:

     parent-structure%component-name

其中父结构(parent-structure)指需要引用的成员所属的派生数据类型(或数据结构)。

派生数据类型构造的一般规则如下:

●派生数据类型的定义当中给出的类型名称不能与任何固有数据类型的名称重合,也不能与任何本模块能够访问的其他派生数据类型的名称重合。

必须保证该名称在它的有效作用域内是指称同一个类型对象。

而派生数据类型内部成员的名称的作用域只局限于该派生类型内部,因此不同派生类型的成员可以使用相同的名称,即使这些不同的派生类型属于同一个作用域。

同样的,不同作用域当中如果出现了相同的派生类型名称,那么它们实际上是不相干的数据对象。

●ENDTYPE语句后面或者省略类型名称,或者后接该类型的名称,不能出现不一致的情况。

●一个作用域内,一个派生类型的名称只能定义一次。

●在一个派生类型的定义当中,PRIVATE语句只能出现一次。

●在一个派生类型的定义当中,SEQUENCE语句也只能出现一次。

●只有当一个类型定义是放置于一个模块的规则说明部分时,才能使用访问控制符PUBLIC或PRIVATE。

●只要派生类型的定义当中出现SEQUENCE语句,就说明该派生类型的所有成员都必须具有顺序属性(即其中也必须出现SEQUENCE),并且在定义中成员定义的次序就说明了该类型的对象的存储序列。

●在一个派生类型的定义当中,必须至少包含一个成员的定义。

●在成员定义当中,任何特定的成员属性都只能出现一次。

●一个成员只有在具有指针属性时,才可声明为属于被定义的派生类型本身。

●任何非指针的数组成员,都必须表示为显形状形式,其上下界都是整型常量

表达式。

●如果成员是指定了长度的字符型数据,那么它的长度必须是整型常量描述表达

式。

如果没有指定长度值,那么默认值为1。

●如果进行成员初始化,那么必须使用双分号间隔符。

●在2种初始化方式中,初始化表达式只能用于非指针变量,也可以说等价赋值符号(=)只能用于非指针变量。

而固有函数NULL()则是用于指针变量的。

●初始化表达式只能在派生类型的作用域当中取值。

●一个派生类型内部的成员当中,可以只有部分成员是默认初始化的,即取得默认初始值,或取得默认初始结合状态,而不是一定要求所有成员都必须初始化。

●一个成员如果是数组,那么它的默认初始值必须满足数组的定义,可以是一个数组构造器,也可以是一个标量,这个标量表示了该数组成员的每个元素的初始值。

下面给出不同情形下构造派生数据类型的例子:

【例6-2】

TYPESET

INTEGERN,M

ENDTYPE

TYPE(SET),DIMENSION(2,2):

:

a,b(3) 

在这个派生类型的定义当中,a和b都是属于派生数据类型SET的数组变量。

【例6-3】

TYPECURRENT

REAL:

HIGH=5.5,LOW=1.2

ENDTYPECURRENT

在这个派生类型的定义当中给出了其唯一实型成员的初始值.

【例6-4】

TYPEemployee_name

  CHARACTER(25)last_name

  CHARACTER(15)first_name

ENDTYPE

 

TYPEemployee_addr

CHARACTER(20)street_name

INTEGER

(2)street_number

INTEGER

(2)apt_number

CHARACTER(20)city

CHARACTER

(2)state

INTEGER(4)zip

ENDTYPE

在上面2个派生类型的定义当中,一个派生数据对象是另一个派生数据对象的成员。

【例6-5】例6-4中定义的数据对象还可以被第3个数据类型引用,如:

TYPEemployee_data

TYPE(employee_name):

:

name

TYPE(employee_addr):

:

addr

INTEGER(4)telephone

INTEGER

(2)date_of_birth

INTEGER

(2)date_of_hire

INTEGER

(2)social_security(3)

LOGICAL

(2)married

INTEGER

(2)dependents

ENDTYPE

【例6-6】

TYPEARTICLE

 CHARACTER(LEN=100)ABSTRACT

 INTEGERLINES

 CHARACTER,POINTER:

TEXT(:

)  

 ENDTYPEARTICLE

在这个派生数据类型里面包含一个指针成员。

【例6-7】

TYPELINK

 INTEGERVALUE

 TYPE(LINK),POINTER:

PREVIOUS=>NULL()

 TYPE(LINK),POINTER:

NEXT=>NULL()

ENDTYPELINK

 

TYPE(LINK),POINTRE:

:

A_LINK

ALLOCATE(LINK)

在这个派生数据类型当中,指针成员的类型已经被定义,这种派生数据类型被广泛应用于链表与树结构。

【例6-8】

TYPE,PRIVATE:

FILE

 INTEGERFILE_NO

 CHARACTER

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 经济市场

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1