Грамматика языков программирования
Описанию грамматики языка предшествует описание его алфавита. Алфавит любого языка состоит из фиксированного набора символов, однозначно трактуемых. Алфавит языков программирования, как правило, связан с литерами клавиатуры печатной машинки. Клавиатуры персональных компьютеров близки к ним по наличию литер.
Алфавиты большинства языков программирования близки друг другу и основываются на буквах латинского алфавита, арабских цифрах и общепринятых спецсимволах, таких как знаки препинания, математических операций, сравнений и обозначений. Большинство популярных языков программирования в своем алфавите содержат следующие элементы:
<буква> : : = AaBbCcDdEeFf и т.д.
<цифра> ::=0123456789
<знак арифметической операции >::=*/+-
<разделитель> ::=.,;:()[]{}':=
<служебное слово> :: = begin end if then else for next и т.д.
<спецсимвол> :: = <знак арифметической операции> | <разделитель> |
<служебное слово>
<основной символ>::=<буква> | <цифра> | <спецсимвол>
<комментарий>::=<любая последовательность символов>
Несмотря на значительные различия между языками программирования, ряд фундаментальных понятий в большинстве из них схожи. Приведем часть этих понятии.
Оператор - одно из ведущих понятий всех языков программирования (теоретически, за исключением чисто декларативных; но в действительности и они используют родственное понятие). Каждый оператор представляет собой законченную фразу языка и определяет однозначно трактуемый этап обработки данных В соответствии с теорией алгоритмов выделяют основные (базисные) операторы языка: присвоения, условный и безусловный переход, пустой оператор. К производным, не основным, относят составной оператор, оператор выбора, оператор цикла и оператор присоединения.
Все операторы языка в тексте программы отделяются друг от друга явными или неявными разделителями, например:
Sl;S2;...;Sn
Операторы выполняются в порядке их следования в тексте программы. Лишь с помощью операторов перехода этот естественный порядок может быть нарушен.
Большая часть операторов ведет обработку величин.Величины могут бытьпостоянными и переменными. Значения постоянных величин не изменяются в ходе выполнения программы. Величина характеризуетсятипом, именем и значением.Наиболее распространенные типы величин - числовые (целые и вещественные), символьные, логические. Тип величины определяется ее значением.
Другая важная классификация величин - простые и структурированные. Простая величина в каждый момент может иметь не более одного значения. Ей соответствует одна ячейка памяти (поскольку термин «ячейка» несколько устарел, часто говорят «машинное слово») или ее эквивалент во внешней памяти компьютера. Структурированная величина, имея одно имя, может иметь разом несколько значений. Эти значения представляют собой элементы (компоненты) величины. Самый широкоизвестный пример - массив, у которого элементы различаются по индексам (номерам). Вопрос о структурировании величин - входных, выходных и промежуточных - для успеха решения прикладной задачи не менее важен, чем вопрос о правильном написании последовательности операторов.
Важнейшие характеристики структурированной величины таковы: упорядоченность (да или нет), однородность (да или нет), способ доступа к элементам, фиксированность числа элементов (да или нет). Так, массив является упорядоченной однородной структурой с прямым доступом к элементам и фиксированным их количеством.
Всем программным объектам в языках даются индивидуальныеимена. Имя программного объекта называют идентификатором (от слова «идентифицировать»). Чаще всего идентификатором является любая конечная последовательность букв к цифр, начинающаяся с буквы:
<идентификатор>::=<буква> | <идентификатор> | <буква>
<идентификатор><цифра>
Как правило, в большинстве языков программированияв качестве идентификатора запрещается использовать служебные слова языка.
Многим слово «идентификатор» не нравится, и в настоящее время чаще употребляют слово «имя», поскольку
<имя>::=<идентификатор>.
Программисты выбирают имена по своему усмотрению. Принципы выбора и назначения имен программным объектам естественны. Следует избегать мало выразительных обозначений, не гоняться за краткими именами. Имена должны быть понятны, наглядны, отражать суть обозначаемого объекта. Например,
Summa, Time, i, j, integral, init и т. п.
Некоторым идентификаторам заранее предписан определенный смысл и их называют стантартными, например, Sin - это имя известной математической функции.
Описания или объявления программных объектов связаны с правилами обработки данных. Данные бывают разные и необходимо для каждого из них определить его свойства. Например, если в качестве данных выступает массив, то необходимо задать его размерность, границы индексов, тип элементов массива. Описательная часть языка программирования является необходимой как для системных программистов - разработчиков трансляторов, которые должны, в частности, проводить синтаксическую и семантическую диагностику программ, - так и для «прикладного» программиста, которому объявления программныхобъектов частооблегчают процесс разработки и отладки программ.
В некоторых языках стандартные описания простых числовых и символьных данных опускают (описания по умолчанию), или в них задаются правила описания по имени объекта. Например, в Фортране переменные, имена которых начинаются с букв I, J, К, L, M, N, могут принимать целые значения (при отсутствии явного описания типа, которое возможно), т.е. определены как числовые данные целого типа. В Бейсике-MSX данные строкового типа присваиваются переменным, имена которых заканчиваются специальным символом $: A$, S1$.
Особый интерес представляют в языках программирования описания нестандартных структур данных, таких как запись, файл, объект, список, дерево и т.п.
Приведем список наиболее употребительных обозначений типов данных, используемых в описаниях:
Целый - Integer
Вещественный - Real
Логический - Boolean
Символьный - Char
Строковый - String
Массив - Array
Множество -Set
Файл - File
Запись - Record
Объект - Object
Переменные играют важнейшую роль в системах программирования. Понятие «переменная» в языках программирования отличается от общепринятого в математике. Переменная - это программный объект, способный принимать некоторое значение с помощью оператора присваивания. В ходе выполнения программы значения переменной могут неоднократно изменяться. Каждая переменная после ее описания отождествляется с некоторой ячейкой памяти, содержимое которой является ее значением. Синтаксис переменной, точнее, ее идентификатора, как правило, имеет вид:
<имя переменной>::=
——><буква>———>
—><буква>———>
—><цифра>——>
—><спецсимвол>
Семантический смысл переменной заключается в хранении некоторого значения. соответствующего ее типу (например, переменная целого типа может принимать значение произвольного целого числа), а также в выполнениис ней операций пересылки в нее и извлечения из нее этого значения.
Функция - это программный объект, задающий вычислительную процедуру определения значения, зависимого от некоторых аргументов. Вводится в языки программирования для задания программистом необходимых ему функциональных зависимостей. В каждом языке высокого уровня имеется в наличии библиотека стандартных функций: арифметических, логических, символьных, файловых и т.п. Функции -стандартные и задаваемые программистом - используются в программе в выражениях.
Выражения строятся из величин - постоянных и переменных, функций, скобок. знаков операций и т.д. Выражение имеет определенный тип, определяемый типом принимаемых в итоге его вычисления значений. Возможны выражения арифметические, принимающие числовые значения, логические, символьные, строковые и т.д. Выражение 5+7 является, несомненно, арифметическим, выражение А + В может иметь cамый разный смысл - в зависимости от того, что стоит за идентификаторами А и В.
Процедура - это программный объект, представляющий некоторый самостоятельный этап обработки данных. По сути, процедуры явились преемниками подпрограмм, которые были введены для облегчения разработки программ еще на самых ранних стадиях формирования алгоритмических языков. Процедура имеет входные и выходные параметры, называемые формальными. При использовании процедуры формальные параметры заменяются на фактические.
Модуль (Unit) -это специальная программная единица, предназначенная для создания библиотек и разделения больших программ на логически связанные блоки.
По сути, модуль - это набор констант, типов данных, переменных, процедур и функций. В состав модуля входят разделы: заголовок, интерфейс, реализация, инициализация.
Заголовок необходим для ссылок на модуль.
Интерфейс содержит объявления, включая процедуры и функции.
Раздел «реализация» содержит тела процедур и функций, перечисленных в интерфейсной части.
Раздел «инициализация»содержит операторы, необходимые для инициализации модуля.
Каждый модуль компилируется отдельно, и каждый элемент модуля можно использовать в программе без дополнительного объявления.
Контрольные вопросы и задания
1. Какие преимущества имеют языки программирования высокого уровняпосравнению с машинно-ориентированными языками?
2. Каковы основные составляющие языка программирования высокого уровня?
3. В чем различия понятий языков программирования от аналогичных понятий математического «языка»?
4. С какой целью используются и что представляют собой металингвистические формулы Бэкуса-Наура?
5. Что представляет собой синтаксическая диаграмма Вирта?
6. В чем различие между постоянными и переменными величинами? Чем характеризуется величина?
7. В чем принципиальная разница между величинами простыми и структурированными?
8. Для чего служит описание величин в программах?
9. В чем состоит назначение функций? процедур? модулей?
§3. ПАСКАЛЬ КАК ЯЗЫК
СТРУКТУРНО-ОРИЕНТИРОВАННОГО ПРОГРАММИРОВАНИЯ
ВВЕДЕНИЕ
Язык Паскаль, начиная с момента своего создания Н.Виртом в 1971 г., играет особую роль и в практическом программировании, и в его изучении. С непревзойденной четкостью в нем реализованы принципы структурного программирования, которые мы рассматривали в п. 1.8. Паскаль стал первым языком, с которым знакомится большинство будущих программистов в мире.
Трансляторы для программ, написанных на Паскале, разработаны для различных компьютеров и в настоящее время имеют множество разновидностей. Они являются компиляторами, обрабатывающими разработанные программистами тексты программ.
Существует много версий языка Паскаль. Различия между ними порой весьма велики. Так, базовая версия Вирта имеет многократно меньшие возможности чем, скажем, версия Турбо-Паскаль 7.0 (первая, фактически - язык для обучения будущих программистов, а вторая - орудие профессиональных разработчиков прикладного программного обеспечения). Тем не менее, это версии одного языка, что, в частности, подтверждается их совместимостью «сверху вниз», т.е. любая программа, соответствующая «младшей» версии, соответствует и «старшей» (за исключением малозначащих синтаксических оговорок). Приведенные ниже тексты программ и примеры соответствуют (если нет специальных оговорок) версиям не ниже Турбо-Паскаль 3.0.
Любая Паскаль-программа является текстовым файлом с собственным именем и с расширением .pas. Рассмотрим в качестве примера текст программы 1 решения квадратного уравнения. Паскаль-программа имеет вид последовательности символов латинских и русских букв, арабских цифр, знаков операции, скобок, знаков препинания и некоторых дополнительных символов. В ней можно выделить описания данных и операторы, описывающие действия, которые надо выполнить машине над этими данными.
Программа I
program KvadUravn; (заголовок программы)
var (список переменных)
а,b,с: real; (коэффициенты уравнения)
d,xlx2: real; (вспомогательные переменные)
begin (начало программы)
writein; (пропуск строки на экране)
writein('введи a,b,c'); read(а,Ь,с); (ввод данных)
d:=b*b-4*a*c; (дискриминант)
if d<0 then (если d<0, то)
write('корней нет') (печатать)
else (иначе)
begin (начало серии команд)
xl:=(-b+sqrt(d))/(2*a);
x2:=(-b-sqrt(d))/(2*а); (вычисляем корни)
write('х1=',х1,' х2=',х2) (печать корней)
end (конец серии)
end.(конец программы)
Схематически программа представляется в виде последовательности восьми разделов:
1) заголовок программы;
2) описание внешних модулей, процедур и функций;
3)описание меток;
4) описание констант;
5) описание типов переменных;
6) описание переменных;
7) описание функций и процедур;
8) раздел операторов.
Не в каждой программе обязательно присутствуют все восемь разделов, в простейшей программе, например, могут быть только 5-й и 8-й разделы.
Каждый раздел начинается со служебного слова, назначение которого зафиксировано в Паскале так, что его нельзя употреблять для других целей (список и перевод служебных слов дан в Приложении).
Рассмотрим пример программы 2, вычисляющей длину окружности и площадь круга по данному радиусу.
Программа 2
program circle;
const
pi=3.14159;
var
r,s,1 : real;
begin
writeln (введите радиус'); readln(r);
s:=pi*r*r; l:=2*pi*r;
writeln('площадь круга=',S:8:4); writeln('длина окружности=', l:8:4)
end.
В этой программе можно выделить четыре раздела. Описание заголовка начинается со служебного слова program, описание констант - const, описание переменных -var, раздел операторов начинается с begin. Программа заканчивается служебным словом end, после которого ставится точка. Описания величин и операторы друг от друга отделяются знаком «точка с запятой».
Для обозначения величин используются имена. Они составляются из латинских букв и цифр, причем первым символом должна быть буква. В примере использованы имена величин - pi, r,s и 1.
Имя программы (в примере - circle) выбирается автором и составляется по такому же правилу.
Постоянные величины (константы) чаще всего бывают числовыми или символьными (но могут быть и других типов, о которых речь пойдет ниже). Значения символьных констант заключаются в апострофы.
Постоянные величины описываются в разделе констант по схеме:
const <имя> = <константа>
В разделе констант может быть описано несколько постоянных величин.
Например:
const
pi=3.14159; k=-15; s='площадь';
Данные, обрабатываемые программой, могут быть разных типов (числа, символы, строки, массивы и т.д.). Тип определяет область допустимых значений, а также операции и функции, применяемые к величинам этого типа. В Паскале имеется несколько встроенных простых типов со стандартными именами.
Группа типов, значения каждого из которых можно перечислить в некотором списке- скалярные типы. Для них определена порядковая функция ord(x) - номер значения х в списке (для целочисленного х ord(x)=x); функции pred(x) - значение в списке, предшествующее х, и suce(x) - значение в списке, следующее за х.
Упорядоченный тип - это тип, значения которого упорядочены в обычном смысле. К данным такого типа применимы операции отношения <,>, <= (меньше или равно), >=(больше или равно), =, <> ( не равно). Для логического типа выполняется неравенство:
false < true.
Переменные описываются в разделе описания переменных посхеме:
var <список имен переменных>: <тип>
Имена в списке разделяются запятой. В этом разделеможет быть описано несколько переменных разного типа, например:
var a,b,c:real; k,l:integer; p:boolean;
Надцелыми величинами (тип integer) определены арифметические операции : * (умножение), div (деление нацело), mod (вычисление остатка от деления), + , -(сложение и вычитание); операции перечислены в порядке старшинства.
Например: 25 div 4 = 6 ; 25 mod 4=1. Целый результат дают некоторые стандартные функции (аргумент функции заключается в круглые скобки):
abs(x) - абсолютная величина целого х;
sqr(x) -квадрат значения х;
trunc(x) - целая часть вещественной величины х;
round(x) - целое число, полученное из вещественного х по правилу округления;
random(x) - случайное целое числоиз интервала от 0 до х.
Например: trunc(4.7)=4 ; round(4.7)=5 ; sqr(3)=9 . Для данных типа byte определены те же операции и функции, что и для данных типа integer.
Над вещественными величинами определены операции: *, +, -, /, а также стандартные функции при вещественном или целом аргументе: abs(x), sqr(x), sin(x), cos(x), arctan(x), ln(x), exp(x), sqrt(x) - квадратный корень из х, int(x) - целая частьизх, random - случайное число из интервала от 0 до 1. Указанные операции и функции дают вещественный результат.
Надлогическими величинами определены операции: not - отрицание, and -конъюнкция, or-дизъюнкция. Логическая функция odd(x) принимает значение true, если целочисленное х является нечетным и false , если четным.
Множество всех символов образуютсимвольные величины (тип char), которые являются упорядоченными, причем 'А' < 'В'< 'С'<...< 'Z', 'а' < 'b'<...< 'z', '0' < 'I'<...< '9'.
Выражения - это конструкции, задающие правила вычисления значений переменных. В общем случае выражения строятся из переменных, констант, функций с помощью операций и скобок.
Эта роль выражений отражена в основном операторе языка - операторе присваивания. Он имеет следующий вид:
<имя переменной> := <выраженне>
Тип переменной и тип выражения должны быть согласованы (величины принадлежат одному и тому же типу). Есть исключение: имя переменной может относиться к типу real, а значение выражения - к типу integer.
Примеры.
l:=2*pi*r; p:=(a+b+c)/2; z:=sqrt(sqr(x)+sqr(y))
В Паскале можно вводить с клавиатуры числовые и символьные данные. Имеются две встроенные процедуры (подпрограммы) ввода:
1) read(<cписок переменных>); 2) readln(<cписок переменных>).
При выполнении процедуры read(xl,x2,...,xN) программа прерывается и компьютер ждет ввода с клавиатуры N значений переменных из списка х1, х2,..., xN. Эти значения - константы соответствующих типов - должны при вводе разделяться пробелами. Набор данных завершается клавишей ввода.
Процедура readin отличается от read только тем, что при завершении ввода курсор перемещается в начало следующей строки.
Пример.
var a,b:real; c:char; d:integer;
...
read(a,c,d,b);
...
Допустимый ввод: 83.14 k 200-7.15
Программа на Паскале может выводить на экран или на принтер значения числовых или символьных выражений. Имеются две процедуры вывода на экран:
1) write(<cписок выражений>); 2) writeln(<cписок выражений>).
Процедура write(xl,x2,...,xN) печатает на экране значения выражений из списка х1, х2, ..., xN. Процедура writeln отличается от write тем, что переводит курсор в начало следующей строки. Для вывода на принтер используются те же процедуры с добавлением служебного слова 1st перед списком выражений.
Пример: write(lst,'нет решений');
На бумаге будет напечатан текст «нет решений».
Для управления печатью используютсяформаты данных. Пусть х - переменная типа real. Если не использовать форматы, то значение х будет выводиться в «плавающей» форме (типа 1.654887892Е-04). Форматы позволяют напечатать вещественное число в естественной форме. Пусть m, n - целые числа. Процедура write(x:m:n) выводит на экран значение переменной х в виде десятичной дроби, причем m определяет общее число выводимых символов, включая цифры, точку и знак числа, n - количество цифр после точки. Если количество выводимых символов меньше m, то перед числом добавляются пробелы.
Пусть, например, х = 387.26. Следующая таблица демонстрирует влияние форматов на вывод значения х:
оператор строка вывода
writeln('*',x) * 3.8726000000E+02
writeln('*',x:8:3) * 387.260
writeln('*',x:8:l) * 387.3
Один формат - ширину поля вывода - можно использовать и для вывода значений выражений типов integer, boolean, char.
Контрольные вопросы
1. Какова последовательность разделов в программе на Паскале?
2. Какие типы данных называются скалярными? упорядоченными?
3. Какие действия допустимы над величинами целого типа? вещественного типа?
4. Как в Паскале осуществляется ввод и вывод данных?
ОСНОВНЫЕ КОНСТРУКЦИИ ЯЗЫКА
Паскаль - язык структурного программирования. Это означает, что программист должен выражать свои мысли очень дисциплинированно, с использованием малого числа четко оговоренных конструкций, используя как чередование их, так и вложения друг в друга. Не рекомендуется (хотя и возможно) использовать оператор перехода goto.
Реализация последовательности действий (т.е. структуры следования) выполняется с помощью составного оператора:
begin <последовательность операторов> end
Раздел операторов в программе всегда является составным оператором. Служебные слова begin и end часто называют операторными скобками.
Для реализацииразвилки в Паскале предусмотрены два оператора: условный оператор и оператор варианта (выбора). Они предназначены для выделенияизсоставляющих их операторов одного, который и выполняется.
Структура и действиеусловного оператора таковы:
If <логическое выраженне>
then <оператор 1>
else <оператор 2>
Условный оператор может быть неполным,т.е. не содержать часть «else <оператор 2>». В этом случае, если значение логического выражения равно false, условный оператор не вызывает никаких действий.
Пример: составим программу, которая определяет длину общей части двух отрезков числовой оси, заданных координатами своих концов соответственно а, b и с, d (а < b, с < d). Если отрезки имеют общую часть, то левая координата общей части отрезков m равнамаксимальному из чисел а и с, а правая n - минимальному из чисел b и d.
Программа 3
program cross;
var a,b,c,d,m,n,l:real;
begin
writeln('введите координаты концов отрезков') ;
read(a,b,с,d) ;
writeln;
if a<c then m:=c else m:=a;
if b<d then n:=b else n:=d;
if m<n then l:=n-m else 1:=0;
writeln("длина общей части отрезков=',1:6:2)
end.
Оператор варианта имеет следующую форму:
case <выражение> of
<список констант 1> : <оператор 1>;
<список констант 2> : <оператор 2>;
…………………………
<список констант N> : <оператор N>
end.
Выражение, стоящее между служебными словами case и of, должно иметь значение ординального типа. Любой список констант может состоять из одной константы.
Оператор варианта вычисляет значение выражения, записанного после case. Если его значение совпадает с одной из констант в некотором списке, то выполняется оператор, стоящий после этого списка. Если значение выражения не совпало ни с одной константой во всех вариантах, то оператор варианта ничего не делает.
В качестве примера приведем программу, которая в зависимости от номера месяца выдает сообщение о времени года.
Программа 4
program seasons;
var k:integers
begin
writeln('введите номер месяца') ;
readin(k);
case k of
1,2,12:writeln('зима');
3, 4,5:writeln('весна') ;
6, 7,8:writeln('лето');
9,10,11:writeln('осень')
end
end.
Для реализации циклов в Паскале имеются три оператора Если число повторений известно заранее, то удобно воспользоваться оператором цикла с параметром. В других случаях следует использовать операторы цикла с предусловием (цикл «пока» ) или с постусловием (цикл «до»).
Цикл с предусловием является наиболее мощным в Паскале. Другие операторы цикла можно выразить через него. Его форма такова:
while - <логическое выражение> do <оператор>
Действие: вычисляется значение логического выражения. Если оно равно true, то выполняется оператор, после чего снова вычисляется значение логического выражения, в противном случае действие заканчивается.
В качестве примера использования такого цикла решим следующую задачу. На склад привозят однородный груз на машинах различной грузоподъемности. На компьютер, управляющий работой склада, поступает информация о весе груза очередной машины. Составить программу подсчета количества машин,прибывшихна склад до его заполнения, если вместимость склада не более 100 тонн.
Введем обозначения: sum - сумма веса груза, хранящегося в этот момент на складе; num - число разгруженных машин; w - масса груза очередной машины. Вначале величины sum и num равны нулю. Цикл разгрузки продолжается, пока выполняется неравенство sum < 100.
Программа 5
program store;
var sum,w:real;
num:integer;
begin
num:=0;sum:=0;
while sum<100do
begin
writeln('введите вес груза машины');
readln(w);
sum:=sum+w;
if sum<=100 then num:=num+l
else writeln('груз уже не поместится')
end;
writeln('число разгруженных машин =',num;3)
end.
Операторцикла с постусловием имеет форму:
repeat <последовательность операторов>
until <логическое выражение>
Действие: выполняется последовательность операторов. Далее вычисляется значение логического выражения. Если оно равно true, то действие заканчивается, в противном случае снова выполняется последовательность операторов и т.д.
Решим предыдущую задачу, применяя цикл с постусловием. Цикл разгрузки заканчивается, если выполняется условие: sum > 100.
Программа 6
program store2;
var sum,w:real; man:integer;
begin
num: =0; sum: =0;
repeat
writeln('введите вес груза машины');
readln(w); sum:=sum+w;
if sum<=100 then num:=num+l .
else writeln('груз ухе не поместится')
until sum>=100;
writeln('количество разгруженных машин =',num:3)
end.
Операторцикла с параметром предусматривает повторное выполнение некоторого оператора с одновременным изменением по правилу арифметической прогрессии значения управляющей переменной (параметра) этого цикла. Оператор цикла с параметром имеет две формы.
Форма1:
for <параметр>:= <выражение1> to <выражение 2> do <оператор>
Параметр, выражение 1, выражение 2 должны быть одного ординального типа;
Параметр в этом цикле возрастает. Действие эквивалентно действию следующего составного оператора:
begin
<параметр>:=<выражение 1>;
while <параметр> <= <выражение 2> do
begin
<оператор>;
<параметр>:=suсс(<параметр>)
end
end.
Если в этом описании отношение <= заменить на >= , а функцию succ на pred, то параметр в цикле будет убывать, в этом случае цикл с параметром принимает форму 2.
Форма 2:
for <параметр>:=<выражение 1> downto <выражение 2> do <оператор>
Пример: составим программу, по которой будет напечатана таблица перевода километров в мили (1 миля = 1,603 км). Параметром цикла можно считать целую величину k - количество километров. Пусть эта величина изменяется от 1 до 10 (с шагом 1, разумеется).
Программа 7
program mili;
const a=1.603;b='км'; с='мили';
var k:integer; m:real;
begin
writeln(b:5,c:7); writeln;
for k:=l to 10 do
begin
m:=k/a; writeln(k:5,m:6:3)
end
end.
Запишем в этой программе цикл с параметром в форме 2:
for k:=10 downto 1 do
begin
m:=k/a; writeln(k:5,m:6:3)
end.
Тогда значения k в таблице будут убывать от 10 до 1 с шагом 1.
Контрольные вопросы
1. Как в Паскале реализуется развилка?
2. В чем различие в назначениях условногооператора и оператора варианта? Как реализуется оператор варианта?
3. Какого типа циклы реализуются в языке Паскаль? каким образом?
СТРУКТУРЫ ДАННЫХ
Мы уже познакомились с простыми типами real, integer, boolean, byte,char.
В Паскале программист по своему желанию может определить новый тип путем перечисления его элементов - перечисляемый тип, который относится к простым ординальным типам.
Описание перечисляемого типа выполняется в разделетипов по схеме:
type <имя типа> = <список имен>
Примеры:
type operator = (plus,minus,multi, divide);
color = (white,red,blue,yelow,purple,green);
В списке должно быть не более 256 имен.
Поскольку перечисляемый тип относится к ординальным, то к его элементам можно применять функции ord(x), pred(x), succ(x) и операции отношения. Отметим, что данные этого типа не подлежат вводу и выводу с помощью функций ввода/вывода и могут использоваться внутри программы для повышения ее читабельности и понятности.
Для иллюстрации работы с перечисляемыми типами приведем программу 8, переводящую английские названия дней недели на русский язык.
Программа 8
programweek;
type days=(mon,tue,wed,thu,fri,sat,sun);
var d:days;
begin
for d:=mon to sun do
case d of
mon: writeln("понедельник");
tue writeln("вторник");
wed writeln("среда");
thu writeln("четверг");
fri writeln("пятница");
sat writein("суббота") ;
sun writeln("воскресенье")
end
end.
Интервальный тип - это подмножество другого уже определенного ординального типа, называемого базовым. Интервал можно задать в разделе типов указанием наименьшего и наибольшего значений, входящих в него и разделяющихся двумя последовательными точками, например:
type days=(mon,tue,wed,thu,fri,sat,sun);
workday s=mon.. fri;
index=1..30;
letter='a'..'z';
Можно задать интервал и в разделе переменных:
vara:1..100;b:-25..25;
Операции и функции - те же, что и для базового типа. Использование интервальных типов в программе позволяет экономить память и проводить во время выполнения программы контроль присваиваний.
Пример: если k - номер месяца в году, то вместо описания
var k:integer;
можно написать
vark:1..12;
Интервальный тип тоже относится к простым ординальным типам.
СОСТАВНЫЕ СТРУКТУРЫ. Данные, с которыми имеет дело ЭВМ, являются абстракциями некоторых реальных или существующих в воображении людей объектов. Мы уже познакомились с некоторыми типами данных: стандартными, перечислимыми, интервалами. Этими типами можно было обойтись при решении простых задач. Однако естественно и часто очень удобно группировать однотипные данные в последовательности - массивы, строки символов, объединять разнотипные данные об одном и том же объекте в виде записей. Значительные удобства представляются пользователю в Паскале при организации однотипных величин в виде множества с соответствующим набором операций: объединения, пересечения и т.д. Наконец, последовательность однотипных величин переменной длины можно представить в Паскале в виде файла данных и хранить на внешних носителях, используя его в разных программах.
Таким образом, подобно составному оператору, содержащему несколько других операторов, составные типы образуются из других типов, при этом существенную роль играет метод образования или структура составного типа.
Часто используемый составной тип - массив. Массив - это последовательность, состоящая из фиксированного числа однотипных элементов. Все элементы массива имеют общее имя (имя массива) и различаются индексами. Индексы можно вычислять, их тип должен быть ординальным. При описании массивов используются служебные слова array и of. В описании массива указывается тип его элементов и типы их индексов.
Схема описания такова:
type <имя типа> = array [<список типов индексов>] оf <тип элементов>
Тип элементов - произвольный, он может быть составным. Число типов индексов называется размерностью массива. После описания типа массива конкретные массивы можно задать в разделе описания переменных.
Например:
type vector = array [1.. 10] of real;
table = array ['A'..'Z',1..5] of integer;
var a,b : vector;
с: table;
Обращение к элементу массива осуществляется с помощью задания имени переменной, за которым следует заключенный в квадратные скобки список индексов элемента.
Например:
а[7]:=3.1; b[k*k+l]:=0; с['М',3]:=-14;
Если массивы имеют одно и то же описание, то во многих версиях Паскаля допустимо их копирование, например b:=а;
Описание массива можно совместить с описанием соответствующих переменных:
var a,b : array [1.. 10] of real;
d : array [byte] of char;
В Турбо-Паскале разрешена инициализация начальных значений составных переменных с помощью, так называемых, типизированных констант. Типизированные константы используются как переменные того же типа. Их применение экономит память, однако они не могут быть использованы для определения других переменных того же типа.
Схема описания констант массива:
const <имя массива>: <тип массива> = (<список значений элементов>)
Тип массива может быть описан ранее:
type digits = array [1 ..5] of char;
const a : digits =('0';2','4';6';8');
Пример: используя массив, составим программу, которая напечатает на экране 20 чисел Фибоначчи.
Последовательность Фибоначчи определяется равенствами
а[1]=а[2]=1; a[k]=a[k-l]+a[k-2] прик>2.
Использование массива позволяет создать эффективную программу. Для вывода каждого члена последовательности отведем на экране 5 позиций.
Программа 9
program fibon; "''
const n=20;
var a: array[l..n] of integer;
k: integer;
begin
a[l]:=l;a[2]:=l;
for k:=3 to n do a[kl:=a[k-l]+a[k-2];
for k:=l to n do write(a[k]:5);
writeln
end.
Рассмотрим часто встречающуюся задачу упорядочения членов числовой последовательности по какому-либо признаку.
Пример: упорядочить члены числовой последовательности по возрастанию.
Используем метод упорядочения, носящий имя «пузырек». Будем просматривать пары соседних элементов последовательно справа налево и переставлять элементы в
паре, если они стоят неправильно:
5,3,2,4,1 → 5,3,2,1,4 → 5,3,1,2,4 →5,1, 3,2,4 → 1,5,3,2,4
В начале просмотра присвоим некоторой логической переменной значение true:
p:=true; если при просмотре пар была хотя бы одна перестановка, изменим значение логической переменной на противоположное: p:=false; это означает, что последовательность еще не была упорядочена и просмотр пар надо повторить. Цикл просмотров заканчивается, если после очередного просмотра выполняется условие: p=true. Последовательность зададим в программе как константмассивиз 10 элементов - целых чисел.
Программа 10
program bubble; '
const a:array[l..10] of integer=(19,8,17,6,15,4,13,2,11,0);
var b,i:integer; p :boolean;
begin c1rscr;
for i:=l to 10 do write(a[i]:3);writeln;writeln;
repeat p:=true;
for i:=10 downto 2 do
if a[i]<a[i-l]
then begin
b:=a[il;a[i]:=a[i-l]; ali-1]:=b;p:=false
end
until p=true;
for i:=l to 10 do write(a[i]:3);
writeln
end.
Обработка элементов двумерных массивов (матриц) обычно выполняется с помощью двойного цикла. Один цикл управляет номером строки, другой - номером столбца.
При решении задач на ЭВМ часто возникает необходимость в использовании последовательностей символов. Такую последовательность можно описать как массив символов, однако в Паскале для таких целей имеется специальный тип - string[n] -строка из n символов, где n <= 255. Способы описания переменных - строк - аналогичны описанию массивов.
1. Строковый тип определяется в разделе описания типов, переменные этого типа - в разделе описания переменных:
type word : string[20];
var a,b,c : word;
2. Можно совместить описание строкового типа и соответствующих переменных в разделе описания переменных:
var a,b,c : string[20];
d : string[30];
3. Можно определить строковую переменную и ее начальное значение какконстант-строку:
const l:string[l 1]='информатика';
Символы, составляющие строку, занумерованы слева направо; к ним можно обращаться с помощью индексов, как к элементам одномерного массива.
Для переменных одного строкового типа определен л