我正在努力阅读文本字符串。我正在使用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
我做错了什么? 有没有更简洁的方法来做到这一点?
答案 0 :(得分: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
答案 1 :(得分: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,因为*
会自动处理它。由于它的简单性,根本不需要子程序。