Учебник по программированию.

Первые шаги. Язык программирования PascalABC.

Предыдущий параграф Назад в содержание Следующий параграф


§10. Структурированные типы. Массивы. Записи. Множества.

Структурированные типы.

К структурированным типам относятся: массивы, записи, множества, файлы. Их объединяет то, что переменные данных типов содержат в себе информацию в виде своеобразных структур. Файлы, в свою очередь, бывают типизированные, текстовые и нетипизированные. Они заслуживают отдельного параграфа и их мы рассмотрим позже.


Массивы.

Переменная типа массив может содержать в себе не одно, а несколько значений какого-либо типа, в том числе это может быть и структурированный тип. Например, мы имеем ряд целых чисел: 4,3,45,55. Что бы хранить этот ряд чисел мы можем создать 4 переменные: i1,i2,i3,i4. А теперь представьте себе, что этот ряд содержит не 4, а 40 целых чисел. Будет достаточно «муторно» набирать вручную 40 переменных. Что бы облегчить данную задачу существуют массивы. В данном случае мы можем создать одну переменную, которая будет содержать в себе 40 значений целых чисел. Делается это следующим образом:


var

  M:array [1..40] of integer;


После имени переменной, после двоеточия, пишется слово array затем в квадратных скобках указывается диапазон значений индексов, пишется слово of  и указывается тип значений, которые будут содержаться в массиве. Индексы необходимы для того, что бы можно было обращаться к тому или иному значению, т.е. у каждого значения есть свой индекс. Индексами могут быть только переменные порядковых типов. Что бы обратиться к какому либо значению в тексте программы необходимо после имени массива в квадратных скобках указать индекс, например в следующем примере мы присваиваем четвёртому элементу массива значение 45:


  M[4]:=45;


Наглядно продемонстрировать структуру массива может следующая таблица:


Индекс элемента массива

[1]

[2]

[3]

[4]

[…]

[40]

Значение элемента массива

4

3

45

55

2


Так же стоит отметить, что в отличии от просто переменных, значения в массиве удобно обрабатывать благодаря индексам, с помощью цикла for to do.

Если у вас в программе будут существовать несколько одинаковых массивов, то (так же как и с порядковыми типами), можно вначале объявить тип массива, а потом объявить переменные этого типа. Для создания своего типа в разделе описания типов, после слова Type, пишется имя типа, затем знак равно затем слово array, далее в квадратных скобках указывается диапазон значений, слово of  и тип значений. Например:


Type

  massiv = array [1..40] of integer;

var

  M:massiv;


Далее пример программы с массивами:


Type

  massiv = array [1..40] of integer;

var

  M:massiv;

  S:array [1..40] of char;

  i:integer;

begin

//Заполняем массивы

  for i:=1 to 40 do

    begin

      M[i]:=random(1000);

      S[i]:=chr(random(32,255));

    end

//Выводим массивы на экран

  for i:=1 to 40 do write(M[i]:4,' ');

  writeln;

  for i:=1 to 40 do write(S[i]);

end.

_________________________________________________________________________

213  523  258  763  821  355  774  750   37  773  300  271  512  456  623  939  743  438  261  565  390   34  362    9  235  778  646  590  938  707  694  586  823  121  561    5  405  912  464  796

