Урок №69. Цикл for

  Юрий  | 

  |

  Обновл. 4 Сен 2021  | 

 208218

 ǀ   47 

Безусловно, наиболее используемым циклом в языке C++ является цикл for.

Цикл for

Цикл for в языке С++ идеален, когда известно необходимое количество итераций. Выглядит он следующим образом:

for (объявление переменных; условие; инкремент/декремент счетчика)
    тело цикла;

Или, преобразуя for в эквивалентный цикл while:

{ // обратите внимание, цикл находится в блоке
    объявление переменных;
    while (условие)
    {
       тело цикла;
       инкремент/декремент счетчика;
    }
} // переменные, объявленные внутри цикла, выходят из области видимости здесь

Переменные, определенные внутри цикла for, имеют специальный тип области видимости: область видимости цикла. Такие переменные существуют только внутри цикла и недоступны за его пределами.

Выполнение цикла for


Цикл for в C++ выполняется в 3 шага:

   Шаг №1: Объявление переменных. Как правило, здесь выполняется определение и инициализация счетчиков цикла, а точнее — одного счетчика цикла. Эта часть выполняется только один раз, когда цикл выполняется впервые.

   Шаг №2: Условие. Если оно равно false, то цикл немедленно завершает свое выполнение. Если же условие равно true, то выполняется тело цикла.

   Шаг №3: Инкремент/декремент счетчика цикла. Переменная увеличивается или уменьшается на единицу. После этого цикл возвращается к шагу №2.

Рассмотрим пример цикла for и разберемся детально, как он работает:

Сначала мы объявляем переменную count и присваиваем ей значение 0. Далее проверяется условие count < 10, а так как count равен 0, то условие 0 < 10 имеет значение true. Следовательно, выполняется тело цикла, в котором мы выводим в консоль переменную count (т.е. значение 0).

Затем выполняется выражение ++count, т.е. инкремент переменной. Затем цикл снова возвращается к проверке условия. Условие 1 < 10 имеет значение true, поэтому тело цикла выполняется опять. Выводится 1, а переменная count увеличивается уже до значения 2. Условие 2 < 10 является истинным, поэтому выводится 2, а count увеличивается до 3 и так далее.

В конце концов, count увеличивается до 10, а условие 10 < 10 является ложным, и цикл завершается. Следовательно, результат выполнения программы:

0 1 2 3 4 5 6 7 8 9

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

Обратите внимание, внешние фигурные скобки здесь необходимы, так как переменная count выходит из области видимости при завершении цикла.

Еще примеры циклов for

Давайте, используя цикл for, напишем функцию вычисления значений в степени n:

Функция возвращает значение base^exponent (число в степени n). base — это число, которое нужно возвести в степень, а exponent — это степень, в которую нужно возвести base.

   Если экспонент равен 0, то цикл for выполняется 0 раз, и функция возвращает 1.

   Если экспонент равен 1, то цикл for выполняется 1 раз, и функция возвращает 1 * base.

   Если экспонент равен 2, то цикл for выполняется 2 раза, и функция возвращает 1 * base * base.

Хотя в большинстве циклов используется инкремент счетчика, мы также можем использовать и декремент счетчика:

Результат:

8 7 6 5 4 3 2 1 0

Также с каждой новой итерацией мы можем увеличить или уменьшить значение счетчика больше, чем на единицу:

Результат:

9 7 5 3 1

Ошибка неучтенной единицы


Одна из самых больших проблем с которой приходится сталкиваться начинающим программистам в циклах for (а также и в других типах циклов) — это ошибка на единицу (или «ошибка неучтенной единицы»). Она возникает, когда цикл повторяется на 1 раз больше или на 1 раз меньше нужного количества итераций. Это обычно происходит из-за того, что в условии используется некорректный оператор сравнения (например, > вместо >= или наоборот). Как правило, эти ошибки трудно отследить, так как компилятор не будет жаловаться на них, программа будет работать, но её результаты будут неправильными.

При написании циклов for помните, что цикл будет выполняться до тех пор, пока условие является истинным. Рекомендуется тестировать циклы, используя разные значения для проверки работоспособности цикла. Хорошей практикой является проверять циклы с помощью данных ввода (чисел, символов и прочего), которые заставляют цикл выполниться 0, 1 и 2 раза. Если цикл работает исправно, значит всё ОК.

Правило: Тестируйте свои циклы, используя входные данные, которые заставляют цикл выполниться 0, 1 и 2 раза.

Пропущенные выражения в цикле

Также в циклах можно пропускать одно или сразу все выражения, например:

Результат:

0 1 2 3 4 5 6 7 8 9

