我想以"简单"的方式使用延迟长度的字符串来读取用户输入.我想这样做的原因是我不想在知道用户输入的大小之前声明字符串的大小.我知道有"复杂"的方法来做到这一点.例如,可以使用iso_varying_string模块:https://www.fortran.com/iso_varying_string.f95 .此外,还有一个解决方案:未定义长度的Fortran字符输入.但是,我希望得到的东西简单,或几乎一样简单,如下所示:
program main
character(len = :), allocatable :: my_string
read(*, '(a)') my_string
write(*,'(a)') my_string
print *, allocated(my_string), len(my_string)
end program
Run Code Online (Sandbox Code Playgroud)
当我运行这个程序时,输出是:
./a.out
here is the user input
F 32765
Run Code Online (Sandbox Code Playgroud)
请注意,没有输出write(*,'(a)') my_string.为什么?
此外,my_string尚未分配.为什么?
为什么这不是Fortran的简单功能?其他语言有这个简单的功能吗?我一般对这个问题缺乏一些基本的了解吗?
Hig*_*ark 11
vincentjs的回答并不完全正确.
Modern(2003+)Fortran 确实允许在赋值时自动分配和重新分配字符串,因此需要一系列语句
character(len=:), allocatable :: string
...
string = 'Hello'
write(*,*)
string = 'my friend'
write(*,*)
string = 'Hello '//string
write(*,*)
Run Code Online (Sandbox Code Playgroud)
是正确的,将按预期工作,并写出3个不同长度的字符串.至少有一个广泛使用的编译器,Intel Fortran编译器,默认情况下不会使用2003语义,因此可能会在尝试编译时引发错误.有关使用Fortran 2003的设置,请参阅文档.
然而,读字符串时,所以你不得不求助于久经考验(此功能不可用,又名宣布足够大小的缓冲区进行任何输入和再分配分配变量的老式的,如果你喜欢)的方式.像这样:
character(len=long) :: buffer
character(len=:), allocatable :: string
...
read(*,*) buffer
string = trim(buffer)
Run Code Online (Sandbox Code Playgroud)
不,我不知道为什么语言标准禁止自动分配read,只是它确实如此.
延迟长度字符是Fortran 2003的一项功能.请注意,链接到的许多复杂方法都是针对早期语言版本编写的.
在Fortran 2003支持下,将完整记录读入字符变量是相对简单的.一个简单的例子,下面的错误处理非常少.这样的程序只需要编写一次,并且可以定制以满足用户的特定要求.
PROGRAM main
USE, INTRINSIC :: ISO_FORTRAN_ENV, ONLY: INPUT_UNIT
IMPLICIT NONE
CHARACTER(:), ALLOCATABLE :: my_string
CALL read_line(input_unit, my_string)
WRITE (*, "(A)") my_string
PRINT *, ALLOCATED(my_string), LEN(my_string)
CONTAINS
SUBROUTINE read_line(unit, line)
! The unit, connected for formatted input, to read the record from.
INTEGER, INTENT(IN) :: unit
! The contents of the record.
CHARACTER(:), INTENT(OUT), ALLOCATABLE :: line
INTEGER :: stat ! IO statement IOSTAT result.
CHARACTER(256) :: buffer ! Buffer to read a piece of the record.
INTEGER :: size ! Number of characters read from the file.
!***
line = ''
DO
READ (unit, "(A)", ADVANCE='NO', IOSTAT=stat, SIZE=size) buffer
IF (stat > 0) STOP 'Error reading file.'
line = line // buffer(:size)
! An end of record condition or end of file condition stops the loop.
IF (stat < 0) RETURN
END DO
END SUBROUTINE read_line
END PROGRAM main
Run Code Online (Sandbox Code Playgroud)