如何在Fortran 90中为动态数组添加新元素

如何在Fortran 90中为动态数组添加新元素,fortran,fortran90,dynamic-arrays,intel-fortran,Fortran,Fortran90,Dynamic Arrays,Intel Fortran,我需要在Fortran 90中使用动态数组,以便在最初无法预测数组的确切大小的情况下使用。所以我写了一段代码,每次在数组末尾添加新元素时,它都应该扩展可分配数组: subroutine DArray() double precision, dimension(:), allocatable :: list allocate(list(1)) list(1) = 1.1 call AddToList(list, 2.2) call AddToList(list, 3

我需要在Fortran 90中使用动态数组,以便在最初无法预测数组的确切大小的情况下使用。所以我写了一段代码,每次在数组末尾添加新元素时,它都应该扩展可分配数组:

  subroutine DArray()

  double precision, dimension(:), allocatable :: list

  allocate(list(1))

  list(1) = 1.1

  call AddToList(list, 2.2)
  call AddToList(list, 3.2)
  call AddToList(list, 4.2)
  call AddToList(list, 5.2)

  print *, list(1)
  print *, list(2)
  print *, list(3)
  print *, list(4)
  print *, list(5)


  end



  subroutine AddToList(list, element)

  double precision :: element
  double precision, dimension(:), allocatable :: list
  double precision, dimension(:), allocatable :: clist

  if(allocated(list)) then
    isize = size(list)
    allocate(clist(isize+1))
    do i=1,isize
        clist(i) = list(i)
    end do
    clist(i+1) = element

    deallocate(list)
    allocate(list(isize+1))

    do i=1,isize+1
        list(i) = clist(i)
    end do

    deallocate(clist)

  end if


  end
有没有人看到我遗漏了什么

由解决

双精度动态阵列的工作代码为:

  module DynamicalArrays

  contains

      subroutine AddToList(list, element)

          IMPLICIT NONE

          integer :: i, isize
          double precision, intent(in) :: element
          double precision, dimension(:), allocatable, intent(inout) :: list
          double precision, dimension(:), allocatable :: clist


          if(allocated(list)) then
              isize = size(list)
              allocate(clist(isize+1))
              do i=1,isize          
              clist(i) = list(i)
              end do
              clist(isize+1) = element

              deallocate(list)
              call move_alloc(clist, list)

          else
              allocate(list(1))
              list(1) = element
          end if


      end subroutine AddToList


  end module DynamicalArrays
可以从中填充数组的演示子例程为:

  subroutine UserDArrayTest()

  use DynamicalArrays


  integer :: i
  double precision, dimension(:), allocatable :: list
  double precision :: temp

  temp = 0.1
  do i=1,10
    temp = temp+1
    call AddToList(list, temp)
  end do

  do i=1,10
    print *, i, list(i)
  end do


  end

请注意,最好将模块代码保存在单独的文件中,但我还发现,当模块代码位于主程序和子例程代码之上时,它也可以工作。

我怀疑,通过查看一个人工制品,您已经注意到了问题,但很快就开始了

对我来说,可疑的线索是:

    allocate(clist(isize+2))
为什么新尺寸不是isize+1?我猜你试过了,但后来程序失败了

了解程序失败的原因可能是崩溃,这是您无法获得正确结果的关键。仔细查看已删除的循环打印语句以确保清晰

do i=1,isize
    clist(i) = list(i)
end do
clist(i+1) = element
您想说将列表中的所有元素复制到clist,然后追加元素。这是正确的。然而

do i=1,isize
    clist(i) = list(i)
end do
! Here, i=isize+1
clist(i+1) = element
! Which means
! clist(isize+2) = element.

总之,在循环之后,循环索引变量没有它在最后一次迭代中的值。

我知道这个问题已经很老了,但我最近不得不构建这样一个子程序,我发现,从Fortran2003开始,有一个漂亮的单行程序:

    SUBROUTINE append_int(vec, val)
    !***********************************************************************
    !> \brief Appends val in vec if not already present
    !> \date 05 2020
    !***********************************************************************
    INTEGER, DIMENSION(:), ALLOCATABLE, INTENT(INOUT)    :: vec
    INTEGER, INTENT(IN)                                  :: val

    ! Remove this test if you don't mind not having unique values
    IF (.NOT. ANY(vec .EQ. val)) THEN
        vec = [vec, val]
    END IF

    END SUBROUTINE
您的阵列将自动重新分配到适当的大小。
另外,您可以为real生成等价的例程,用于将一个数组附加到另一个数组。。。然后将它们全部封装在一个接口中,这样无论数据的类型如何,您都可以调用相同的子例程。

您有什么问题/错误?程序在deallocatelist上冻结,不再运行任何程序。并没有打印出错误,它只是冻结,什么也不做。你们可能不是说Fortran 90,但在DArray中,必须为AddToList提供一个:它有可分配的伪参数。我用实现的接口更新了这个问题。但它们对我来说仍然不能正常工作……请不要太多地改变问题,也不要使用任何[已解决的]标签。这个问题是未来读者的参考,通过其他方式可以看出它有一个公认的答案。这不是一个讨论论坛。哦,哇,它现在工作得非常好,修正了clistisize+1=元素,我不知道在fortran中,end do之后的最后一个索引变成了isize+1。另外,你知道在每个子程序的开头,如果我想使用动态数组,是否可以避免6行这样的接口?也许有可能以某种方式将它们放在USE语句和模块上?我更喜欢使用模块而不是接口块的方式来提供显式接口,在这里搜索示例将很容易找到。在我们继续讨论代码推荐时,我还将介绍move_alloc的内在特性。甚至可以考虑链接列表而不是动态调整大小。非常感谢。我刚刚添加了模块修正,现在情况看起来更好了。还有一个修正,数组不需要最初分配和移动。我在问题的顶部使用了更改,其他用户可以很容易地找到完整的代码。实际上,让我们为另一个故事保留链接列表:是的,即使问题要求Fortran 90,在这里也可能有用。我们在更一般的问题和答案中确实有这样的内容,但最终会有人惊讶地发现数组的下界在添加元素后发生了变化。@francescalus你是什么意思?这个过程不安全?@hermantouthrot,这个过程是安全的,但它可能以意想不到的方式改变事情。考虑分配VEC0:5,源= [1,2,3,4,5,6];打印*,lboundvec;调用append_intvec,6;打印*,lboundvec;调用append_intvec,7;打印*,lboundvec。