Версия для печати


Управляющие структуры
http://www.delphikingdom.com/asp/viewitem.asp?catalogID=1111

Andrew Fionik
дата публикации 25-01-2005 05:48

урок из цикла: Азы Delphi.

Управляющие структуры

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

Существует три основных программных структуры, управляющих выполнением программы. Это:
  1. последовательное выполнение;
  2. ветвление или выбор;
  3. цикл.

Любая программа, в той или иной комбинации использует эти управляющие структуры. Этих трех структур достаточно чтобы запрограммировать программу любой сложности и записать порядок выполнения любого вычислительного процесса (кем и когда это было доказано, я, честно говоря, не помню). До сего момента, в примерах программ мы использовали только одну управляющую структуру - последовательное выполнение.

Оператор последовательного выполнения задает способ выполнения команд по порядку, одна за другой. Команды выполняются ровно в той последовательности, в которой они присутствуют в тексте программы. Управляющая структура, задающая последовательное выполнение, также называется операторными скобками и обозначается парой ключевых слов begin и end. Примером использования операторных скобок может служить любая программа, из рассмотренных нами на протяжении предыдущих лекций. Команды, располагающиеся внутри операторных скобок, выполняются по очереди. Компилятор трактует эту последовательность команд как один оператор, который должен быть выполнен от начала (begin) до конца (end). Прервать исполнение этой последовательности могут только специальные операторы (raise, Exit, Halt, Abort), но о них позже. Отдельное, самостоятельное, использование операторных скобок бессмысленно, т.к. любая последовательность операторов, не принадлежащих к другим управляющим структурам, выполняется последовательно по умолчанию. Операторные скобки используются только в связке с другими управляющими структурами и ключевыми словами.

Оператор ветвления задает выполнение одного или нескольких операторов в зависимости от результата вычисления контрольного выражения. Существуют три управляющие структуры, задающие ветвление - if ... then, if ... then ... else, case ... of.

Оператор цикла задает многократное (повторяющееся, циклическое) выполнение группы операторов, которое прерывается по достижению определенного состояния, определяемого как результат вычисления контрольного выражения. Вычисление выражения происходит на каждой итерации цикла. Существуют четыре управляющие структуры, задающие цикл - for...to...do, for...downto...do, repeat...until, while...do. Разница между ними заключается в способе и моменте вычисления контрольного выражения.

Кроме этих трех базовых управляющих структур существует четвертая конструкция - безусловный переход. Фактически под безусловным переходом подразумевается комбинация из пары операторов goto и label где goto указывает программе, что надо передать управление в точку обозначенную оператором label. При программировании на языках низкого уровня, различных вариантах Ассемблера, использование безусловных переходов явление рядовое. В частности, потому что без них никак не обойтись в силу технических особенностей языка. Использование безусловного перехода в языках высокого уровня (в том числе и Delphi) является дурным тоном, т.к. ухудшает "читабельность" программы.

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

Другие варианты безусловного перехода, как ни странно, улучшают "читабельность" и упрощают структуру программы. Это происходит потому, что при их использовании переход выполняется по строго предопределенным правилам и в строго определенное место. К другим операторам безусловного перехода относятся:

  1. Exit - выход из процедуры, функции или программы (применяется очень часто, для упрощения алгоритма).
  2. Break - выход из цикла (применяется редко).
  3. Continue - немедленное выполнение следующей итерации цикла (применяется редко).


Логический тип данных (boolean)

Поведение управляющих структур зависит от значения контрольных (управляющих) выражений, которые имеют логический тип. В Delphi существует логический тип данных - boolean. Переменные типа данных boolean могут принимать одно из двух значений TRUE (ИСТИНА) или FALSE (ЛОЖЬ). Логические выражения - выражения, тип результата которых является boolean. Логические выражения используются для определения истинности или ложности какого-либо состояния (условия) в программе. Например, нам нужно определить является ли введенное пользователем значение положительным:

program BoolDemo01;
var
	IsPositive:Boolean; // объявляем переменную логического типа
	Number:Double; // вводимые данные
