Обычно переменные описываются в начале программы (модуля). При этом компилятор заранее выделят память для размещения этих переменных. Такие переменные называются статическими. Статический массив объявляется также в начале программы. Занимаемая ими память не меняется до завершения программы.
Иногда возникает необходимость выделять память под переменные в процессе работы программы, например, когда:
В этих случаях на помощь приходит динамическое выделение памяти. В Fortrane-е для этого появились Динамические массивы.
Динамические массивы описываются без указания размера (только с указанием количества размерностей). Далее в программе, в том месте, когда определяется требуемый размер, память может быть выделена в ходе выполнения.
Например, программе потребуется выполнять операции с массивом, в котором хранятся оценки студентов после сессии. Но программист, когда пишет программу, не знает, сколько будет студентов.
Тогда описывается динамический массив Mark:
implicit none
integer, allocatable :: Mark(:)
integer N_students,val
...
Определяется требуемый размер массива:
read *, N_students
Выделяется память под массив:
allocate(Mark(N_students),stat=val)
...
Когда он становится ненужным, необходимо освободить память:
deallocate(Mark)
Аналогично для 2-ух мерного массива:
implicit none
integer, allocatable :: GrpMarks(:,:)
integer N_students,n_grp,val
...
read *, n_grp,N_students
allocate(GrpMarks(n_grp,N_students),stat=val)
...
deallocate(GrpMarks)
Распределяемые массивы декларируются так же как статические. Общий вид таков:
type, ALLOCATABLE [,атрибут ] :: name
Они должны включать атрибут ALLOCATABLE и ранг массива, но не могут специфицировать
протяженность ни в каком измерении. Вместо этого используется двоенточие (:)
для кажого измерения. Например:
INTEGER, DIMENSION(:), ALLOCATABLE :: a ! ранг 1 INTEGER, ALLOCATABLE :: b(:,:) !ранг 2 REAL, DIMENSION(:), ALLOCATABLE :: c ! ранг1
После декларации распределяемые массивы не имеют соответствующей памяти и на них нельзя ссылаться, пока не будет явно выделена память.
Оператор ALLOCATE динамически выделяет требуемое количество памяти и связывает
ее с распределяемым массивом.
ALLOCATE( имя(границы) [,STAT] )
С помощью одного оператора ALLOCATE можно распределить несколько массивов - каждый с различными границами, образом или рангом. Если не специфицирована меньшая граница, она полагается равной 1. Только распределяемый массив с неопределенной для него памятью может быть объектом оператора ALLOCATE:
n=10 ALLOCATE( a(100) ) ALLOCATE( b(n,n), c(-10:89) )
Память, использованная распределяемым массивом, должно быть освобождено (когда
он перестал быть нужен) с помощью оператора DEALLOCATE:
DEALLOCATE( имя_массива [,STAT] )
Оператор DEALLOCATE позволяет освободить несколько массивов.
Следующие операторы освобождают память из предыдущего примера:
DEALLOCATE ( a, b ) DEALLOCATE ( c, STAT=test ) IF (test .NE. 0) THEN STOP ' ошибка возвращения ' ENDIF
Хорошей практикой программирования считается возвращение любой памяти, которая была зарезервирована с помощью оператора ALLOCATE .
Остерегайтесь: учтите, что любые данные, сохраненные в памяти динамического
массива, недоступны после ее освождения!
Распределяемые массивы могут быть в одном из двух статусов (состояний):
Статус массива может быть проверен с помощью встроенной логической функции ALLOCATED:
AllOCATED( имя )
которая возвращает значение:
Например:
IF( ALLOCATED(x) ) DEALLOCATE( x )
или:
IF( .NOT. ALLOCATED( x ) ) ALLOCATE( x(1:10) )
После декларации статус распределяемого массива будет иметь значение 'не распределен в данный момент' и получит значение 'распределен' только после того, как успешно будет выполнен оператор ALLOCATE. Когда программа продолжится и память, использованная конкретным массивом, будет возвращена, статус массива вернется к значению 'не распределен в данный момент '. Возможно повторять этот цикл распределения и возвращения памяти массиву (возможно с различным размером и протяженностью каждый раз) любое число раз в одной и той же программе.