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

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

write(*, *) b end

subroutine swap(a, b)

! a и b - массивы, перенимающие форму

real a(:), b(:)

real c(size(a))

! c - автоматический массив

c = a

 

a = b

 

b = c

 

end subroutine swap

 

Замечание. Если оформить swap как внутреннюю подпрограмму программы shos, то не потребуется задавать интерфейсный блок к swap, поскольку внутренние (равно как и модульные) процедуры обладают явно заданным интерфейсом.

К автоматическим объектам относятся объекты данных, размеры которых зависят от неконстантных описательных выражений (разд. 5.6) и которые не являются формальными параметрами процедуры. Такие объекты не могут иметь атрибуты SAVE и STATIC.

Границы автоматического массива или текстовая длина автоматической строки фиксируются на время выполнения процедуры и не меняются при изменении значения соответствующего выражения описания.

4.9. Массивы - формальные параметры процедур

В процедурах форма и размер массива - формального параметра могут определяться в момент вызова процедуры. Можно выделить 3 вида массивов - формальных параметров: заданной формы, перенимающие форму и перенимающие размер.

4.9.1. Массивы заданной формы

Границы размерностей массивов - формальных параметров могут определяться передаваемыми в процедуру значениями других параметров. Например:

integer, parameter :: n = 5, m = 10, k = m * n real a(m, n) / k*1.0 /, b(m, n) / k*2.0 /

call swap(a, b, m, n) write(*, *) b

end

subroutine swap(a, b, m, n)

! a и b - массивы заданной формы

integer m, n

real a(m*n), b(m*n)

! c - автоматический массив

real c(size(a))

c = a

 

a = b

 

132

4. Массивы

b = c

end subroutine swap

Такие массивы - формальные параметры называются массивами заданной формы. В примере их форма задается формальными параметрами m и n.

Из примера видно, что формы фактического и соответствующего ему формального параметра - массива могут отличаться. В общем случае могут вычисляться как нижняя, так и верхняя граница размерности. Общий вид размерности таких массивов:

[нижняя граница] : [верхняя граница]

Нижняя и верхняя границы - целочисленные описательные выражения

(разд. 5.6).

Вычисленные границы массива фиксируются на время выполнения процедуры и не меняются при изменении значения соответствующего описательного выражения.

При работе с такими массивами необходимо следить, чтобы размер массива - формального параметра не превосходил размера ассоциированного с ним массива - фактического параметра.

Если фактическим параметром является многомерный массив и соответствующим ему формальным параметром является массив заданной формы с тем же числом измерений, то для правильного ассоциирования необходимо указать размерности массива - формального параметра такими же, как и у массива - фактического параметра. Исключение может составлять верхняя граница последней размерности массива, которая может быть меньше соответствующей границы массива - фактического параметра.

Если в качестве фактического параметра задан элемент массива, то формальный параметр ассоциируется с элементами массива-родителя начиная с данного элемента, и далее по порядку.

Пример. Вывести первый отрицательный элемент каждого столбца матрицы.

ineger, parameter :: m = 4, n = 5 integer j

real :: a(m, n) = 1.0

a(1, 1) = -1.0; a(2, 2) = -2.0; a(3, 3) = -3.0 do j = 1, n

call prifin(a(1, j), m , j)

! В prifin доступны все элементы

end do

! столбца j начиная с первого и все

end

! последующие элементы матрицы a

subroutine prifin(b, m, j)

 

integer m, i, j

! Вектор b содержит все элементы

real b(m)

do i = 1, m

! столбца j матрицы a

if(b(i) < 0) then

 

133

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

print *, 'Столбец ', j, '. Элемент ', b(i) return

end if end do

print *, 'В столбце ', j, ' нет отрицательных элементов' end subroutine prifin

4.9.2. Массивы, перенимающие форму

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

[нижняя граница] :

где нижняя граница - это целое описательное выражение, которое может зависеть от данных в процедуре или других параметров. Если нижняя граница опущена, то ее значение по умолчанию равно единице. Например, при вызове

real x(0:3, 0:6, 0:8) interface subroutine asub(a) real a(:, :, :)

end

end interface

...

call asub(x)

соответствующий перенимающий форму массив объявляется так:

subroutine asub(a)

 

 

 

real a(:, :, :)

 

 

 

print *, lbound(a, 3), ubound(a, 3)

!

1

9

