Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Размещение массивов в памяти




Lesson 4

Массивы

В одной переменной в каждый конкретный момент может храниться только одно значение. Это бывает не очень удобно, когда в задаче приходится иметь дело с набором однотипных величин. Например, требуется написать программу для обработки данных о возрасте жителей города. Для этого пришлось бы создать в программе несколько десятков, а то и сотен тысяч переменных. В таких случаях необходимо использовать массив.

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

Количество используемых индексов массива может быть различным. Массивы с одним индексом называют одномерными, с двумя – двумерными и т. д. Одномерный массив нестрого соответствует вектору в математике, двумерный – матрице. Чаще всего применяются массивы с одним или двумя индексами, реже – с тремя, ещё большее количество индексов встречается крайне редко.

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

Общая форма записи элемента массива:

Name(список индексов)

Здесь Name – имя массива; список индексов – список индексных выражений. Индексное выражение может быть целой константой, целой переменной или целым выражением.

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

A(3), A(J), A(I+1) – элементы одномерного массива A.

B(3, 4), B(I, J), B(I+1, I+2) – элементы двумерного массива B.

Одномерные массивы

Описание одномерных массивов

Выделение памяти для хранения одномерных массивов производится с помощью атрибута dimension в описании массива:

тип массива, dimension (границы массива):: список имен массивов

Здесь тип массива – тип всех элементов массива, один из типов данных, используемых в Фортране.

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

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

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

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

Примеры описания одномерных массивов.

1) Описание вещественных массивов А, В, С:

real, dimension (1:20):: A, B, C то же, что

real, dimension (20):: A, B, C

Объявлены три вещественных массива из 20 элементов с номерами от 1 до 20.

2) Описание целочисленного массива Number:

integer, dimension (-3:3):: Number

Объявлен целочисленный массив из 7 элементов с номерами от –3 до 3.

3) Описание символьного массива student:

character*20,dimension(1:30)::student

Для массива student выделено 30 строк по 20 байт, всего 600 байт.

4) При объявлении массивы можно инициализировать с помощью конструктора массива, например:

integer, dimension (1:10):: digit=(/0,1,2,3,4,5,6,7,8,9/)

5) С помощью конструктора массива можно создавать массивы констант, например:

integer, parameter, dimension (1:5):: digit=(/0,1,2,3,4/)

6) Если задавать границы массива в виде именованных констант, то при необходимости изменить размер массива, вносить изменение можно только в одном месте:

integer, parameter:: L_digit=10

integer:: i

integer, dimension (L_digit: L_digit+10):: digit

do i=L_digit, L_digit+10

digit(i)=i

Enddo

В программе объявлен целочисленный массив из 11 элементов с номерами от 10 до 20. Каждому элементу массива присваивается значение, равное его номеру.

7) Устаревшее допустимое, но не рекомендуемое описание массивов:

integer A(34), B(34), C(7)

Лучше записать так:

integer, dimension (1:34):: A, B

integer, dimension (1:7)::С

Ввод и вывод одномерных массивов

Ввод одномерного массива

Можно ввести значения отдельных элементов массива, перечислив их в списке ввода оператора read, например:

integer, parameter:: N=5

real, dimension (1:N):: array

open (1, file=’in.txt’)

read (1,*) array(1), array(2), array(3), array(4), array(5)

Из файла «in.txt» вводятся значения пяти элементов вещественного массива array. Но не всегда массивы состоят из пяти элементов, и их перечисление в списке ввода довольно утомительно. Попробуем сократить запись, используя оператор цикла:

do i=1, N

read (1,*) array(i)

Enddo

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

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

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

(Список ввода, переменная = начальное значение, конечное значение, шаг)

read (1,*) (array(i), i=1,N)

В этом варианте длина списка ввода равна N. Каждая строка файла может содержать произвольное количество значений. Оператор вводит N значений и размещает их в первых N элементах массива.

В следующем операторе неявного цикла

read (1,*) (array(i), i=1,5,2)

список ввода состоит из трех элементов array(1), array(3), array(5).

Из файла, связанного с устройством 1 будут прочитаны 3 первых значения (!), которые будут присвоены элементам массива array(1), array(3), array(5).

Если нужно ввести весь массив, в операторе read можно записать имя массива без индексов, например:

real, dimension (1:5):: array

open (1, file=’in.txt’)

