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

4. Массивы

Массив - это именованный набор из конечного числа объектов одного типа. Объектами (элементами) массива могут быть данные как базовых, так и производных типов. Используя атрибут PARAMETER, можно задать массив-константу. В отличие от простых переменных, предназначенных для хранения отдельных значений, массив является составной переменной. Также к составным относятся объекты символьного и производного типов.

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

Массивы могут быть статическими и динамическими. Под статические массивы на этапе компиляции выделяется заданный объем памяти, которая занимается массивом во все время существования программы. Память под динамические массивы выделяется в процессе работы программы и при необходимости может быть изменена или освобождена. К динамическим массивам относятся массивы-ссылки, размещаемые и автоматические массивы. Последние могут появляться только в процедурах.

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

4.1. Объявление массива

Массив характеризуется числом измерений, которых может быть не более семи. Число измерений массива называется его рангом. Число элементов массива называется его размером. Также массив характеризуется

формой, которая определяется его рангом и протяженностью (экстентом)

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

real b(2, 3, 10)

объявляет массив b ранга 3. Размер массива равен 2*3*10 = 60. Форма массива - (2, 3, 10).

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

real c(4:5, -1:1, 0:9)

Ранг, форма и размер массивов b и c совпадают. Такие массивы называются согласованными.

Нижняя граница и последующее двоеточие при объявлении массива могут быть опущены, тогда по умолчанию нижняя граница принимается

108

4. Массивы

равной единице. Объявление массива выполняется при объявлении типа либо операторами DIMENSION, ALLOCATABLE и POINTER. Также массив можно объявить в операторе COMMON. Приведем различные способы объявления статического одномерного массива целого типа из 10 элементов.

Можно использовать оператор объявления типа:

integer a(10)

! или a(1:10)

Зададим границы в виде константного выражения (что рекомендуется):

integer, parameter :: n = 10 integer a(1:n)

Используем теперь атрибут DIMENSION: integer, dimension(10) :: a

а затем оператор DIMENSION:

integer a dimension a(10)

Приведенные объявления статического одномерного массива определяют массив a из 10 объектов (элементов) с именами a(1), a(2), ..., a(10). Схема расположения элементов массива a в памяти компьютера приведена на рис. 4.1.

Ячейка памяти

a(1) a(2) . . .

a(10)

Рис. 4.1. Расположение элементов массива в памяти ЭВМ

Запись a(i) отсылает нас к i-му элементу массива a. Переменную i

называют индексной переменной или просто индексом.

Динамический одномерный массив можно объявить, применяя операторы ALLOCATABLE или POINTER:

real a, b

 

allocatable a(:)

! Измерения динамического массива

pointer b(:)

! задаются двоеточием (:)

или атрибуты ALLOCATABLE или POINTER:

real, allocatable :: a(:)

 

real, pointer :: b(:)

 

При объявлении

статического массива может быть выполнена

его инициализация:

 

integer a(10) /1, 2, 3, 4, 4, 4, 5, 5, 5, 5/

или с использованием коэффициента повторения:

109

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

integer a(10) /1, 2, 3, 3*4, 4*5/

или с использованием оператора DATA:

integer a(10)

data a /1, 2, 3, 3*4, 4*5/

или с использованием конструктора массива: integer :: a(10) = (/ 1, 2, 3, 4, 4, 4, 5, 5, 5, 5 /)

или с использованием в конструкторе массива циклического списка: integer :: i, j, a(10) = (/ 1, 2, 3, (4, i = 4, 6), (5, i = 7, 10) /)

Во всех приведенных примерах после инициализации массива a

a(1) = 1, a(2) = 2, a(3) = 3, a(4) = 4, a(5) = 4, a(6) = 4, a(7) = 5, a(8) = 5, a(9) = 5, a(10) = 5.

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

Одним оператором может быть выполнено объявление более одного массива. Например, оператор

real b(-3:3) /7*1.0/, g2(6:8)

! Массив g2 не определен

объявляет два одномерных массива - массив b из семи элементов с именами b(-3), b(-2), ..., b(3) и массив g2 из трех элементов с именами g2(6), g2(7), g2(8). Все элементы массива b равны 1.0.

Пример. Найти сумму элементов одномерного массива. real b(-3:5) /1.1, 2.2, 3.3, 4.4, 5.5, 4*7.8/, s

s = 0.0

 

do k = -3, 5

 

s = s + b(k)

 

end do

 

write(*, *) ' s = ', s

! s = 47.7

! Та же задача решается с применением встроенной функции SUM:

