使用 Fortran 90 将 txt 文件读入可分配数组时出现错误结果

问题描述

我正在尝试解决与保留值相关的问题,当我在下面显示代码 (fortran) 中使用 de/allocate 时,制作了一个副本数组,但问题仍然存在。我已经看到与该主题相关的链接

Fortran array automatically growing when adding a value

How to get priorly-unknown array as the output of a function in Fortran

如果我知道数组维度(从 txt 文件输入),这将很容易并且没有任何意义(对于此代码而言)。

可能我犯了一些错误(其中一个很明显:分钟维度与预期总维度)。如果有人指定它们,我将不胜感激。尽管如此,我还是无法理解制作复制数组如何解决问题,因为我需要解除/分配临时变量和主变量。

那么,是否可以使用重新分配(取消/分配)读取没有“可变维度”信息的 txt?

这是代码(使用 f90):

program prueba
    implicit none
    integer,dimension(:),allocatable :: minuto,temp
    integer :: IoUnit,ierr
    integer :: i = 1
    integer :: n = 1

    open(newunit = IoUnit,file = 'datos.txt')
    read(IoUnit,*)

    allocate(minuto(n),temp(n))
    minuto = 0; temp = 0
    !-------------------------------------------

    do
        read(unit = IoUnit,fmt = '(i2)',iostat = ierr) temp(i)
        if (ierr/=0) exit

            if (mod(size(temp,1),5)==0) then
                deallocate(minuto)
                allocate(minuto(i))
                minuto((i-4):i) = temp((i-4):i)
            end if
        i = i+1
        deallocate(temp)
        allocate(temp(i))
    end do

    close(IoUnit)

print*,minuto

end program prueba

(我知道实现相同目标的更好方法,这只是加深练习)

我使用这个数据示例(来自 txt):

min
 5
10
15
20
25
30
35
40
45
50
55
 0

结果如下:

-2144186072 1 -2144186072 1 25 0 35 40 45 50

解决方法

在重新分配过程中,您会取消分配 minuto 并且不保存其旧数据。

这是一个可以为您工作的示例程序

program prueba
  implicit none

  integer,allocatable :: minuto(:)
  integer,parameter   :: n = 2
  integer              :: iounit,ierr,temp(n),i

  open (newunit = iounit,file = 'datos.txt')
  read (iounit,*)

  ! init minuto. needed for move_alloc in first call
  allocate (minuto(0))

  i = 1
  do
    read (unit = iounit,fmt = '(i2)',iostat = ierr) temp(i)

    ! exit loop. still save temp(1:i-1)
    if (ierr /= 0) then
      if (i > 1) call save_temp(i-1)
      exit
    end if

    ! save all of temp
    if (i == n) call save_temp(n)

    i = mod(i,n) +1
  end do

  close (iounit)

  print *,minuto

contains
  subroutine save_temp(n_temp)
    !! append temp(1:n_temp) to minuto

    integer,intent(in) :: n_temp

    integer,allocatable :: temp_reloc(:)

    ! save old data from minuto into temp_reloc
    call move_alloc(minuto,temp_reloc)

    allocate (minuto(size(temp_reloc) + n_temp))

    ! init first part of minuto by its old data
    minuto(:size(temp_reloc))   = temp_reloc

    ! append temp's data
    minuto(size(temp_reloc)+1:) = temp(1:n_temp)
  end subroutine
end program

输出

$  gfortran -g3 -Wall -fcheck=all a.f90 && ./a.out
           5          10          15          20          25          30          35          40          45          50          55           0