Fortran字符格式字符串作为子例程参数
我正在努力阅读文本字符串。我正在使用gfortran 4.9.2 下面我编写了一个小的子程序,我想在其中提交write格式作为参数 理想情况下,我希望能够与您联系Fortran字符格式字符串作为子例程参数,fortran,gfortran,Fortran,Gfortran,我正在努力阅读文本字符串。我正在使用gfortran 4.9.2 下面我编写了一个小的子程序,我想在其中提交write格式作为参数 理想情况下,我希望能够与您联系 call printarray(mat1, "F8.3") 例如,以该格式打印矩阵mat1。列数应在子例程内自动确定 subroutine printarray(x, udf_temp) implicit none real, dimension(:,:), intent(in) :: x ! array to
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
我做错了什么?
有没有更简洁的方法可以做到这一点?除了实际的错误(不使用输入参数),整个过程可以做得更简单:
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
除了实际的错误(不使用输入参数),整个过程可以做得更简单:
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
下面是我将尝试解决的问题的摘要:您希望有一个子例程,它将以指定的格式打印指定的二维数组,这样每一行都打印在一行上。例如,假设我们有真实的数组:
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位小数的浮点值(real)
现在,在子例程中创建格式时,您犯了几个错误。首先,尝试使用udf
创建udf2
字符串。这是一个问题,因为尽管您已经分配了udf
,但没有分配任何内容(在@francescalus的评论中指出)。因此,您会看到报告的错误消息:Fortran运行时错误:意外元素'(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循环(“版本3”)非常简单。它不需要显式的NCOL计数,因为
*
会自动处理它。由于它的简单性,实际上根本不需要子例程。下面是我将尝试解决的问题的摘要:您想要一个子例程,它将使用sp打印指定的二维数组指定的格式,每行打印在一行上。例如,假设我们有真实数组:
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位小数的浮点值(real)
现在,您在子例程中创建格式时犯了几个错误。首先,您尝试使用udf
创建udf2
字符串。这是一个问题,因为尽管您分配了udf
的大小,但没有为其分配任何内容(在@francescalus的评论中指出)。因此,您会看到报告的错误消息:Fortran运行时错误:意外元素’(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循环(“版本3”)非常简单。它不需要显式的NCOL计数,因为
*
自动处理它。由于它的简单性,实际上根本不需要子程序。在文件where2.f95(unit=6,file='stdout'的第38行len=10时调试输出)Fortran运行时错误:意外元素'(8[次1(进程19607)以代码02退出]调试输出,当len=*位于文件where2.f95(unit=6,file='stdout')的第38行时。Fortran运行时错误:意外元素'(8[次1(进程19634)以代码02退出)不要把你想让人们理解的内容放进评论中,格式还不够好。你实际上没有使用udf\u temp
anywhere-voting的值作为一个简单的打字错误来结束。如果你能解释一些真正的误解,我可能会收回投票。此外,在引用它之前,你没有定义udf
(在udf2=trim(txt1)//adjustl(udf)
)中,“8”
如何显示在错误消息中令人费解。我认为所显示的代码并不是实际给出错误的代码。当len=10出现在文件where2.f95(unit=6,file='stdout')的第38行时调试输出Fortran运行时错误:意外的元素(8[substander 1(process 19607)当len=*位于文件where2.f95(unit=6,file='stdout')的第38行时,以代码02退出]调试输出Fortran运行时错误:意外元素'(8[次1(进程19634)以代码02退出)未放入注释ma