Опубликован: 25.06.2014 | Уровень: для всех | Доступ: платный | ВУЗ: Учебный центр "ANIT Texno Inform"
Лекция 10:

Циклы и переключатель case

Аннотация: В данной лекции мы изучим работу с циклами for, while, repeat, и переключателем case. Рассмотрим весь материал на небольших практических примерах, показывающих все особенности работы с циклами.

Цель лекции

Изучение циклов и оператора выбора case. Применение этих инструментов на практике в различных случаях.

Циклы

На этой лекции мы поговорим еще об одном способе организовать логику программы - о циклах. Довольно часто программисту приходится выполнять какой-то участок кода заданное количество раз, или до тех пор, пока не наступит какое-то условие. Такой повтор кода и называется циклом.

Цикл - последовательный повтор части кода от нуля раз до бесконечности.

Действительно, бывают условия, при которых цикл не выполняется ни разу. А бывает и так, что цикл начинает выполняться бесконечно, при этом программа "зависает" - не реагирует на клавиатуру и мышь, не дает продолжать с ней работу. Но это уже ошибка программиста. Циклы бывают двух видов - по счетчику, и по условию. Первые выполняются заданное количество раз, вторые - пока не наступит определенное логическое условие. Именно второй тип циклов начинающие программисты могут "зациклить", не предусмотрев гарантированного наступления условия их завершения. Но давайте-ка по порядку.

Цикл for…to…do

Цикл for…to…do выполняется определенное количество раз, по счетчику. Счетчик представляет собой переменную целочисленного типа - обычно используют integer, но если цикл должен выполниться 10-20 раз, вполне можно обойтись типом byte, чтобы не тратить впустую лишних 3 байта оперативной памяти. Синтаксис цикла следующий:

for <счетчик>:= <начальное значение> to <конечное значение> do <оператор>;
    

Здесь, счетчик, как говорилось выше - переменная целого типа. Начальное и конечное значения - целые числа, например, от 1 до 10. Оператор - та часть кода, которую нужно выполнить нужное количество раз. Нередко бывает так, что нужно выполнить не один оператор, а несколько. В этом случае делают составной оператор, поместив весь нужный код между операторными скобками begin…end:

for <счетчик>:= <начальное значение> to <конечное значение> do begin
   Оператор 1;
   Оператор 2;
   …
   Оператор n;
end;
    

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

Загрузите Lazarus с новым проектом. Сохраните его в папку 10-01 там, где вы храните все учебные проекты. Проект назовите, скажем, MyCycles. Как назвать главную форму, вам уже, наверное, не нужно напоминать? Посреди окна установите простую кнопку TButton, переименовывать её не нужно, но в Caption напишите

for…do
    

Сгенерируйте для кнопки событие OnClick, в котором напишите следующий код:

procedure TfMain.Button1Click(Sender: TObject);
var
  b: byte;
begin
  for b:= 1 to 10 do ShowMessage('Проход цикла №' + IntToStr(b));
end;
    

Что, по-вашему, произойдет при нажатии на кнопку? Выйдет окошко с сообщением "Проход цикла №1". Как только вы нажмете <OK>, выйдет новое сообщение "Проход цикла №2". И так будет 10 раз, при этом b будет автоматически увеличиваться на 1. После того, как b станет равно 10, и цикл выполнится в последний раз, процедура Button1Click завершит работу и управление перейдет обратно главной форме.

В данном примере цикл for наращивал счетчик по возрастающей, от 1 до 10. Но у этого цикла есть ещё одна форма, когда счетчик не увеличивается, а уменьшается на единицу:

for <счетчик>:= <начальное значение> downto <конечное значение> do <оператор>;
    

Разница здесь только в том, что вместо ключевого слова to мы указываем downto. И, разумеется, в этом случае начальное значение счетчика должно быть больше конечного значения. Переделайте строку с циклом так:

  for b:= 10 downto 1 do ShowMessage('Проход цикла №' + IntToStr(b));
    

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

Инструкции break и continue

Циклы не всегда нужно выполнять от начала, и до конца. Иногда, в зависимости от условий, бывает необходимо пропустить какие-то шаги цикла, или вовсе досрочно завершить цикл. Для этого и служат инструкции break и continue.

Break - инструкция досрочного завершения работы цикла.

Изменим пример процедуры Button1Click. Предположим, нам нужно вывести на экран результаты деления числа 100 на числа от -10 до 10. НО! На ноль делить нельзя, поэтому мы выполним проверку: если второе число - ноль, мы завершим цикл. А чтобы нам не пришлось много раз нажимать на <OK>, как в прошлом примере, результаты мы соберем в одну строку и в конце цикла разом выведем её на экран. Итак, код:

procedure TfMain.Button1Click(Sender: TObject);
var
  s: string; //для сбора результатов деления
  b: ShortInt; //счетчик
  r: real; //результат деления
