Я пытаюсь решить проблемы, связанные с сохранением значений, когда я использую de/allocate в коде, показанном ниже (fortran), создавая массив копий, но проблема не устранена. Я уже видел ссылки по теме:
Массив 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
Обязательно всегда включайте все проверки компилятора. gfortran -g -Wall -fcheck=all
. Valgrid или sanitizations -fsanitize=address,undefined
также полезны, чтобы выяснить, откуда берутся неинициализированные значения.
В minuto((i-4):i)
вы не присваиваете значения всем значениям этого массива. Как видите, только последние пять значений соответствуют ожиданиям.
Франческал прав. вы можете использовать move_alloc
на minuto
, затем выделить его большего размера и повторно скопировать в него сохраненные значения (сохраненные с помощью move_alloc).
@VladimirF Спасибо, я не знал некоторых из этих флагов. Это будет полезно.
В процессе перераспределения вы освобождаете 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
Я хотел бы отметить, что move_alloc()
- это Fortran 2003, а не Fortran 90. В наши дни это не имеет большого значения, но @Isaac, похоже, просил Fortran 90, в частности. В противном случае все ссылки, которые он получил ранее (также в предыдущем вопросе), также применимы.
Пожалуйста, используйте тег fortran для всех вопросов по Fortran.