write(*, *) ' s = ', sum(b)

! s = 47.7

Аналогично выполняется объявление двумерного массива:

integer b(2, 4)

! Статический массив из восьми элементов

real, pointer :: c(:, :)

! Динамический массив-ссылка

Первое объявление определяет двумерный массив b из восьми элементов с именами b(1,1), b(2,1), b(1,2), b(2,2), b(1,3), b(2,3), b(1,4), b(2,4).

Двумерный массив b(1:2, 1:4) можно представить в виде таблицы (рис. 4.2), содержащей 2 строки и 4 столбца.

110

4. Массивы

 

 

 

 

 

 

j

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

2

 

3

4

 

i

1

b(1, 1)

b(1, 2)

b(1, 3)

b(1, 4)

 

2

b(2,

1)

b(2,

2)

b(2, 3)

b(2,

4)

Рис. 4.2. Представление двумерного массива в виде таблицы

Память компьютера является одномерной, поэтому элементы двумерного массива b расположены в памяти в линейку так, как это показано на рис. 4.3.

 

 

 

 

 

 

 

 

Ячейка

1

-1

2

-2

3

-3

4

-4

памяти

 

 

 

 

 

 

 

 

 

b(1, 1)

b(2, 1)

b(1, 2)

b(2, 2)

b(1, 3)

b(2, 3)

b(1 ,4)

b(2, 4)

 

Рис. 4.3. Расположение элементов двумерного массива в памяти ЭВМ

Запись b(i, j) отсылает нас к j-му элементу массива в его i-й строке, где i и j - индексы массива b.

Во многих языках программирования, например в СИ, элементы двумерного массива располагаются в памяти ЭВМ по строкам, в Фортране

– по столбцам, т. е. быстрее изменяется первый индекс массива. В более общем случае в Фортране для многомерного массива при размещении его элементов в памяти ЭВМ закономерность изменения индексов можно отобразить вложенным циклом (на примере трехмерного массива a(2, 4, 6):

do k = 1, 6

 

do j = 1, 4

! Быстрее всего изменяется индекс i

do i = 1, 2

размещение в памяти элемента с именем a(i, j, k)

end do end do end do

Иными словами, при размещении многомерного массива в памяти ЭВМ быстрее всего изменяется самый левый индекс массива, затем следующий за ним индекс и т. д.

Это обстоятельство следует учитывать при В/В и инициализации многомерного массива. В случае двумерного массива перечисление значений приведет к инициализации по столбцам (соответствие элемент - значение показано на рис. 4.3):

integer b(2, 4) / 1, -1, 2, -2, 3, -3, 4, -4 /

Инициализация по строкам может быть выполнена оператором DATA: data ((b(i, j), j = 1, 4), i = 1, 2) /1, -1, 2, -2, 3, -3, 4, -4/

111

! p = 193.2612

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

или в конструкторе массива при надлежащем применении функции RESHAPE:

integer :: b(2, 4) = reshape((/

 

 

 

&

1,

-1

2

-2

&

3

-3

4

-4

/), shape = (/ 2, 4 /), order = (/ 2, 1 /))

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

real b(-2:1, 6:8) /1.1, 2.2, 3.3, 4.4, 5.5, 7*-1.1/, p integer i, j

p = 1.0 do j = 6, 8

do i = -2, 1

if(b(i, j) > 0) p = p * b(i, j) end do

end do

write(*, *) ' p = ', p ! p = 193.2612

! Для вычисления произведения можно применить встроенную функцию PRODUCT: p = product(b, mask = b > 0.0)

write(*, *) ' p = ', p

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

do j = 6, 8

do i = -2, 1 ! Перебираем элементы очередного столбца массива if(b(i, j) > 0) p = p * b(i, j)

end do end do

отработает быстрее, чем цикл

do i = -2, 1

 

do j = 6, 8

! Неестественный порядок перебора элементов

if(b(i, j) > 0) p = p * b(i, j)

! массива b

end do

 

end do

 

Это объясняется тем, что в первом случае во внутреннем цикле обеспечивается естественная и поэтому более производительная последовательность доступа к элементам массива.

Индексом массива может быть целочисленное выражение:

real :: b(5, 10) = 5.1

 

 

 

real :: a(5, 5), c(30), r = 7.0

 

 

 

c(int(r)*2 + 1) = 2.0

! Индекс массива - целочисленное выражение

a(1, 2) = b(int(c(15)), int(sqrt(r)))

 

 

write(*, *) a(1, 2), b(2, 2)

!

5.100000

5.10000

112