#15 Одномерные массивы и работа с ними в Паскале. Задание собственного типа данных. Примеры

Одномерный массив — это фиксированное количество элементов одного и того же типа, объединенных одним именем, где каждый элемент имеет свой номер (индекс).
ором этого же кода, но в более подробном

Для чего нужны массивы

Фактически массивы позволяют использовать огромное количество переменных (своих элементов) без отдельного объявления каждого из этих элементов.

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

При дальнейшем чтении урока последняя мысль станет более понятной.

Объявление массива

Массив является сложным (составным) типом данных, так как представляет из себя целый набор элементов.

Объявить массив можно двумя способами:

  1. Не объявляя новый тип данных -- например так:
    var 
       a : array [1..10] of integer; // объявляем массив целых чисел из 10 элементов
  2. Объявив новый тип данных и используя его -- например так:
    //или
    type  // секция объявления типов
      myArr = array[1..10] of integer; // массив из 10 элементов
    { Мы объявили myArr -- тип данных представляющий собой массив 
    целых чисел из 10 элементов  с индексами от 1 до 1 }
    var
      a: myArr; // объявляем переменную типа  myArr
    
    

- то есть в конечном итоге всё сводится к объявлению переменной в секции var, но имеется возможность отдельно задать собственный тип в секции type (до секции var) как это показано выше.

Работа с конкретными элементами массива

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

Рассмотрим пример программы (можно запустить):

type  // секция объявления типов
  myArr = array[1..3] of char; //  массив из 3 элементов символьного типа

var
  a: myArr; // объявляем переменную типа  myArr

begin
   // инициаллизируем первый и третий элементы массива
   a[1] := '3';
   a[3] := '&'; // присваиваем значение элементу по индексу 3

   // выведем на экран значения трёх элементов через пробел
   writeln(a[1], '|', a[2], '|', a[3]);

   // проверим равен ли неициаллизированный элемент пробелу:
   if (a[2] = ' ') then
      writeln('['+a[2]+'] -- probel')
   else
      writeln('['+a[2]+'] -- ne probel, kod simvola:', ord(a[2]));

   readln();
end. 

-- в этой программе мы:

  • объявили собственный тип данных (массив из 3 символьных элементов);
  • присвоили первому и третьему элементу значения (инициализировали их);
  • вывели на экран все три элемента массива -- причём второй неинициализированный элемент отобразится как пустой;
  • c помощью оператора ветвления узнали совпадает ли этот неинициаллизрованный элемент с пробелом (является ли он пробелом -- вышло что нет) и с помощью стандартно функции ord() вывели его код в таблице ASCII, код $0$ соответствует пустому элементу. Таким образом мы выяснили, что неициализированные элементы массива типа char равны т.н. пустому символу.

Обход/перебор элементов массива

В программировании распространён термин т.н. обхода массива -- то есть перебора его элементов в каком-то порядке с произвольной целью.

Перебор нужен в том числе чтобы:

  • Инициализировать значения нескольких или вообще всех элементов массива.
  • Считывать значения элементов массива.
  • И вообще для любой "массированной" работы с элементами (т.е. такой где их используется много).

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

type  // секция объявления типов
  myArr = array[1..3] of integer; // массив из 3 элементов
var
  a: myArr; // объявляем переменную типа  myArr
  i : integer;
begin

   { обходим первый раз массив,
      значения которого ещё не инициализированы,
      с целью присвоить значения элементам
   }
   for i:=low(a) to high(a) do
   begin
     writeln('vvedite element massiva nomer ', i, ':');  // пояснение для пользователя
     readln(a[i]);  // считываем элемент i массива 'a' из консоли
   end;

   // выводим массив значения элементов на экран
   writeln('elementi vvedennogo vami massiva:');
   for i:=low(a) to high(a) do // обходим массив второй раз, теперь уже с целью вывода его значений
     writeln(a[i], ' <-- a[', i, '] ');

   readln();
end. 

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

Инициализация массива случайными значениями -- пример процедуры

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

Приведём пример программы, которая делает подобное:

var i: integer;
    a: array [1..10] of integer;

