Одномерные массивы в Pascal: объявление, заполнение, поиск и сортировка

Одномерные массивы в Pascal: объявление, заполнение, поиск и сортировка Полезное

Одномерный массив в Pascal — это набор из фиксированного числа элементов одного типа под общим именем, где к каждому элементу обращаются по одному индексу: a[3] — третий элемент массива a, если индексы начинаются с 1. Границы индекса задает программист при объявлении, например array[1..10] of integer.

Ниже — объявление, заполнение, вывод, сумма и максимум, поиск, сортировка пузырьком, передача в процедуру и защита от выхода за границы. Программы проверены в Free Pascal 3.2.2, вывод фактический.

Три понятия, которые путают

Термин Что это Пример
Индекс Номер ячейки, по которому обращаются к элементу i в a[i]
Значение элемента То, что лежит в ячейке a[i] = 25
Диапазон индексов Допустимые номера, задаются при объявлении 1..8, 0..9, -5..5

Нижняя граница не обязана быть единицей: array[0..9] и array[-5..5] тоже корректны, а индексом может быть и char или перечисление. В учебных задачах чаще берут 1..N.

Минимальная рабочая программа

Сначала целиком: объявляем массив из 8 элементов, заполняем квадратами чисел, выводим, считаем сумму и ищем максимум вместе с его позицией.

program ArrayBasics;
const
  N = 8;
var
  a: array[1..N] of integer;
  i, sum, maxVal, maxPos: integer;
begin
  { заполнение по формуле: квадраты чисел 1..N }
  for i := 1 to N do
    a[i] := i * i;

  { вывод в одну строку }
  for i := 1 to N do
    write(a[i], ' ');
  writeln;

  { сумма и максимум с его индексом }
  sum := 0;
  maxVal := a[1];
  maxPos := 1;
  for i := 1 to N do
  begin
    sum := sum + a[i];
    if a[i] > maxVal then
    begin
      maxVal := a[i];
      maxPos := i;
    end;
  end;
  writeln('Сумма: ', sum);
  writeln('Максимум: ', maxVal, ' на позиции ', maxPos);
end.

Вывод:

1 4 9 16 25 36 49 64 
Сумма: 204
Максимум: 64 на позиции 8

Что здесь важно:

  • Размер вынесен в константу N. Если понадобится 100 элементов, меняется одна строка, а не все циклы.
  • Массив целиком на экран не выводится: writeln(a) для статического массива не скомпилируется, нужен цикл по индексам.
  • Максимум начинают с a[1], а не с нуля. Иначе на массиве из одних отрицательных чисел программа вернет 0, которого в массиве нет.
  • Сумму обнуляют перед циклом: в Free Pascal локальные переменные процедур не инициализируются, и надеяться на ноль нельзя.

Способы заполнить массив

По формуле — как в примере выше: a[i] := i * i. Подходит, когда значение зависит от номера.

Случайными числами — удобно для проверки программы на больших данных:

Randomize;                     { новая последовательность при каждом запуске }
for i := 1 to N do
  a[i] := Random(100) + 1;     { Random(100) дает 0..99, значит a[i] в 1..100 }

Вывод разный от запуска к запуску. Без Randomize последовательность повторяется — так удобнее отлаживать.

С клавиатуры — когда количество элементов заранее неизвестно, объявляют массив с запасом и хранят фактическую длину в отдельной переменной:

program ReadArr;
const
  NMAX = 100;
var
  a: array[1..NMAX] of integer;
  n, i: integer;
begin
  write('Сколько чисел (1..', NMAX, ')? ');
  readln(n);
  if (n < 1) or (n > NMAX) then
  begin
    writeln('Нужно число от 1 до ', NMAX);
    halt(1);
  end;
  for i := 1 to n do
    read(a[i]);
  for i := n downto 1 do
    write(a[i], ' ');
  writeln;
end.

