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

4. Массивы

При объявлении массива помимо задающих динамические массивы атрибутов ALLOCATABLE и POINTER и атрибута задания формы массива DIMENSION могут быть использованы атрибуты INTENT, OPTIONAL, PARAMETER, PRIVATE, PUBLIC, SAVE и TARGET.

4.2. Массивы нулевого размера

Массив, как, впрочем, и строка, может иметь нулевой размер. Всегда, когда нижняя граница превосходит соответствующую верхнюю границу, массив имеет размер 0. Например:

real b2(0, 15), d(5, 20, 1:-1)

 

 

 

print *, size(b2), size(d)

!

0

0

Массивы нулевого размера всегда считаются определенными и при использовании подчиняются обычным правилам.

4.3. Одновременное объявление объектов разной формы

При необходимости можно одним оператором объявлять объекты разной формы. Так, оператор

real, dimension(10) :: a, b, b2(15), d(5, 20)

объявляет массивы a и b формы (10), массив b2 формы (15) и массив d формы (5, 20). То есть приоритетом при использовании атрибута DIMENSION обладает явное описание формы массива.

Оператор

integer na, nb, a(10), d(5, 20)

объявляет скаляры na и nb и массивы a и d разной формы.

4.4. Элементы массива

В этом разделе мы обобщим понятие элемента массива. Массив может содержать элементы встроенных и производных типов данных:

type order

! Описание заказа

integer ordnum, cus_id

character(15)

item(10)

end type

! Примеры массивов символьного и производного типа

character(20) st(10) /10*'T-strings'/

! st - массив строк

type(order) cord, orders(100)

! orders - массив заказов

Приведенные описания определяют массивы st, orders, cord%item и orders(k)%item (k - целое и 0 k 100). Элементы массивов являются скалярами.

Примеры элементов массивов:

st(7), orders(15), cord%item(7), orders(10)%item(8)

113

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

Из символьного массива можно извлечь еще один объект данных - подстроку, например:

print *, st(7)(1:6) ! T-stri

или

character(15) itord

orders = order( 2000, 455, (/ ('Item', k = 1, 10) /) )

itord = orders(10)%item(8)

 

print *, itord(3:4)

! em

Однако содержащаяся в символьном массиве подстрока по соглашению не рассматривается как элемент массива.

В общем случае элемент массива - это скаляр вида

частный указатель [%частный указатель...]

где частный указатель есть

частное имя [(список индексов)]

Если частный указатель является именем массива, то он обязан иметь список индексов, например orders(10)%item(8). Число индексов в каждом списке индексов должно равняться рангу массива или массива - компонента производного типа. Каждый индекс должен быть целым скалярным выражением, значение которого лежит в пределах соответствующих границ массива или массива-компонента.

4.5. Сечение массива

Получить доступ можно не только к отдельному элементу массива, но и к некоторому подмножеству его элементов. Такое подмножество элементов массива называется сечением массива. Сечение массива может быть получено в результате применения индексного триплета или векторного индекса, которые при задании сечения подставляются вместо одного из индексов массива.

Индексный триплет имеет вид:

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

Каждый из параметров триплета является целочисленным выражением. Шаг изменения индексов может быть и положительным и отрицательным, но не может равняться нулю. Все параметры триплета являются необязательными.

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

114

4. Массивы

положителен или нижняя граница меньше верхней и шаг отрицателен, то последовательность является пустой.

Пример:

real a(1:10)

 

a(3:7:2) = 3.0

! Триплет задает сечение массива с элементами

 

! a(3), a(5), a(7), которые получат значение 3.0

a(7:3:-2) = 3.0

! Элементы a(7), a(5), a(3) получат значение 3.0

При отсутствии нижней (верхней) границы триплета ее значение принимается равным значению нижней (верхней) границы соответствующего экстента массива. Так, a(1:5:2) и a(:5:2) задают одно и то же сечение массива a, состоящее из элементов a(1), a(3), a(5). Сечение из элементов a(2), a(5), a(8) может быть задано так: a(2:10:3) или a(2::3).

