Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
современный фортран , Бортеньев.pdf
Скачиваний:
242
Добавлен:
26.03.2015
Размер:
2.34 Mб
Скачать

О. В. Бартеньев. Современный ФОРТРАН

Заметьте, что в

последнем случае FORALL обеспечивает доступ к

диагонали матрицы,

чего нельзя сделать при помощи сечений массивов.

Пример 4. Формируется вектор a из сумм вида m

xi , (m =1, 2, , n) .

 

i=1

 

program vec_a

integer(4), parameter :: n = 10 integer(4) i

!Инициализация массива x: real(4) :: x(n) = (/ (i, i = 1, n) /), a(n)

!Массив x после инициализации:

!1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 forall(i = 1:n) a(i) = sum(x(1:i))

print '(1x, 10f5.1)', a(1:n)

! 1.0 3.0 6.0 10.0 15.0 21.0 28.0 36.0 45.0 55.0

end program vec_a

Замечание. Оператор и конструкция FORALL введены стандартом Фортран 95.

4.8. Динамические массивы

4.8.1. Атрибуты POINTER и ALLOCATABLE

При использовании статических массивов перед программистом всегда стоит проблема задания их размеров. В некоторых случаях эта проблема не имеет удовлетворительного решения. Так, если в массиве хранятся позиционные обозначения элементов печатной платы или интегральной схемы, то в зависимости от сложности проектируемого устройства может потребоваться массив размером от 10 до 1000 и более элементов. В таком случае лучше использовать динамические массивы, размеры которых можно задать и изменить в процессе выполнения программы. В Фортране существует 3 вида динамических массивов: массивы-ссылки, размещаемые массивы и автоматические массивы.

Динамические массивы-ссылки объявляются с атрибутом POINTER, который может быть задан или в операторе объявления типа, или посредство оператора POINTER. Размещаемые массивы объявляются с атрибутом ALLOCATABLE, который задается или в операторе объявления типа, или посредством оператора ALLOCATABLE.

Автоматические массивы создаются в процедурах, и их размер определяется при вызове процедуры.

Память под массивы-ссылки и размещаемые массивы может быть выделена оператором ALLOCATE. Напомним, что выделяемая под массивссылку оператором ALLOCATE память называется адресатом ссылки. Массив-ссылка также получает память после его прикрепления к уже имеющему память адресату (разд. 3.11.2). Например:

126

4. Массивы

real, pointer :: a(:), c(:), d(:)

! Одномерные массивы-ссылки

integer, allocatable :: b(:, :)

! Двумерный размещаемый массив

real, allocatable, target :: t(:)

! Размещаемый массив-адресат

real a3

 

allocatable a3(:, :, :)

! Оператор ALLOCATABLE

real, target :: t2(20)

! Статический массив-адресат

allocate(a(10), a2(10*2), a3(2, 2, 5), b(5, 10), t(-30:30))

c => t

! Прикрепление ссылок к динамическим

d => c

! ранее получившим память адресатам

c => t2

! Прикрепление ссылки к статическому адресату

4.8.2. Операторы ALLOCATE и DEALLOCATE

Оператор ALLOCATE создает адресаты ссылок и размещает массивы, заданные с атрибутом ALLOCATABLE. Синтаксис оператора:

ALLOCATE(var | array(shape_spec_list)

&

[, var | array(shape_spec_list)).[, STAT = ierr])

 

var - имя размещаемой ссылки, которое может быть компонентом структуры.

array - имя массива-ссылки или размещаемого массива, которое может быть компонентом структуры.

shape_spec_list - список вида ([lo:]up[, [lo:]up] ...]), задающий форму размещаемого массива. Число задающих границы размерности пар должно совпадать с рангом размещаемого массива или массива-ссылки. Параметры lo и up являются целыми скалярными выражениями и определяют соответственно нижнюю и верхнюю границу протяженности по соответствующему измерению массива. Если параметр lo: опущен, то по умолчанию нижняя граница принимается равной единице. Если up < lo, размер массива равен нулю.

STAT - параметр, позволяющий проконтролировать, удалось ли разместить массив. Любая неудача, если не задан параметр STAT, приводит

кошибке этапа исполнения и остановке программы. Параметр указывается

воператоре ALLOCATE последним.

ierr - целочисленная статусная переменная, возвращающая 0, если размещение выполнено удачно; в противном случае возвращается код ошибки размещения, например:

integer, allocatable :: b(:, :) integer m/5/, n/10/, ierr allocate(b(m, n), stat = ierr) if(ierr .ne. 0) then

write(*, *) 'Ошибка размещения массива b. Код ошибки: ', ierr stop

end if

127

О. В. Бартеньев. Современный ФОРТРАН

Причиной ошибки может быть, например, недостаток памяти или попытка разместить ранее размещенный и не освобожденный оператором

DEALLOCATE объект.

Оператор ALLOCATE выделяет память и задает форму массиву или адресату ссылки. Для освобождения выделенной под размещаемый массив памяти используется оператор DEALLOCATE. После освобождения памяти размещаемый массив может быть размещен повторно с новым или прежним размером.

Поскольку порядок выделения памяти не регламентируется, то спецификация формы массива не может включать справочную функцию массива, имеющую аргументом массив того же оператора ALLOCATE. Так, ошибочен оператор

