将数组传入/传出程序 Fortran 90 的函数

cdm*_*004 3 fortran

我正在尝试将数组传递到函数中,以便能够计算将替换该数组中的原始值的新值。但是,我不断收到返回的零,我不知道为什么。我的代码如下:

program HW10
    implicit none
    integer :: i
    integer, parameter :: &
    p=38      !lines to read
    real, parameter :: &
    g=9.81    !Value of gravity acceleration
    integer , dimension(p) :: direction, speed, rh, speedconv
    real, dimension (p) :: pressure, height, temp, dewpt, mixr
    real :: average, knots

    open(1,file='HW10input.txt', status='old', action='read')

    10 format (F6.1, T9, F6.1, T16, F5.1, T23, F5.1, T33, I2, T38, F4.2, T46, I3, T53, I3)

    do i=1,p
        read(1,10)pressure(i), height(i), temp(i), dewpt(i), rh(i), mixr(i), direction(i), speed(i)
    end do


    close (1)

    open(2, file='outputfilehw10.txt', status='new', action='write') 
    do i=1,p
    write (*, 20) pressure(i), height(i), temp(i), dewpt(i), rh(i), mixr(i), direction(i), speed(i)
    20 format (F6.1, T9, F6.1, T16, F5.1, T23, F5.1, T33, I2, T38, F4.2, T46, I3, T53, I3)
    end do
    write (*,*) 'Average= ', average(temp, p)
    do i=1,p
        write (*,*) 'Wind Speeds: ', knots(speed, p)
    end do
end program HW10
Run Code Online (Sandbox Code Playgroud)

当我到达底部的函数“knots”时,问题就出现了。该函数如下所示:

real function knots (x, n)
integer, intent(in) :: n
real, dimension(n), intent(inout) :: x
integer :: i

do i = 1, n
    x(i) = (x(i) * 0.514444 )
end do 
return x
end function knots
Run Code Online (Sandbox Code Playgroud)

该代码将很好地读取数据,因为我的代码可以正确显示它。然而,当我想查看风速数组中变化的数据时,所有数据点都为零。我是 Fortran 新手,所以我不太确定该怎么做。提前致谢!

d_1*_*999 5

如果我尝试使用 gfortran 4.8.3 编译问题中给出的代码(将所有代码放在同一个文件中),则会出现以下两个错误:

第一个错误:

return x
      1
Error: Alternate RETURN statement at (1) is only allowed within a SUBROUTINE
Run Code Online (Sandbox Code Playgroud)

第二个错误:

        write (*,*) 'Wind Speeds: ', knots(speed, p)
                                           1
Warning: Type mismatch in argument 'x' at (1); passed INTEGER(4) to REAL(4)
Run Code Online (Sandbox Code Playgroud)

让我们处理第一个 - 与许多其他编程语言不同,它不用于设置返回值。

那么,为什么编译器只是抱怨您在函数而不是子例程中完成了此操作,而不是编译器抱怨您在此处放置了一个值呢?有一个称为交替返回的历史功能,有点像使用goto- 这些只允许在子例程中使用。

因此,让我们替换return xreturn-- 这可以避免编译器错误,但是代码如何知道要返回什么值?在 fortran 中定义函数时,您可以显式指定结果的名称,但如果您不这样做,那么它会假设您的结果是与函数同名的变量,因此在您的情况下knots. 因此,在您的代码中,调用了要返回的变量knots,但它从未被设置为任何内容。通过“巧合”,看起来用于存储结果的内存位(从未明确设置为任何内容)要么被编译器初始化为零,要么您只是访问恰好充满零的未初始化内存。

那么我们该如何解决这个问题呢?让我们明确定义结果

function knots (x, n) result(y)
  implicit none
  integer, intent(in) :: n
  real, dimension(n), intent(inout) :: x
  real, dimension(n) :: y
  integer :: i

  do i = 1, n
     y(i) = (x(i) * 0.514444 )
  end do
  return
end function knots
Run Code Online (Sandbox Code Playgroud)

如果我们尝试编译,我们现在会收到一个新错误!

write (*,*) 'Wind Speeds: ', knots(speed, p)
                                    1
Error: The reference to function 'knots' at (1) either needs an explicit INTERFACE or the rank is incorrect
Run Code Online (Sandbox Code Playgroud)

具有参数/返回值的函数/子例程通常需要定义一个接口。有很多方法可以实现这一点,我将通过将函数放入模块中来实现:

module myknots
  implicit none
  public :: knots
contains
  function knots (x, n) result(y)
    implicit none
    integer, intent(in) :: n
    real, dimension(n), intent(inout) :: x
    real, dimension(n) :: y
    integer :: i

    do i = 1, n
       y(i) = (x(i) * 0.514444 )
    end do
    return
  end function knots
end module myknots
Run Code Online (Sandbox Code Playgroud)

然后我们需要添加use myknots, only: knots到主程序的顶部。现在只剩下第二个错误了。

这告诉我们您已将整数数组传递给需要实数的函数。这是因为speed被声明为整数,但x在结中被声明为实数。为了解决这个问题,让我们创建一个新的knots函数,其中x被声明为整数。我还将使用显式接口来允许我们使用名称来引用任一版本的结knots。这样做myknots模块看起来像

module myknots
  implicit none
  private
  public :: knots

  interface knots
     module procedure knots_r
     module procedure knots_i
  end interface knots
contains
  function knots_r (x, n) result(y)
    implicit none
    integer, intent(in) :: n
    real, dimension(n), intent(inout) :: x
    real, dimension(n) :: y
    integer :: i

    do i = 1, n
       y(i) = (x(i) * 0.514444 )
    end do
    return
  end function knots_r

  function knots_i (x, n) result(y)
    implicit none
    integer, intent(in) :: n
    integer, dimension(n), intent(inout) :: x
    real, dimension(n) :: y
    integer :: i

    do i = 1, n
       y(i) = (x(i) * 0.514444 )
    end do
    return
  end function knots_i
end module myknots
Run Code Online (Sandbox Code Playgroud)

主程序看起来像

Program HW10
  use myknots, only: knots
  implicit none
  integer :: i
  integer, parameter :: &
       p=38      !lines to read                                                                                                                                                                                    
  real, parameter :: &
       g=9.81    !Value of gravity acceleration                                                                                                                                                                    
  integer , dimension(p) :: direction, speed, rh, speedconv
  real, dimension (p) :: pressure, height, temp, dewpt, mixr
  real :: average

  open(1,file='HW10input.txt', status='old', action='read')

10 format (F6.1, T9, F6.1, T16, F5.1, T23, F5.1, T33, I2, T38, F4.2, T46, I3, T53, I3)

  do i=1,p
     read(1,10)pressure(i), height(i), temp(i), dewpt(i), rh(i), mixr(i), direction(i), speed(i)
  end do


  close (1)

  open(2, file='outputfilehw10.txt', status='new', action='write')
  do i=1,p
     write (*, 20) pressure(i), height(i), temp(i), dewpt(i), rh(i), mixr(i), direction(i), speed(i)
20   format (F6.1, T9, F6.1, T16, F5.1, T23, F5.1, T33, I2, T38, F4.2, T46, I3, T53, I3)
  end do
  write (*,*) 'Average= ', average(temp, p)
  do i=1,p
     write (*,*) 'Wind Speeds: ', knots(speed, p)
  end do
end program HW10
Run Code Online (Sandbox Code Playgroud)

这已经解决了所有直接问题,但您仍然无法生成可执行文件,因为您尚未定义该average函数。希望上述步骤足以让您自己实现这一点。