begin
	Write(''Please enter a number ''); // выводим приглашение к вводу
	ReadLn(Number); // читаем ввод пользователя
	// сравниваем Number с нулем, а результат сравнения записываем в IsPositive
	IsPositive:=Number > 0;
	WriteLn(''Is number positive? '', IsPositive); // выводим результат сравнения
end;

В данном случае значение переменной Number сравнивается с нулем. В случае, если значение Number больше чем 0, то значение выражения Number > 0 будет истинным (TRUE). Если значение Number будет не больше чем 0 (меньше или равно), то значение выражения Number > 0 будет ложным (FALSE). Таким образом, переменной IsPositive будет присвоено значение TRUE или FALSE. В логических (по-другому их называют булевскими, или булевыми - калька с английского языка) выражениях могут участвовать следующие логические операторы:

ОператорУнарный/бинарныйОписаниеПример использования
Операторы сравнения
=бинарный Возвращает TRUE, если операнды равны и FALSE, если не равны. A=B
> бинарный Возвращает TRUE, если первый операнд больше чем второй и FALSE во всех остальных случаях. A>B
< бинарный Возвращает TRUE, если первый операнд меньше чем второй и FALSE во всех остальных случаях. A
>= бинарный Возвращает TRUE, если первый операнд больше или равен второму и FALSE во всех остальных случаях. A>=B
<= бинарный Возвращает TRUE, если первый операнд меньше или равен второму и FALSE во всех остальных случаях. A<=B
<> бинарный Возвращает TRUE, если операнды не равны. A<>B
Логические операторы
and бинарный Логическое "И". Возвращает TRUE, если первый и второй операнд содержат TRUE. A and B
or бинарный Логическое "ИЛИ". Возвращает TRUE, если хотя бы один из операндов содержит TRUE. A or B
xor бинарный Логическое "Взаимоисключающее ИЛИ". Возвращает TRUE, если один и только один из операндов содержит TRUE. A xor B
not унарный Логическое "НЕ". Возвращает TRUE, если операнд содержит FALSE. Возвращает FALSE, если операнд содержит TRUE. not A
Операторы вхождения в множество
in бинарный Возвращает TRUE, если первый операнд, содержится (входит) во втором. A in B
Оператор принадлежности к типу
is бинарный Возвращает TRUE, если первый операнд принадлежит к объектному или интерфейсному типу, указываемому вторым операндом. A is B

Для операторов сравнения, тип операндов должен совпадать (или быть совместимым) и поддерживать сравнение значений. Например, это упорядоченные (Integer, Real, Double, Cardinal и др.) и строковые (String, Char и др.) типы данных. Для логических операторов, операнды должны быть логического типа (Boolean). Логический тип данных одновременно является и порядковым типом, в котором первым элементом является FALSE, а вторым TRUE.

Результаты вычисления простейших логических выражений

ОператорПервый операнд (A)Второй операнд (B)ВыражениеРезультат
andTRUETRUEA and BTRUE
TRUEFALSEFALSE
FALSETRUEFALSE
FALSEFALSEFALSE
orTRUETRUEA or BTRUE
TRUEFALSETRUE
FALSETRUETRUE
FALSEFALSEFALSE
xorTRUETRUEA xor BFALSE
TRUEFALSETRUE
FALSETRUETRUE
FALSEFALSEFALSE
notTRUEотсутствуетnot AFALSE
FALSEотсутствуетTRUE
Нижележащие выражения не являются логическими, хотя и могут возвращать результат типа boolean. Они используют особенность логического типа данных, то, что он является еще и перечислимым упорядоченным типом данных.
OrdTRUEотсутствуетOrd(A)1
FALSEотсутствует0
SuccTRUEотсутствуетSucc(A)не имеет смысла, при вычислении будет ошибка времени выполнения
FALSEотсутствуетTRUE
PredTRUEотсутствуетPred(A)FALSE
FALSEотсутствуетне имеет смысла, при вычислении будет ошибка времени выполнения


Приоритет операторов при вычислении логических выражений

