Muszę pracować z tablicami, ale nie wiem na początku rozmiaru tych tablic, wiem tylko, że jest skończony. Zasugerowano, aby użyć dynamicznych tablic opisanych w To pytanie. Nie jestem pewien, jak go używać. Co muszę zrobić, to coś takiego:

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

Kiedy używam następującego kodu, który w moim umyśle powinien dodać 2 do mojej tablicy

  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

Otrzymuję następujący wynik:

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

Co ja robię źle?

0
mattiav27 22 marzec 2020, 18:19

1 odpowiedź

Najlepsza odpowiedź

W Fortran nie używaj wskaźników - Allocatable tablice są sposobem na wykonanie tego i prawie wszystkie dynamiczne zarządzanie pamięcią. Przydzielane tablice są łatwiejsze w użyciu i bezpieczniejsze, nie jest dla nich niemożliwe, aby mieć wiele błędów, które wskaźniki ułatwiają wprowadzenie do kodu. Jednym z takich błędów jest przecieki pamięci - niemożliwe jest przeprowadzenie wycieku pamięci z alokowaną tablicą, ponieważ automatycznie zostaną automatycznie zawarte, gdy wychodzą z zakresu; Niedługo nie ma do czynienia z tablicy, a czasami może chcesz zaoszczędzić pamięć, a niektóre mogą nawet rozważyć go dobrego stylu, ale częściej nie tylko uderzając w końcu (Sub) Programu i poleganie na automatycznej DealLokalizacja dość.

Z drugiej strony wskaźniki może spowodować wycieki pamięci, wśród wielu innych problemów, które są przydzielane macierze po prostu nie cierpieć. Wskaźniki do danych powinny być używane tylko do bardzo małej liczby przypadków narożnych, które jeśli tylko uczą się języka, o którym możesz zapomnieć. W rzeczywistości, jeśli uczysz się języka, jest bardzo blisko prawdy, aby powiedzieć, że nigdy nie powinieneś używać wskaźników, alokacji tablice są sposobem na przejście.

Ok, co powiedziałeś, jak to zrobić, piszesz swój kod w nowoczesnym Fortranu. Cóż, oto prosta wersja dla jednego wymiarowego przypadku - może być bardziej wydajny, ale jest to podstawa tego, co należy zrobić

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$ 

W rzeczywistym, kod produkcyjny uniknąłbym niektórych kopii i przydziałów pamięci poprzez przechowywanie nowych danych w tymczasowym buforze, a gdy bufor jest pełny dołączenie wszystkich tego w jednym miejscu

Obudowa wielu wymiarów jest trudniejsza jak w konstruktorach tablic Fortran ([] rzeczy) może być tylko jeden wymiarowy. Możesz zrobić "sprytne" rzeczy z reshape Intryinsic do pracy, ale myślę, że wynikowy kod nie jest tylko brzydki, ale bardzo mylący. Tak więc w tym przypadku wolałbym używać podprogramu. Prosta wersja jest poniżej

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$ 

Ponownie w prawdziwym kodzie, dołączyłbym wiele linii jednocześnie.

3
Ian Bush 23 marzec 2020, 10:28