read (1,*) array! длина списка ввода равна 5

В этом случае длина списка ввода оператора read определяется размером массива из его описания. Если данных в файле недостаточно для заполнения всех элементов массива, фиксируется ошибка выполнения программы.

Вывод одномерного массива

Все, сказанное о вводе массивов, можно отнести и к операторам вывода массивов, с одним важным дополнением – вывод должен быть форматным.

Очевидно, что для вывода элементов массива, так же как и для ввода, целесообразно использовать циклы.

Пример 1. Вывод всех элементов одномерного массива:

integer, parameter:: Len = 256! количество элементов

real, dimension (1:Len):: array

open (1, file=’out.txt’)

write (1,40) array! длина списка вывода равна 256

40 format (F6.2)! длина списка спецификаций равна 1

В операторе write использовано имя массива без индексов, поэтому длина списка вывода равна длине массива, определенной в его описании. Так как эта длина превышает длину списка спецификаций формата, то список спецификаций используется многократно, причем после каждого его использования вывод начинается с новой строки. Элементы массива будут выведены «в столбик», то есть по одному элементу в строке. Для распечатки такого файла потребуется несколько листов бумаги.

Для более компактного вывода элементов массива используем повторитель перед спецификацией формата:

40 format (10F6.2)

В этом случае количество строк в файле ’out.txt’ уменьшится в 10 раз, а последняя строка содержит только 6 значений.

Пример 2. Вывод второй половины одномерного массива:

При решении этой задачи не обойтись без циклов.

integer, parameter:: Len = 256

integer:: i! индексная переменная

real, dimension (1:Len):: array

open (1, file=’out.txt’)

do i = Len/2+1, Len

write (1,40) array(i)! длина списка вывода равна 1

End do

40 format (10F6.2)

Количество выводимых элементов равно 128, и все они принадлежат второй половине массива. Но использование повторителя формата не спасло от вывода «в столбик» – ведь длина списка вывода равна единице, а каждый оператор write начинает вывод с новой строки. Из 10 спецификаций формата 9 не используются.

Решить проблему поможет неявный цикл:

integer, parameter:: Len = 256

Integer:: i

real, dimension (1:Len):: array

open (1, file=’out.txt’)

write (1,40) (array(i),i=Len/2+1,Len)! длина списка вывода равна 128

40 format (10F6.2)

Список вывода длиной 128 элементов выводится в 13 строк по 10 элементов в строке (последняя строка неполная, в ней 8 элементов)

Примеры задач.

Пример 3. Создать и вывести в два столбца целочисленный массив, значения элементов которого – квадраты чисел натурального ряда от 1 до 10

program make_array

integer, parameter:: count = 10! количество элементов

integer, dimension (1:count):: Q! целочисленный массив

integer:: i! индексная переменная

do i=1, count

Q(i) = i**2

Enddo

open (1, file=’out.txt’)

write (1,40) Q

40 format (2I6)

Список вывода длиной 10 элементов выводится в 5 строк по 2 элемента в строке.

Пример 4. Вычислить средний балл, полученный на экзамене группой студентов, и количество студентов, чья оценка выше среднего балла. Предполагается, что студентов не больше 100.

1) Количество студентов вводится из первой строки исходного файла, а оценки студентов, представленные целыми числами, – из остальных строк. Входные данные в файле разделяются запятыми, пробелами или переводом строки. Исходные данные, подготовленные в файле 'in.txt', имеют вид:

20 50 44 37 17 14 48 39 19 30

2) Результаты выполнения программы с этими исходными данными должны иметь вид:

Оценки 10 студентов

20 50 44 37 17

14 48 39 19 30

Средняя оценка: 31.8

Количество студентов с оценкой выше средней: 5

Программа

Многомерные массивы

Массив в Фортране может иметь до семи измерений. Число измерений называется размерностью или рангом массива; количество элементов в измерении называется протяженностью массива в данном измерении.

При выделении памяти для многомерных массивов в атрибуте dimension описания массива следует указать границы индексов по каждому измерению массива:

тип, dimension (список границ):: список имен массивов

Длина списка границ массива равна рангу (размерности) массива. Границы массива – константные целые выражения, задающие нижнюю и верхнюю границы индекса по соответствующему измерению. Размер массива равен произведению его протяженностей по всем измерениям.

Из описания массива array