Логические выражения вычисляются аналогично обычным математическим операциям - слева направо. Для логических операторов определен следующий порядок вычисления:

  1. not
  2. and
  3. or, xor
  4. =, >=, <=, <>, in, is

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

Пример:

const
	A=TRUE;
	B=FALSE;
	C=TRUE;
	D=5
	E=6;
var
	F:Boolean;
begin
	F:=A and B or C; // F = TRUE
	F:=A and (B or C); // F = TRUE
	F:=not A xor B and C; // F = FALSE
	F:=not ((A xor B) and C); // F = FALSE
	F:=(D<>E) and C; // F = TRUE
	F:=(D>E) and not B; // F = FALSE
	F:=not A xor (D=E); // F = TRUE
end;

Полный и короткий способы вычисления логических выражений

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

F:=A and C or B;

Для полного способа вычисления вначале будет вычислено значение выражения A and C и помещено во временную область памяти. После этого сохраненное выражение будет сравнено с B с использованием операции or. Результат вычисления будет записан в переменную F.

Для короткого способа вычисления вначале будет вычислено значение выражения A and C. Если значение выражения A and C истинно, то не имеет смысла сравнивать его с B через or, т.к. независимо от значения B результатом сравнения будет так же истина. Если же значение выражения A and C ложно, то сравнение с B через or будет произведено.

Способ вычисления логических выражений управляется директивой компилятора {$B+} и {$B-} или {$BOOLEVAL ON} и {$BOOLEVAL OFF}, или настройками IDE - Tools -> Options -> Compiler -> Complete boolean eval.

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

G:=(A<>0) and (5/A > 3);

Вначале A сравнивается с нулем. Если A содержит нулевое значение, то переменной G сразу присваивается значение FALSE. Независимо от значения выражения (5/A > 3), все выражение (A<>0) and (5/A > 3) будет ложным, т.к. один из его операндов (A<>0) уже вычислен и является ложным. Поэтому выражение (5/A > 3) не вычисляется. Если бы использовалось полное вычисление логических выражений, то вычисление 5/A привело бы к ошибке "деление на 0", однако этого не происходит, потому что данное выражение будет вычисляться только тогда, когда A не равно 0.

Ветвление

Ветвление необходимо, когда перед программой ставится вопрос выбора. Ветвление используется обычно в двух случаях: Любая конструкция ветвления работает следующим образом: Конструкция if...then

Конструкция if...then, пожалуй, является самой часто используемой среди прочих конструкций ветвления. Синтаксис оператора:

if Condition then Operator;
Конструкция if...then завершается точкой с запятой.

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

if Condition then begin OperatorSequence end;
Здесь OperatorSequence обозначает последовательность операторов выполняющихся по порядку.

Если результат вычисления управляющего выражения Condition будет ложным, то управление передается оператору, следующему за оператором ветвления if … then …

Конструкция if...then...else

Эта конструкция является развитием предыдущей. Если if...then дает возможность либо выполнять блок кода, либо не выполнять его, то if...then...else предоставляет возможность выполнить один из двух, альтернативных кусков. Синтаксис оператора:

if Condition then Operator1 else Operator2;

Condition - как и в предыдущем случае, выражение результат которого имеет логический тип. Operator1 и Operator2 - операторы или группы операторов, объединенных операторными скобками, которые будут выполнятся в зависимости от Condition. Если Condition истинно, то будет выполняться Operator1. Если ложно, то будет выполняться Operator2.
else - ключевое слово, разделяющее альтернативные варианты кода.

Обратите внимание, что после Operator1, перед else, точка с запятой не ставится.

Примеры:

Грузовик на мосту

По мосту собирается ехать многоосный грузовик. Допустимая нагрузка на одну ось составляет 5 тонн. Известна общая масса грузовика и количество осей. Требуется определить разрешен ли въезд на мост для этого грузовика. В случае превышения допустимой нагрузки следует вывести соответствующее сообщение.

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

Вот пример простейшей программы, которая решает такую задачу:

program IfDemo01;
{$APPTYPE CONSOLE}
const
	MaxWeight=5; // максимальная нагрузка на ось
