- •1. Приступаем к изучению языка delphi
- •I love Delhi
- •20 Degrees Celsius is 68 degrees Fahrenheit.
- •4.2 Light are 265608 astronomical units
- •2. Представление данных переменными
- •Integer is 4 bytes
- •Integer is 2147483647
- •Integer is -2147483648
- •3. Составные типы данных
- •Volume: Integer;
- •Volume: 1.40
- •Var a: array of integer;
- •4. Циклы и выражения сравнения
- •1952 Hudson Hornet
- •1951 Kaiser
- •5. Операторы ветвления и логические операции
- •If проверяемое_условие then
- •3 Spaces, 13 charaters total in sentence
- •If проверяемое_условие then
- •27 Is right!
- •6 Entries or enter a negative value.
- •4 Numbers in massive greater then your number
- •2 Spaces
4. Циклы и выражения сравнения
Обзор возможностей цикла FOR
В программе нередко требуется выполнять неоднократно повторяющиеся действия, такие как, например, поочередное сложение элементов массива или двадцатикратную распечатку какого-нибудь хвалебного отзыва. Цикл for упрощает эту задачу. Обратимся к тексту листинга 4.1, а затем обсудим, каким образом он работает.
Программа 4_1
// Краткий обзор возможностей цикла for
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
var
i: Integer;
begin
for i:=1 to 5 do
Writeln('Delphi knows loops.');
Writeln('Delphi knows when to stop.');
Readln;
end.
Результат:
Delphi knows loops.
Delphi knows loops.
Delphi knows loops.
Delphi knows loops.
Delphi knows loops.
Delphi knows when to stop.
Оператор for обеспечивает циклическое повторение некоторого оператора (в частности, составного оператора) заданное число раз. Повторяемый оператор называется телом цикла. Повторение цикла определяется некоторой управляющей переменной (счетчиком), которая увеличивается или уменьшается на единицу при каждом выполнении тела цикла. Повторение завершается, когда управляющая переменная достигает заданного значения.
Оператор for записывается в одной из следующих форм:
for <счетчик>:=<начальное значение> to <конечное значение> do
<оператор>;
или
for <счетчик>:=<начальное значение> downto <конечное значение> do
<оператор>;
<счетчик> — локальная управляющая переменная порядкового типа. В начале выполнения оператора for ей присваивается <начальное зназначение> После каждого очередного выполнения тела цикла <оператор> ее значение увеличивается (в первой форме с to) или уменьшается (во второй форме с downto) на единицу. Когда значение управляющей переменной достигает значения <конечное значение>, тело цикла выполняется последний раз, после чего управление передается оператору, следующему за структурой for. <начальное значение> и <конечное значение> являются выражениями, совместимыми по типу с управляющей переменной.
Если заданные начальное и конечное значения равны друг другу, тело цикла выполняется только один раз. Если в форме с to начальное значение больше конечного или в форме с downto начальное значение меньше конечного, то тело цикла не выполняется ни разу.
Программа 4_2
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
var
i, limit: Integer;
begin
Write('Enter the starting countdown value: ');
Readln(limit);
for i:=limit downto 1 do
Writeln('i = ', i);
Writeln('Done now that i = ', i);
Readln;
end.
Результат:
Enter the starting countdown value: 4
i = 4
i = 3
i = 2
i = 1
Done now that i = 0
Хотелось бы еще раз обратить внимание читателя на полезность применения циклов. В листинге 4_3 цикл используется для подсчета и сохранения значений факториалов первых 16 чисел. Факториалы вычисляются следующим образом. Нулевой факториал записывается как 0! и, по определению, равен 1. Затем 1! равен 1*1! или 1. Далее 2! равен 2*1! или 2. Затем 3! равен 3*2! или 6 и т.д. Таким образом, факториал каждого целого числа является произведением этого целого числа на факториал предыдущего целого числа. В рассматриваемой программе для подсчета факториалов последовательности чисел и сохранения их в массиве используется один цикл. Затем в ней используется второй цикл для отображения результатов подсчета. Кроме того, в этой программе представлено использование внешних объявлений значений переменных.
Программа 4_3
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
const
ArSize = 15;
var
factorials: array[0..ArSize] of Real;
i: Integer;
begin
factorials[0] := 1.0;
factorials[1] := 1.0;
for i := 2 to ArSize do
factorials[i] := i * factorials[i - 1];
for i := 0 to ArSize do
Writeln(i, '! = ', factorials[i]:0:0);
Readln;
end.
Результат:
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
10! = 3628800
11! = 39916800
12! = 479001600
13! = 6227020800
14! = 87178291200
15! = 1307674368000
Как можно заметить, значения факториалов быстро увеличиваются!
Примечания к программе
Приведенная выше программа создает массив для хранения значений факториалов. При этом нулевой элемент массива равен 0!, первый элемент массива — 1! и т.д. Вследствие того, что первые два факториала равны 1, данная программа для первых двух элементов массива factorials устанавливает значение 1,0 (не следует забывать о том, что индекс первого элемента массива равен 0). После этого используется цикл для задания произведения индекса массива на предыдущий факториал в качестве значения каждого факториала. В этом цикле демонстрируется возможность использования счетчика цикла как обычной переменной в теле цикла.
В программе показано также, каким образом цикл for действует в тесной связи с массивами, обеспечивая при этом удобные средства поочередного доступа к каждому элементу массива. Кроме того, в ней для создания символического представления размера массива применяется переменная типа const - ArSize. Она используется во всех операциях, в которых задействован размер массива, в частности, при определении массива и ограничений для циклов, которые обрабатывают массив. Следовательно, для того, чтобы расширить возможности данной программы, скажем, до вычисления 20 факториалов, достаточно задать для переменной ArSize значение 20 и повторно скомпилировать код. Таким образом, применение символической константы позволяет избежать изменения констант от 16 до 20 в каждом отдельном случае.
Доступ к символам строки с помощью цикла for
Цикл for предоставляет непосредственный доступ поочередно к каждому символу строки. Например, программа из листинга 4_4 позволяет вводить строку, а затем отображать ее посимвольно в обратном порядке. При этом функция Length подсчитывает количество символов в строке, а затем это значение используется в выражении инициализации цикла для присвоения i значения позиции последнего символа в строке, не считая пустого символа. Для перемещения по строке в обратном порядке в данной программе используется оператор downto в цикле for, который уменьшает на 1 индекс массива на каждой итерации цикла.
Программа 4_4
// использование цикла for для обработки строк
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
const
ArSize = 20;
var
word: String[ArSize];
i: Integer;
begin
Write('Enter a word: ');
Readln(word);
//отображение символов строки в обратном порядке
for i:=Length(word) downto 1 do
Write(word[i]);
Readln;
end.
Результат:
Enter a word: animal
lamina
Программа выводит слово animal (животное) в обратном порядке.
Составные операторы или блоки
Формат (или синтаксис) оператора for может показаться ограниченным, поскольку тело данного цикла должно состоять из одного оператора, а это неудобно, если операторов может потребоваться больше. К счастью, существует специальный синтаксический прием, позволяющий обойти это ограничение и вставить в тело цикла сколько угодно операторов. Он заключается в использовании ключевых слов begin и end для построения составного оператора или блока. Блок состоит из пары фигурных скобок и операторов, которые в них заключены, при этом с точки зрения синтаксиса блок считается единым оператором. Например, в программе из листинга 4_5 операторы begin и end используются для объединения трех отдельных операторов в единый блок. Это дает возможность ввести в тело цикла запрос ввода данных пользователем, обеспечить чтение ввода и выполнение вычислений. В данной программе выполняется подсчет текущей суммы вводящихся чисел.
Программа 4_5
// демонстрация применения блока операторов
program Project1;
{$APPTYPE CONSOLE}
var
i, number: Integer;
sum: Real;
begin
sum := 0.0;
Write('The Amazing Accounto will sum and average ');
Writeln('five numbers for you.');
Writeln('Please enter five values: ');
for i := 1 to 5 do
begin //здесь начинается блок
Write('Value ', i, ': ');
Readln(number);
sum := sum + number;
end; //завершение блока
Write('Five exquisite choice indeed! ');
WriteLn('The sum to ', sum:0:0);
Writeln('and average to ', sum / 5:0:1);
Readln;
end.
Результат:
The Amazing Accounto will sum and average five numbers for you.
Please enter five values:
Value 1: 1942
Value 2: 1948
Value 3: 1957
Value 4: 1974
Value 5: 1980
Five exquisite choice indeed! The sum to 9801
and average to 1960.2
Допустим, что отступ в тексте программы оставлен, однако при этом опущены операторы begin и end:
for i := 1 to 5 do
Write('Value ', i, ': '); //здесь завершается цикл
Readln(number);
sum := sum + number;
Write('Five exquisite choice indeed! ');
Компилятор игнорирует отступ, и поэтому в цикле окажется только один оператор. Таким образом, цикл отобразит пять запросов ввода данных и больше ничего. По завершении цикла программа перейдет к следующим строкам, выполняя чтение и суммирование единственного числа.
Выражения сравнения
Компьютер — не только средство для беспрерывного "перемалывания" чисел, его возможности гораздо шире. Он обладает способностью сравнивать значения, и именно это свойство служит для него основанием для принятия решений. Указанная возможность воплощена в операторах сравнения. Каждое выражение сравнения сводится к значению True типа Boolean, если результат сравнения оказывается истинным, и к значению False типа Boolean, если результат сравнения оказывается ложным. Именно поэтому данные операторы вполне пригодны для применения в условии продолжения цикла.
Операторы сравнения
Оператор |
Значение |
< |
Меньше |
<= |
Меньше или равно |
= |
Равно |
> |
Больше |
>= |
Больше или равно |
<> |
Не равно |
Операторы сравнения обладают более низким приоритетом, чем арифметические операторы. Это означает, что выражение
x + 3 > y – 2 //выражение 1
соответствует выражению
(x + 3) > (y – 2) //выражение 2
а не выражению
x + (3 > y) – 2 //выражение 3
Цикл while
Структура while...do используется для организации циклического выполнения оператора, называемого телом цикла, пока выполняется некоторое условие. Синтаксис управляющей структуры while...do:
while (условие продолжение цикла) do
тело цикла
Сначала программа проверяет условие продолжения цикла. Если в результате вычисления этого выражения получается логическое значение True, выполняются операторы в теле цикла. Подобно циклу for, тело данного цикла состоит из одного оператора или блока, определяемого операторами begin .. end. После завершения выполнения тела цикла программа возвращается к условию продолжения цикла и вычисляет его еще раз. Если данное условие оказывается True, то программа снова выполняет тело цикла. Подобный цикл проверки и выполнения продолжается до тех пор, пока в результате вычисления выражения не получится логическое значение False. Ясно, что если требуется, чтобы цикл в конечном итоге был завершен, в теле цикла должно быть выполнено некоторое действие, которое могло бы оказать влияние на значение условия продолжения цикла. Цикл while является циклом с входным условием продолжения цикла. Таким образом, если в результате вычисления условие продолжения цикла оказывается ложным с самого начала, программа вообще не выполняет тело цикла.
В листинге 4_6 демонстрируется работа цикла while. В данном цикле осуществляется последовательное обращение к каждому символу строки и отображение его ASCII-кода. Цикл завершается по достижении нулевого символа. Такой способ пошагового обращения к символам строки вплоть до нулевого символа является типичным для обработки строк в C++. Благодаря тому, что строка содержит собственный маркер завершения, программам зачастую не требуется явного указания длины строки.
Программа 4_6
В цикле осуществляется последовательное обращение к каждому символу строки и отображение его ASCII-кода.
program Project1;
{$APPTYPE CONSOLE}
var
sName: String;
i, iLength: Integer;
begin
Write('Your first name, please: ');
Readln(sName);
iLength := Length(sName); //определяем длину строки
Writeln('Here is your name, verticalized and ASCIIized:');
i := 1;
while i <= iLength do
begin
Writeln(sName[i], ': ', Ord(sName[i]));
Inc(i);
end;
Readln;
end.
Результат:
Your first name, please: Muffy
Here is your name, verticalized and ASCIIized:
M: 77
u: 117
f: 102
f: 102
y: 121
Условие продолжения цикла while выглядит следующим образом:
while i <= iLength do
Это условие позволяет проверить, является ли переменная i меньше или равна переменной iLength. Для успешного выполнения такой проверки в теле цикла необходимо изменять значение переменной i. Поэтому в конце тела цикла осуществляется приращение значения этой переменной. Если этого не делать, цикл будет каждый раз обрабатывать один и тот же элемент массива, выводя символ и его код до тех пор, пока пользователь не сможет завершить выполнение программы. Подобный бесконечный цикл является одной из наиболее распространенных ошибок. Она зачастую возникает в том случае, когда забывают обновить определенное значение в теле цикла.
Для вывода ASCII-кода каждого символа в рассматриваемой программе выполняется преобразование типа символа, который содержится в элементе sName[i], в целочисленный тип при помощи функции Ord которая возвращает порядковый номер символа.
Цикл repeat..until
Структура repeat...until используется для организации циклического выполнения совокупности операторов, называемой телом цикла, до тех пор, пока не выполнится некоторое условие. Синтаксис управляющей структуры repeat...until:
repeat
тело цикла
until (условие продолжение цикла);
Точка с запятой после последнего оператора тела цикла (перед ключевым словом until) может опускаться.
Структура работает следующим образом. Выполняются операторы тела цикла. Затем вычисляется <условие>, которое должно возвращать результат булева типа. Если выражение условия возвращает False, то повторяется выполнение операторов тела цикла и после этого снова вычисляется условие. Такое циклическое повторение цикла продолжается до тех пор, пока проверяемое условие не вернет True. После этого цикл завершается и управление передается оператору, следующему за структурой repeat...until.
Поскольку проверка условия осуществляется после выполнения операторов тела цикла, то эти операторы заведомо будут выполнены хотя бы один раз, даже если условие сразу истинно. С другой стороны, программист должен быть уверен, что условие рано или поздно вернет true. Если этого не произойдет, то программа «зациклится», т.е. цикл будет выполняться бесконечно. Иногда такие бесконечные циклы используются. Но в этом случае внутри тела цикла должно быть предусмотрено его прерывание в какой-то момент, например, оператором break, прерывающим цикл, или функциями Exit или Abort, вызывающими прерывание не только цикла, но и функции или процедуры, внутри которой выполняется данный цикл.
Программа 4_7
//программа, демонстрирующая цикл с постусловием
program Project1;
{$APPTYPE CONSOLE}
var
n: Integer;
begin
Write('Enter numbers in the range 1-10 to find ');
Writeln('my favorite number');
repeat
Readln(n);
until n = 7;
Writeln('Yes, 7 is my favorite.');
Readln;
end.
Результат:
Enter numbers in the range 1-10 to find my favorite number
9
4
7
Yes, 7 is my favorite.
Программа 4_8
// пользователь указывает шаг итерации
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
var
i, by: Integer;
begin
i := 0;
Write('Enter an integer: ');
Readln(by);
Writeln('Counting by ', by, 's:');
while i<100 do
begin
Writeln(i);
i := i + by;
end;
Readln;
end.
Результат:
Enter an integer: 30
Counting by 30s:
0
30
60
90
Программа 4_9
// обратная перестановка содержимого массива
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
const
ArSize = 20;
var
word: String[ArSize];
i, j: Integer;
temp: Char;
begin
Write('Enter a word: ');
Readln(word);
//фактическое изменение массива
j := 1;
i := Length(word);
while j < i do
begin //начало блока
temp := word[i];
word[i] := word[j];
word[j] := temp;
Dec(i);
Inc(j);
end; //конец блока
Writeln(word);
Writeln('Done');
Readln;
end.
Результат:
Enter a word: take
ekat
Done
Программа 4_10
// обратная перестановка содержимого строки №2
program Project1;
{$APPTYPE CONSOLE}
uses
StrUtils;
var
sWord: String;
begin
Write('Enter a word: ');
Readln(sWord);
//фактическое изменение массива
sWord := ReverseString(sWord);
Writeln(sWord);
Writeln('Done');
Readln;
end.
Результат:
Enter a word: take
ekat
Done
Вложенные циклы и двумерные массивы
Итак, цикл for естественным образом подходит для обработки массивов. Сделаем еще шаг в этом направлении и рассмотрим применение одного цикла for в другом цикле for для обработки двумерных массивов (речь идет о вложенных циклах).
Прежде всего ознакомимся с понятием двумерного массива. Применявшиеся до сих пор массивы называются одномерными, поскольку каждый такой массив можно наглядно представить в виде одной строки данных. Двумерный массив более схож с таблицей, имеющей строки и столбцы данных.
Объявить двумерный массив можно таким образом:
var A1: array[1..10,1..3] of Integer;
Этот оператор описывает двумерный массив, который можно представить себе как таблицу, состоящую из 10 строк и 3 столбцов.
Доступ к значениям элементов многомерного массива обеспечивается через индексы, перечисляемые через запятую. Например, А1[4,3] — значение элемента, лежащего на пересечении четвертой строки и третьего столбца.
Предположим, что требуется вывести содержимое всего массива. В этом случае для изменения строк можно воспользоваться одним циклом for, а для изменения столбцов — вторым, вложенным циклом for:
Программа 4_11
// двумерный массив
program Project1;
{$APPTYPE CONSOLE}
var
a1: array[1..10,1..3] of Integer;
x, y: Integer;
begin
for y := 1 to 10 do
begin
for x := 1 to 3 do
Write(a1[y,x]);
Writeln;
end;
Readln;
end.
ВОПРОСЫ ДЛЯ ПОВТОРЕНИЯ (4)
В чем заключается различие между циклом с предусловием и циклом с постусловием?
Что будет выведено в результате выполнения следующего фрагмента кода, если включить его в реальную программу:
for i:=0 to 4 do
Write(i);
Writeln;
Что будет выведено в результате выполнения следующего фрагмента кода, если включить его в реальную программу:
var
j: Integer = 0;
begin
while j < 11 do
begin
Write(j);
j := j + 3;
end;
Writeln;
Writeln(j);
Readln;
end.
Создайте цикл while, который выводит значения 1, 2, 4, 8, 16, 32, 64 при увеличении в 2 раза значения счетчика на каждом шаге цикла.
Каким образом можно включить в тело цикла несколько операторов?
Упражнения по программированию (4)
Напишите программу, которая запрашивает у пользователя ввод двух целых чисел. Затем эта программа должна вычислить и отобразить сумму всех целых чисел, находящихся в пределах между двумя введенными целыми числами и включая их. При этом предполагается, что первым вводится меньшее целое число. Например, если пользователь вводит 2 и 9, то программа сообщает, что сумма всех целых чисел от 2 до 9 составляет 44.
Напишите программу, которая запрашивает ввод чисел. После ввода каждого числа сообщается общая сумма введенных до сих пор чисел. Программа завершается после ввода нуля.
Дафна сделала вклад на сумму $100 под простые проценты, которые составляют 10%. Итак, ежегодно ее вклад дает доход в сумме 10% от первоначального вклада, или $10:
проценты = 0.10 * начальный остаток
В то же время Клео сделала вклад на сумму $100 под сложные проценты, которые составляют 5%. Другими словами, 5% от текущего остатка, с учетом начисленных ранее процентов:
проценты = 0.05 * текущий остаток
Доход Клео за первый год составит 5% от суммы вклада $100, что даст остаток $105. В следующем году ее доход в виде 5% от суммы $105 составит $5.25 и т.д. Напишите программу, которая определяет, сколько лет потребуется для того, чтобы сумма вклада Клео превысила сумму вклада Дафны, а затем отображает сумму обоих вкладов в этот момент.
Допустим, что читатель занимается продажей книги "Delphi для дураков". Напишите программу, которая требует ввода объема ежемесячных продаж этой книги в течение года (в экземплярах книг, а не в денежном выражении). В этой программе должен быть использован цикл, предлагающий ввести данные продаж за каждый месяц. Для этого используется строковый массив, инициализированных с присвоением строковых названий месяцев года. Введенные данные сохраняются в массиве значений типа Integer. После этого программа должна найти сумму содержимого массива и выдать отчет об общем объеме продаж за год.
Выполните упражнение 4, однако на сей раз воспользуйтесь двумерным массивом для хранения введенных данных о продажах за 1-й квартал в течение трех лет. Выдайте отчет об общем объеме продаж за каждый год в отдельности и в целом за все годы.
Разработайте структуру с именем саr, в которой хранится следующая информация об автомобиле: его марка в виде строки (массива символов), а также год его выпуска в виде целого числа. Напишите программу, которая запрашивает пользователя о том, сколько автомашин следует ввести в каталог. Затем программа должна использовать оператор new для создания нового динамического массива в соответствии с указанным количеством структур саr. Далее она должна выдать запрос ввода марки (которая может состоять из нескольких слов) и года выпуска автомашины для каждой структуры. Следует заметить, что этот процесс требует некоторого внимания, поскольку при этом поочередно осуществляется чтение строковых и числовых данных. И, наконец, программа должна отобразить содержимое каждой структуры. Результат выполнения программы должен выглядеть примерно следующим образом:
How many cars do you wish to catalog? 2.
Car #1:
Please enter the make: Hudson Hornet
Please enter the year made: 1952
Car #2:
Please enter the make: Kaiser
Please enter the year made: 1951
Here is your collection: