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

Fortran 专栏收录该内容
2 篇文章 0 订阅
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


博主认为这篇文章中讲解的子程序和自定义函数非常的清楚明了。。

  • 1
    点赞
  • 0
    评论
  • 5
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值