Типичные недочеты и ошибки в работе с массивами

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

Таблица 42. Статический массив

Нехорошо, неправильно Правильно – статический массив Пояснения
Real X(10) Real,& dimension(1:10)::Y Real,dimension(1:10)::X,Y Конформные массивы дают единым списком
Integer::N=10 !переменная Real,dimension(1:N)::X Неверно: размерность-переменная Integer,parameter::N=10!размерность N – константа Real,dimension(1:N)::X Размерность статического массива должна быть константой.
RealX(10) Real,dimension(1:10)::Y нехорошо, размерность 10 надо менять во многих местах Integer,parameter::N=10!размерность N – константа Real,dimension(1:N)::X,Y Меняем только N – перекомпилируем
Real,dimension(1:10)::X .. x (i)= Y(i) Ошибка не при компиляции, а при компоновке: Y – un­resolved external Real,dimension(1:10)::X,Y x(i) = y(i) x,Y – оба массивы не описали y – во­с­­принимается не как массив, а как неизвес­т­ная функцияотодногоаргументаy(i)
Real,dimension(1:4)::X,Y Y(i) = x (i) Ошибка при компиляции Real,dimension(1:4)::X,Y i =4; y (i) = x (i) x,Y – оба массивы не описали y – во­с­­принимается как ошибка
Real,dimension(1:4)::X,Y x(i)=y(i)! индекс i = ? Real,dimension(1:4)::X,Y do i =1,4 x (i)= y(i) enndo Ошибка при выполнении: защита записи – индекс не определен
Real,dimension(1:4)::X,Y x(i)=y(i)! индекс i = ? Real,dimension(1:4)::X,Y X = Y Ошибка при выполнении: – индекс i не определен

Таблица 43.

Динамический массив

Нехорошо, неправильно Правильно-динамический массив Пояснения
Real,dimension(:)::X Неправильно – надо allocatable Real,allocatable,& dimension(:)::X нужен атрибут allocatable размернос­ть свободна ! форма (1:4) – неправильно
Real,allocatable,& dimension(1:4)::X
Real,dimension(1:4)::X=1 real,allocatable,& dimension(:)::Y !allocate(y(1:size(x))) Y = X Real,dimension(1:4)::X,Y=1 real,allocatable, & dimension(:)::y allocate(y(1:size(x))) y = x забыли allocate:адрес y не определен
Real,dimension(1:4)::X=4 Real,dimension(1:8)::z=8 Real,allocatable,& dimension(:)::Y allocate(y(1:size(x))) Y=X ! deallocate(y) allocate(y(1:size(z))) y = z real,dimension(1:4)::X=4 Real,dimension(1:8)::Z=8 real, allocatable,& dimension(:)::y allocate(y(1:size(x))) Y = X deallocate(y) allocate(y(1:size(z))) y = z забыли deallocate В результатеповторный allocate не выполняется
Real,allocatable,& dimension(:)::X Integer :: N=8 allocate(X(1:N))   Real,dimension(1:8)::X     ошибки нет, но нет смысла строить дина­мический массив постоянного объема

Таблица 44. Выражения и присваивания с массивами

Нехорошо, неправильно Правильно Пояснения
Real,dimension(1:4)::P Real,dimension(1:8)::Q P= Q; Q= P плохо: массивы разной длины Real,dimension(1:4)::X,Y X=(/ 3.1, 3.7, -15. /) Y= X**2+3*X+1 Массив = Выражение и присваивают, и строят выражение то­ль­ко из конформных массивов, исключение – скаляры как sin(z) или 1 в выражении
Real,dimension(1:4)::X Real,dimension(1:4,1:3)::M M= X; X= M плохо: массивы с разным числом измерений не присваивают Real:: z=0.72 Real,dimension(1:4)::X Real,dimension(1:4,1:3)::M=1 X=sin(z) + 1; M(:,1)=X; M(:,2)=2
Real,dimension(1:4,1:3) :: M Real,dimension(1:3, 1:4)::K M=K !shape(M)≠shape(K) Real,dimension(1:4,1:3)::M,K Real,dimension (1:4,-1:1)::R K = M ; M= R shape(M)=shape(K)=shape(R) конформные массивы - это массивы одинаковой формы [1:4,1:3], нумерация может быть разная


Таблица 45. Встроенные функции для работы с массивами

Нехорошо, неправильно Правильно Пояснения
Real,dimension(1:8)::X Print *, sum(X, X>0 ) Real,dimension(1:8)::X Print *, sum(X, mask=X>0 ) Mask – 3-ий аргумент: -надо указать имя mask -задать после 2-го аргумента
Print *, sum(X, 1,X>0 )
Real,dimension(1:8)::X Print *,count(Array=X,X>0 ) Real,dimension(1:8)::X Print *, count(X>0 ) У функции count нет аргумента array
Real,dimension(1:8)::X Print*,sum(X(1:4),mask=X>0) Real,dimension(1:8)::X Print*,sum(X(1:4),mask=X(1:4)>0) На ошибку Size(X(1:4))≠ Size(X) укажет компилятор
Real,dimension(1:8)::X Real g; integer N g = sum(X(1:N), mask=X>0 ) правильно только при N=8 Real,dimension(1:8)::X Real g; integer:: N=4 g =sum(X(1:N), mask=X(1:N)>0 ) правильно при любом N≤8 Size(X(1:N))≠Size(X) компилятор не укажет на ошибку при неизвестном N
IntegerN Real,dimension(1:8)::A N= MinLoc(A) MinLoc- возвращает вектор, ко­то­рый не конформен скаляру N Real,dimension(1:8)::A IntegerN N=sum(MinLoc(A)) Найти номер максимального элемента из массива A.   Также правильно:N=sum(MinLoc(A))
Real,dimension(1:8)::A IntegerN; Integer &, dimension(1:1)::Num Num=MinLoc(A); N=Num(1)

