Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Delphi через Прат.doc
Скачиваний:
2
Добавлен:
14.11.2019
Размер:
631.81 Кб
Скачать

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)

  1. В чем заключается различие между циклом с предусловием и циклом с постусловием?

  2. Что будет выведено в результате выполнения следующего фрагмента кода, если включить его в реальную программу:

for i:=0 to 4 do

Write(i);

Writeln;

  1. Что будет выведено в результате выполнения следующего фрагмента кода, если включить его в реальную программу:

var

j: Integer = 0;

begin

while j < 11 do

begin

Write(j);

j := j + 3;

end;

Writeln;

Writeln(j);

Readln;

end.

  1. Создайте цикл while, который выводит значения 1, 2, 4, 8, 16, 32, 64 при увеличении в 2 раза значения счетчика на каждом шаге цикла.

  2. Каким образом можно включить в тело цикла несколько операторов?

Упражнения по программированию (4)

  1. Напишите программу, которая запрашивает у пользователя ввод двух целых чисел. Затем эта программа должна вычислить и отобразить сумму всех целых чисел, находящихся в пределах между двумя введенными целыми числами и включая их. При этом предполагается, что первым вводится меньшее целое число. Например, если пользователь вводит 2 и 9, то программа сообщает, что сумма всех целых чисел от 2 до 9 составляет 44.

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

  3. Дафна сделала вклад на сумму $100 под простые проценты, которые составляют 10%. Итак, ежегодно ее вклад дает доход в сумме 10% от первоначального вклада, или $10:

проценты = 0.10 * начальный остаток

В то же время Клео сделала вклад на сумму $100 под сложные проценты, которые составляют 5%. Другими словами, 5% от текущего остатка, с учетом начисленных ранее процентов:

проценты = 0.05 * текущий остаток

Доход Клео за первый год составит 5% от суммы вклада $100, что даст остаток $105. В следующем году ее доход в виде 5% от суммы $105 составит $5.25 и т.д. Напишите программу, которая определяет, сколько лет потребуется для того, чтобы сумма вклада Клео превысила сумму вклада Дафны, а затем отображает сумму обоих вкладов в этот момент.

  1. Допустим, что читатель занимается продажей книги "Delphi для дураков". Напишите программу, которая требует ввода объема ежемесячных продаж этой книги в течение года (в экземплярах книг, а не в денежном выражении). В этой программе должен быть использован цикл, предлагающий ввести данные продаж за каждый месяц. Для этого используется строковый массив, инициализированных с присвоением строковых названий месяцев года. Введенные данные сохраняются в массиве значений типа Integer. После этого программа должна найти сумму содержимого массива и выдать отчет об общем объеме продаж за год.

  2. Выполните упражнение 4, однако на сей раз воспользуйтесь двумерным массивом для хранения введенных данных о продажах за 1-й квартал в течение трех лет. Выдайте отчет об общем объеме продаж за каждый год в отдельности и в целом за все годы.

  3. Разработайте структуру с именем са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:

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]