integer, dimension (0:6,0:12):: array

следует, что это целочисленный массив, ранг которого равен 2. Протяженности двух измерений массива равны соответственно 7 и 13, размер массива равен 7*13 = 91.

Каждый элемент массива может иметь до семи индексов, характеризующих его положение в массиве, например:

A(3, 4, I, J), B(1, 2, 3, 4, 5, 6, 7), C(I+1).

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

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

Массив, описанный оператором

integer, dimension (1:3,1:4):: A

можно изобразить в виде матрицы

Подчеркнутый элемент A(2,3) находится в матрице на пересечении строки с номером i=2 и столбца с номером j=3.

Секции массива

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

Для выбора подмножества элементов в измерении используется триплет вида:

index1:index2:index3

Здесь index1 и index2 – нижняя и верхняя границы диапазона индексов в выбранном измерении, index3 – шаг изменения индексов. Значения index1 и index2 не могут выходить за пределы границ массива в соответствующем измерении.

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

Секция массива, в свою очередь, представляет собой массив.

Примеры секций массива рассмотрим для массивов

integer, dimension (1:30)::A

real, dimension (0:5, 0:9)::B

1) A(i:k:1)– одномерный массив, состоящий из элементов массива A с i -го по k -ый включительно

2) A(:k)– одномерный массив, состоящий из элементов массива с первого по k -ый включительно

3) A(:9:2)– одномерный массив, состоящий из элементов массива A с нечетными индексами с первого по 9-ый включительно (A1, A3, A5, A7, A9)

4) A(i:i)– одномерный массив, состоящий из одного элемента, равного A(i)

5) B(2, 1:n-1:1)- одномерный массив, состоящий из элементов второй строки массива В с первого по (n-1) -ый включительно.

6) B(2,:) – одномерный массив, состоящий из всех элементов второй строки массива В.

7) B(:2,:4) – двумерный массив, левая верхняя четверть массива B.

8) Нижняя граница может превосходить верхнюю, а шаг при этом должен быть отрицательным – это позволяет выбирать элементы массива в обратном порядке, например, секция

B(I, 9:0:-2)

состоит из элементов B(I, 9), B(I, 7), B(I, 5), B(I, 3), B(I, 1)

Размещение массивов в памяти

Для правильного использования массивов необходимо представлять, как они хранятся в памяти. Память компьютера является одномерной. Массив размещается в последовательно расположенных ячейках памяти. Например, элементы одномерного массива

real, dimension (0:6):: A

хранятся в памяти в порядке возрастания их индексов:

a(0), a(1), a(2), a(3), a(4), a(5), a(6)

В Фортране естественным порядком размещения элементов массива является такой, когда крайний левый индекс изменяется быстрее всего, второй слева – медленнее и так далее. Медленнее всего изменяется крайний правый индекс. Каждый индекс последовательно принимает все значения из диапазона индексов.

Например, элементы трехмерного массива

real, dimension (1:2, 1:2, 1:2):: A

хранятся в памяти в следующем порядке:

a(1,1,1), a(2,1,1), a(1,2,1), a(2,2,1), a(1,1,2), a(2,1,2), a(1,2,2), a(2,2,2),

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

Например, элементы матрицы , объявленной оператором

real, dimension (1:2, 1:3):: A

хранятся в памяти в следующем порядке:

a(1,1), a(2,1), a(1,2), a(2,2),a(1,3), a(2,3)

Ввод и вывод массивов

Традиционное представление матрицы в математике – по строкам. Если таким образом подготовить в текстовом файле матрицу, рассмотренную выше, то элементы в этом файле будут расположены по строкам – сначала первая строка, затем – вторая:

a(1,1), a(1,2), a(1,3), a(2,1),a(2,2), a(2,3)

Оператор

read (1,*) A

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

В файле a(1,1), a(1,2), a(1,3), a(2,1),a(2,2), a(2,3) – для сравнения.

В памяти a(1,1), a(2,1), a(1,2), a(2,2),a(1,3), a(2,3)

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

Оператор

write (1,*) A

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

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

read (1,*) A; Write (2,*) A

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

Ввод двумерного массива

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

Пример

integer, parameter:: kLine=2, kCol=3! число строк и столбцов

integer:: nLine, nCol! номера строки и столбца

real, dimension (1: kLine,1: kCol):: A! массив

