Как передать распределяемые массивы подпрограмм в Fortran
Следующий код возвращает ошибку сегментации, потому что выделяемый массив, который я пытаюсь передать, не распознается должным образом (размер возвращает 1, когда он должен быть 3). На этой странице (http://www.eng-tips.com/viewthread.cfm?qid=170599) аналогичный пример, похоже, указывает на то, что он должен отлично работать в F95; мой файл кода имеет расширение.F90, но я попытался изменить его на F95, и я использую gfortran для компиляции.
Я предполагаю, что проблема должна быть в том, как я передаю распределяемый массив подпрограмме; Что я делаю не так?
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%!
PROGRAM test
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%!
IMPLICIT NONE
DOUBLE PRECISION,ALLOCATABLE :: Array(:,:)
INTEGER :: iii,jjj
ALLOCATE(Array(3,3))
DO iii=1,3
DO jjj=1,3
Array(iii,jjj)=iii+jjj
PRINT*,Array(iii,jjj)
ENDDO
ENDDO
CALL Subtest(Array)
END PROGRAM
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%!
SUBROUTINE Subtest(Array)
DOUBLE PRECISION,ALLOCATABLE,INTENT(IN) :: Array(:,:)
INTEGER :: iii,jjj
PRINT*,SIZE(Array,1),SIZE(Array,2)
DO iii=1,SIZE(Array,1)
DO jjj=1,SIZE(Array,2)
PRINT*,Array(iii,jjj)
ENDDO
ENDDO
END SUBROUTINE
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%!
Ответы
Ответ 1
Если у процедуры есть фиктивный аргумент, который является allocatable, то явный интерфейс требуется в любой области вызова.
(Существует множество вещей, требующих явного интерфейса, а также выделяемый манекен.)
Вы можете предоставить этот явный интерфейс самостоятельно, поместив блок интерфейса для своей подпрограммы внутри основной программы. Альтернативный и далекий, гораздо лучший вариант заключается в том, чтобы поместить подпрограмму внутри модуля, а затем использовать этот модуль в основной программе - затем автоматически создается явный интерфейс. Вот пример этого на сайте eng-tips, на который вы указали ссылку - см. Сообщение от xwb.
Обратите внимание, что для фиктивного аргумента имеет смысл иметь атрибут allocatable, если вы собираетесь сделать что-то, связанное с его статусом распределения - запросите его статус, перераспределите его, освободите его и т.д.
Ответ 2
Также обратите внимание, что ваш выделяемый array
фиктивных аргументов объявляется с intent(in)
, что означает, что его статус распределения будет принадлежать соответствующему фактическому аргументу (и он не может быть изменен во время процедуры). Фактический аргумент, переданный вашей подпрограмме, может быть нераспределенным и, следовательно, незаконным для ссылки, даже с явным интерфейсом. Компилятор не будет знать этого, и поведение запросов, таких как size
не определено в таких случаях.
Следовательно, сначала вам нужно проверить статус распределения array
с allocated(array)
прежде чем ссылаться на его содержимое. Я бы предложил предложить реализовать циклы по всему массиву с lbound
и ubound
, поскольку в целом вы не можете быть уверены в границах array
:
subroutine subtest(array)
double precision, allocatable, intent(in) :: array(:,:)
integer :: iii, jjj
if(allocated(array)) then
print*, size(array, 1), size(array, 2)
do iii = lbound(array, 1), ubound(array, 1)
do jjj = lbound(array, 2), ubound(array, 2)
print*, array(iii,jjj)
enddo
enddo
endif
end subroutine
Ответ 3
Это простой пример, который использует атрибуты фиктивного аргумента с модулем.
module arrayMod
real,dimension(:,:),allocatable :: theArray
end module arrayMod
program test
use arrayMod
implicit none
interface
subroutine arraySub
end subroutine arraySub
end interface
write(*,*) allocated(theArray)
call arraySub
write(*,*) allocated(theArray)
end program test
subroutine arraySub
use arrayMod
write(*,*) 'Inside arraySub()'
allocate(theArray(3,2))
end subroutine arraySub