Fortran函数:子程序、函数——出自《Fortran 95 程序设计》 彭国伦

1.子程序subroutine的使用
program main

call sub1()

call sub2()

end program main

subroutine sub1()

end subroutine sub1

subroutine sub2()

end subroutine sub2

!子程序最后通常是return命令,返回调用它的地方,注意不是stop,如是stop则程序结束,结果难料。
!return可以省掉,可以出现在子程序的任何地方,提早返回。
exmaple:
subroutine message()
implicit none
write (*, *) “hello”
return
end 

子程序之间可以相互调用,子程序可在任何地方被别人调用,甚至可以自己调用自己,即“递归”。
子程序独立的拥有属于自己的变量声明,与其他程序互不相干,同时拥有自己的行代码。
参数传递:fortran 采用的是传址调用(call by address/call by reference),即调用时候传递出去的参数,和子程序中接收的参数使用相同的内存地址来记录数据。因此在主程序中传过来的参数,在子程序中可以被重新设置,主程序中参数内容跟着子程序中的改变而改变,在程序中可以改变主程序中的变量值。需要注意!!C采用的是传值调用,混合使用的时候需要注意。

2.自定义函数( FUNCTION)
自定义函数要先声明,再使用,执行后会返回一个数值。
program ex0807
implicit none
real :: a = 1
real :: b = 2
real, external :: add !声明add是一个函数,而不是变量。调用函数不必使用call命令。
write (*, *) add(a, b)
stop
end program ex0807

function add(a, b)
implicit none
real :: a, b   !输入的参数
real :: add   !add跟函数名称一样,这里不是用来声明变量,而是声明这个函数会返回的数值类型。
add = a+b
return
end function
!声明中多了一个external这个形容词,用来表示这里要声明的不是一个可以使用的变量,而是一个可以调用的函数。external可以省掉,但是建议不要省,容易辨别是函数而不是变量。

也可以这样声明上面的函数:
real function add(a, b)
implicit none
real :: a, b
add = a+b
return
end function

使用函数的一个不成文规定:“传递给函数的参数,只要读取就好,不要去改变它的数据”。如果要改变输入参数的数值时,最好使用子程序,而不是函数。

3.全局变量COMMON : 是f77中使用全局变量的方法,用来定义一块共享内存。
全局变量让不同程序声明出来的变量使用相同的内存位置,是一种不同程序之间传递参数的方法。
(1)common的使用:
program ex0810
implicit none
integer :: a, b
common a, b   !定义a,b是全局变量中的第一和第二个变量

call showcommon

stop
end program

subroutine showcommon()
implicit none
integer :: num1, num2
common num1, num2 !定义num1, num2是全局变量中的第一和第二个变量
write (*, *) num1, num2
return
end suroutine showcommon
!common的变量不可以随便用data的命令来设置他们的初值。取全局变量的时候,根据声明它们时的相对位置关系来作对应,而不是使用变量的名称来对应。任何一个地方改变了全局变量的值,程序中所有的程序都可以观察到这个变动,因为使用的是相同的内存位置。
!可以将变量归类,放在彼此独立的common区间中,避免麻烦。
exmaple:
integer :: a, b
common /group1/ a
common /group2/ b
….
stop
end

subroutine showgroup1()
….
common /group1/ num1

return
end

subroutine showgroup2()

common /group2/ num2

return
end

!当需要共享的数据不多,而且只有几个少数的程序需要使用这些数据的时候则使用参数传递。需要共享大笔数据,或是很多个不同的程序都需要使用这些数据的时候就使用全局变量。

4. block data
common设置初值:要在block data 程序模块使用data 命令来设置初值。
program ex0812
….
common a,b
common /group1/ c, d
common /group2/ e, f
….
stop
end

block data
implicit none
integer a,b
common a, b
data a, b /1, 2/
integer c, d
common /group1/ c, d
data c, d /3, 4/
integer e, f
common /group2/ e, f
data e, f /5, 6/
end block data

block data这一段程序是类似于子程序,是一个独立的程序模块,拥有自己的变量声明,不过不需要别人调用就可以自己执行。这段程序在主程序执行之前就会生效,但是功能只在于设置全局变量的初值,不能有其他的执行命令。
block data 的模样结构:
block data name     !name 可以省掉
implicit none
integer …    !变量声明
real …
common …!把变量放到common空间中
common /group1/ …
data var1, var2…       !同样使用data设定初值

end block data name ! 或end或end block data

!全局变量不可以声明成常量,所以block data 中不可以出现parameter.
!注意事项:变量的类型,变量的位置。 (!可以使用f90中的方法使用全局变量!)

5.函数中的变量
传递常数的时候要注意类型的正确性。
数组作为接收用的参数时候,可用变量来赋值它的大小,甚至不去赋值大小。
函数中接受到的参数,事实上它们的内存地址都在执行函数前配置完毕,因此参数在函数中的声明就不会再去配置新的内存来使用,所以可以使用变量来赋值数组的大小。甚至可以不赋值数组的大小,因为数组在进入子程序前就配置到了空间。在函数中赋值数组的大小只是用来方便检查,不会重新配置内存。
函数中使用数组参数时只要不超过它的实际范围就行,可以将一维变成二维(列优先),改变坐标范围等等。
一般传递数组时最好也顺便输入它原来声明的大小,函数中才会知道数组能使用的范围。
!传递字符串变量时也可以不特别赋值它的长度。
!多维数组在传递时只有最后一维可以不赋值大小,其他的都必须赋值大小。
!!建议将数组实际声明的大小全部传递出去是比较好的做法。!!

6.变量的生存周期
在声明中加上save可以增加变量的生存周期,保留住所保存的数据。
subroutine sub()
implicit none
integer :: count = 1
save count
….
end subroutine sub

或 integer, save :: count =1
每次子程序被调用时都会记得上次被调用时候留下来的数值。
注意:变量的初值只会设置一次,第一次调用的时候设置初值,不是每次都会去重新设置初值。

7.传递函数:类似于C中的函数指针。
可以把函数名称当作参数传递出去:
example:
program ex0821
real, external :: func !声明func是自定义函数 !形容词都不能省掉
real, intrinsic :: sin   !声明sin是库函数

call ExecFunc (func) !输入自定义函数func
call ExecFunc (sin)    !输入库函数sin

stop
end program

subroutine ExecFunc (f)
implicit none
real, external :: f   !声明参数f是个函数
write (*, *) f(1.0)   !执行输入的函数f
return
end

real function func (num)
implicit none
real :: num
func = num**2
return
end function

子程序也可以当作参数传递出去:
program ex0822
implicit none
external sub1, sub2   !声明sub1和sub2是子程序名称
call sub(sub1)
call sub(sub2)
stop
end program ex0822

subroutine sun (sun_name)
implicit none
external sub_name !声明 sub_name是个子程序
call sun_name ( )    !调用输入的子程序sub_name
return
end subroutine

subroutine sub1( )
implicit none
write (*, *) “sub1”
end subroutine

subroutine sub2( )
implicit none
write (*, *) “sub2”

end subroutine

 

via: encaidx的专栏

发表评论

电子邮件地址不会被公开。 必填项已用*标注

CAPTCHA

*