АЙТИШНЫЙ САЙТ ПЕТРА СЕМИЛЕТОВА

ПЕТР СЕМИЛЕТОВ

ПРОСТО С++: УРОК 8

Циклы - как в программе повторять одно и то же

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

Пример циклов из жизни. Лепить пирожки, пока не закончится тесто. Варить картошку и проверять вилкой, сварилась ли, пока картошка не станет мягкой. Или - съесть один за другим десять пончиков и сытым завалиться спать.

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

В С++ есть три вида циклов. Первый вид обеспечивается оператором while, что переводится как “пока”, покуда. Пока истинно заданное условие, выполняется тело цикла. Условие помещается в круглые скобки после слова while, а тело цикла - в фигурные скобки, как любой другое составное выражение.

Рассмотрим пример 09-01.cpp:

#include <iostream>

using namespace std;

int main (int argc, char *argv[])
{
  string s;

  while (s != "выход")
            {
              cout << "введите слово: ";
              cin >> s;
              cout << "спасибо!"  << endl;
            }
  
  return 0;
}

Мы объявляем строковую переменную s, и потом запускаем цикл.

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

В теле цикла мы просим пользователя ввести слово, и оно записывается в переменную s, после чего программа пишет “спасибо!”.

while (s != "выход") означает, что мы задали такое условие, при котором значение s не равно слову “выход”.

Напомню, что while переводится как “пока”, “покуда”. Итак, всё вместе значит - пока значение переменной s не станет равно слову “выход”, мы продолжаем выполнять цикл, те выражения, которые заключены в его теле между фигурными скобками. Точка выполнения доходит в теле цикла до строки

   cout << "спасибо!"  << endl;

И возвращается к началу, к проверке условия:

   while (s != "выход")

Если s на этом этапе не равна слову “выход”, то снова начинается выполнение цикла с первой строчки его тела, с

   cout << "введите слово: ";

А если равна, то происходит, еще на уровне проверки условия, выход из цикла и выполнение программы дальше. А поскольку наша программа на этом и заканчивается, то следует завершение программы.

Каждое выполнение тела цикла, его прогонка, называется итерацией.

У цикла на основе while есть вариант, где условие выполнения цикла проверяется не в начале цикла, а в конце, при этом конечно же самая первая итерация идет безо всякой проверки.

Пример 09-02.cpp:

#include <iostream>

using namespace std;

int main (int argc, char *argv[])
{
  string s;

  do
      {
        cout << "введите слово: ";
        cin >> s;
        cout << "спасибо!"  << endl;
       }
  while (s != "выход")
  
  return 0;
}

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

Наконец, третий вид цикла это цикл for - в переводе означает “для”, более широко - “условие и действия для каждой итерации”.

Например, мы хотим вывести на экран числа от 1 до 21. Давайте решим эту задачу без циклов и с циклами.

Без цикла это будет громоздко и нудно, 09-03.cpp:

#include <iostream>

using namespace std;

int main (int argc, char *argv[])
{
  cout << "1" << endl;
  cout << "2" << endl;
  cout << "3" << endl;
  cout << "4" << endl;
  cout << "5" << endl;
  cout << "6" << endl;
  cout << "7" << endl;
  cout << "8" << endl;
  cout << "9" << endl;
  cout << "10" << endl;
  cout << "11" << endl;
  cout << "12" << endl;
  cout << "13" << endl;
  cout << "14" << endl;
  cout << "15" << endl;
  cout << "16" << endl;
  cout << "17" << endl;
  cout << "18" << endl;
  cout << "19" << endl;
  cout << "20" << endl;
  cout << "21" << endl;
  
  return 0;
}

Как бы мы решили эту задачу при помощи цикла while?

09-04.cpp:

#include <iostream>

using namespace std;

int main (int argc, char *argv[])
{
  int i = 1;

  while (i < 22)
            {
              cout << i++ << endl;
            }
 
  return 0;
}

Итак, объявляем вне цикла переменную i - программисты любят i, сокращение от индекс.

Затем условием цикла ставим, что цикл выполняется пока i меньше 22, и в теле цикла мы выводим на консоль значение i, увеличивая его с каждой итерацией, прогонкой цикла, на единицу.