Инициализацию счетчика мы прописали вне тела цикла, а инкремент счетчика — внутри тела цикла. В самом операторе for мы указали только условие. Иногда бывают случаи, когда не требуется объявлять счетчик цикла (потому что у нас он уже есть) или увеличивать его (так как мы увеличиваем его каким-то другим способом).

Хоть это и не часто можно наблюдать, но в операторе for можно вообще ничего не указывать. Стоит отметить, что подобное приведет к бесконечному циклу:

for (;;)
    тело цикла;

Вышеприведенный пример эквивалентен:

while (true)
    тело цикла;

Объявления переменных в цикле for


Хотя в циклах for обычно используется только один счетчик, иногда могут возникать ситуации, когда нужно работать сразу с несколькими переменными. Для этого используется оператор Запятая. Например:

Этот цикл присваивает значения двум ранее объявленным переменным: aaa = 0 и bbb = 9. Только с каждой итерацией переменная aaa увеличивается на единицу, а bbb — уменьшается на единицу.

Результат выполнения программы:

0 9
1 8
2 7
3 6
4 5
5 4
6 3
7 2
8 1
9 0

Примечание: Вышеприведенный цикл можно переписать следующим образом:

В этом случае запятая в объявлении переменных является частью синтаксиса, а не использованием оператора Запятая. Но эффект идентичен.

Использование циклов for в старых версиях С++

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

Позднее это было запрещено, но вы все еще можете увидеть подобное в старом коде.

Вложенные циклы for

Подобно другим типам циклов, одни циклы for могут быть вложены в другие циклы for. В следующем примере мы разместили один for внутри другого for:

С одной итерацией внешнего цикла выполняется три итерации внутреннего цикла. Следовательно, результат выполнения программы:

a012
b012
c012
d012
e012

Заключение

Циклы for являются наиболее часто используемыми циклами в языке C++. Несмотря на то, что их синтаксис, как правило, немного запутывает начинающих программистов, вы очень скоро к нему привыкните и ощутите всю мощь и удобство этих циклов.

Тест

Задание №1

Напишите цикл for, который выводит каждое четное число в диапазоне от 0 до 20.

Ответ №1

Задание №2

Напишите функцию sumTo(), которая принимает целочисленный параметр с именем value и возвращает сумму всех чисел от 1 до значения value.

Например, если значением value является 5, то sumTo(5) должен возвратить 15, исходя из 1 + 2 + 3 + 4 + 5.

Подсказка: Используйте переменную вне тела цикла для хранения суммы чисел, как в примере с функцией pow() в подзаголовке «Еще примеры циклов for».

Ответ №2

Задание №3

Что не так со следующим циклом?

Ответ №3

Этот цикл for выполняется до тех пор, пока count >= 0. Другими словами, он работает до тех пор, пока переменная count не станет отрицательным числом. Однако, поскольку count является типа unsigned, то эта переменная никогда не сможет быть отрицательной. Следовательно, этот цикл бесконечный! Как правило, рекомендуется избегать использования типов unsigned в цикле, если на это нет веских причин.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (379 оценок, среднее: 4,96 из 5)
Загрузка...

