【问题标题】:How to declare array of allocatable scalars in Fortran?如何在 Fortran 中声明可分配标量数组?
【发布时间】:2012-01-14 06:29:09
【问题描述】:

可分配数组在 Fortran 90 及更高版本中是可能的。

INTEGER, ALLOCATABLE, DIMENSION(:) :: test_int_array

在 Fortran 2003 中可以使用可分配的标量,例如可分配的字符。

CHARACTER(LEN=:), ALLOCATABLE :: test_str

我想知道是否可以声明一个可分配字符的固定或可分配数组? (可能像下面的东西,不幸的是没有编译。)

CHARACTER(LEN=:), ALLOCATABLE, DIMENSION(4) :: test_str_array

【问题讨论】:

    标签: arrays fortran character


    【解决方案1】:
        program test_alloc
    
       character (len=:), allocatable :: string
    
       character(len=:), allocatable :: string_array(:)
    
       type my_type
          character (len=:), allocatable :: my_string
       end type my_type
       type (my_type), dimension (:), allocatable :: my_type_array
    
       string = "123"
       write (*, *) string, len (string)
       string = "abcd"
       write (*, *) string, len (string)
    
       allocate(character(5) :: string_array(2))
       string_array (1) = "1234"
       string_array (2) = "abcde"
       write (*, *) string_array (1), len (string_array (1))
       write (*, *) string_array (2), len (string_array (2))
    
       allocate (my_type_array (2))
       my_type_array (1) % my_string = "XYZ"
       my_type_array (2) % my_string = "QWER"
       write (*, *) my_type_array (1) % my_string, len (my_type_array (1) % my_string)
       write (*, *) my_type_array (2) % my_string, len (my_type_array (2) % my_string)
    
    end program test_alloc
    

    我在http://software.intel.com/en-us/forums/showthread.php?t=77823 找到了语法。它适用于 ifort 12.1,但不适用于 gfortran 4.6.1。尝试创建用户定义类型的工作也没有奏效。

    【讨论】:

    • Gfortran 有一个错误,即在字符分配语句中需要编译时间常数。否则,具有可分配组件的派生类型的可分配数组在 gfortran 中工作了相当长的一段时间。
    • 非常感谢您的宝贵时间和帮助!正如您所提到的,string_array 似乎确实是可分配字符串的可分配数组。但是,必须在之后声明字符串具有相等的长度。你能帮忙评论一下我是否理解这个限制吗?另一种解决方法需要用户定义的类型,该类型本身包含可分配的字符串,确实有效,但似乎引入了更多复杂性。如果这种用户定义的类型方式是唯一的解决方法,也许我会坚持使用固定长度的字符串。
    • 你是对的,一个数组必须由相同的实体组成。在这种情况下,您可以将可分配数组想象成一种更好的指针。
    • 非常感谢你们知识渊博的cmets!
    【解决方案2】:

    我最近开发了一个类来处理可变大小的字符串。我没有对其进行太多测试,但它似乎编译得很好。我基本上创建了一个只存储单个字符的类,并且由于您可以在派生类型中拥有可分配的派生类型,因此它只比您理想中想要的更深一层。无论哪种方式,您都可能只会使用接口。代码如下:

      module string_mod
      implicit none
      ! Implimentation:
    
      ! program test_string
      ! use string_mod
      ! implicit none
      ! type(string) :: s
      ! call init(s,'This is');            write(*,*) 'string = ',str(s)
      ! call append(s,' a variable');      write(*,*) 'string = ',str(s)
      ! call append(s,' sized string!');   write(*,*) 'string = ',str(s)
      ! call compress(s);                  write(*,*) 'string, no spaces = ',str(s)
      ! call delete(s)
      ! end program
    
      private
      public :: string
      public :: init,delete
      public :: get_str,str ! str does not require length
      public :: compress,append
      public :: print,export
    
      interface init;      module procedure init_size;            end interface
      interface init;      module procedure init_string;          end interface
      interface init;      module procedure init_copy;            end interface
      interface append;    module procedure app_string_char;      end interface
      interface append;    module procedure app_string_string;    end interface
      interface compress;  module procedure compress_string;      end interface
      interface str;       module procedure get_str_short;        end interface
      interface get_str;   module procedure get_str_string;       end interface
      interface delete;    module procedure delete_string;        end interface
      interface print;     module procedure print_string;         end interface
      interface export;    module procedure export_string;        end interface
    
      type char
        private
        character(len=1) :: c
      end type
    
      type string
        private
        type(char),dimension(:),allocatable :: s ! string
        integer :: n                             ! string length
      end type
    
      contains
    
      subroutine init_size(st,n)
        implicit none
        type(string),intent(inout) :: st
        integer,intent(in) :: n
        if (n.lt.1) stop 'Error: string must be of size > 1 in string.f90'
        call delete(st)
        allocate(st%s(n))
        st%n = n
      end subroutine
    
      subroutine init_string(st,s)
        implicit none
        type(string),intent(inout) :: st
        character(len=*),intent(in) :: s
        integer :: i
        call init(st,len(s))
        do i=1,st%n
          call init_char(st%s(i),s(i:i))
        enddo
      end subroutine
    
      subroutine init_copy(a,b)
        implicit none
        type(string),intent(inout) :: a
        type(string),intent(in) :: b
        integer :: i
        call check_allocated(b,'init_copy')
        call init(a,b%n)
        do i=1,b%n
        call init_copy_char(a%s(i),b%s(i))
        enddo
        a%n = b%n
      end subroutine
    
      subroutine check_allocated(st,s)
        implicit none
        type(string),intent(in) :: st
        character(len=*),intent(in) :: s
        if (.not.allocated(st%s)) then
          write(*,*) 'Error: string must be allocated in '//s//' in string.f90'
        endif
      end subroutine
    
      subroutine delete_string(st)
        implicit none
        type(string),intent(inout) :: st
        if (allocated(st%s)) deallocate(st%s)
        st%n = 0
      end subroutine
    
      subroutine print_string(st)
        implicit none
        type(string),intent(in) :: st
        call export(st,6)
      end subroutine
    
      subroutine export_string(st,un)
        implicit none
        type(string),intent(in) :: st
        integer,intent(in) :: un
        integer :: i
        call check_allocated(st,'export_string')
        do i=1,st%n
          write(un,'(A1)',advance='no') st%s(i)%c
        enddo
      end subroutine
    
      subroutine app_string_char(st,s)
        implicit none
        type(string),intent(inout) :: st
        character(len=*),intent(in) :: s
        type(string) :: temp
        integer :: i,n
        n = len(s)
        call init(temp,st)
        call init(st,temp%n+n)
        do i=1,temp%n
          call init_copy_char(st%s(i),temp%s(i))
        enddo
        do i=1,n
          call init_char(st%s(temp%n+i),s(i:i))
        enddo
        call delete(temp)
      end subroutine
    
      subroutine app_string_string(a,b)
        implicit none
        type(string),intent(inout) :: a
        type(string),intent(in) :: b
        call append(a,str(b))
      end subroutine
    
      subroutine compress_string(st)
        implicit none
        type(string),intent(inout) :: st
        type(string) :: temp
        integer :: i,n_spaces
        if (st%n.lt.1) stop 'Error: input string must be > 1 in string.f90'
        n_spaces = 0
        do i=1,st%n
          if (st%s(i)%c.eq.' ') n_spaces = n_spaces + 1
        enddo
        call init(temp,st%n-n_spaces)
        if (temp%n.lt.1) stop 'Error: output string must be > 1 in string.f90'
        do i=1,temp%n
          if (st%s(i)%c.ne.' ') temp%s(i)%c = st%s(i)%c
        enddo
        call init(st,temp)
        call delete(temp)
      end subroutine
    
      function get_str_short(st) result(str)
        type(string),intent(in) :: st
        character(len=st%n) :: str
        str = get_str_string(st,st%n)
      end function
    
      function get_str_string(st,n) result(str)
        implicit none
        type(string),intent(in) :: st
        integer,intent(in) :: n
        character(len=n) :: str
        integer :: i
        call check_allocated(st,'get_str_string')
        do i=1,st%n
          str(i:i) = st%s(i)%c
        enddo
      end function
    
      subroutine init_char(CH,c)
        implicit none
        type(char),intent(inout) :: CH
        character(len=1),intent(in) :: c
        CH%c = c
      end subroutine
    
      subroutine init_copy_char(a,b)
        implicit none
        type(char),intent(inout) :: a
        type(char),intent(in) :: b
        a%c = b%c
      end subroutine
    
      end module
    

    【讨论】:

    • 这很有趣,但我很难理解它是如何回答这个问题的。是的,你可以创建一个这些类型的数组,但是你可以创建一个简单类型的数组,只包含一个延迟长度的 Fortran 字符串。但是您甚至没有显示这样的数组,问题是关于它们的。
    • 是的,我同意它不能直接解决问题,这更像是一种解决方法。我过去曾遇到过这个问题,发现我附加的编译代码没有任何关于 fortran 2003 或任何编译器的投诉。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-27
    • 2015-05-26
    • 1970-01-01
    相关资源
    最近更新 更多