Пример:

real a(10), r /4.5/

! Элементы a(2), a(5), a(8) получат значение 4.0

a(2::3) = 4.0

a(7:9) = 5.0

! Элементы a(7), a(8), a(9) получат значение 5.0

a(:) = 3.0

! Все элементы массива получат значение 3.0

a(::3) = 3.0

! Сечение из элементов a(1), a(4), a(7), a(10)

a(::int(r / 2)) = 3.0

! Параметр триплекса - целочисленное выражение

print *, size(a(4:3))

! 0 (сечение нулевого размера)

 

! Функция SIZE возвращает размер массива

Нижняя граница триплета не может быть меньше нижней границы соответствующего экстента массива. Так, ошибочно задание сечения a(-2:5:3) в массиве a(1:10). Верхняя граница триплета должна быть такой, чтобы последний элемент задаваемой триплетом последовательности не превышал верхней границы соответствующего экстента массива. Например, в массиве a(1:10) допустимо сечение a(3:12:5). Верхняя граница триплета всегда должна присутствовать при использовании триплета в последней размерности перенимающего размер массива (разд. 4.9.3).

В случае многомерного массива сечение может быть задано посредством подстановки индексного триплета (впрочем, так же, как и векторного индекса) вместо одного или нескольких индексов, например:

real a(8, 3, 5) a(1:4:2, 2:3, 4) = 4.0

В заданном сечении в первом измерении индекс может принимать значения 1 и 3, во втором - 2 и 3, а в третьем - только 4. Таким образом, сечение обеспечивает доступ к элементам a(1, 2, 4), a(1, 3, 4), a(2, 2, 4) и a(2, 3, 4). Поскольку в третьем измерении сечения индекс фиксирован, то сечение является двумерным массивом с формой (2, 2).

115

! Запишем число вхождений k в строку i в ! массив b. Сечение a(i, :) является
! i строкой массива

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

Частными случаями сечений двумерного массива являются его строки и столбцы, например:

integer a(5, 8)

 

a(3, :) = 3

! Сечение - третья строка матрицы

a(:, 4) = 7

! Сечение - четвертый столбец матрицы

Пример. В какой строке матрицы чаще встречается заданное число k.

integer, parameter :: m = 3, n = 5 integer :: a(m, n), b(m), i, k = 2, km(1)

a = reshape((/

1,

2,

2,

4,

3,

&

 

2,

4,

2,

8,

2,

&

 

-2,

2,

6,

2,

2

/), shape = (/m, n/), order = (/2, 1/))

do i = 1, m

b(i) = count(a(i, :) == k) end do

km = maxloc(b)

print *, 'Строки в которых k = ', k, ' входит наибольшее число раз' do i = 1, m

if(b(i) == b(km(1))) print *, 'Строка ', i end do

end

Замечание. Массив b можно сформировать, не применяя цикла:

b = count(a == k, 2)

! Функция COUNT рассмотрена в разд. 4.12.1.

Векторный индекс является одномерным целочисленным массивом, содержащим значения индексов, попадающих в сечение исходного массива, например:

real a(20), b(10, 10)

! vi, vj - целочисленные массивы;

integer :: vi(3), vj(2)

vi= (/1, 5, 7/)

! используются как векторные индексы

vj= (/2, 7/)

! для задания сечений массивов a и b

a(vi) = 3.0

! a(1), a(5), a(7) получат значение 3.0

b(2, vj) = 4.0

! b(2, 2), b(2, 7) - значение 4.0

b(vi, vj) = 5.0

! b(1, 2), b(1, 7), b(5, 2), b(5, 7),

 

! b(7, 2) и b(7, 2) - значение 5.0

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

real a(10, 8) /80 * 3.0/, b(5) b = a(3, (/5, 3, 2, 7, 2/))

116

4. Массивы

В массив b попадут значения элементов сечения массива a: a(3, 5), a(3, 3), a(3, 2), a(3, 7) и вновь a(3, 5).

