TURBO PASCAL

Новости           

Программы

Turbo Pascal

Игры

Документация

"Странности"

FAQ

Ссылки

Гостевая книга

Рассылка

Благодарности

От автора

 

 

 
Зацикливаемся
Вступление
Теория
Программа
Голосование
Послесловие

Вступление

Здраствуйте, те кто читает эту рассылку!
Имеем счастье доложить - программа минимум уже выполнена! Читата из первого сообщения в гостевой книге нашего сайта гласит: " Я знаю много рассылок по программированию. И большенство из них умирали не доходя до циклов... " Этот выпуск посвящён циклам. Так что назначайте теперь программу максимум :)
Написать её можно на мыло или на сайте там же можно взять предыдущие выпуски рассылки.
В прошлый раз было голосование - результаты в том же разделе.

Теория

 

Сегодня мы поговорим о циклах. Что это такое? Давайте представим, что вам необходимо вывести на экран слово ПРИВЕТ! двадцать раз. Писать: writeLn ('ПРИВЕТ'); 20 раз !!! А если нужно сто раз? А если заранее неизвестное число раз?? Как быть? Вот тут и нужны циклы.
Цикл - кусок кода, который повторяется определённое число раз (бесконость - это тоже определённое число раз!).

Цикл FOR

Этот цикл наиболее часто используется в программах ввиду его чрезвычайной удобности. Итак знакомтесь, цикл for!
Давайте рассмотрим его использованние на примере с выводом слова привет на экран. Да давайте оговоримся, что будем опускать стандартные куски программы типа Program, var, begin, end. И ещё одно соглашение об именах переменных: обычно именами i и j дают переменным целого типа и их объявление мы тоже будем опускать. Итак пример:

for i := 1 to 20 do
     writeLn ('Привет!');

Цикл записывается так for переменная_цикла := начальное_значение to конечное_значение do операторы;

В нашем примере мы взяли в качестве переменной цикла взята переменная i, начальное значение 1, конечное - 20. Что это значит? А это значит, что цикл будет выполняться для i = 1, 2, 3, 4, 5 ... 19, 20. Т.е. 20 раз. Каждый раз мы прибавляем к i еденицу. При этом начальное и конечное значение переменной цикла может задаваться численным выражением (например for i := 1 to 3*65 do ....) или выражением с переменной (например for i := X + Y to X * Y / Z + 45 *j do ....). При этом эти значения вычисляются компилятором один раз перед выполнением цикла. Например, результат такой программы:

Program   Test;

var  
   i : integer;
   x : integer;
begin  
     x := 10;
     for i := 0 to х do  
     begin  
       writeLn (i, ' ', x);
       x := x + 2
     end  
end.

Будет таким :
0 10
1 12
2 14
3 16
4 18
5 20
6 22
7 24
8 26
9 28
10 30

Как видите предел i не поменялся, хотя х мы меняем! Использую цикл for нужно соблюдать следующее правило: не нужно менять переменную цикла (т.е. ту переменную, по которой идёт цикл, у нас это была i) внутри него.
Есть ещё один альтернативный вариант цикла for, который используется, когда считать нужно не "снизу вверх" а "сверху вниз". Например мы хотим изменять i не от 1 до 20, а наоборот от 20 до 1. Тогда наш цикл примет вид:

for i := 20 downto 1 do
     writeLn ('Привет!');

Теперь i = 20, 19, ... 2, 1. А так всё аннологично. Основное неудобство состоит в том, что мы не можем задавать закон изменения переменной цикла. Однако и это не так страшно, как кажется на первый взгляд.

Цикл WHILE

Цикл номер два: while! Этот цикл называется циклом с предусловием. Записывается он так:
while условие do оператор;
Такой цикл выполняется пока условие истинно. И прекращается в противном случае. Например такой цикл:

while 1 do
	writeLn ('Привет!');

Приведёт к "зависанию" компьютера, т.к. выражение 1 всегда истинно (не могут же быть числа ложными). выйдти из этого цикла можно нажатием клавиши Ctrl+Break (Ctrl+C) - стандартный выход из ДОС программ. Проверка истистинности условия проводится как и в операторе if.
Давайте покажем, как оператором While можно заменить for:

i := 1;
x := 10;
while i  <=  x do
begin
   writeLn (i, ' ', x);
   x := x + 1;
   i := i + 1
end;