При вводе 4, затем 10 20 30 40 программа печатает числа в обратном порядке: 40 30 20 10. Проверка n перед циклом обязательна: без нее ввод 150 приведет к записи за пределы массива.

Еще один вариант — инициализация при объявлении. В Free Pascal и Delphi это выглядит так: a: array[1..8] of integer = (5, 3, 8, 1, 9, 2, 7, 4);. В других средах синтаксис может отличаться.

Линейный поиск элемента

Задача: найти, на какой позиции стоит число x, или сообщить, что его нет. Проходим массив слева направо и останавливаемся на первом совпадении.

program LinearSearch;
const
  N = 8;
  a: array[1..N] of integer = (5, 3, 8, 1, 9, 2, 7, 4);
var
  i, x, pos: integer;
begin
  x := 9;
  pos := 0;             { 0 = не найдено: вне диапазона 1..N }
  i := 1;
  while (i <= N) and (pos = 0) do
  begin
    if a[i] = x then
      pos := i;
    i := i + 1;
  end;
  if pos > 0 then
    writeln('Число ', x, ' найдено на позиции ', pos)
  else
    writeln('Числа ', x, ' в массиве нет');
end.

Вывод: Число 9 найдено на позиции 5. Здесь использован while, а не for, потому что цикл должен закончиться сразу после находки. Значение 0 для «не найдено» работает только потому, что индексы начинаются с 1; при диапазоне 0..9 нужен другой признак, например отдельная переменная found: boolean.

Сортировка пузырьком: сначала руками

Пузырьковая сортировка сравнивает соседние элементы и меняет их местами, если левый больше правого. За один проход самый большой из неотсортированных элементов «всплывает» в конец. Вот массив 5 3 8 1 9 2 7 4 после каждого прохода:

Проход Состояние массива Были обмены
1 3 5 1 8 2 7 4 9 да
2 3 1 5 2 7 4 8 9 да
3 1 3 2 5 4 7 8 9 да
4 1 2 3 4 5 7 8 9 да
5 1 2 3 4 5 7 8 9 нет — стоп

На пятом проходе обменов не было, значит массив уже упорядочен, и оставшиеся проходы можно не делать. Теперь то же в коде:

program BubbleSort;
const
  N = 8;
var
  a: array[1..N] of integer = (5, 3, 8, 1, 9, 2, 7, 4);
  i, j, tmp: integer;
  swapped: boolean;
begin
  for i := 1 to N - 1 do
  begin
    swapped := false;
    for j := 1 to N - i do
      if a[j] > a[j + 1] then
      begin
        tmp := a[j];
        a[j] := a[j + 1];
        a[j + 1] := tmp;
        swapped := true;
      end;
    if not swapped then
      break;
  end;
  for i := 1 to N do
    write(a[i], ' ');
  writeln;
end.

Вывод: 1 2 3 4 5 7 8 9. Внутренний цикл идет до N - i, а не до N: во-первых, хвост уже отсортирован, во-вторых, при j = N обращение a[j + 1] вышло бы за границу массива. Пузырек нагляден, но медленный (порядка N² сравнений); на больших данных берут быструю сортировку или слиянием.

Выход за границы массива и {$R+}

Самая частая ошибка с массивами — обращение к индексу вне диапазона. Неверный код: цикл до 6 при массиве из 5 элементов.

program OutOfRangeNoCheck;
var
  a: array[1..5] of integer;
  i: integer;
begin
  for i := 1 to 6 do
    a[i] := i * 10;
  writeln('Готово');
end.

Результат в Free Pascal с настройками по умолчанию: программа печатает Готово без ошибок. Но значение 60 записано в память за пределами массива и может испортить соседние переменные; поведение непредсказуемо.

Исправление для отладки — включить проверку диапазонов директивой {$R+} в начале программы (или ключом компилятора -Cr):

program OutOfRange;
{$R+}
var
  a: array[1..5] of integer;
  i: integer;
begin
  for i := 1 to 6 do
    a[i] := i * 10;
  writeln('Готово');
end.