NQAOЛбя[щcЏC%бµэfsЂэјb№Р/#(їqTйBr†t§Р§ъШ


Обратите внимание, что переменная i в цикле for to do одновременно является счётчиком цикла и индексом массива. В этом и заключается удобство обработки массивов по сравнению с просто переменными. Так же стоит заметить, что в данной программе была использована системная функция random, которая была рассмотрена в предыдущем параграфе. Ей удобно заполнять массив, что бы ни придумывать значения самому. Очень часто заполнение массивов случайными числами необходимо для проверки работоспособности программы.

Ещё стоит отметить следующий нюанс, если вы укажете индекс, выходящий за рамки указанного диапазона, то это приведёт к ошибке во время выполнения программы. При компиляции данная ошибка не будет выведена. Поэтому будьте внимательны при обработке массива в цикле for to do, вы должны указать начальное и конечное значения, соответствующие указанному диапазону индексов массива.

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

Далее небольшой пример:


var m:array ['A'..'Z'] of integer;

    c:char;

begin

  for c:='A' to 'Z' do

   begin

     m[c]:=random(500);

     write(m[c],' ');

   end;

end.

_________________________________________________________________________

200 249 404 152 256 334 336 265 136 404 274 61 107 141 317 368 127 241 423 31 185 475 267 90 227 69


Все массивы, которые были приведены в примерах, называют одномерными т.к. они имеют лишь один индекс. Массивы могут быть двух, трёх и более мерными. При этом они имеют два, три и более индекса. При объявлении многомерного массива или типа массива в квадратных скобках необходимо указать через запятую не один диапазон индексов, а несколько. Пример:


var

  m: array [1..5,1..5] of integer;

  i,k:integer;

 

begin

  writeln('      1   2   3   4   5');

  writeln;

  for i:=1 to 5 do

    begin

      write(i,'  ');

      for k:=1 to 5 do

        begin

          m[i,k]:=random(100);

          write(m[i,k]:4);

        end;

      writeln;

    end;

end.

_____________________________________

      1   2   3   4   5


1    22  41  68   8  40

2    91  57   2  17  92

3    41  38  46  91  55

4    17  82  92  93  80

5    17  94  36  49   9


В данном примере был объявлен двухмерный массив в котором имеется два индекса. Оба индекса имеют диапазон от одного до пяти. Такой массив можно сравнить с матрицей размера 5x5, что наглядно видно из результата работы программы. Т.е. любой двумерный массив можно воспринимать как двухмерную матрицу со столбцами и строками. Первый диапазон индексов в данном примере является строками, и формируется переменной i, а второй диапазон индексов является столбцами и формируется переменной k.

В 8 параграфе была приведена программа SortirovkaBookv. Она располагала по алфавиту четыре буквы. С помощью массива данная задача может быть решена по-другому:


Var c: array [1..4] of char;

    temp:char;

    i,k:byte;

begin

  c[1]:='к';

  c[2]:='ф';

  c[3]:='в';

  c[4]:='а';

  for k:=1 to 3 do

   for i:=1 to 3 do

    begin

     if c[i+1]<c[i] then

      begin

       temp:=c[i+1];

       c[i+1]:=c[i];

       c[i]:=temp;

      end;

    end;

  for i:=1 to 4 do write(c[i]:2);

end.

__________________________________

а в к ф

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

Плюс ко всему сказанному следует сказать, для того что бы элементам одного массива присвоить значения элементов другого массива не обязательно использовать цикл for to do, для этого можно использовать оператор присваивания, при этом размерность массивов должна быть одинаковая:


var m1,m2: array [1..5] of integer;


begin

  .........

  m1:=m2;

  .........

end.


Так же стоит заметить, что арифметические операции и операции сравнения с массивами неприменимы.


Записи.

Рассмотрим такую задачу. Необходимо написать программу учёта овощей на базе. С учётом того, что мы знаем, мы можем решить её следующим образом. Создаём два массива. Первый будет массив символов, где каждый символ будет обозначать свой овощ. Второй будет массив целых чисел, где будет содержаться количество овощей на базе. Индексы первого массива будут соответствовать индексам второго массива. Например, если в первом массиве картошке соответствует индекс 2, то во втором массиве элемент с индексом 2 будет содержать количество картошки на базе. Приведём пример такой программы, в которой реализован поиск овоща по его символу и вывод его на экран:


Var

  Ovoshi: array [1..5] of char;//Массив имён овощей

  Kolichestvo: array [1..5] of word;//Массив количеств овощей

  c:char;//Переменная для ввода нужного овоща

  i:word;//Переменная счётчик для индексов массивов

begin

  Ovoshi[1]:='O'; Kolichestvo[1]:=30//Огурцы

  Ovoshi[2]:='K'; Kolichestvo[2]:=156; //Картошка

  Ovoshi[3]:='P'; Kolichestvo[3]:=353; //Помидоры

  Ovoshi[4]:='M'; Kolichestvo[4]:=34//Морковь

  Ovoshi[5]:='L'; Kolichestvo[5]:=45//Лук

  c:='M';//Ввод нужного овощя

//Поиск нужного овоща в массиве

  For i:=1 to 5 do if Ovoshi[i]=c then break;

//Выод найденного овоща на экран

  Write('Овощей ',Ovoshi[i],' на базе находится ',Kolichestvo[i],'.');

end.

_________________________________________________________________________

Овощей M на базе находится 34.


В принципе здесь всё нормально, для такой задачи такой подход вполне приемлем. А теперь представьте, что нам необходимо учитывать ещё следующие данные: сорт, дата поступления, цена. В этом случае нам понадобиться уже пять массивов. В принципе можно пойти тем же путём и решить задачу с пятью массивами. Однако в Pascal есть для этого тип данных запись. Переменная типа запись может содержать в себе одновременно несколько данных различных типов. Например, создадим переменную Ovosh типа запись, которая будет содержать в себе следующие данные: название, сорт, дата поступления, цена, количество:


Var

  Ovosh: record

    name:char;

    sort:char;

    data:byte;

    cena:byte;

    kol:word end;


Что бы создать переменную типа запись необходимо после имени переменной и двоеточия написать слово record, затем перечислить названия данных с указанием типов этих данных и написать слово end (которое закрывает список данных). Эти данные называют полями записи. В программе доступ к этим полям осуществляется следующим образом: пишется имя переменной, затем ставится точка и пишется название поля. Между названием переменной, точкой и именем поля можно поставить пробел, ошибки не будет, однако нагляднее, если пробела нет. Следующий пример продолжение предыдущего:


begin

  ovosh.name:='K';

  ovosh.sort:='1';

  ovosh.data:=352;

  ovosh.cena:=9;

  ovosh.kol:=354;

  Writeln('Овощ  сорт  дата поступления  цена  количество на базе');

  Writeln(ovosh.name:4,ovosh.sort:6,ovosh.data:18,

                                            ovosh.cena:6,ovosh.kol:20);

end.

_________________________________________________________________________

Овощ  сорт  дата поступления  цена  количество на базе

   K     1                96     9                 354


Теперь, умея пользоваться записями, можем создать массив записей. Для этого вначале объявим тип, а затем массив значений этого типа:


Type

  Ovosh = record

    name:char;

    sort:char;

    data:byte;

    cena:byte;

    kol:word end;

Var Ovoshi: array [1..5] of Ovosh;   

begin

  ovoshi[1].name:='K';

  ovoshi[1].sort:='1';

  ovoshi[1].data:=352;

  ovoshi[1].cena:=9;

  ovoshi[1].kol:=354;

  Writeln('Овощ  сорт  дата поступления  цена  количество на базе');

  Writeln(ovoshi[1].name:4,ovoshi[1].sort:6,ovoshi[1].data:18,

                                   ovoshi[1].cena:6,ovoshi[1].kol:20);

end.

_________________________________________________________________________

Овощ  сорт  дата поступления  цена  количество на базе

   K     1                96     9                 354


Как видите, в случае с большим количеством информации, данный подход предпочтительнее.

Стоит сделать небольшое отступление и сказать про переменную Ovoshi: такая структура информации называется базой данных. Причём каждый элемент массива называется записью, а name, sort, data, cena, kol называются полями записи. При постановке задачи, данная задача может звучать следующим образом: «Необходимо создать базу данных овощей на складе». Вообще тема баз данных достаточно обширная и должна занимать целую книгу. Здесь я сделал отступление для того, что бы вы имели представление, что это такое.

Поле записи может быть любого типа. Если поле записи является типом запись, то доступ к полям этой записи осуществляется с помощью ещё одной точки. Например:


Type

  Ovosh = record

   name:char;

   sort:char end;

  Cena = record

   rubl:word;

   kop:byte

    end;

Var

  Kartofel: record

   P1:Ovosh;

   P2:Cena;

   Kol:Word

    end;

Begin

  Kartofel.P1.name:='K';

  Kartofel.P1.sort:='1';

  Kartofel.P2.rubl:=9;

  Kartofel.P2.kop:=52;

  Kartofel.kol:=542;

end.


В большой программе этих точек может получиться огромное количество. Что бы сократить запись кода существует оператор присоединения With do. Далее на примере предыдущей программы будут продемонстрированы различные варианты использования этого оператора:


Begin

  With Kartofel do P1.name:='K';

  With Kartofel.P1 do sort:='1';

  With Kartofel.P2 do

    begin

     rubl:=9;

     kop:=52;

    end;

   With Kartofel do kol:=542;

end.



Множества.

Множество в Pascal это набор беспорядочных данных любого типа (который называется базовым). Всего переменная типа множества может содержать в себе 256 элементов, причём никаких порядковых номеров у этих элементов нет. Для того, что бы объявить переменную типа множества существует словосочетание set of, после которого следует название базового типа:


var

  d:set of integer;

 

Или:


Type

  m = set of integer

var

  d:m;


Для того, что бы «заполнить» множество используется оператор присваивания, причём элементы множества указываются через запятую в квадратных скобках. При этом возможно использование типа диапазон, т.е. указать начальное и конечное значения через две точки, тогда все значения, входящие в этот диапазон, будут принадлежать множеству. Пример:


   d:=[5,2,4..9];


Множество можно вывести на экран с помощью процедуры Write или Writeln:


begin

  d:=[5,2,4..9];

  write(d);

end.

________________

[2,4,5,6,7,8,9]


Обратите внимание, что при выводе на экран элементы располагаются в порядке возрастания, и что повторяющихся элементов нет.

Множество можно объявить как константу:


Const

   YN:set of char = ['Y','y','N','n'];


Для работы с множествами существуют следующие операции:

Операция сложения (объединение множеств). В результате сложения множеств получается новое множество, в котором присутствуют все элементы всех складываемых множеств, но в единственном экземпляре:


var

  M,m1,m2:set of integer;

begin

  m1:=[5,2];

  m2:=[5,6..8];

  M:=m1+m2+[1];

  write(M);

end.

_________________________

[1,2,5,6,7,8]


Далее пример как можно с помощью операции сложения заполнить множество из 10 элементов случайными числами:

var

  M:set of integer;

  i:byte;

begin

  for i:=1 to 10 do

  M:=M+[random(100)];

  write(M);

end.

______________________________

[2,11,25,35,44,45,65,72,84,94]


Операция вычитания (разность множества). В результате вычитания множеств получается новое множество, в котором присутствуют все элементы первого множества за исключением тех элементов, которые присутствуют во втором. Или другими  словами из первого множества убираются элементы, которые есть во втором множестве. Пример:


var

  M,m1,m2:set of integer;

begin

  m1:=[5,2];

  m2:=[5,6..8];

  M:=m1-m2-[7];

  write(M);

end.

__________________________

[2]


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


var

  M,m1,m2:set of integer;

begin

  m1:=[5,2];

  m2:=[5,6..8];

  M:=m1*m2;

  write(M);

end.

_________________________

[5]


Сравнение множеств. Множества можно сравнивать друг с другом. Множества считаются равными, если все элементы одного множества присутствуют в другом. Для сравнения используются знак равно (=) и знак не равно (<>):


var

  m1,m2:set of integer;

begin

  m1:=[5,2];

  m2:=[5,2];

  if m1 = m2 then Write('Множества равны друг другу')

    else Write('Множестав не равны друг другу.');

end.

_____________________________________________________

Множества равны друг другу


Проверка включения. Одно множество считается входящим в другое, если все его элементы содержатся в другом. Проверка включения проводится знаками больше либо равно (<=) или меньше либо равно (>=). Пример:


var

  m1,m2:set of integer;

begin

  m1:=[5,2];writeln('m1 = ',m1);

  m2:=[5,2,6..10];writeln('m2 = ',m2);

  if m1 <= m2 then Writeln('Множества m1 входит в множество m2')

    else Writeln('Множества m1 не входит в множество m2');

  if m1 >= m2 then Writeln('Множества m2 входит в множество m1')

    else Writeln('Множества m2 не входит в множество m1');

end.

________________________________________________________________

m1 = [2,5]

m2 = [2,5,6,7,8,9,10]

Множества m1 входит в множество m2

Множества m2 не входит в множество m1


Проверка принадлежности. Для того, что бы проверить принадлежит ли переменная или константа множеству существует логическая операция in. С помощью данной операции удобно производить контроль вводимых данных, например:


Const

  Y:set of char = ['Y','y'];

var c:char

begin

  While not (c in Y) do

   begin

    Writeln('Для выхода из программы нажмите Y');

    readln(c);

   end;

end.

__________________________________________________

Для выхода из программы нажмите Y

u

Для выхода из программы нажмите Y

y


В данном параграфе мы рассмотрели следующие структурированные типы данных: массивы, записи, множества. Научились ими пользоваться и узнали в каких случаях можно их использовать.


Задачи.

1. Перерешать 4-ую задачу из 9 параграфа используя массивы. Соответственно создать два массива значений и . Вначале заполнить их, а затем вывести их на экран. Значения этих массивов вывести в виде 5 столбиков по 10 строчек в каждом. Соответственно порядок вывода будет сверху вниз.

2. Перерешать предыдущую задачу с помощью одного массива используя тип запись.

3. Пользователь вводит с клавиатуры символ. Необходимо вывести на экран сообщение о том, что это за символ. Это может быть буква латинского или русского алфавита, в противном случае вывести сообщение, что символ не является буквой.

4. Создать два произвольных множества целых чисел с помощью функции random. Вывести их на экран. Определить являются ли они равными. Вывести на экран элементы, которые входят в оба множества.


Решение.

1.

Var M,w:array [1..60] of real;

    r:real;

    i:byte;

begin

  r:=62.83/60;

  For i:=1 to 60 do

   begin

     w[i]:=r*i;

     M[i]:=2*3202*(1+0.1143*0.065)/

       ((1-w[i]/62.83)/0.065+0.065/(1-w[i]/62.83)+2*0.1143*0.065);

   end;

  Write('  w       M       w       M       w       M       w');

  Writeln('M       w       M  ');

  for i:=1 to 12 do

    begin

      write(w[i]:5:2,' ',M[i]:7:2,'   ');

      write(w[i+12]:5:2,' ',M[i+12]:7:2,'   ');

      write(w[i+24]:5:2,' ',M[i+24]:7:2,'   ');

      write(w[i+36]:5:2,' ',M[i+36]:7:2,'   ');

      write(w[i+48]:5:2,' ',M[i+48]:7:2,'   ');

      writeln;

    end;

end.

_________________________________________________________________________


  w       M       w       M       w       M       w       M       w       M 

1.05  424.19   13.61  531.03   26.18  708.91   38.75 1060.79   51.31 2022.49  

2.09  431.43   14.66  542.40   27.23  729.20   39.79 1106.02   52.36 2173.01  

3.14  438.92   15.71  554.26   28.27  750.66   40.84 1155.12   53.41 2341.02  

4.19  446.68   16.75  566.65   29.32  773.40   41.89 1208.60   54.45 2526.42  

5.24  454.71   17.80  579.59   30.37  797.54   42.93 1267.02   55.50 2725.78  

6.28  463.04   18.85  593.14   31.42  823.20   43.98 1331.07   56.55 2928.12  

7.33  471.67   19.90  607.33   32.46  850.54   45.03 1401.53   57.59 3106.33  

8.38  480.63   20.94  622.21   33.51  879.72   46.08 1479.32   58.64 3200.98  

9.42  489.93   21.99  637.83   34.56  910.93   47.12 1565.53   59.69 3095.63  

10.47  499.60   23.04  654.25   35.60  944.38   48.17 1661.42   60.74 2603.88  

11.52  509.66   24.08  671.52   36.65  980.32   49.22 1768.43   61.78 1546.67  

12.57  520.13   25.13  689.72   37.70 1019.01   50.26 1888.20   62.83    0.00


2.

Type TMw = record

         M:real;

         w:real end;

Var Mw:array [1..60] of TMw;

    r:real;

    i:byte;

begin

  r:=62.83/60;

  For i:=1 to 60 do

   begin

     Mw[i].w:=r*i;

     Mw[i].M:=2*3202*(1+0.1143*0.065)/

        ((1-Mw[i].w/62.83)/0.065+0.065/(1-Mw[i].w/62.83)+2*0.1143*0.065);

   end;

  Write('  w       M       w       M       w       M       w');

  Writeln('       M       w       M  ');

  for i:=1 to 12 do

    begin

      write(Mw[i].w:5:2,' ',Mw[i].M:7:2,'   ');

      write(Mw[i+12].w:5:2,' ',Mw[i+12].M:7:2,'   ');

      write(Mw[i+24].w:5:2,' ',Mw[i+24].M:7:2,'   ');

      write(Mw[i+36].w:5:2,' ',Mw[i+36].M:7:2,'   ');

      write(Mw[i+48].w:5:2,' ',Mw[i+48].M:7:2,'   ');

      writeln;

    end;

end.


Результат работы программы тот же самый.


3.

Const lat:set of char = ['A'..'Z','a'..'z'];

      rus:set of char = ['А'..'Я','а'..'я'];

Var c:char;

begin

  Writeln('Введите символ.');

  readln(c);

  if c in lat then writeln('Вы ввели букву латинского алфавита.');

  if c in rus then writeln('Вы ввели букву русского алфавита.');

  if (not(c in lat))and(not(c in rus)) then

   writeln('Вы ввели символ не являющийся буквой');

end.

____________________________________________________________________

Введите символ.

П

Вы ввели букву русского алфавита.


4.

Var m1,m2,m3:set of integer;

    i,k:byte;

begin

  k:=random(20);

  for i:=1 to k do

    m1:=m1+[random(-100,+100)];

  k:=random(20);

  for i:=1 to k do

    m2:=m2+[random(-100,+100)];

  writeln('m1');

  Writeln(m1);

  writeln('m2');

  Writeln(m2);

  if m1=m2 then writeln('Множества получились одинаковыми.')

    else writeln('Множества получились не одинаковыми.');

  m3:=m1*m2;

  if m3<>[]then

    begin

      Writeln('В оба множества входят следующие элементы:');

      writeln(m3);

    end

   else writeln('Общих элементов в множествах нет.');

end.

_____________________________________________________________

m1

[-95,-87,-83,-77,-74,-71,-51,-43,-42,-32,-18,7,9,38,48,54,75,90]

m2

[-87,-86,-38,-37,-23,-15,4,8,63,64,75,77,87,91]

Множества получились не одинаковыми.

В оба множества входят следующие элементы:

[-87,75]




Предыдущий параграф Назад в содержание Следующий параграф