Демидов Основы программирования в примерах на языке ПАСЦАЛ 2010
.pdfной, например к числу с плавающей запятой. Если преобразование невозможно, возникает ошибка времени выполнения.
Система вывода передаёт на экран дисплея последовательность символов. При выводе значения числовой переменной происходит обратное преобразование числа в строку.
Впримере для ввода данных используется процедура readln, а для вывода текста и значений переменных – процедуры write и writeln стандартной библиотеки.
Вчём же заключается работа программиста с точки зрения пользователя?
Операторы и операции позволяют выполнять некоторые действия над данными. Обращение к данным происходит, так или иначе, через переменные. Таким образом, задача программиста состоит в том, чтобы обеспечить сбор данных от пользователя, преобразовать их и выдать пользователю результат на основе конечных значений переменных.
Понятие блока и замечания по стилю
Для удобства восприятия текста программы человеком принято структурировать программу – разделять на независимые блоки и подчёркивать вложенность блоков друг в друга с помощью отступов от начала строки. Блок представляет собой последовательность инструкций, логически связанных между собой и выполняющих в совокупности относительно независимый участок работы. Принято выделять блоки с помощью составного оператора begin end.
В приведённом примере код структурирован и снабжён комментариями. Таким образом, подчёркнута структура программы, что также облегчает её понимание. Обратите внимание на то, как названы типы и переменные, как подобраны ключевые слова. Из названий можно сделать некоторые выводы о назначении обозначаемой сущности, а ведь это сильно облегчает понимание программы. Возьмём за правило выбирать осмысленные идентификаторы для вводимых типов, переменных, функций. В противном случае разобраться в программе с такими идентификаторами, как asdf, vv12, type2 и fff4, будет невозможно. В сообществах программистов существуют негласные стилистические правила именования.
Сравните:
program mypr; var M,N: integer;
21
function f(M,N: integer): boolean; var K, bb: integer;
a: Boolean; begin
a := false;
if N > M then K := M else K := N; for bb := 2 to K do
a := a or (N mod bb = 0) and (M mod bb = 0); f := a;
end; begin
readln(N); readln(M);
if f(M,N) then writeln(M, ' and ', N, ' are not coprime.') else writeln(M, ' and ', N, ' are coprime.');
end.
Возьмём за правило структурировать программы.
Синтаксис
Основные строительные элементы программы для типового операторного языка рассмотрены. Пришло время взглянуть на сам язык с точки зрения его лексики, грамматики, правил орфографии и пунктуации, которые будем называть синтаксисом.
def. Алфавит – множество допустимых символов языка программирования.
Подробно алфавит описан в обширной литературе по языку Паскаль, здесь же приведены лишь основные сведения. Алфавит языка Паскаль включает прописные и строчные латинские буквы, арабские цифры и специальные символы. Из букв, цифр и знака подчеркивания строятся идентификаторы. Спецсимволами являются ключевые слова, знаки операций, знаки пунктуации, разделители. Идентификаторы не должны совпадать со спецсимволами.
Впримере использованы следующие ключевые слова:
для операторов – begin, end, if, then, else, for, to, do;
встроенные логические и арифметические операции – or, mod, and;
другие – program, var, function.
Впримере использованы следующие знаки пунктуации:
; отделяет операторы, объявления;
:отделяет переменную от ее типа;
, отделяет элементы списка друг от друга;
=логическая операция равенства;
22
( ) круглые скобки, обрамляющие списки параметров или выражения;
:= оператор присваивания; > операция сравнения «больше»;
// однострочный комментарий;
'апостроф (обрамляет строку);
. конец программы, а также отделение целой и дробной части числа, отделение записи и поля записи.
Разделителями являются пробел, управляющие символы, комментарии.
Общая структура программы на языке Паскаль
Программа coprimes включала следующие разделы:
заголовок программы (program);
раздел объявления переменных (var);
раздел процедур и функций (procedure/function);
тело программы (begin … end.).
Также в программе могут присутствовать:
раздел объявления констант (const);
раздел объявления типов данных (type);
раздел объявления используемых модулей (uses);
раздел объявления меток (label).
Кроме заголовка и тела программы разделы могут повторяться. Тело программы является обязательным разделом.
Таким образом, минимальная программа на Паскале выглядит следующим образом:
begin end.
А программа, печатающая на дисплее приветствие, выглядит так:
begin
writeln("Hello world!"); end.
В языке Паскаль принят следующий подход: сначала необходимо сделать объявления переменных, типов и только затем исполь-
23
зовать. В языке C++ переменные можно объявлять по ходу программы, но также до их использования.
Встроенные, определяемые и типизированные константы
Константы именуются для удобства. Например, чтобы не писать каждый раз число Пи до 7-го знака, можно определить его один раз
ввиде константы с нужной точностью и обращаться к ней по имени.
Удобно объявлять в виде констант предельные значения, например границы массивов. Этот приём минимизирует число правок
висходном тексте программы при необходимости изменить какоелибо предельное значение.
Константы определяются с помощью ключевого слова const. Если при определении константы указывается её тип, то она становится типизированной и может играть роль переменной, отличие от обычных переменных только в том, что она инициализирована, т.е. ей присвоено начальное значение:
const
//константы pi и e – определены в модуле Math pi = 3.14159;
max = 16;
//объявление типизированной константы (переменной) k: integer = 89;
var
a,b: array[1..max] of real; i: integer;
begin
for i:=1 to max do begin a[i] := pi*i;
b[i] := a[i]*pi; end;
end.
Роль типизации в операторных языках
Далее рассмотрим способы представления данных, их типы и переменные. Как уже говорилось, тип данных – поименованное множество значений, допускающее определённые действия над значениями. Помимо множества значений тип определяет:
множество допустимых операций;
множество допустимых преобразований в другие типы;
внутреннюю структуру хранения данных.
24
Какие проблемы решают с помощью типизации? Типы данных имеют огромное значение при проектировании программ, играют большую роль при компиляции и во время исполнения программы.
Проектирование. Как показал опыт программирования, разные типы данных по-разному эффективны для разных задач: одни типы данных хороши для хранения (компактны), другие – для поиска (организованы), третьи – для проведения вычислений и т.п. Таким образом, типы данных во многом определяют способы обработки данных и общее быстродействие программы, а значит, конструировать типы данных в отрыве от задачи недальновидно. Поэтому при проектировании типы данных разрабатываются с учётом алгоритмов их последующей обработки.
Компиляция. Человеку свойственно ошибаться. Типы данных помогают компилятору минимизировать ошибки в программе до её исполнения. При компиляции осуществляется сверка типов переменных и присваиваемых им значений. Если присваивается выражение, то тип выражения определяется на основе типов его аргументов и использованных операций. Кроме того, осуществляется проверка допустимости аргументов операций, например, строки нельзя умножать, а массивы сравнивать.
Исполнение. В объектно-ориентированном программировании во время выполнения программы используется механизм динамического определения типа объекта для вызова полиморфных методов класса.
Здесь следует отметить, что введение типов в язык программирования оборачивается и увеличением сложности построения программ, а также снижением гибкости. Языки сценариев, как правило, являются нетипизированными, что делает их лёгкими для освоения и использования, но всё же менее производительными.
Введение в типы данных
Какие типы данных используются в программировании? Типы данных можно условно разделить на несколько групп: простые, структурированные, процедурный тип и указатели. К простым относятся числовые типы (целые, вещественные), логический, перечисляемый, строковый (в зависимости от языка программирования строка может являться простым типом, как в языке Паскаль, а может быть разновидностью массивов, как, например, в Си).
25
К структурированным типам данных относятся массивы, записи, классы, файлы, множества.
Процедурный тип определяет число и тип аргументов процедуры (функции); значениями данного типа являются соответственно процедуры или функции. Этот тип играет большую роль в собы- тийно-ориентированном программировании.
Механизм указателей позволяет оперировать адресами участков памяти, в которых размещаются значения переменных, как значениями особого типа. Это важнейший механизм для построения динамических структур данных в частности в объектноориентированном программировании.
Как задаются множества значений типа? С точки зрения математики множество значений типа можно задать двумя способами: перечислив все возможные значения или указав способ получения всех значений. С точки зрения операторного языка программирования множество значений типа данных определяется в основном внутренним представлением значений в памяти ЭВМ и механизмами контроля типов.
Множество значений простого типа определяется способом внутреннего представления. Так, для целых чисел с шагом 1 максимальное число определяется как 28*N, где N – число байт, отводимое для представления числа в ЭВМ с двоичной системой счисления. Если требуется хранить знак числа, то для этого отводится один бит, что в два раза уменьшает диапазон допустимых чисел. Если требуется хранить число с плавающей запятой, то часть памяти отводится под мантиссу, а часть – под порядок числа. Таким образом, числа с плавающей запятой имеют разную точность представления. Множество значений строкового типа определяется алфавитом языка и максимальной длиной строки, зависящей от внутреннего представления.
Множество значений структурированного типа есть декартово произведение множеств значений типов элементов, составляющих структурированный тип.
Как определяются новые типы данных? Они определяются с помощью встроенных механизмов определения типов и встроенных (стандартных) типов данных. Встроенные механизмы определения типов позволяют определять новые структурированные типы данных. Для каждой группы структурированных типов имеется свой механизм – своего рода метатип, который нужно конкретизи-
26
ровать для построения нового типа. Например, для определения массива необходимо сначала определить тип элементов массива, а для определения записи необходимо определить структуру записи
– набор типизированных полей записи.
Целые и вещественные встроенные типы, как правило, зависят от длины машинного слова в битах (разрядности ЭВМ), например 8, 16, 32, 64. Машинное слово целиком помещается в регистры процессора, а значит, обрабатывается быстро и просто.
Полезным свойством типизированных переменных является то, что с помощью оператора присваивания на основе информации о типе можно создавать копии значений переменной, поскольку известен размер памяти, занимаемый значениями. Как следствие, значения переменных структурированных типов (массивы или записи) можно копировать без поэлементного присваивания. При работе с указателями следует иметь в виду, что в случае присваивания создаётся лишь копия адреса области памяти, а не собственно области памяти.
В Java механизм указателей отсутствует, однако возможность создавать динамические структуры данных имеется: в момент присваивания создаётся копия области памяти, в которой размещается динамическая структура. В Object Pascal работа с динамическими массивами возможна без применения указателей.
27
Глава 3. Типы данных языка Паскаль
Рассмотрим типы данных языка:
1)простые типы данных;
2)указатели;
3)структурированные типы данных;
4)процедурный тип.
Некоторые типы уже встроены в язык и не требуют объявления, их называют стандартными или встроенными типам данных. Все остальные типы необходимо объявлять с помощью специальных конструкций.
Квстроенным типам относятся:
простые целые и вещественные типы;
логический тип Boolean;
символьный тип Char и тип-строка String;
текстовый файл Text;
нетипизированный указатель pointer;
тип-строка с завершающим нулевым символом PChar.
Числовые типы
Как уже говорилось, целые и вещественные типы отличаются количеством байтов, отводимых под представление числа, а также способностью представлять отрицательные числа. В языке Паскаль определены следующие числовые типы:
Byte |
1 |
байт |
0..(28–1), беззнаковые целые |
Word |
2 |
байта |
0…(216–1), беззнаковые целые |
Shortint |
1 |
байт |
-27..(27–1), знаковые целые |
Integer |
2 |
байта |
-215..(215–1), знаковые целые |
Longint |
4 |
байта |
-231..(231–1), знаковые целые |
Real |
6 |
байт |
11–12 значащих разрядов |
Single |
4 |
байта |
7–8 значащих разрядов |
Double |
8 |
байт |
15–16 значащих разрядов |
Extended |
10 байт |
19–20 значащих разрядов |
|
Comp |
8 |
байт |
19–20 значащих разрядов, целые |
Переменные вещественных типов могут принимать как положительные, так и отрицательные значения. Значения задаются либо явно с помощью констант, либо неявно через выражения. Примеры объявления и задания переменных:
28
type
Numeric = integer; var
i: integer; m,n: real; number: Numeric;
begin
i := 3;
I := $F3; // шестнадцатиричный формат m := -5.78;
m:= 8e-5; // формат со степенью: 8*10-5
n:= m + 3.13*2 - i;
number := i; end.
Все числа представляются в двоичной системе счисления. Для представления знаковых чисел старший бит используется для указания знака (0 – у положительных, 1 – у отрицательных).
Логический тип
Переменные логического типа Boolean могут принимать только два значения False (ложь) и True (истина). Выполняется постулат False < True. Во внутреннем представлении ЭВМ ложь представляется нулём, а истина – единицей. Есть и другие логические типы, в которых истинным считается любое значение, отличное от нуля:
var
flag: boolean; a, b: integer;
begin
a := 3; b := 4;
flag := false; flag := a < b;
flag := flag and (a=b); end.
Рассмотрим несколько примеров, в которых участвуют переменные логического типа:
if a = true then … if a = false then …
if i < j then a := true else a := false;
if a then …
if not a then …
a := i < j;
29
if i < j then a := false
else a := true; |
|
a |
:= |
not (i < j); |
|
|
a |
:= |
i >= j; |
Эквивалентные формы записи в правом столбце более предпочтительны.
Рассмотрим записи
if i < j then a := true;
и
a := i < j;
Можно ли считать их эквивалентными? Нет, так как присваивание в первом случае выполняется не всегда, а только когда i < j.
Символы и строки
Почему в ASCII-таблице (рис. 1) всего 256 символов? Встроенный символьный тип Char объединяет символы коди-
ровки ASCII. По своей мощности символьный тип равен типу Byte, т.е. имеет всего 256 различных значений. Все символы имеют свой собственный код в таблице ASCII от 0 до 255. Таким образом, для однобайтовой кодировки, примером которой является кодировка ASCII, возможно 256 различных символов.
Как видно из таблицы, символы английского алфавита идут в алфавитном порядке. При сравнении символов реально сравниваются их коды в таблице, поэтому символ 'a' будет меньше всех остальных символов алфавита. Заглавные буквы представляются другими символами и соответственно имеют другие коды. Помимо букв в ASCII-таблице закодированы цифры, знаки пунктуации, управляющие символы (перевод строки, табуляция и др.), символы псевдографики. Символьные константы записываются в одинарных кавычках. Узнать код символа можно с помощью функции ord(), а получить символ по коду можно с помощью функции chr() или поставив знак # перед кодом.
30