var
	AxisCount:Integer; // количество осей у грузовика
	TotalWeight:Double; // общий вес грузовика
	WeightPerAxis:Double; // фактическая нагрузка на ось
begin
	AxisCount:=3; // наш грузовик трехосный
	TotalWeight:=18.3; // весит вместе с грузом 18.3 тонны
	WeightPerAxis:=TotalWeight/AxisCount; // вычислим фактическую нагрузку на ось
	// если фактическая нагрузка на ось превышает максимальную, выводим сообщение
	if WeightPerAxis>MaxWeight then WriteLn(''Too heavy!!!'');
	// выведем фактическую нагрузку на ось
	WriteLn(''Weight per axis is: '',WeightPerAxis);
end.

Будет выведен следующий результат:
Too heavy!!!
Weight per axis is: 6.1

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

program IfDemo02;
{$APPTYPE CONSOLE}
var
	MaxWeight:Double; // максимальная нагрузка на ось
	AxisCount:Integer; // количество осей у грузовика
	TotalWeight:Double; // общий вес грузовика
	WeightPerAxis:Double; // фактическая нагрузка на ось
begin
	Write(''Enter axis weight limit: ''); // выведем приглащение к вводу
	ReadLn(MaxWeight); // прочитаем максимальную нагрузку с клавиатуры
	
	Write(''Enter axis count: ''); // выведем приглащение к вводу
	ReadLn(AxisCount); // прочитаем количество осей с клавиатуры
	
	Write(''Enter total weight: ''); // выведем приглащение к вводу
	ReadLn(TotalWeight); // прочитаем массу грузовика с клавиатуры

	WeightPerAxis:=TotalWeight/AxisCount; // вычислим фактическую нагрузку на ось
	// если фактическая нагрузка на ось превышает максимальную, выводим сообщение
	if WeightPerAxis>MaxWeight then WriteLn(''Too heavy!!!'');
	
	// выведем фактическую нагрузку на ось
	WriteLn(''Weight per axis is: '',WeightPerAxis);
end.

Диалог с программой будет выглядеть так (ввод пользователя обозначен жирным шрифтом):
Enter axis weight limit: 4
Enter axis count: 2
Enter total weight: 10.5
Too heavy!!!
Weight per axis is: 5.25 


Работа со строками

Из строки введенной в виде Фамилия Имя Отчество выделить только фамилию.

program ifdemo03;
{$APPTYPE CONSOLE}
var
	FullName:String; // Ф.И.О. одной строкой
	LastName:String; // фамилия
	FirstSpacePosition:Integer; // позиция первого пробела, искомого в FullName