Сечения с повторяющимися значениями индексов не могут появляться в правой части оператора присваивания и в списке ввода оператора READ. Например, присваивание

real a(10)

a(/5, 3, 2, 7, 2/) = (/1.2 , 1.3, 1.4, 1.5, -1.6/)

недопустимо, поскольку 1.4 и -1.6 не могут одновременно храниться в a(2). Размер сечения равен нулю, если векторный индекс имеет нулевой

размер.

Сечение массива с векторным индексом не может быть внутренним файлом, адресатом ссылки. Если сечение массива с векторным индексом является фактическим параметром процедуры, то оно рассматривается как выражение и соответствующий формальный параметр должен иметь вид связи INTENT(IN). При использовании заданного векторным индексом сечения в качестве фактического параметра в процедуре создается копия этого сечения, которую и адресует соответствующий формальный параметр.

Сечение массива (заданное индексным триплетом или векторным индексом) сохраняет большинство свойств массива и может быть, в частности, использовано в качестве параметра встроенных функций для массивов, элементных и справочных функций и пользовательских процедур.

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

integer, parameter :: n = 10

 

 

integer :: a(n, n) /100 * 3.0/, i

 

 

integer :: b(n * n)

 

 

integer :: v(n) = (/ (i + n * (i - 1), i = 1, n) /)

 

a(9, 9) = -1

! v - векторный индекс, содержащий

b=reshape(a, shape = (/100/))

! номера элементов главной диагонали

 

! массива a; b(v) - сечение массива b

print *, sum(b(v), mask=b(v)>0)

!

27

Использование сечений позволяет более эффективно решать задачи, для которых раньше применялись DO-циклы (разд. 7.5).

Пример. Поменять порядок следования элементов массива. integer :: i, a(10) = (/ (i, i = 1, 10) /)

a = a(10:1:-1)

 

print '(10i3)', a

! 10 9 8 7 6 5 4 3 2 1

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

117

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

частный указатель [%частный указатель ...] ... [(диапазон подстроки)]

где частный указатель есть

частное имя [(список индексов сечения)]

Число индексов сечения в каждом списке должно равняться рангу массива или массива - компонента структуры. Каждый индекс сечения

должен быть либо индексом, либо индексным триплетом, либо векторным индексом, например:

real a(8, 5, 5)

a(4, 1:4:2, (/2, 5/)) = 4.0 ! 4 - индекс; 1:4:2 - индексный триплет; ! (/2, 5/)) - векторный индекс

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

Диапазон подстроки может присутствовать, только если последний частный указатель относится к символьному типу и является скаляром или имеет список индексов сечения.

Пример сечения, состоящего из подстрок массива: character(len = 20) st(10) /10*'Test String'/

print *, st((/1, 3, 10/))(5:8)

! Str Str Str

print *, st(2:6:2)(5:8)

! Str Str Str

Сечение массива, имя которого заканчивается именем компонента структуры, также является компонентом структуры.

Пример сечений, содержащих массивы - компоненты структур:

type order

! Описание заказа:

integer(4) ordnum, cus_id

! номер заказа, код покупателя

character(15) item(10)

! список вещей заказа

end type

! ords - массив заказов

type(order) cord, ords(100)

cord%item(2:6) = 'dress'

 

ords(5:7:2)%item(7) = 'tie'

 

ords(9)%item((/1, 8, 9/)) = 'blazer'

 

ords(9)%item((/8, 9/))(8:9) = '20'

! dress tie

print *, cord%item(3), ords(5)%item(7)

print *, ords(9)%item(1), ords(9)%item(8)

! blazer blazer 20

Образуемое из массивов - компонентов структур сечение не может содержать более одного нескалярного объекта. Так, попытка создать сечение вида

ords(5:7:2)%item((/ 1, 8, 9 /)) = 'none'

вызовет ошибку компиляции.

Частное имя справа от частного указателя не должно иметь атрибут POINTER. Так, нельзя задать сечение list(1:15:2)%ival в таком примере:

118