Типичные недочеты и ошибки в работе с массивами
На массивы приходится наибольшее число нововведений и оригинальных возможностей современного Фортрана, поэтому в помощь начинающим методичка дополнена данным разделом. Массив – не самый простой объект, поэтому требуются практические разъяснения.
Таблица 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 – unresolved 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 ! | 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 ! | 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( | 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) В процедуреотложенное (deferred) определение размерности. 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)).. 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(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 |