Далее показаны три возможности написания оператора read.

1) использовать неявный цикл по строкам массива, представив каждую строку в виде секции массива A(nLine,1: kCol):

read (1,*)(A(nLine,1: kCol), nLine =1, kLine)

2) в том же неявном цикле по строкам в секции-строке диапазон индекса столбца использовать по умолчанию A(nLine,:):

read (1,*)(A(nLine,:), nLine =1, kLine)

3) в неявном цикле по строкам массива использовать вложенный неявный цикл по столбцам этого массива:

read (1,*)((A(nLine,nCol),nCol=1,kCol),nLine=1,kLine)

Вывод двумерного массива

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

Для вывода массива из предыдущего примера можно воспользоваться следующими операторами:

write (2,*) ‘Матрица’

do nLine = 1, kLine! цикл по строкам

write (2,11) A(nLine,:)! строка – секция массива

Enddo

11 format (20(F7.2))

Здесь каждой строке соответствует оператор write. Повторитель спецификаций формата не должен быть меньше, чем длина строки массива.

Более компактно то же самое можно записать с использованием неявного цикла:

write (1,11)(A(nLine,:), nLine =1, kLine)

11 format (‘Матрица’/<kCol>(F7.2))

Здесь для вывода всего массива используется один оператор write, то есть длина списка вывода равна длине массива. Для того, чтобы каждая строка массива была выведена в отдельной строке файла, служит повторитель спецификации в операторе format. Если в качестве повторителя используется переменная, ее имя заключается в угловые скобки.

Пример 1. Вывести в виде матрицы элементы нижней правой четверти вещественной матрицы A из 4 строк и 6 столбцов.

real, dimension (1:4, 1:6):: A! массив

integer:: nLine! номер строки

write (1,11)(A(nLine, 4:6), nLine =3, 4)

11 format (3(F7.2))

Пример 2. Вывести в виде одномерных массивов элементы главной и побочной диагоналей квадратной вещественной матрицы A размером Size ´ Size.

integer, parameter:: Size=8! число строк и столбцов

integer:: Number! номера строки и столбца

real, dimension (1: Size,1: Size):: A! массив

! главная диагональ

write (1,11)(A(Number, Number), Number=1, Size)

! побочная диагональ

write (1,11)(A(Number, Size-Number+1), Number= Size, 1, -1)

11 format (<Size>(F7.2))

Примеры задач.

Пример 3. Создать и вывести вещественную матрицу, значение каждого элемента которой равно квадратному корню из суммы его индексов.

integer, parameter:: kLine=2, kCol=3! число строк и столбцов

integer:: nLine, nCol! номера строки и столбца

real, dimension (1: kLine,1: kCol):: A! массив

do nLine = 1, kLine! цикл по строкам

do nCol = 1, kCol! цикл по столбцам

A(nLine, nCol) = SQRT (Real (nLine+nCol))

Enddo

Enddo

write (2,11)(A(nLine,:), nLine =1, kLine)

11 format (<kCol> (F7.2))

Обратите внимание – аргумент функции SQRT должен быть вещественным.

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

1) Цикл по строкам – внешний, в каждой строке – цикл по столбцам.

2) Вместо значения максимального по модулю элемента отслеживается его номер в строке jmax. По индексам элемента доступно его значение.

Характеристики массивов

Общая форма описания свойств объекта имеет вид:

тип объекта, список атрибутов:: список объектов

Атрибут – это свойство объекта, которое может быть определено в операторе объявления типа. Атрибуты задаются ключевыми словами dimension, allocatable, intent, parameter и другими.

К характеристикам массива относятся:

1) Имя массива.

2) Тип массива, то есть тип его элементов.

3) Количество измерений или ранг массива задается атрибутом dimension. Количество измерений массива может быть от единицы до семи. Для каждого измерения указываются нижняя и верхняя границы индекса элементов массива.

4) Форма массива – см. ниже.

5) Размер массива равен количеству элементов в нем.

6) Так как все элементы массива однотипны, объем памяти, занимаемый массивом, равен количеству памяти для одного элемента, умноженному на длину массива.

7) Способ размещения в памяти (массив статический или динамический) определяется атрибутом allocatable.

8) Назначение массива как аргумента процедуры определяется атрибутом intent.

9) Массив констант объявляется с атрибутом parameter

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...