{ Процедура получает значение переменной a по ссылке }
procedure initIntArrayOfSeven(var a: array of integer);
var min, max: integer;
begin
   randomize(); // инициал. датчик случайных чисел (вызов стандартной процедуры)

   min := -5; // левая граница
   max := 10; // правая граница

   { обходим переданный массив
     и инициализируем массив случайными числами}
   for i:=low(a) to high(a) do
      a[i] := min + random(max - min + 1);
end;

begin    // далее программа использующая нашу процедуру

  initIntArrayOfSeven(a); { заполняем массив случайными числами, 
          передаем переменную в процедуру по ссылке }
  for i:=low(a) to high(a) do // обходим наш массив
     write(a[i], ' ');  // выводим очередное его значение

  readln(); // удерживаем консоль
end.  

Пояснения:

Влияние способа описания типа массива на работу с индексами при передаче в подпрограмму, процедуру ("с нуля или с единицы")

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

Начнем, базовый пример "потери индексации" массива :

var i: integer;
    a: array [1..5] of integer;

procedure showArray(a: array of integer);
begin
   for i:=low(a) to high(a) do
      write(i, ' ');
end;

begin
  writeln('Индексы были:');
  for i:=low(a) to high(a) do
      write(i, ' ');
  writeln();
  writeln('Индексы стали:');
  showArray(a);
  readln();
end.   

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

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

type  // секция объявления типов
  myArr = array[1..5] of integer;
var i: integer;
    a: array [1..5] of integer;

procedure showArray(a: myArr);
begin
   for i:=low(a) to high(a) do
      write(i, ' ');
end;

begin
  writeln('Индексы были:');
  for i:=low(a) to high(a) do
      write(i, ' ');
  writeln();
  writeln('Индексы стали:');
  showArray(a);
  readln();
end.
     

Ниже можно найти видео с разбором этого же кода, но в более подробном формате.

Видео-материалы

  • Разбор проблемы "потери индексов" при передаче массива в подпрограмму: https://youtu.be/K2zpmZtoYWk
  • Еще про работу с индексами и про выход за границы массивов: https://youtu.be/fZqNMseOPow

Самостоятельная работа

