Упорядоченная совокупность каких–либо однородных данных называется массивом. Примерами таких данных могут быть результаты экспериментов, цифры статистической отчетности, табличные значения той или иной функции, список фамилий сотрудников учреждения, их должностных окладов и т.п.
Элементы каждого массива пронумерованы, хранятся в памяти ЭВМ под соответствующими номерами (индексами) и могут быть в любой момент вызваны по одному в программу для необходимых действий над ними. Работа с массивами имеет наибольший удельный вес и особое значение в практическом применении ЭВМ.
Массивы могут быть числовыми и символьными, а также одно– и многомерными.
Одномерный массив можно представить в виде строки или столбца соответствующих элементов, значение каждого из которых определяется его порядковым номером (индексом). В практике программирования одномерный массив часто называется вектором. Двумерный массив –это таблица, состоящая из нескольких строк и столбцов. Такие массивы принято называть матрицами. Значение каждого элемента матрицы определяется номерами (индексами) строки и столбца, которым принадлежит этот элемент.
Трехмерный массив – это стопка матриц одного размера. Значение каждого элемента такого массива определяется номерами (индексами) страницы в стопке, а также строки и столбца на этой странице. Необходимо иметь в виду, что в языке PASCAL индексы могут выражаться константами, переменными и арифметическими выражениями. Таким образом размерность массива выражается количеством индексов, которое необходимо указать для определения каждого элемента этого массива:
для одномерного массива один индекс, например:
X5, Y2, Zk, T2n–1 и т.п.;
для двумерного два индекса, например:
a3,4, bi,j, r2i,k+1 и т.п.;
для трехмерного три индекса, например:
U3,4,8, P2k,j+1,3m и т.п.
Аналогично определяются массивы и большей размерности, которая в языке PASCAL практически не ограничена.
Все элементы массивов в программах используются со своими индексами, которые записываются после имени массива в квадратных скобках и (если их несколько) разделяются запятыми:
a[37]; v[k]; w[2*i+1];
x[3,5]; y[i,j]; z[k–1,2*m+1];
r[2,4,6]; s[k,l,m]; t[i+2,j–1,3*k+n].
При программировании работы с массивами прежде всего необходимо помнить, что каждый из них в программе должен быть описан. Это требование обязательно как для массивов, которые вводятся в качестве исходных данных, так и для тех, которые формируются в самой программе в результате каких–либо вычислений.
Цель описания массива состоит в том, чтобы предупредить вычислительную систему об ожидаемом количестве элементов массива, под которые система резервирует необходимое число ячеек оперативной памяти, а также о порядке расположения элементов массива в этих ячейках, числе и типе индексов каждого элемента.
Описание может осуществляться двумя способами: как в разделе типов (Type), так и в разделе переменных (Var).
Например, массив Х, состоящий из 20 вещественных чисел с индексами от 1 до 20; может быть описан так:
1–й способ:
Type X= array [1..20] of real;
Var X: real;
или
2–й способ:
Var X: array [1..20] of real;
Общий вид описания в разделе var:
A: array [T1,Т2,...,Tк] of тип;
где А– имя массива; Т1,Т2,...,Тk – типы индексов; тип – это тип элементов массива. Служебные слова array..... of real можно перевести как “массив из вещественных чисел”. Аналогично определяются массивы из других чисел, символов и т.п.
Например, массив фамилий студентов академгруппы из 25 человек может быть описан так:
Var Fam: array [1..25] of string[20];
В этом описании запись string[20]; означает, что массив состоит из строковых данных, длинной не более 20 символов (букв) каждое.
Рассмотрим еще один пример: пусть в программе необходимо работать с матрицей М из целых чисел:
В данном случае элементы массива имеют тип integer. Массив двумерный; первый индекс–номер строки изменяется в пределах от 1 до 3; второй индекс–номер столбца изменяется от 1 до 4. Описание этого массива выглядит так:
м: array [1..3,1..4] of integer;
Задав конкретные значения индексов, можно выбрать определенный элемент этого массива. Например, оператор n:=m[2,3] присвоит величине n значение, стоящее на пересечении 2–й строки и 3–го столбца, т.е. число 42. Аналогично, оператор
к:=m[1,1] + m[3,3];
выполнит сложение чисел 10+19.
Отметим здесь, что описание массивов в разделе Type более экономно в случаях использования в программе нескольких одинаковых по размерности и составу массивов, в то время как описание в разделе Var удобнее, когда в программе используются массивы разной размерности и состава.
Например, фрагмент программы:
Type mas= array [1..100] of real;
Var x,y,z: mas;
Описывает три одномерных массива вещественных чисел с количеством элементов до 100 шт. в каждом с именами х, y, z. Описание же этих массивов в разделе Var потребуют три строки:
Var x: array [1..100] of real;
y: array [1..100] of real;
z: array [1..100] of real;
Наконец, необходимо иметь в виду, что в описаниях массивов диапазон изменения индексов может быть большим, чем тот, что реально будет использоваться в программе. Так каждый из описанных выше массивов х, y, z в программе может состоять из любого числа элементов от 1 до 100, но не один не может иметь более 100 элементов.
Далее в данном пособии рассматриваются задачи, связанные с обработкой одно– и двумерных числовых массивов.
ВВОД И ВЫВОД МАССИВОВ
Отметим прежде всего, что действия с массивами, как правило, предполагают многократное повторение тех или иных операций, поэтому основными операторами в этих действиях являются операторы циклические. Эта особенность в полной мере относится и к операциям ввода и вывода.
Ввод массивов
Если число элементов массива невелико, скажем порядка 10–15, то ввод его может быть выполнен обычным способом с помощью оператора read, включенного в простой (для одномерного массива) или сложный (для многомерного) цикл. Заметим также что, если массив вводится в качестве исходных данных, то для проверки правильности ввода целесообразно предусматривать и вывод вводимых величин. Рассмотрим соответствующие примеры:
Пример 1.2. Ввести массив целых чисел l (к=1,2,...10) с одновременным выводом их для проверки.
program Vvod 1;
Var l: array [1..10] of integer;
k: integer;
Begin
writeln ('Массив исходных данных')
for k:=1 to 10 do
Begin
read (l[k]); write (l[k]);
end;
(продолжение программы)
Пример 2.2. Ввести матрицу R(3,4)
Обозначим i – номер строки матрицы, j – номер столбца. Тогда общий элемент матрицы обозначится ri,j. При вводе элементов матрицы с клавиатуры по строкам необходимо после прочтения последнего элемента строки переходить к новой строке. Для этого удобно использовать комбинацию операторов read и readln.
program Vvod 2;
Var r: array [1..3,1..4] of real;
i,j: integer;
Begin
for i=1 to 3 do
Begin
for j=1 to 3 do read(r[i,j]);
readln(r[i,4]);
end;
(продолжение программы)
Совершенно так же может быть осуществлен ввод этой матрицы по столбцам. В этом случае операторы циклов по индексам i и j следует поменять местами, а числа при вводе набирать в последовательности их расположения по столбцам. Соответствующий фрагмент программы применительно к данному примеру будет иметь вид:
Begin
for j:=1 to 4 do
Begin
for i=1 to 2 do read(r(i,j));
readln(r(3,j));
end;
(продолжение программы)
Отметим, что ввод массивов с помощью операторов read имеет одно существенное неудобство. Как известно, первоначальный вариант программы практически никогда не бывает без ошибок, которые могут обнаруживаться как на стадии компиляции программы, так и на стадии ее выполнения. В последнем случае выявление и исправление ошибок связано с многократными пробными запусками программы. При каждом таком запуске элементы массива приходится набирать на клавиатуре заново. Это весьма неудобно даже для массивов из 10–15 элементов, не говоря уже о больших.
Более удобным в таком случае является ввод с использованием констант типа массив, который при работе программы осуществляется автоматически.
Пример 2.3. Ввести одномерный массив Vec: 8.2 4.9 9.7 6.3 3.1,
а также матрицу Маt
В данном случае ввод может быть выполнен в разделе описания констант:
program Vvod 3;
{константы типа массив}
Const Vec: array [1...5] of real=(8.2,4.9,9.7,6.3,3.1);
Mat: array [1..3,1..4] of integеr=((10,20,30,40),
(50,60,70,80),(25,35,45,55));
i,j: integer;
Begin
(продолжение программы)
В дальнейшем в программе обращения к элементам описанных массивов будут обычными: Vес[i], Mat[i,j] и т.п. Общее правило использования констант типа массив таково: после описания массива и знака = числовые значения его элементов записываются в скобках через запятую, для двумерных массивов элементы каждой строки записываются в отдельных скобках.
Однако и описанный способ ввода не слишком удобен, когда число элементов массива выражается десятками, не говоря уже о сотнях и более.
В таком случае выходом из положения является предварительная запись массива в файл, хранящийся в памяти отдельно от программы. При каждом запуске программы чтение элементов массива из этого файла и передача их в программу будет осуществляться уже автоматически. Не излагая всех вопросов, относящихся к понятию файлов и к операциям с ними, проиллюстрируем этот способ на примерах записи файлов на диск. Эти примеры всегда могут быть использованы в качестве образцов, где следует оставить неизменным все стандартные части, изменив лишь имена и параметры в соответствии с конкретными условиями решаемой задачи.
При записи массива в виде файла следует различать имя массива, програмное имя файла, а также его имя, под которым он записывается в соответствующий каталог на диск. Последние два имени могут быть как разными, так и одинаковыми.
Пример 2.4. Записать в текущий каталог, в файл с именем fd (файл данных) массив y состоящий из 50 вещественных чисел:
program Vvod4;
Var fd: file of real;
y: array [1..50] of real;
k: integer;
Begin
assign(fd,'fd');
rewrite(fd);
for k:=1 to 50 do writeln(fd,y[k]);
close(fd);
End.
По этой программе при наборе на клавиатуре каждого очередного числа y оно будет записываться под соответствующим номером в файл с именем fd. В этом фрагменте переменными(зависящими от выбора программиста) являются: имя файла – fd, имя массива – y; число элементов в нем –50, обозначение индекса – к, и место нахождения формируемого файла – запись 'fd' в операторе аssign. Все остальные записи являются стандартными. Поясним кратко смысл основных из них.
Запись fd: file оf real; объявляет переменную fd файлом, состоящим из вещественных чисел.
Оператор assign связывает файл, программное имя которого fd,с местом его расположение и именем, под которым он записывается на этом месте. В приведенном примере assign(fd,'fd') означает, что файл с именем fd записывается под тем же именем в текущий каталог. Оператор assign в данном случае мог бы выглядеть и так, например:
assign (fd,'masdat')
Это означало бы, что имя файла в программе fd, а его имя в текущем каталоге masdat. Если же, мы хотим записать этот файл в корневой каталог диска а: под именем, скажем, fajl.dat, то оператор assign следует представить в виде:
assign (fd,'a:\fajl.dat')
Иными словами в апострофах оператора assign записывается путь к месту нахождения формируемого файла и его имя на этом месте. Оператор rewrite (fd); открывает файл для записи, оператор close (fd) закрывает его.
При необходимости вызова в программу массива, записанного в виде файла, выполняется аналогичная по смыслу группа операторов.
Пример 2.5. Ввести массив а из 150 целых чисел, записанный файлом в каталоге DANNYE на диске A:, под именем mas.dat.
program Vvod_5;
Var f: file of integer;
a: array [1..150] of integer;
n: integer;
Begin
assign (f,'a:\DANNYE\mas.dat');
reset(f);
for n:=1 to 150 do read (f,a[n]);
close(f);
(Продолжение программы)
Здесь f – программное имя файла (разумеется произвольное); оператор Reset(f) открывает этот файл для чтения, все остальные операторы рассмотрены выше.
По этому фрагменту 150 целых чисел, записанных на дискете, будут переданы в программу под именами а1,а2,...,а150 и могут обрабатываться в ней в соответствии с необходимостью.