allocate(a(10), b(size(a)))

! Неверно

Вместо него следует задать два оператора:

allocate(a(10))

allocate(b(size(a))) ! Правильно

Если присутствует параметр STAT= и статусная переменная ierr является динамической, то ее размещение должно быть выполнено в другом, предшествующем операторе ALLOCATE.

Изменение переменных, использованных для задания границ массива, после выполнения оператора ALLOCATE не окажет влияния на заданные границы. Например:

n = 10

! Размещение массива a(10:20)

allocate(a(n:2*n))

n = 15

! Форма массива a не меняется

Размещаемый массив может иметь статусы "не размещен", "размещен" и "не определен". Попытка адресовать массив со статусом "не размещен" приводит к непредсказуемым результатам. Для определения, размещен ли размещаемый массив, используется встроенная функция ALLOCATED, возвращающая значение стандартного логического типа, равное .TRUE., если массив размещен, и .FALSE. - в противном случае. (Напомним, что для определения статуса ссылки используется функция ASSOCIATED.) Например:

real, allocatable :: b(:, :) real, pointer :: c(:, :) integer :: m = 5, n = 10 allocate(b(m, n), c(m, n)) if(allocated(b)) b = 2.0 if(associated(c)) c = 3.0

При использовании размещаемого массива в качестве локальной переменной процедуры следует перед выходом из процедуры выполнить

128

4. Массивы

освобождение отведенной для него памяти (в противном случае размещаемый массив приобретет статус "не определен"):

subroutine delo(n) integer n, ierr

integer, allocatable :: ade(:) allocate(ade(n), stat = ierr) if(ierr /= 0) stop 'Allocation error'

...

deallocate(ade) end subroutine delo

Объявленный в модуле размещаемый массив после размещения в использующей модуль программной единице имеет статус "размещен" в любой другой использующей (после размещения массива) этот модуль программной единице. Например:

module wara integer n

integer, allocatable :: work(:, :) end module wara

program two

 

 

use wara

! Выделяем память под массив work

call rewo( )

work = 2

! Массив work размещен в подпрограмме rewo

print *, work(5, 5)

!

2

call delo(4)

 

 

print *, work(5, 5)

!

4

end program two

 

 

subroutine rewo( )

 

 

use wara

 

 

print '(1x, a\)', 'Enter n: '

 

 

read(*, *) n

 

 

allocate(work(n, 2 * n))

 

 

end subroutine rewo

 

 

subroutine delo(k)

 

 

use wara

 

 

integer k

! Размещать work не нужно, поскольку

work(5, 5) = k

end subroutine delo

! он размещен в подпрограмме rewo

Таким же свойством обладают и ссылки, т. е. если в последнем примере в модуле wara объявить ссылку

integer, pointer :: work(:, :)

то выделенный ей в подпрограмме rewo адресат будет доступен и в главной программе, и в подпрограмме delo.

129

О. В. Бартеньев. Современный ФОРТРАН

Попытка разместить уже размещенный массив всегда приводит к ошибке. Однако прикрепленную (ранее размещенную) ссылку можно разместить повторно, в результате чего она прикрепляется к новому, созданному оператором ALLOCATE адресату, например:

real, pointer :: a(:)

! Размещение ссылки a

allocate(a(10))

allocate(a(20))

! Прикрепление ссылки a к другой области памяти

Однако такое переразмещение ссылки приведет к созданию неиспользуемой и недоступной памяти. Чтобы этого избежать, следует до переназначения ссылки выполнить оператор

deallocate(a)

Оператор DEALLOCATE освобождает выделенную оператором ALLOCATE память и имеет синтаксис

DEALLOCATE(a-list [, STAT = ierr])

a-list - список из одного или более имен размещенных объектов (массивов, массивов-ссылок или простых ссылок), разделенных запятыми. Все элементы списка должны быть ранее размещены оператором ALLOCATE либо, в случае ссылок, должны иметь созданного оператором ALLOCATE адресата. Адресатом в списке a-list ссылки должен являться полный объект (например, адресатом освобождаемой DEALLOCATE ссылки не может быть сечение, элемент массива, подстрока). Напомним, что открепление ссылки, получившей не созданного оператором ALLOCATE адресата, выполняется оператором NULLIFY.

STAT - необязательный параметр, позволяющий проконтролировать, удалось ли освободить память. Любая неудача, если не задан параметр STAT, приводит к ошибке исполнения и к остановке программы. Параметр STAT должен появляться в операторе последним.

ierr - целочисленная переменная, возвращающая 0, если память удалось освободить; в противном случае возвращается код ошибки. Если ierr является динамической переменной, то она не может быть освобождена использующим ее оператором DEALLOCATE.

Попытка освобождения неразмещенного объекта вызовет ошибку выполнения.

Если оператором DEALLOCATE выполнено освобождение массива с атрибутом TARGET, то статус подсоединенной к массиву ссылки становится неопределенным и к ней можно обращаться только после ее прикрепления к другому объекту.

Пример:

integer, allocatable :: ade(:)

 

real, pointer :: ra, b(:)

! Размещаем массивы ade и b

allocate(ade(10), ra, b(20))

130