3

我正在尝试编写一个小型实用程序,它可以将菜单条目列表作为字符串(理想情况下,在子程序调用中明确定义),将这些字符串显示为编号选项,并要求用户选择一个。验证的责任留给调用例程。我的第一次尝试使用以与数组初始化语句相同的方式定义的显式字符串数组,但失败了,因此我尝试了使用续行发送带有“标记”字符的单个显式字符串的方法。

以下似乎适用于 Cygwin 下的 gfortran 4.7.3:

PROGRAM menutest
IMPLICIT NONE
INTEGER :: n
CALL menu(n, 'This is option 1$&
              Option Two$&
              Option number three$' )
WRITE(*,*) 'You chose option ' ,n
END PROGRAM menutest

SUBROUTINE menu(n, entrylist)
IMPLICIT NONE
INTEGER :: n, i, nitems,pos1,pos2
CHARACTER (LEN=*) :: entrylist
!
pos1 = 1
pos2 = 1
i=1
! Loop over entries
DO
  entrylist = entrylist(pos1:)
  pos2 = INDEX(entrylist,'$')
  IF (pos2 == 0) THEN
     EXIT
  END IF
  WRITE (*,'(A,I2,A,A)') '(',i,') ',entrylist(:pos2-1)
  i = i+1
  pos1 = pos2+1
END DO
WRITE(*,*) 'Choose an option from the menu'
READ(*,*) n
END SUBROUTINE menu

不幸的是,使用 Linux gfortran 4.5.x 失败了。我需要一个能够在尽可能多的编译器和尽可能多的平台上可靠运行的解决方案。我希望能够在我的程序中多次调用它,不同长度的字符串列表的长度不同。

有没有人有更好的解决方案?

4

2 回答 2

2

你当然可以发送一个字符串数组:

CALL menu(n, [character(20) :: 'This is option 1', &
                               'Option Two', &
                               'Option number three'] )
write(*,*) 'You chose option ' ,n

contains
  subroutine menu(n, entrylist)
    CHARACTER(len=*),intent(in) :: entrylist(:)
    integer, intent(out) :: n
    integer i
    do i=1,size(entrylist)
      write(*,*) trim(entrylist(i))
    end do
    read(*,*) n
  end subroutine

end

这种形式的数组构造函数是 Fortran 2003。如果你必须避免它,那么通过元素的正常分配来构建数组。

strings(1) = 'This is option 1'
strings(2) = 'Option Two'
strings(3) = 'Option number three'
call menu(n, strings)

请注意,子例程需要一个显式接口,因此在这个简短示例中它是一个内部过程。您通常希望它在完整程序的模块中。

于 2013-10-31T08:37:07.747 回答
0

简单的修复,不要修改作为文字传递的字符串:

!  entrylist = entrylist(pos1:)  <-- get rid of this offending line
   pos2 = pos1-1+INDEX(entrylist(pos1:),'$')
   IF (pos2 == pos1-1) THEN

      ...

   WRITE (*,'(A,I2,A,A)') '(',i,') ',entrylist(pos1:pos2-1)

用 gfortran 4.x 测试

于 2013-10-31T14:18:13.307 回答