Так как нижняя граница в описании массива a отсутствует, то после вызова подпрограммы в ней будет определен массив a(4, 7, 9). Если нужно сохранить соответствие границ, то массив a следует объявить так:

real a(0:, 0:, 0:)

В интерфейсном блоке по-прежнему массив a можно объявить: real a(:, :, :)

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

Если для работы с массивом в процедуре нужно знать значения его границ, то их можно получить, использовав функции LBOUND и UBOUND (разд. 4.12.3.2).

134

! Возвращает первый отрицательный элемент ! последнего столбца матрицы c
! Процедура, формальными параметрами которой ! являются перенимающие форму массивы, ! должна обладать явным интерфейсом
! nga и ngb - соответственно последние ! отрицательные элементы матриц a и b
! Ищем nga и ngb

4. Массивы

Пример. Даны матрицы a и b разной формы. В какой из них первый отрицательный элемент последнего столбца имеет наибольшее значение?

program neg2 interface

integer function FindNeg(c) integer :: c(:, :)

end function FindNeg end interface

integer a(4, 5), b(-1:7, -1:8) integer nga, ngb, ngmax

a = 1; a(3, 5) = -2 b = 2; b(2, 8) = -3 nga = FindNeg(a) ngb = FindNeg(b)

if(nga == 0) print *, 'В последнем столбце матрицы а нет отрицательных элементов' if(ngb == 0) print *, 'В последнем столбце матрицы b нет отрицательных элементов' ngmax = max(nga, ngb)

! Если не все матрицы имеют отрицательный элемент в последнем столбце - STOP if(ngmax == 0) stop

if(nga == ngmax) print *, 'В матрице a' if(ngb == ngmax) print *, 'В матрице b' end

integer function FindNeg(c) integer :: c(:, :)

integer cols, i FindNeg = 0

cols = ubound(c, dim = 2) ! Номер последнего столбца в массиве c do i = lbound(c, 1), ubound(c, 1)

if(c(i, cols) < 0) then

FindNeg = c(i, cols) ! Вернем найденный отрицательный элемент return

end if end do

end function FindNeg

Результат:

В матрице a

4.9.3. Массивы, перенимающие размер

В перенимающем размер массиве - формальном параметре вместо верхней границы последней размерности проставляется звездочка (*). (Таким же образом задаются перенимающие длину строки.) Остальные границы должны быть описаны явно. Перенимающий размер массив может отличаться по рангу и форме от соответствующего массива - фактического параметра. Фактический параметр определяет только размер массива - формального параметра. Например:

135

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

real x(3, 6, 5), y(4, 10, 5)

 

 

 

call asub(x, y)

 

 

 

...

 

 

 

subroutine asub(a, b)

 

 

 

real a(3, 6, *), b(0:*)

 

 

 

print *, size(a, 2)

!

6

 

print *, lbound(a, 3), lbound(b)

!

1

0

Перенимающие размер

массивы

не

имеют определенной формы.

Это можно проиллюстрировать примером:

real x(7)

call assume(x)

...

subroutine assume(a) real a(2, 2, *)

При такой организации данных между массивами x и a устанавливается соответствие:

x(1) = a(1, 1, 1)

x(2) = a(2, 1, 1)

x(3) = a(1, 2, 1)

x(4) = a(2, 2, 1)

x(5) = a(1, 1, 2)

x(6) = a(2, 1, 2)

x(7) = a(1, 2, 2)

т. е. в массиве a нет элемента a(2, 2, 2). (Размер массива a определяется размером массива x и равен семи.)

Так как перенимающие размер массивы не имеют формы, то нельзя получить доступ ко всему массиву, передавая его имя в процедуру. (Исключение составляют процедуры, не требующие форму массива, например встроенная функция LBOUND.) Так, нельзя использовать только имя перенимающего размер массива в качестве параметра встроенной функции SIZE, но можно определить протяженность вдоль фиксированной (т. е. любой, кроме последней) размерности.

Можно задать сечения у перенимающего размер массива. Однако в общем случае надо следить, чтобы все элементы сечения принадлежали массиву. Так, для массива a из последнего примера нельзя задать сечение a(2, 2, 1:2), поскольку в массиве a нет элемента a(2, 2, 2).

Необходимо следить, чтобы при работе с перенимающими размер массивами не происходило обращений к не принадлежащим массиву ячейкам памяти. Так, следующий фрагмент будет выполнен компьютером, но исказит значение переменной d:

program bod

integer b(5) /5*11/, d /-2/ call testb(b)

136