首页 > 解决方案 > 需要帮助来理解这个功能

问题描述

我必须使用数组,但一开始我不知道这些数组的大小,我只知道它是有限的。有人建议我使用这个问题中描述的动态数组。我不确定如何使用它。我需要做的是这样的:

REAL,pointer,dimension(:,:)array
do i=1, max
   array(i)=value
end do

当我使用以下代码时,我认为应该将 2 添加到我的数组中

  PROGRAM dynamic_array
  IMPLICIT NONE
  INTEGER,pointer,dimension(:)::vettore
  integer i,val

  allocate(vettore(1))
  vettore(1)=1
  do i=1,10
        array(i)=append(i,vettore,2)
  end do

  do i=1, 20
        write(*,*) array(i)
  end do

  deallocate(array)
  Contains
  (...)
  end program

我得到以下输出:

           1
           2
 -1216226408
           4
           0
           6
           0
           8
          48
          10
          81
           0
  1836017711
  1634545509
  1634301044
  1919111983
  1851881065
  1160733033
  1414808908
  1229868882

我究竟做错了什么?

标签: fortran

解决方案


在 Fortran 中不要使用指针 - 可分配数组是执行此操作的方法,几乎​​所有动态内存管理都是如此。可分配数组更容易使用和更安全,它们不可能有许多错误,这些错误使得指针很容易引入你的代码。一个这样的错误是内存泄漏 - 可分配数组不可能发生内存泄漏,因为一旦超出范围就会自动解除分配;明确地解除分配数组并没有错,有时您可能想节省内存,有些人甚至可能认为它是一种很好的风格,但通常不仅仅是打到(子)程序的末尾并依赖于自动解除分配是足够。

另一方面,指针可能会导致内存泄漏,以及可分配数组根本不会遇到的许多其他问题。指向数据的指针应该只用于极少数的极端情况,如果你只是学习你可以忘记的语言。事实上,如果你正在学习这门语言,那么说你永远不应该使用指针非常接近事实,可分配数组是要走的路。

好的,你是如何用现代 Fortran 编写代码的。好吧,这是一维情况的简单版本-可以提高效率,但这是应该做的基础

ian@eris:~/work/stack$ cat append.f90
Program append

  Implicit None

  Integer, Dimension( : ), Allocatable :: vettore
  Integer :: i

  ! Allocate vettore to size zero
  Allocate( vettore( 1:0 ) )

  ! Repeatedly append to the vector
  ! The alloctable array will automatically resize appropriately
  Do i = 1, 20
     vettore = [ vettore, 2 * i ]
  End Do

  ! Print out the vector
  Do i = 1, 20
     Write( *, * ) i, vettore( i )
  End Do

End Program append
ian@eris:~/work/stack$ gfortran-8 -fcheck=all -Wall -Wextra -pedantic -std=f2008 append.f90 
ian@eris:~/work/stack$ ./a.out
           1           2
           2           4
           3           6
           4           8
           5          10
           6          12
           7          14
           8          16
           9          18
          10          20
          11          22
          12          24
          13          26
          14          28
          15          30
          16          32
          17          34
          18          36
          19          38
          20          40
ian@eris:~/work/stack$ 

在实际的生产代码中,我会通过将新数据存储在临时缓冲区中来避免一些副本和内存分配,一旦缓冲区已满,就可以一次性添加所有内容

多维情况更难,因为 Fortran 数组构造函数([] 东西​​)只能是一维的。您可以使用 RESHAPE 内在函数来做“聪明”的事情来解决这个问题,但我认为生成的代码不仅丑陋,而且也非常令人困惑。因此,在这种情况下,我更愿意使用子程序。下面是一个简单的版本

ian@eris:~/work/stack$ cat append_2d.f90
Module append_module

  Implicit None

  Public :: append_2d

  Private

Contains

  Subroutine append_2d( existing, new )

    Implicit None

    Integer, Dimension( :, : ), Allocatable, Intent( InOut ) :: existing
    Integer, Dimension( :    ),              Intent( In    ) :: new

    Integer, Dimension( :, : ), Allocatable :: tmp

    Integer :: n1, n2

    ! Get size of the EXISTING data
    n1 = Size( existing, Dim = 1 )
    n2 = Size( existing, Dim = 2 )

    ! Allocate the temporary to the new size
    Allocate( tmp( 1:n1, 1:n2 + 1 ) )

    ! Copy over the exisiting data
    tmp( 1:n1, 1:n2 ) = existing

    ! Add the new data
    tmp( :, n2 + 1 ) = new

    ! Move the allocation back 
    Call Move_alloc( tmp, existing )

  End Subroutine append_2d

End Module append_module

Program test_append_2d

  Use append_module, Only : append_2d

  Implicit None

  Integer, Dimension( :, : ), Allocatable :: vettore
  Integer :: i

  ! Allocate vettore to size zero
  Allocate( vettore( 1:2, 1:0 ) )

  ! Repeatedly append to the vector
  Do i = 1, 20
     Call append_2d( vettore, [ i, 2 * i ] )
  End Do

  ! Print out the vector
  Do i = 1, 20
     Write( *, * ) i, vettore( :, i )
  End Do

End Program test_append_2d
ian@eris:~/work/stack$ gfortran-8 -fcheck=all -Wall -Wextra -pedantic -std=f2008 append_2d.f90
ian@eris:~/work/stack$ ./a.out
           1           1           2
           2           2           4
           3           3           6
           4           4           8
           5           5          10
           6           6          12
           7           7          14
           8           8          16
           9           9          18
          10          10          20
          11          11          22
          12          12          24
          13          13          26
          14          14          28
          15          15          30
          16          16          32
          17          17          34
          18          18          36
          19          19          38
          20          20          40
ian@eris:~/work/stack$ 

再次在实际代码中,我将一次附加多行。


推荐阅读