begin
  Write(''Please enter full name: ''); // выводим приглашение к вводу
  ReadLn(FullName); // читаем с клавиатуры Ф.И.О. одной строкой

  // если введенная строка не пустая, то будем работать с ней,
  if FullName<>'''' then
  begin {Вот они, операторные скобки. Операторы содержащиеся внутри них
	будут выполнятся только тогда, когда FullName будет содержать не
	пустую строку}
	// получим позицию первого пробела в FullName
	FirstSpacePosition:=Pos('' '', FullName);
	if FirstSpacePosition>0 then // если позиция пробела больше 0, то
		LastName:=Copy(FullName,1,FirstSpacePosition-1) {... скопируем
		содержимое FullName с первого символа по символ предыдущий пробелу}
	else
		LastName:=FullName; {... но если пробел не найден, то примем что вся
		строка является фамилией}
	WriteLn(''Last name is: "'', LastName,''"'');
  end // закрываем операторные скобки
  else
    WriteLn(''Empty string''); // если строка пустая, то выводим сообщение
end.

Конструкция case…of

Оператор выбора, в отличие от обычного ветвления, дает возможность выполнить один из нескольких операторов, в зависимости от значения управляющего выражения. Управляющее выражение не обязательно должно иметь логический тип результата. Тип результата может принадлежать к любому перечислимому типу данных. Например: Byte, Char, Cardinal, Boolean, Integer и т.п.

Синтаксис
case OrdinalExpression of
caselist1:Operator1;
caselist2:Operator2;
…
caselistN:OperatorN;
end;
или
case OrdinalExpression of
caselist1:Operator1;
caselist2:Operator2;
…
caselistN:OperatorN;
else
	OperatorElse;
end;
где:

OrdinalExpression должно быть обязательно перечислимого типа. Это значит, что OrdinalExpression не может быть, например строкой.

Список значений caselist может быть задан следующим образом:
  1. Одиночное значение.
  2. Список значений, разделенных запятой.
  3. Диапазон значений, разделенных двумя точками - "..".
Значения в caselist обязательно должны быть константными, т.е. вычисляемыми на этапе компиляции. В качестве значений не могут быть использованы не константные выражения или переменные.

Алгоритм работы case
  1. Вычисляется значение управляющего выражения OrdinalExpression.
  2. Производится поиск соответствующего caselist, в который входит значение управляющего выражения.
  3. Если соответствующий caselist найден, то выполняется оператор Operator, соответствующий найденному списку значений caselist.
  4. Если caselist не найден и при этом присутствует часть else, то выполняется оператор OperatorElse.
  5. Управление передается оператору, следующему за end.


Циклы

Оператор for задает фиксированное количество итераций цикла. Синтаксис оператора for:

for LoopVariable:=StartValue to StopValue do Statement;
или
for LoopVariable:=StartValue downto StopValue do Statement;
Где:

Переменная-счетчик перед выполнением цикла должна быть объявлена в секции объявления переменных (var). Переменной счетчиком может быть только переменная, принадлежащая к порядковым типам данных (Integer, Byte, Cardinal, Char, любой перечислимый пользовательский тип и т.п.)

Алгоритм работы цикла for следующий:
  1. Переменной-счетчику (LoopVariable) присваивается стартовое значение (StartValue).
  2. Вычисляется выражение окончания цикла (StopValue).
  3. Если LoopVariable больше чем StopValue, то управление передается на строку следующую за оператором цикла.
  4. Выполняется тело цикла (Statement).
  5. Значение LoopVariable увеличивается на единицу.
  6. Продолжается выполнение с пункта 3.

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



Пример:

program ForDemo1;
{$APPTYPE CONSOLE}
const
	MaxI=10;
var
	I:Integer;
begin
	for I:=0 to MaxI do WriteLn(I);
end;

Данный пример последовательно выводит на консоль числа от 0 до 10 включительно.

Оператор цикла while…do

Оператор while в первую очередь отличается от for тем, что не требует переменной-счетчика. Синтаксис оператора while…do:

while Condition do Statement; где

Выполнение Statement происходит до тех пор, пока Condition истинно. Вычисление Condition и проверка на истинность происходит перед выполнением Statement. Таким образом, если с самого начала Condition будет ложным, то Statement не будет выполнен никогда.

Пример:

Вывести на консоль числа от 0 до 10 включительно, через одно. Фактически повторить то, что уже сделано программой ForDemo01, только с небольшим отличием.

program WhileDemo1;
{$APPTYPE CONSOLE}
const
  MaxI=10;
var
  I:Integer;
begin
  I:=0; // зададим начальное значение I
  while I<=10 do // пока I<=10 выполняем
  begin
    WriteLn(I); // печать значения I
    I:=I+2; // увеличиваем значение I на два
  end;
end.

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

Оператор цикла repeat…until

Оператор цикла repeat…until работает аналогично while, за исключением того, что вычисление контрольного выражения происходит после итерации, а не до нее. Соответственно решение о прекращении цикла принимается после итерации. Это означает, что repeat…until выполняет всегда, как минимум одну итерацию. Кроме того, выполнение цикла будет происходить до тех пор, пока контрольное выражение ложно. Цикл завершается тогда, когда контрольное выражение станет истинным. Группу операторов, выполняемую в цикле, не нужно заключать в операторные скобки, т.к. repeat…until уже являются своеобразными операторными скобками.

Синтаксис repeat…until:
repeat Statement until Condition;


Пример:

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

program RepeatDemo1;
{$APPTYPE CONSOLE}
var
  I:Double;
  R:Double;
begin
  repeat // повторять ...
    Write(''Please enter a number: ''); // вывести приглашение для пользователя
    ReadLn(I); // прочитать ввод с клавиатуры
    R:=I/2; // разделить I пополам и присвоить результат R
    WriteLn(''I/2='',R); // вывести результат деления
  until R<5; // ... до тех пор когда R станет меньше 5
end.

Еще примеры использования управляющих структур

Пример 1:

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

program controldemo1;
{$APPTYPE CONSOLE}
var
	PositiveCount, NegativeCount:Cardinal;
	UserInput: Integer;
begin
	// выведем приглашение
	WriteLn(''Program will count of positive and negative numbers.'');
	WriteLn(''Please enter integer numbers.'');
	WriteLn(''To end work of program please enter 0.'');
	// обнулим счетчики положительных и отрицательных чисел
	PositiveCount:=0;
	NegativeCount:=0;
	repeat // будем повторять цикл, ...
		// выведем приглашение к вводу числа
		Write(''Please enter a number: '');
		// прочитаем ввод пользователя с клавиатуры
		ReadLn(UserInput);
		if UserInput>0 then // если пользователь ввел число больше 0, то
	   	  PositiveCount:=PositiveCount+1 // увеличим счетчик положительных чисел
		else // иначе
		   if UserInput<0 then // если пользователь ввел число меньше 0, то
		     // увеличим счетчик отрицательных чисел
		     NegativeCount:=NegativeCount+1;
		{если пользователь ввел число не больше и не меньше нуля, то ни один из
		счетчиков не будет увеличен}
	until UserInput=0; // ... завершим цикл когда пользователь введет 0
	// выведем результаты расчета
	WriteLn(''Count of positive numbers: '',PositiveCount);
	WriteLn(''Count of negative numbers: '',NegativeCount);
	// и подождем когда пользователь нажмет Enter
	WriteLn(''Press Enter.'');
	ReadLn;
end.

Пример 2:

Пользователь должен ввести 5 вещественных чисел. Программа должна обнаружить среди них самое маленькое и самое большое и вывести их.

program controldemo2;
{$APPTYPE CONSOLE}
const
	MaxDouble=1.7e+308; // максимально возможное значение переменной типа Double
	MinDouble=5.0e-324; // минимально возможное значение переменной типа Double
var
	I:Cardinal; // счетчик введенных значений
	X, // введенное значение
	MinX, // самое маленькое из введенных значений
	MaxX:Double; // самое большое из введенных значений
begin
	// выведем приглашение
	WriteLn(''Please enter five floating point numbers.'');
	WriteLn(''Program will tell minimal and maximal of them.'');
	// инициализируем минимальные и максимальные значения
	MinX:=MaxDouble;
	MaxX:=MinDouble;
	for I:=1 to 5 do // для I=1 к 5 выполнять
		begin
			// выведем приглашение к вводу
			Write(''Step: '', I, ''. Please enter floating point number: '');
			// прочитаем ввод с клавиатуры
			ReadLn(X);
			{если введенное число меньше самого маленького, то значит что это
			число будет считаться самым маленьким среди введенных}
			if X<MinX then MinX:=X;
			{если введенное число больше самого большого, то значит что это
			число будет считаться самым большим среди введенных}
			if X>MaxX then MaxX:=X;
		end;
	// выведем результаты
	WriteLn(''MinX='', MinX, ''; MaxX='', MaxX);
	// подождем пользователя, пока он не нажмет на Enter
	WriteLn(''Press Enter...'');
	ReadLn;
end.

Обратите внимание на строки:
MinX:=MaxDouble;
MaxX:=MinDouble;

Перед началом анализа мы присвоили переменной, которая должна хранить самое маленькое значение, максимально возможное для её типа значение. Для чего? Очень просто. Первое, введенное пользователем число, окажется гарантированно меньшим, чем значение в MinX, и таким образом результат выражения X С MaxX все в точности так же, но наоборот.

P.S. Вооруженные знаниями об основных управляющих структурах мы можем продолжить изучение… типов данных, более сложных и более мощных - массивов, записей, множеств, пользовательских перечислимых типов. Но об этом в следующей лекции.