Как то же самое выразить через цикл for? Пример 09-05.cpp:

#include <iostream>

using namespace std;

int main (int argc, char *argv[])
{

   for (int i = 1; i < 22; i++)
         cout << i << endl;
  
  return 0;
}

Что же, в цикле for и условие цикла, и приращение счетчика вынесены в сам заголовок цикла, и даже объявление переменной-счетчика i там же. Тело цикла коротко, если оно как у нас одной строкой, можно не заключать его в фигурные скобки. Это касается и циклов с while.

Итак, формат цикла for таков.

После слова for мы в круглых скобках пишем, разделяя точкой с запятой:

объявление переменной-счетчика с начальным значением; условие, при котором продолжает выполняться цикл; математическое действие над счетчиком

Цикл for может содержать в своем заголовке несколько переменных-счетчиков и проверок условий, а также действий над счетчиками, что разделяется запятыми. Однако это усложняет читаемость кода.

Пример 09-06.cpp:

#include <iostream>

using namespace std;

int main (int argc, char *argv[])
{
   for (int x = 1, y = 1; x < 10; x++, y++)
         cout << "x: " << x << " y: " << y << endl;
  
  return 0;
}

Здесь в цикле мы объявляем переменные x и y, и каждую увеличиваем на единицу, пока x меньше 10.

Помните! Переменные, объявленные в заголовке цикла или его теле, вне цикла не видны, не существуют.

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

  for (int i = 1; i < 5; ++i)
      cout << i << endl;

или эдак:

  for (int i = 1; i < 5; ++i)
      cout << i << endl;

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

А в цикле while работают как префиксные!

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

09-05-01.cpp

#include <iostream>

using namespace std;

int main (int argc, char *argv[])
{
   cout << "for:" << endl;

   for (int i = 1; i < 5; i++)
         cout << i << endl;
}

В итоге на консоль выведется:

for:
1
2
3
4

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

09-05-02.cpp

#include <iostream>

using namespace std;

int main (int argc, char *argv[])
{
   cout << "while:" << endl;

   int x = 1;

   while (x++ < 5)
         cout << x << endl;

  return 0;
}

Ради интереса поменяйте x++ на ++x и посмотрите, что будет. Короче говоря, в условии цикла здесь имеет значение постфиксная ли форма, или префиксная, а вот в тело цикла пойдет уже увеличенное на единицу значение x.

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

09-05-03.cpp

#include <iostream>

using namespace std;

int main (int argc, char *argv[])
{
   cout << "while:" << endl;

   int x = 1;

   while (x < 12)
         cout << x++ << endl;

  return 0;
}

Внутри цикла можно использовать два ключевых слова, break - прервать и continue - продолжить.

break вызывает немедленный выход из тела цикла и переход к следующему после тела цикла выражению.

continue вызывает переход к новой итерации цикла, к его заголовку, то есть если вы по какой-то причине не хотите выполнять эту итерацию дальше, а хотите начать новую, то надо вызвать continue.

Пример 09-07.cpp поможет разобраться в этом, особенно это очевидно, если откомпилировать, запустить эту программу и смотреть по исходному коду, как она работает:

#include <iostream>

using namespace std;

int main (int argc, char *argv[])
{
  int x;
  int i = 0;

  while (s != "выход")
            {
              cout << "итерация номер "  << ++i << endl;              

              cout << "введите число и нажмите энтер: ";
              cin >> x;
              cout << "спасибо!" << endl;

              if (x == "1")
                 break;

             if (s == "2")
                 continue;

             cout << "достигли конца цикла" << endl;

            }
  
   cout << "вот тут мы вышли из цикла" << endl;

  return 0;
}

Если пользователь вводит число “1”, мы вызываем break, если ввел “2”, вызываем continue. Счетчик i выводится в начале цикла, и мы видим номер каждой итерации. Наконец, в конце цикла на экран выводится сообщение, что вы достигли конца цикла.

А после выхода из цикла мы увидим надпись “вот тут мы вышли из цикла”.

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

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

На сегодня всё!

Поддержать курс:

Навигация:

Оглавление

Предыдущий урок

Следующий урок