如何在Fortran中声明可分配标量数组?

时间:2022-09-20 21:29:06

Allocatable arrays are possible in Fortran 90 and up.

在Fortran 90及更高版本中可以使用可分配的阵列。

INTEGER, ALLOCATABLE, DIMENSION(:) :: test_int_array

Allocatable scalars such as allocatable characters are possible in Fortran 2003.

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

CHARACTER(LEN=:), ALLOCATABLE :: test_str

I am wondering is it possible to declare an array, fixed or allocatable, of allocatable characters? (Possibly like something below, which does not compile unfortunately.)

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

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

2 个解决方案

#1


7  

    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

I found the syntax at http://software.intel.com/en-us/forums/showthread.php?t=77823. It works with ifort 12.1 but not with gfortran 4.6.1. Trying the work around of creating a user-defined type didn't work either.

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

#2


0  

I developed a class recently to handle variable sized strings. I haven't tested it much, but it seems to compile fine. I basically made a class that just stores a single character, and since you can have an allocatable derived type inside a derived type, it's just one level deeper than what you'd ideally want. Either way, you're likely only going to use interfaces anyway. Here's the code:

我最近开发了一个类来处理可变大小的字符串。我没有测试过多少,但似乎编译得很好。我基本上创建了一个只存储单个字符的类,因为你可以在派生类型中有一个可分配的派生类型,它只比你理想的要深一级。不管怎样,你可能只会使用接口。这是代码:

  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

#1


7  

    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

I found the syntax at http://software.intel.com/en-us/forums/showthread.php?t=77823. It works with ifort 12.1 but not with gfortran 4.6.1. Trying the work around of creating a user-defined type didn't work either.

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

#2


0  

I developed a class recently to handle variable sized strings. I haven't tested it much, but it seems to compile fine. I basically made a class that just stores a single character, and since you can have an allocatable derived type inside a derived type, it's just one level deeper than what you'd ideally want. Either way, you're likely only going to use interfaces anyway. Here's the code:

我最近开发了一个类来处理可变大小的字符串。我没有测试过多少,但似乎编译得很好。我基本上创建了一个只存储单个字符的类,因为你可以在派生类型中有一个可分配的派生类型,它只比你理想的要深一级。不管怎样,你可能只会使用接口。这是代码:

  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