Задачи

  1. Задайте в коде программы массив из семи чисел:
    1 12 45 6 7 18 99

    Затем обойдите это массив, выводя его значения на экран.

  2. Пользователь вводит 7 чисел одно за другим, сохраните их в массив, выведите этот массив на экран.
    Примечание: вывод значений массива сделайте в отдельном цикле.
  3. У вас есть массив:
    type
      myArr = array[1..8] of char; 
    var
      a: myArr;
    

    -- символьный, из 8 элементов.

    Пользователь вводит любые символы (после каждого нажимает Enter), до тех пор пока не введет символ решетки #

    Задача: сохранить в массив символы, которые ввел пользователь (до символа # или до окончания места в массиве) и вывести их на экран, значения не используемых ячеек массива выводиться не должны.

  4. Пользователь вводит массив целых чисел из 7 элементов. Найдите из них самое большое число и выведите его на экран.

    Подсказка: Для лучшего понимания или если не ясно как решать, см. разбор решения (в т.ч. типичной для этой задачи ошибки): https://youtu.be/5h2Ln_Y0BFwэтому вопросу)

  5. Пользователь вводит массив целых чисел из 7 элементов. Найдите из них два самых больших числа и выведите их на экран.

    Примеры для проверки:

    1 2 2 1 1 1 1
    Ответ: 2 2
    -1 -2 -2 -1 -1 -1 -1
    Ответ: -1 -1
    -1 -2 -2 5 4 -1 -1
    Ответ: 5 4
  6. У вас есть массив чисел от 1 до 17, выведете его на экран, обходя в цикле таким образом:
    1
    2 3
    4 5 6
    7 8 9 10
    11 12 13 14 15
    16 17

    ПРИМЕЧАНИЕ: эту задачу можно решить, как вложенными циклами, так и вообще одним циклом (что более изящно).

  7. Пользователь вводит целые числа в цикле. Запишите в массив целых чисел (из 3 элементов) все нечетные отрицательные. Как только массив будет заполнен, завершите цикл ввода новых значений пользователем и распечатайте полученный массив.
  8. Заполните массив целых чисел (длиной 8 элементов) случайными значениями от -5 до 5.
    Сохраните все неотрицательные числа первого массива во второй массив
    и выведете этот второй массив на экран (если количество сохраненных чисел во втором массиве меньше, чем его длина, то выведете только их, не обходя неинициализированные яйчейки).

    Примечание: для лучшего понимания можно посмотреть видео-разбор решения.

  9. Заполнить массив из 9 элементов случайными числами, далее получить случайное число $N$ из диапазона от 1 до 9 и затем "удалить" элемент с позиции $N$ из массива, "сдвинув" значения влево и заполнив все что справа нулями.
    Например:
    |1|3|4|5|4|7|-8|-9|

    Путь n=2, тогда после работы программы мы должны получить:

    |1|4|5|4|7|-8|-9|0|


    Примечание:
    операции сдвига элементов массива оформите в виде подпрограммы.

  10. Заполните массив из 5 элементов случайными числами из любого диапазона.

    Далее пользователь вводит в цикле значения от 1 до 5 -- удаляйте из массива очередной элемент с позиции очередного введенного пользователем числа, сдвигая оставшиеся элементы массива влево, заполняя то, что справа нулями. Распечатывайте промежуточной состояние массива, после каждого удаления.

    Цикл должен работать до тех пор, пока в массиве не останется ненулевых элементов или пока пользователь не введет число большее чем 5 или меньшее чем 1.

    Например:

    |1|3|7|5|4| // исходный массив
    3 // ввод пользователя
    |1|3|5|4|0| // промежуточный результат
    3 // ввод пользователя
    |1|3|4|0|0| // промежуточный результат
    2 // ввод пользователя
    |1|4|0|0|0| // промежуточный результат
    1 // ввод пользователя
    |4|0|0|0|0| // промежуточный результат
    1 // ввод пользователя
    |0|0|0|0|0| // промежуточный результат
    // Cообщение о завершении, т.к. все элементы удалены
    

    -- в данном случае программа завершилась, так как удалены все элементы.
    Если бы пользователь ввел число 10 или -5 - то это тоже была бы ситуация для завершения, но элементы в массиве ещё бы остались.

    Примечание: оформить код сдвига элемента как функцию.

  11. Заполнить массив из 9 элементов случайными числами из диапазона от нуля до $N$, и затем удалите из этого массива все элементы равные $M$, причем удаление необходимо производить "сдвигом" влево оставшихся элементов на позиции элементов, совпавших с $M$.

    Решить двумя способами:

    • 1) Любым
    • 2) Провести операцию сдвига за одно прочтение исходного массива (для этого нам потребуется еще один массив, где мы будем хранить какие-то значения)
  12. Напишите функцию, которая определяет являются ли значения переданного массива целых чисел уникальными относительно друг друга.
    Протестируйте работу функции на массиве из 7 случайных элементов из диапазона от 1 до 15-ти.

    Например для массива:

    |1|5|4|5|6|7|8|

    -- функция должна "сообщить", что он неуникальный

    а для:

    |1|15|4|5|6|7|8|

    -- что уникальный.

  13. Пусть есть процедура, которая умеет сдвигать массив влево на 1 элемент, начиная с указанного символа (устанавливая последний элемент равным нулю):

    type newArr = array [1..5] of integer;
     
    procedure shiftArr(var promArr: newArr; k:integer);
    var j:integer;
    begin
      for j:=k to 4 do
        promArr[j]:=promArr[j+1];
      promArr[high(promArr)]:=0;
    end;

    Задача: У вас есть исходный массив случайных целых чисел из 5 элементов. Пользователь вводит три числа целых числа, сохраните их во второй массив и затем проведите сдвиг элементов исходного массива, для каждого случая их совпадения с элементами из второго массива, для сдвига используйте процедуру shiftArr().

    Пример 1:

    Исходный массив: 1 5 6 8 9
    Числа пользователя:
    2
    4
    5
    Ответ:
    1 6 8 9 0

    Пример 2:

    Исходный массив: 1 5 6 8 9
    Числа пользователя:
    8
    4
    6
    Ответ:
    1 5 9 0 0

    Пример 3:

    Исходный массив: 1 5 6 5 9
    Числа пользователя:
    5
    4
    6
    Ответ:
    1 9 0 0 0
    
  14. Напишите функцию, которая определяет являются ли значения переданного массива целых чисел уникальными относительно друг друга, если среди есть неуникальные элементы, то удалите их, сдвинув значения влево, заполняя оставшиеся справа ячейки нулями.

    Протестируйте работу функции на массиве из 7 случайных элементов из диапазона от 1 до 15-ти.
    Например для:

    |1|-3|5|-3|9|5|8|

    получим:

    |1|9|8|0|0|0|0|
  15. Напишите программу, которая будет заполнять массив из 10 элементов случайными числами из диапазона от 0 до 20, при этом в полученном массиве не должно быть одинаковых значений.
  16. Напишите функцию, которая принимает на вход целое число N и возвращается строку, содержащую арифметическое выражение вида:
    a1 # a2 # ..... # aN

    Где:

    • a1, a2,....., aN -- случайные числа из диапазона от 1 до 100
    • # - один из случайных знаков (*, +, -)
  17. Дан массив длиной $N$ (не более 100 элементов). Проверить, что в нем в встречаются все числа от 0 до k, где $0 \leq k \lt N $.

    Указание: Проверку массива на соответствие условиям задачи вынести в подпрограмму (функцию)

    Подсказки:

  18. Дан массив длиной $N$ (не более 100 элементов). Проверить, что в этом массиве на отрезке индексов от $m$ до $p$ ( $ 1 \leq m \lt p \leq N $, считая что массив индексируется с единицы) встречаются все числа от 0 до k, где $0 \leq k \lt N $.

    Указание: Проверку массива на соответствие условиям задачи вынести в подпрограмму (функцию)

  19. Дан массив длиной $N$ (где $10 \leq N \lt 100 $). Найти в этом массиве отрезок длиной F, такой что на нем встречаются все числа от 0 до k, где $0 \leq k \lt F $ (если отрезок такой длины F, содержащий все указанные числа, существует, в противном случае сообщите, что его не существует).

    В качестве ответа (если отрезок найден) получите его начальный и конечных индекс - $m$ и $p$ ( $ 1 \leq m \lt p \leq N $, считая что массив индексируется с единицы)

    Указание: Проверку массива на соответствие условиям задачи вынести в подпрограмму (процедуру, которая вычислит нужные индексы, если есть)
    Подсказка: можно использовать функцию проверки отрезка в массиве из предыдущей задачи.

  20. *
    Дан массив длиной $N$ (не более 100 элементов), состоящий из случайно выбранных чисел из диапазона от $0$ до $k$, где $0 \leq k \lt N $.
    Найдите в этом массиве длину самого короткого фрагмента, который содержит все числа от от $0$ до $k$.

    Например:

    • Для N = 6, k=2:
      $ 2\; \underbrace{0\; 2 \;2 \;1}_{\text{длина=4}}\; 1 $
    • Для N = 10, k=2:
      $ 2\; 0\; 2\; 2\; 1\; 1\; 0\; \underbrace{0\; 1\; 2}_{\text{длина=3}} $
    • Для N = 15, k=3:
      $ 2\; 0\; 2\; 2\; 3\; 3\; 0\; 0\; 2 \; 3 \; \underbrace{0 \; 3 \; 2 \; 1}_{\text{длина=4}} \; 0 $
    • Для N = 7, k=2:
      $ 0\; \underbrace{ 1 \;0 \;0 \;0 \;2}_{\text{длина=5}}\; 0 $

      Для быстрой проверки кода через запуск используйте следующий тип массива:

      type
          ArrOfInt = array[1..100] of integer;
  21. Даны два массива по 20 элементов каждый (заполните случайными числами, так чтобы среди элементов массива при очередном запуске программы могли встретиться и отрицательные и положительные числа).

    Сравните каждый 3-ий элемент 1-ого массива с каждый 2-ым элементов 2-ого массива - сравнение проводите пока не закончится та выборка, которая короче.

    Например пусть мы имеем два массива (запишу лишь начальные элементы):

    1 | 2 | -10 | 5 | 0 | 12 | 2 | 8 ....
    0 | 3 | 4 | 9 | 7 | 5 | -8 | 3.....

    для них программа должна вывести:

    -10 меньше 3
    12 больше 9
    

    - других сравнений не последует, так как новых из "каждых третьих элементов" в 1-ом массиве больше нет.

  22. У вас есть два массива целых чисел по 10 элементов в каждом.
    Выведите на экран все числа из первого массива, которые не содержаться во втором.
  23. Задача про Бинарные часы:

    бинарные часы задача программирование
    Пояснение:
    На картинке выше фото часов, которые показывают время следующим образом:

    • в верхнем ряду отображают текущий час 4мя лампочками (битами) если лампа горит, складываем ее значение в основное т.е. 2 + 1 = 3 часа (в 12ти часовом формате)
    • В нижней линии 6 лампочек (бит) и они кодируют 16 + 8 + 1 = 25 минут.

    Задача:
    Напишите программу, которая принимает у пользователя два целых числа (часы и минуты) и выводит в консоль полученное время в формате бинарных ASCII-часов 0-11 ч. и 0-59 мин.

    Также отметим, что:

    • 12 часов "не выводиться" а соответствует пустым значениям/нулям (- - - -)
    • аналогично в минутах "не выводиться" 60 минут (- - - - - -)

    Для случая с фотографии выше (время 3:25) ASCII-вариант будет выглядеть как:

      - - + +
    - + + - - +

    А, если бы время было 10:40, то :

      + - + -
    + - + - - -
    

    Примечания:

    • Решение данной задачи не требует вычислений в двоичной системе (достаточно знать как считают в обычной десятичной)
    • Историческая справка: задача была предложена к добавлению в курс по Паскалю участником boris68 летом 2021 г. (см. исходный текст)
  24. *
    Задача про банкомат:

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

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

    Например, пусть у нас набор купюр 1000, 500, 100 и 50 рублей:

    • Сумму 350 рублей: по задаче следует выдать как: 3 по 100 и 1 по 50
    • Сумму 520 рублей: таким набором разменять нельзя.

    Указания по возможному оформлению (можно оформлять и иначе):

    Напишите процедуру, которая:

    1. принимает на вход число (сумму) по значению
    2. массив "достоинств" купюр отсортированный по убыванию (предположим, что видов купюр не может быть больше 10) по значению
    3. массив для "количеств купюр" по ссылке
    4. булевский параметр успешности подбора купюр (некоторые суммы вообще разменять нельзя)

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

Что ещё почитать

  1. Урок 14. Одномерные массивы. Работа с элементами: http://learnpascal.ru/vvedenie-v-paskal/...
vedro-compota's picture

// min := 5;  max := 10; 
// min + random(max - min + 1) = 
// -5..10
-5 + random(10 - -5 + 1) = -5  + (0..15) = (-5..10)
//5..10
5 + random(10 - 5 + 1) = 5 + (0..5) = (5..10) 
//-10..-5
-10 + random(-5 - -10 + 1) = -10 +  random(6) =  -10 + (0..5) = (-10..-5) 

_____________
матфак вгу и остальная классика =)

vedro-compota's picture

var a: array [1..3] of integer;

|0|0|0|
a[номерячейки] = 3;

получим:

|0|3|0|

_____________
матфак вгу и остальная классика =)

vedro-compota's picture

цикл:
  ......
  массив[cчетчик] := очередноеЗначение;
  cчетчик := новоеЗначениеСчечика; // напр.  cчетчик := cчетчик + 1;

_____________
матфак вгу и остальная классика =)

vedro-compota's picture

возможное начало обхода массива:

b := low(a);
c := high(a);
for i:=b to c do

_____________
матфак вгу и остальная классика =)

Pages