Fortran字符格式字符串作为子例程参数

问题描述 投票:0回答:2

我正在努力阅读文本字符串。我正在使用gfortran 4.9.2。

下面我写了一个小子程序,其中我想提交写格式作为参数。

理想情况下,我希望能够调用它

call printarray(mat1, "F8.3")

例如,打印出该格式的矩阵mat1。应在子程序内自动确定列数。

subroutine printarray(x, udf_temp)
implicit none
real, dimension(:,:), intent(in) :: x           ! array to be printed     
integer, dimension(2)            :: dims        ! array for shape of x
integer                          :: i, j
character(len=10)                :: udf_temp    ! user defined format, eg "F8.3, ...
character(len = :), allocatable  :: udf         ! trimmed udf_temp
character(len = 10)              :: udf2
character(len = 10)              :: txt1, txt2
integer                          :: ncols       ! no. of columns of array
integer                          :: udf_temp_length

udf_temp_length = len_trim(udf_temp)
allocate(character(len=udf_temp_length) :: udf)

dims = shape(x)
ncols = dims(2)
write (txt1, '(I5)') ncols
udf2 = trim(txt1)//adjustl(udf)
txt2 = "("//trim(udf2)//")"

do i = 1, dims(1)
   write (*, txt2) (x(i, j), j = 1, dims(2))        ! this is line 38
end do

end suroutine printarray

当我设置len = 10

character(len=10) :: udf_temp

我得到编译错误:

call printarray(mat1, "F8.3")
                      1
Warning: Character length of actual argument shorter than of dummy argument 'udf_temp' (4/10) at (1)

当我设置len = *

character(len=*) :: udf_temp

它在运行时编译:

At line 38 of file where2.f95 (unit = 6, file = 'stdout')
Fortran runtime error: Unexpected element '(    8

我究竟做错了什么?有没有更简洁的方法来做到这一点?

fortran gfortran
2个回答
1
投票

以下是我将尝试解决的问题摘要:您希望有一个子程序,它将打印具有指定格式的指定二维数组,以便每行打印在一行上。例如,假设我们有真正的数组:

real, dimension(2,8) :: x
x = reshape([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16], shape=[2,8], order=[2,1])

! Then the array is:
!    1.000   2.000   3.000   4.000   5.000   6.000   7.000   8.000
!    9.000  10.000  11.000  12.000  13.000  14.000  15.000  16.000

我们想使用格式"F8.3",它打印浮点值(实数),字段宽度为8和3位小数。

现在,在子例程中创建格式时,您会犯一些错误。首先,您尝试使用udf来创建udf2字符串。这是一个问题,因为虽然你已经分配了udf的大小,但没有为它分配任何东西(在@francescalus的评论中指出)。因此,您会看到您报告的错误消息:Fortran runtime error: Unexpected element '( 8

在下文中,我进行了一些简化更改并演示了一些(稍微)不同的技术。如图所示,我建议使用*来指示格式可以无限次应用,直到输出列表的所有元素都被访问过。当然,明确说明应用格式的次数(即"(8F8.3)"而不是"(*(F8.3))")很好,但后者的工作量略少。

program main
    implicit none

    real, dimension(2,8) :: x
    character(len=:), allocatable :: udf_in

    x = reshape([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16], shape=[2,8], order=[2,1])
    udf_in = "F8.3"
    call printarray(x, udf_in)

contains
    subroutine printarray(x, udf_in)
        implicit none
        real, dimension(:,:), intent(in) :: x
        character(len=*), intent(in)     :: udf_in

        integer                        :: ncols         ! size(x,dim=2)
        character(len=10)              :: ncols_str     ! ncols, stringified
        integer, dimension(2)          :: dims          ! shape of x
        character(len=:), allocatable  :: udf0, udf1    ! format codes
        integer                        :: i, j          ! index counters

        dims = shape(x)                                 ! or just use: ncols = size(x, dim=2)
        ncols = dims(2)

        write (ncols_str, '(i0)') ncols                 ! use 'i0' for min. size

        udf0 = "(" // ncols_str // udf_in // ")"        ! create string: "(8F8.3)"
        udf1 = "(*(" // udf_in // "))"                  ! create string: "(*(F8.3))"

        print *, "Version 1:"
        do i = 1, dims(1)
            write (*, udf0) (x(i, j), j = 1,ncols)      ! implied do-loop over j.
        end do

        print *, "Version 2:"
        do i = 1, dims(1)
            ! udf1: "(*(F8.3))"
            write (*, udf1) (x(i, j), j = 1,ncols)      ! implied do-loop over j
        end do

        print *, "Version 3:"
        do i = 1, size(x,dim=1)                         ! no need to create nrows/ncols vars.
            write(*, udf1) x(i,:)                       ! let the compiler handle the extents.
        enddo

    end subroutine printarray
end program main

观察:最终的do-loop(“Version 3”)非常简单。它不需要显式计算ncols,因为*会自动处理它。由于其简单性,根本不需要子程序。


1
投票

除了实际的错误(不使用输入参数),这整个事情可以更简单地完成:

  subroutine printarray(m,f)
  implicit none
  character(len=*)f
  real m(:,:)
  character*10 n
  write(n,'(i0)')size(m(1,:))
  write(*,'('//n//f//')')transpose(m)
  end subroutine
  end

请注意,不需要循环结构,因为当达到格式指定的数据长度时,fortran将自动编写整个数组,换行。

或者你可以使用循环结构,然后你可以在格式中使用'*'重复计数,并且不需要内部写入来构造格式字符串。

  subroutine printarray(m,f)
  implicit none
  character(len=*)f
  real m(:,:)
  integer :: i
  do i=1,size(m(:,1))
     write(*,'(*('//f//'))')m(i,:)
  enddo
  end subroutine
  end
© www.soinside.com 2019 - 2024. All rights reserved.