Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Fortran 使用延迟长度字符串读取用户输入_Fortran - Fatal编程技术网

Fortran 使用延迟长度字符串读取用户输入

Fortran 使用延迟长度字符串读取用户输入,fortran,Fortran,我希望以“简单”的方式使用延迟长度字符串来读取用户输入。我之所以要这样做,是因为我不想在知道用户输入的大小之前声明字符串的大小。我知道有很多“复杂”的方法可以做到这一点。例如,可以使用iso_变量_字符串模块:。此外,这里还有一个解决方案:。然而,我希望有一个简单的,或者说几乎一样简单的东西,如下所示: program main character(len = :), allocatable :: my_string read(*, '(a)') my_string write(*

我希望以“简单”的方式使用延迟长度字符串来读取用户输入。我之所以要这样做,是因为我不想在知道用户输入的大小之前声明字符串的大小。我知道有很多“复杂”的方法可以做到这一点。例如,可以使用iso_变量_字符串模块:。此外,这里还有一个解决方案:。然而,我希望有一个简单的,或者说几乎一样简单的东西,如下所示:

program main

  character(len = :), allocatable :: my_string
  read(*, '(a)') my_string
  write(*,'(a)') my_string
  print *, allocated(my_string), len(my_string)

end program
运行此程序时,输出为:

./a.out
here is the user input

F       32765
请注意,
write(*,“(a)”my_string
没有输出。为什么?

另外,
my_string
尚未分配。为什么?


为什么这不是Fortran的一个简单功能?其他语言有这个简单的功能吗?我对这个问题缺乏基本的了解吗?

延迟长度数组就是:延迟长度。在为数组赋值之前,仍然需要使用
allocate
语句分配数组的大小。一旦分配了它,就不能更改数组的大小,除非
取消分配
,然后用新的大小重新分配。这就是为什么会出现调试错误

FORTRAN不提供一种动态调整字符数组的方法,例如 STD::String 类,例如C++。在C++中,可以初始化<代码> STD::String VaR =“TEMP”< /C>,然后将其重新定义为<代码> var =“临时”< /C> >,不需要任何额外的工作,这是有效的。这只可能是因为调整大小是由

std::string
类中的函数在幕后完成的(如果超过缓冲区限制,则会使大小加倍,这在功能上相当于使用2倍大的数组重新
allocate
ing)


实际上,在Fortran中处理字符串时,我发现的最简单的方法是分配一个相当大的字符数组,以适合大多数预期的输入。如果输入的大小超过了缓冲区,那么只需通过使用更大的大小重新分配来增加数组的大小。可以使用
trim

删除尾随空白,vincentjs的答案不太正确

Modern(2003+)Fortran确实允许在赋值时自动分配和重新分配字符串,因此

character(len=:), allocatable :: string
...
string = 'Hello'
write(*,*)
string = 'my friend'
write(*,*)
string = 'Hello '//string
write(*,*)
是正确的,将按预期工作,并写出3个不同长度的字符串。至少有一种广泛使用的编译器“英特尔Fortran编译器”默认情况下不使用2003语义,因此在尝试编译此编译器时可能会出错。有关使用Fortran 2003的设置,请参阅文档

但是,当读取字符串时,此功能不可用,因此您必须求助于经过尝试和测试的(如果您愿意,也称为老式)方法,即为任何输入声明足够大小的缓冲区,然后分配可分配变量。像这样:

character(len=long) :: buffer
character(len=:), allocatable :: string
...
read(*,*) buffer
string = trim(buffer)
不,我不知道为什么语言标准禁止在
read
上自动分配,只是它确实禁止。

你知道做你想做的事情有“复杂”的方法。我将回答你的前两个“为什么”,而不是解决这些问题

与内在赋值不同,
read
语句没有首先将目标变量分配给即将到来的对象的正确大小和类型参数(如果它不是这样的话)。事实上,输入列表中的项目需要分配。Fortran 2008,9.6.3明确指出:

如果输入项或输出项是可分配的,则应进行分配

无论可分配变量是具有延迟长度的字符、具有其他延迟长度类型参数的变量还是数组,都是这种情况

还有另一种方法可以声明具有延迟长度的字符:为其指定
指针
属性。但是,正如我们也看到的,这对你没有帮助

如果输入项是指针,则它应与可定义的目标关联

write
语句没有输出的原因与您看到字符变量没有分配的原因有关:您没有遵循Fortran的要求,因此不能期望未指定的行为


我将推测为什么会有这种限制。我认为有两种明显的方法可以放松限制

  • 一般允许自动分配
  • 允许分配延迟长度字符
第二种情况很简单:

如果输入项或输出项是可分配的,则应进行分配,除非它是具有延迟长度的标量字符变量

然而,这是笨拙的,这样的特殊情况似乎违背了整个标准的精神。对于这种特殊情况,我们还需要一个经过仔细考虑的分配规则

如果我们选择分配的一般情况,我们可能会要求未分配的有效项是列表中的最终有效项:

integer, allocatable :: a(:), b(:)
character(7) :: ifile = '1 2 3 4'
read(ifile,*) a, b
然后我们不得不担心

type aaargh(len)
  integer, len :: len
  integer, dimension(len) :: a, b
end type
type(aaargh), allocatable :: a(:)
character(9) :: ifile = '1 2 3 4 5'

read(ifile,*) a
它很快就会变得很乱。这似乎有很多问题需要解决,有不同的方法,不同的难度,解决阅读问题


最后,我还要注意,在数据传输语句期间可以进行分配。尽管当变量出现在输入列表中时必须分配(如现在的规则),但如果有效项由定义的输入处理,则派生类型的已分配变量的组件

延迟长度字符是Fortran 2003的一项功能。请注意,链接到的许多复杂方法都是针对早期语言版本编写的

在Fortran 2003支持下,将完整记录读入字符变量相对简单。下面是一个错误处理非常少的简单示例。这样的程序只需要编写一次,并且可以通过cu
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