Комментариев: 47

  1. Сашуня:

    Первое задание:

    Второе задание:

  2. SOM:

    Друге завдання

  3. Edman:

    Есть ли разница, в том какой ставить инкремент/декремент, постфиксный или префиксный к счётчику в скобках for ?

  4. fapah13:

    Второе задание с группировкой по столбцам

  5. Иннокентий:

    Циклы в C++ действительно очень крутые, на мой взгляд тот же for в C++ удобней чем он же в Python. Спасибо автору за понятное объяснение!

  6. ОЛЕГ-777:

    Задание 2:
    Немного усложнил задание. В программе пользователь самостоятельно вводит и начальное число и конечное число исследуемого интервала (можно и отрицательные числа). Кроме того оператор goto не дает ввести второе число меньше первого и гоняет пользователя бесконечное количество раз по циклу, пока пользователь не введет второе число больше первого.

    main.cpp:

  7. Андрей:

    Благодарю, вы объясняете лучше чем учителя в моей шараге

    1. Фото аватара Юрий:

      Для этого и делалось 🙂

  8. Ruslan:

    Задание № 2

  9. Ruslan:

  10. Вася:

    Кто решит проще?)

    1. Владимир:

      Проще уже невозможно будет написать

  11. Яна:

    1. Айнур:

      Ваш код не будет работать, так как функция imput() у вас не сделана, а Вы ее вызываете

  12. Павел:

    Попробовал написать программу проверки на палиндромность числа. Прога работает как надо, однако ошибка в конце кода вылазит. Не могу понять с чем связано. Подскажите плиз (использую Visual Studio 2019).
    Ошибка:
    Run-Time Check Failure #2 — Stack around the variable 'q' was corrupted.

    Код программы:

    1. Сергей:

      В строке 12 функция strlen(q) всегда вернет 0 (в результате (n = strlen(q) — 1)=-1).
      Это связано с тем, что q объявлена как символьное (char) и заполняется массив из символов. А функция работает с переменной типа string.

  13. Павел Карпов:

    Вот моя программа, оцените)

    1. Валера:

      Не делай запутанные программы, на продакшене это никому не надо

  14. armus1:

    Задача №2

  15. Игорь:

    2-я задача:

  16. Игорь:

    пришло на ум 2 решения первой задачи
    1-е решение:

    2-е решение(с использованием ветвления if):

  17. Алексей:

    Решение задания № 2:

    Результат:

    4
    10
    4
    Program ended with exit code: 0

    Вопрос:
    Когда я прогоняю переменную "а" через функцию toSum(), я меняю ее значение.
    Однако, после выполнения функции, переменная имеет свое прежнее значение.
    Как так? Переменная "а" создана во внешнем блоке, во вложенном блоке (в функции) преобразуется. Почему она не изменилась?
    Или функцию нельзя рассматривать как вложенный блок? (Не баг, а фитча.)

    1. Анастасия:

      "a" передаётся в функцию по значению, то есть в параметр value из Вашей функции копируется значение "а", далее вы меняете само value в функции и получившееся значение возвращаете в main тоже в качестве простого числа. "а" при этом не страдает.

  18. Максим:

    Зацените задумку

    Задание 2

  19. Фёдор:

    Помогите разобраться, почему в обоих случаях total имеет одно и то же значение, хотя счётчик count различается на единицу.

    Заранее спасибо)

    1. Анастасия:

      totalOne при первой итерации прибавляет 0 к 0, то есть тотал останется прежним (0), а на второй итерации он уже догонит totalTwo, и дальше они работают одинаково, поэтому и результат одинаковый.

  20. Владимир:

    задача №2

  21. Вячеслав:

    разобрался с примером задания 2 как у Александра и немного добавил и вот что получилось:

  22. Вячеслав:

    во втором задании программа ничего не выводит что я сделал не так?

    1. Владимир:

      Она и не будет ничего выводить. В коде нет ни одного std::cout, который бы выводил сообщение в консоль.

  23. Александр:

    Цикл for может быть сложным для новичков потому, что это не for 🙂

    В том смысле, что он ничего не имеет общего с классическими циклами for (базовые алгоритмические структуры, реализация в Паскале, Бейсике и т.п.)

    Я обычно говорю ученикам (особенно переходящим на С++ с паскаля), что "цикла for в С++ нет. Зато есть отличный фороимитатор. Мы пишем for, но на самом деле это няшная и удобная форма while"

    1. Константин:

      Ты ещё маленького ребёнка (который букву "р" "невыговаливает") подучи это слово произносить!:-)Шутка!

  24. Андрей:

    Объясните, пожалуйста, для чего Вы инициализировали переменную total? (Для проверки условия true или false?)

    и можете подробно объяснить строчку

    1. Александр:

      математика процесса:

      a^0 = 1
      a^n = a * a^(n - 1)

  25. corsair123:

    Я попался с unsigned и отрицательной переменной в цикле. Долго глаза "ломал", а тут статья.
    Спасибо огромное!!! Здорово всё объяснил. Удачи.

    1. Фото аватара Юрий:

      Рад, что смог помочь 🙂

    2. Владимир:

      Поломай ещё с вот этим:

      Подсказка: с этим циклом тоже что-то не так. Тем не менее, он так же скомпилируется, как и цикл в тесте.

      1. Игорь:

        Помоему должно быть ++i. При i++ значение i=0 побывает в цикле 2 раза и в результате выведутся числа от 0 до 11… или я что-то путаю в инкрементах?

        1. Игорь:

          Ан нет, я переосмыслил )) от 0 до 10 и есть ведь 11 чисел… всё, что после if и до return нужно взять в блок, иначе в цикле выполнится только строка после if (11 раз \n) и 1 раз вывод значения k

        2. Александр:

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

      2. Геннадий:

        Привет!
        Должно быть в цикле int i = 1;

      3. Геннадий:

        Прошу прощения))… Должно быть так в Вашем коде:

        Тогда от 0 до 9 показывает

        1. Mihawk:

          Ну и вдобавок: если нужно вывести от 0 до 10 !включительно!, то стоит поменять условие на i <= 10 =)

  26. Алексей:

    Задача 2

  27. Дмитрий:

    Решение на первый вопрос, не много странный но работает 🙂

  28. beksheikh:

    Хотя я прошел эту часть.(в учебе)но все грамотно говорите.и нашел кое что новое)спасибо за инфу.С уважением Я.

    1. Фото аватара Юрий:

      Пожалуйста 🙂

Добавить комментарий

Ваш E-mail не будет опубликован. Обязательные поля помечены *