Попробуйте этот код... ну как эффект не тот? :) Давайте разберёмся в чём дело. А вся проблемма в том, что условие (максимальное значение) для цикла for считается зарание один раз заранее! А у нас оно всё время меняется. Ок. Теперь посмотрите результат программы: она останавливается при i = 32 757. Давайте посмотрим ещё один вариант:

i := 1;
x := 10;
while i  <>  x do
begin
   writeLn (i, ' ', x);
   x := x + 1;
   i := i + 1
end;

Запустите и подождите немного.... СТОП! А откуда там отрицательные числа?? Ведь мы прибавляем каждый раз по 1 и 1, т.е. i и х растут ???

Давайте разберёмся по подробнее. Что из себя представляет числовая прямая? Это окружность максимального радиуса, т.е. радиуса бесконечность. Такая окружность вырождается в прямую. Однако для целых чисел (типа integer) эта "бесконечность" известна - 32767 (помните выпуск Типы данных?). Счечик i можно представить, как точку, которая движется по этой окружности. Когда i доходит до максимума, то она становится отрицательной, т.е. -32767!!

А помните предыдущий пример, где всё останавливалось при x = 32 767. Почему так вышло? Прибавляя к х = 32767 один что мы получаем: x + 1 = -32767 !!!! А условие цикла у нас стоит i <= x т.е. когда х = 32 767 i = 32 757, далее х + 1 = -32 767 i + 1 = 32 758 т.е. условие i <= x не выполняется! И поэтому мы выходим из цикла!
Поэтому аккуратнее с максимальным значение integer, оно не такое большое, как может показаться!

Теперь напишем нормальный вариант цикла for через цикл while:

i := 1;
x := 10;
Temp := x;
while i  <= Temp do
begin
   writeLn (i, ' ', x);
   x := x + 1;
   i := i + 1
end;

Здесь мы заранее посчиталь верхнюю границу цикла в переменную temp и тем самым всё работает правильно.

Ну и напоследок...

Ну вот мы подошли к последнему циклу. Он называется цикл с постусловием, цикл: repeat-until ! Этот цикл в общем и целом анологичен while, но есть два отличия. Вот как он записывается: repeat оператор until условие;

Итак его отличия от while:

  1. самое важное: проверка условия совершается после выполнения оператора. Таким образом этот цикл обязательно выполнится хотя бы один раз. В то время как while, может и не выполняться ни разу.
  2. не самое важное, но очень нужно запомнить, что критерием прекращения цикла является тот случай, когда условие истинно, а если оно ложно, то цикл продолжится! В то время как в while абсолютно противоположная ситуация.

Давайте же рассмотрим какой-нить пример:

i := 10;
repeat
     writeLn (i);
	 i := i - 1
until i = 0;

Этот цикл выполняется пока i не равно нулю. Т.е. для значений i = 10, 9, 8 ..... 2, 1. Обратите внимание, что мы не используем операторы begin-end т.к. этот цикл доспукает использовать в своём теле сколько хочешь операторов в отличие от while и for.

Вот написал и вспомнил о том, что не сказал, что такое тело цикла :( Вот дырявая башка! Итак тело цикла - это та последовательность операторов, которая выполниется. Т.е. например все операторы между repeat и until - это и есть тело цикла.

Программа

Итак сегодня мы продолжим изучать Отладчик и напишем ещё одну программу.
Наша новая программа - факториал! Что такое факториал? По определению факториал числа n (обозначается n! ) n! = 1 * 2 * 3 *....* (n-1) * n - т.е. перемножение чисел от 1 до n. Итак вот программа:

Program Factorial;

uses CRT;

var
   n, i : integer;
   Result : longint;
begin
     ClrScr;

     Write ('Какое значение? ');
     ReadLn (n);

     Result := n;

     for i := 0 to n do
     begin
         Result := Result * i
     end;	

     writeLn ('Результат: ', Result);
	 ReadLn
end.

Давайте же помотрим результат!!!! Запускаем вводим число... ЧТО ЭТО ЗА НАФИГ??? Почему 0? ... запускаем вновь ... опять 0! Досада. Видимо в программу залезла логическая ошибка! Ну вот теперь мы познаем всю мощь отладчика!
Итак строки:

begin
     ClrScr;

     Write ('Какое значение? ');
     ReadLn (n);

Выглядят довольно понятно и ошибка явно не в них. Так зачем же нам тратить наше драгоценное время на их пошаговое исполнение? Давайте сразу же перейдем к следующей строке. Наведите на неё курсор и нажмите Ctrl+F8 (меню Debug - > Add breakpoint) Она подсветится красным цветом. Что же такого чудесного мы сделали? А вот что: мы добавили breakpoint (по-русски: брякпоинт, бряк:) - точку остановки. Когда исполнение программы дойдёт до этой строчки, то мы сразуже перейдём в режим по-шагового исполнения. Увидите список бряков можно Debug -> Breakpoints.
Итак бряк есть, теперь нам нужно всё время смотреть, что же у нас в переменной Result. Этого можно добится двумя путями.

  1. Добавить внутрь цикла строчку типа: writeLn (Result);
  2. Использовать отладчик.

Второе на мой взгляд несколько предпочтительнее :) Давайте сделаем вот что: выберем Debug -> Add Watch или Ctrl+F7 - в появившемся диалоге укажем имя нашей переменной: Result (в поле Watch expression) Появится окно watches (если не появилось, то Debug -> Watch). В нём вы увидите значение переменной Result. Так же можно для практики добавить туда и переменные i и n. Так тепрь мы можем наблюдать, что же там внутри и как меняются переменные.