Таблица 46.

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

Нехорошо, неправильно Правильно Пояснения
Real,dimension(1:4,1:3)::M read(1,*)M Нехорошо: читают, как хранится в памяти – по столбцам Integer i Real,dimension(1:4,1:3)::M read(1,*) ( M(i,1:3),i=1,4) Надо читать по строкам Матрица ошибочно читается по столбцам, а обычно читают по строкам.
Real,dimension(1:4,1:3)::M write (1,7) M 7format(3f5.1) integer i ; Real, & dimension(1:4,1:3)::M write(1,7) ( M(i,:),i=1,4) 7format (3 f5.1) вывод изменен – по строкам Матрица выводится по столбцам, а надо выводить по строкам
Real,dimension(1:4,1:3)::M write(1,7)(M(i,1:3),i=1,4) 7format (4 f5.1) Ошибочно: 4 –число строк Real,dimension(1:4,1:3)::M write (1,7) ( M(i,1:3),i=1,4) 7format ( 3 f5.1) Надо 3– число столбцов 1-й индекс – строка 2-ой индекс - столбец Перепутали числа: сто­л­бцов 3, а строк 4.
Real,dimension(1:3,1:3)::K read(1,*)K !чтение транспонирует K 7 format(3 f5.1) write (2,7) K Real,dimension(1:3,1:3):: K read (1,7) (K (i,1:3),i=1,3) write (2,7) ( K (i,1:3),i=1,3) 7 format(3f5.1) Матрица K хранится по столбцам. При неправильном вводе и вы­во­де – создается иллюзия правильности..
Вывести левую половину матрицы (2 из 4 колонок) Real,dimension(1:2,1:4)::A write(2,7)(A(i,1:2), i=1,2) 7 format(‘левая’/2f5.1) ! перед каждой строкой чисел – заголовок левая Вывести левуюполовину матрицы (2 из 4 колонок) Real,dimension(1:2,1:4) :: A write (2,7)(A(i,1:2), i=1,2) 7 format(‘левая’/ 2(f5.1) ) Неправильно левая 4.0 4.0 левая 4.0 4.0 Правильно левая 4.0 4.0 4.0 4.0 4.0 4.0
Вывести левую половину матрицы (2 из 4 колонок) Integer :: N=2 Real,dimension(1:2,1:4)::A write(2,7)(A(i,1:2), i=1,2) 7format(‘левая’/ & (<N>f5.1)) Ошибка компилятора FPS40 Вывести левуюполовину матрицы (2 из 4 колонок) Integer:: N Real,dimension(1:2,1:4) ::A N=2; write (2,7)(A(i,1:2), i=1,2) 7 format (‘левая’ / <N>(f5.1)) Только так работает в FPS40 Неправильно левая 4.0 4.0 4.0 4.0 Правильно левая 4.0 4.0 4.0 4.0



Таблица 47.

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

Нехорошо, неправильно Правильно Пояснения
Program имя Real,dimension(:) :: X Неправильно: в главной: размерность неизвестна, а надо allocatable или константу Functionимя(X) real,intent(in),& dimension(:)::X Integer N N=size(X)   В процедуреотложенное (defer­red) определение размерности. N – лучшеизмерить при помощивстроеннойфункции N=size(X) Память под массив-аргумент распределена в вызывающей программе. В процедуре массив не статический, не динамический – он перенимает адрес и размерность у фактического аргумента..
Function имя( N, X ) Integer,intent(in)::N Real,dimension(1:N) :: X нехорошо, размерность N – величина, зависящая от X
Function имя(X) Real,dimension(:) :: X для аргумента X нет intent(in), но сообщения нет PureFunction имя(X) real,intent(in),& dimension(:)::X есть pure – будет сообщение intent–атрибут аргумента процедуры
Program имя Integer::N Real,dimension(1:N) :: X Размерность статического массива – толькоконстанта Functionимя(N) Integer,intent(in)::N Real,dimension(1:N) :: X Размерность – переменная, только в процедуре автоматический динамический массив размещается автоматически при входе, освобождается – при выходе из процедуры
Programunallocated Real,dimension(1:4)::X=1 real,allocatable, & dimension(:)::y open(1,file='su.txt') allocate(y(1:size(x))) call s(x,y) write(1,*) 'y=', y .. allocate(y(1:size(x)).. contains subroutine s (x, y) real,intent(in),& dimension(:)::X real,intent(out),& dimension(:)::Y y=x End subroutine s EndProgramunallocated Процедура правильная, а в главной забыли allocate В результатевидим y= Вместо правильного y= 1. 1. 1. 1. при наличии allocate
Programunallocated Real,dimension(1:4)::X=1 real,allocatable, & dimension(:)::y open(1,file='su.txt') ! allocate(y) call s(x,y) write(1,*) 'y=',y contains .. allocate(y(1:size(x))) .. contains subroutine s(x,y) real,intent(in),& dimension(:)::X real,intent(out), & dimension(1:size(x))::y Y=X End subroutine s endProgram unallocated Процедура правильная, а в главной забыли allocate. В результате массив y имеет неопределенный адрес.
Functionsi(X) Real :: si real,intent(in),& dimension(:)::X si=sin(X) Functionsi(X) real,dimension(:) :: si real,intent(in),& dimension(:)::X si=sin(X) массивоподобной функции забыли дать атрибут массива – dimension

Наши рекомендации