begin
  for b:= -10 to 10 do begin  //начало цикла
    //если ноль, не делим, а сразу выходим из цикла:
    if b = 0 then break;
    // делим:
    r:= 100 / b;
    //теперь добавляем результат в строку s:
    s:= s + '100 / ' + IntToStr(b) + ' = ' + FloatToStr(r) + #13;
  end;  //конец цикла

  //теперь разом выводим все полученные результаты:
  ShowMessage(s);
end;
    

Я постарался дать подробные комментарии, но всё же остановимся на некоторых моментах. Прежде всего, бросается в глаза, что переменной b вместо предыдущего типа byte мы назначили тип ShortInt. Ведь нам нужно считать от -10 до 10, а byte имеет диапазон от 0 до 255, отрицательные величины этим типом не поддерживаются. Тип ShortInt также занимает 1 байт, но он имеет диапазон от -128 до 127, и в данном случае подходит нам больше всего. Если же мы попытаемся оставить счетчику тип byte, то компилятор просто выведет ошибку нарушения допустимого диапазона, и не соберет исполняемую программу, не запустит её.

Далее, для получения результатов деления мы использовали переменную типа real. Ведь деление одного целого числа на другое не всегда даст целое число! Например, 100 / -8 = -12,5. Поэтому и переменная для результата у нас вещественного типа.

Затем у нас начинается цикл. Вначале мы проверяем, не равна ли b нулю. Если равна, то сразу же завершаем цикл, при этом управление передается на следующий за циклом оператор

ShowMessage(s);
    

Если b не равна нулю, то цикл продолжает свою работу, выполняя деление 100 на b. Поскольку значение b будет изменяться при каждом проходе, то и результат все время будет другой. И так будет, пока b не поменяет значение от -10 до 0. Как только это случится, цикл закончится.

Самой сложной строкой цикла является оператор сбора строки s:

s:= s + '100 / ' + IntToStr(b) + ' = ' + FloatToStr(r) + #13;
    

Смотрите, как формируется эта строка. В начале выражения у нас стоит "s + ", то есть, предыдущее значение s не теряется, а добавляется к новой строке, причем при первом проходе цикла s еще пуста, зато потом она уже будет содержать текст! Затем мы собираем строку из разных частей. Сначала идет часть "100 / ", затем к ней добавляется значение счетчика b, преобразованное в строку, затем добавляется часть строки " = ". Потом к строке добавляется результат деления, преобразованный функцией FloatToStr() в строковое выражение. И в самом конце мы добавляем символ перехода на новую строку #13. Таким образом, у нас каждое выражение будет на новой строке, не смешиваясь в кашу. В результате нажатия на кнопку мы получим следующее сообщение:

Досрочный выход из цикла

Рис. 10.1. Досрочный выход из цикла

Как видите, строка цикла

if b = 0 then break;
    

не позволила нам сделать деление на ноль, и мы избежали ошибки. Но тут сразу бросается незавершенность работы цикла. А как же целая часть, от 1 до 10?! Чтобы исправить положение, замените break на continue:

if b = 0 then continue;
    
Continue - инструкция пропуска оставшейся части цикла и переход к новому шагу цикла. Цикл при этом не завершается.

Нажав на кнопку, вы убедитесь, что теперь цикл выполняется до конца, от -10 до 10, пропустив лишь нулевое значение. Однако и тут дотошный пользователь сможет найти недостаток. Куда делся ноль то? Ну да, на ноль делить нельзя, но что-то ведь нужно вывести в этой позиции! Давайте поступим, как стандартный калькулятор Windows: в случае, если b равно нулю, выведем сообщение, что деление на нуль запрещено. Нам нужно только изменить условие if, сделав составной оператор:

if b = 0 then begin
  s:= s + 'Деление на нуль запрещено';
  continue;
end;
    

Как видите, в случае, если b равна нулю, мы в данной позиции выводим соответствующее сообщение, после чего пропускаем всю оставшуюся часть данного шага цикла (не делаем деление).

На всякий случай, полный код процедуры:

procedure TfMain.Button1Click(Sender: TObject);
var
  s: string; //для сбора результатов деления
  b: ShortInt; //счетчик
  r: real; //результат деления
begin
  for b:= -10 to 10 do begin  //начало цикла
    //если ноль, не делим, а пропускаем шаг цикла с соответствующим сообщением:
    if b = 0 then begin
      s:= s + 'Деление на нуль запрещено' + #13;
      continue;
    end;
    //сначала делим:
    r:= 100 / b;
    //теперь добавляем результат в строку s:
    s:= s + '100 / ' + IntToStr(b) + ' = ' + FloatToStr(r) + #13;
  end;  //конец цикла

  //теперь разом выводим все полученные результаты:
  ShowMessage(s);
end;
    

В результате мы получим такое сообщение:

Пропуск шага цикла

Рис. 10.2. Пропуск шага цикла
Инга Готфрид
Инга Готфрид
Александр Скрябнев
Александр Скрябнев

Через WMI, или используя утилиту wmic? А может есть еще какие более простые пути...

Нина Фисенко
Нина Фисенко
Россия, Саратов, Саратовский государственный университет им Чернышевского, 1972
Галина Талисман
Галина Талисман
Россия