Ну вот, теперь запускаем программу (Ctrl+F9), вводим для примера 5 и сразу же оказываемся внутри программы.
Заметьте, что у нас такие значения: Result = 0, i = 0, n = 5. Давим на F8 (не забыли что это такое:) Result изменился с 0 на 5 (делаем вывод: оператор := работает правильно, ошибка не в нём :))))

Входим в цикл (давим F8)... Заметьте, что я специально добавил в цикл конструкцию begin-end (в неё нет надобности). Я это сделал, что бы при отладке внутри цикла у нас подсветка двигалась :) а иначе она просто будет висеть на строчке: Result := Result * i; и создаётся впечатление остановки программы.

Итак проходим первый этап цикла (i = 0) опа!! Вот оно! Result сразу же изменился на 0 ! Давайте посмотрим, что же будет дальше... а дальше он так и останется 0. Можно заметить, что мы умножаем Result на i, но ведь в начале цикла i = 0 т.е. мы умножаем на 0 и поэтому Result всегда 0! УРА! Нашли ошибку! Прервём исполнение программы (Ctrl+F2). Для устранения ошибки мы сделаем следующее: в цикле i должно изменяться от 1 до n. Я надеюсь, что переписать программу для вас не составит труда. Итак исправим, уберём бряк (на той строчке Ctrl+F8)

Запустим программу... ВОТ ЧЁРТ! Теперь Result не 0 но очень уж большой!!!! В чём же дело?? Давайте повторим всё заново: поставим бряк и запустим её снова... введём 5... Постойте ка а почему это у нас Result в начале равен 5?? Ведь факториал это произведение от 1 до n ??? Да вот же в чём дело! Мы вначале присваиваем Result := n; А надо так: Result := 1; Теперь всё нормально!
Давайте удалим всю отладочную информацию: Очистим все бряки (Debug -> Breakpoints . кнопка Clear All) Удалим все просмоторщики (в окне watches правая кнопка мыши из меню Clear All) и выполним программу заново.

Ещё одна мелочь, которая не сразу бросается в глаза: переменная Result у нас типа longint, однако и этого не достаточно, что бы вместить факториалы чисел больше 31! Как подсчитать факториал для любых чисел мы поговорим попозже. Обязательно поговорим!

Голосование

Итак в прошлый раз нам было интересно узнать, что вы думаете по поводу нового дизайна рассылки. Так вот только после выхода выяснилось, что в почтовой программе the Bat! некоторые места отображаются некорректно. Поэтому лучше чиать странику в Opere'e или ещё лучше в Internet Explorer'e. Соответственно дизайн рассылки некоторое время останется неизменным, а потом мы чего-нибудь придумаем получше. Кстате голосование доступно до 5 ноября по этой ссылке.

Послесловие

За сим позвольте откланятся.

Если, что надо - мыльте ibp7@yandex.ru.
© 2002 Использование материалов без согласия авторов запрещено.
 

На первую страницу

 

Rambler's Top100 PROext: Top 1000 Rambler's Top100
(с)Все права защищены

По всем интересующим вопросам прошу писать на электронный адрес

Hosted by uCoz