Теперь программа останавливается на ошибочной записи:

Runtime error 201 at $0000000000400168

Код 201 в Free Pascal — ошибка проверки диапазона, адрес зависит от платформы; с модулем SysUtils будет исключение ERangeError. Проверка замедляет программу, ее включают на время разработки. Само исправление — граница цикла: надежнее всего for i := Low(a) to High(a).

Массив как параметр процедуры

Массив нельзя передать, описав его тип прямо в заголовке (procedure P(a: array[1..5] of integer) не скомпилируется). Сначала объявляют именованный тип:

program ArrayParam;
const
  N = 5;
type
  TArr = array[1..N] of integer;

function Sum(const arr: TArr): integer;
var
  i, s: integer;
begin
  s := 0;
  for i := 1 to N do
    s := s + arr[i];
  Sum := s;
end;

procedure FillSquares(var arr: TArr);
var
  i: integer;
begin
  for i := 1 to N do
    arr[i] := i * i;
end;

var
  a: TArr;
begin
  FillSquares(a);
  writeln('Сумма квадратов 1..', N, ': ', Sum(a));
end.

Вывод: Сумма квадратов 1..5: 55. var — процедура меняет исходный массив; const — только чтение; без модификатора передается копия, изменения не видны снаружи.

Статический и динамический массив

Все примеры выше — статические массивы: размер известен при компиляции и не меняется. В Free Pascal и Delphi есть и динамические массивы, размер которых задается во время работы:

program DynArr;
var
  d: array of integer;
  i: integer;
begin
  SetLength(d, 4);
  for i := 0 to High(d) do
    d[i] := i + 1;
  writeln('Low=', Low(d), ' High=', High(d), ' Length=', Length(d));
  for i := Low(d) to High(d) do
    write(d[i], ' ');
  writeln;
end.

Вывод:

Low=0 High=3 Length=4
1 2 3 4 
Статический Динамический
Объявление array[1..N] of integer array of integer + SetLength
Размер Фиксирован при компиляции Задается и меняется при работе
Индексы Любой диапазон, например 1..N Всегда с 0 до Length - 1
Где есть Любой Pascal Free Pascal, Delphi, PascalABC.NET; в стандартном Pascal нет

Ловушка: цикл for i := 1 to Length(d) пропустит первый элемент и выйдет за последний. for i := Low(d) to High(d) работает для обоих видов.

Выводы

  • Одномерный массив — фиксированный набор однотипных элементов с одним индексом; диапазон индексов задается при объявлении и не обязан начинаться с 1.
  • Размер выносите в константу, а циклы пишите через Low/High, чтобы не ошибиться с границами.
  • Максимум и минимум начинают с первого элемента, а не с нуля; поиск с остановкой удобнее писать через while.
  • Выход за границы в Free Pascal по умолчанию не ловится; на время отладки включайте {$R+}.
  • Динамические массивы индексируются с нуля — это главное отличие от привычных статических 1..N.

Где применяется / связь с практикой

Освойте тему на практике

Массив — основа учебных алгоритмов: поиск, сортировки, префиксные суммы, бинарный поиск. Задачи на массивы часто дают на собеседованиях, а навык работы с индексами переносится на любой язык. Если хочется разобрать алгоритмы и структуры данных системно, с оценкой сложности и практикой, посмотрите курс «Алгоритмы и структуры данных». Для знакомства с темой подойдут бесплатные открытые уроки Otus.

FAQ

Можно ли в Pascal объявить массив с индексами от 0?
Да, array[0..9] of integer — обычное объявление на 10 элементов. Важно, чтобы циклы использовали те же границы, поэтому удобнее писать Low(a) и High(a).

Можно ли присвоить один массив другому целиком?
Да, если оба объявлены одним именованным типом (например, TArr): b := a копирует все элементы. Сравнивать массивы через = так же нельзя — сравнение пишут циклом.

OTUS Журнал
Скидка 5% 14-20 сентября на курсы (popup)