While это инструкция цикла с предусловием

В этом параграфе мы познакомимся с операторами ветвления if и switch, циклами while, do-while и for, а также с оператором goto.

Оператор if

Условный оператор if записывается так:

if (condition) {
    // код, который исполнится в случае, когда условие condition истинно
}

Дополнительно можно добавить ветку кода для случая, когда условие ложно:

if (condition) {
    // код, который исполнится, если condition истинно
} else {
    // код, который исполнится, если condition ложно
}

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

if (condition1) {
    // случай, когда condition1 истинно
} else if (condition2) {
    // случай, когда condition1 ложно, а condition2 истинно
} else if (contition3) {
    // случай, когда condition1 и condition2 ложны, а condition3 истинно
} else {
    // случай, когда condition1, condition2 и condition3 ложны
}

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

На месте condition может стоять любое выражение логического типа. Простейшие примеры таких выражений — это проверка на равенство (==) и неравенство (!=), а также сравнения на меньше / больше (<, <=, > и >=):

int main() {
    int x;
    std::cin >> x;
    if (x <= 0) {
        std::cout << "zero or negativen";
    } else if (x == 1) {
        std::cout << "onen";
    } else if (x == 2) {
        std::cout << "twon";
    } else {
        std::cout << "manyn";
    }
}

Сложные условия

Условия можно комбинировать с помощью логических операторов && (И), || (ИЛИ) и ! (НЕ). Рассмотрим пример, где проверяется принадлежность точки разным интервалам на прямой.

int main() {
    int a, b, x;
    /* Тут должна быть логика заполнения объявленных переменных,
    но мы её опустили, чтобы не отвлекаться */

    if (a <= x && x <= b) {
        // точка x лежит на отрезке [a; b]
    } else {
        // точка x лежит вне отрезка [a; b]
    }

    // то же самое можно было бы проверить так:
    if (!(x < a || x > b)) {  // отрицание
        // точка x лежит на отрезке [a; b]
    } else {
        // точка x лежит вне отрезка [a; b]
    }
}

Обратите внимание, что двойное неравенство некорректно проверять через a <= x <= b. Так можно написать, но смысл будет совсем другим: результат сравнения a <= x будет приведён к нулю или единице, и полученное число будет сравниваться с b.

Операторы сравнения имеют больший приоритет, чем логические операторы, поэтому скобки вокруг элементарных сравнений в сложных условиях не обязательны. А вот оператор отрицания имеет высокий приоритет, поэтому в последнем примере он применяется к условию в скобках. Таблицу приоритета операторов C++ можно посмотреть здесь.

Операторы && и || ведут себя лениво: если первого аргумента уже достаточно для ответа, то второй аргумент вычисляться не будет. Например, в выражении condition1 && condition2 второе условие не вычисляется, если первое ложно. Это часто используют для проверок корректности:

    int a, b;
    // ...
    if (a != 0 && b % a == 0) {
        // b делится на a
    }

Сравнение чисел с плавающей точкой

Рассмотрим программу, которая проверяет равенство 0.1 + 0.2 == 0.3:

#include <iostream>

int main() {
    double x = 0.1, y = 0.2;
    if (x + y == 0.3) {
        std::cout << "EQUAL ";
    } else {
        std::cout << "NOT EQUAL ";
    }

    std::cout << x + y << "n";
}

Логично было бы предположить, что программа выведет EQUAL 0.3, потому что $0.1 + 0.2 = 0.3$. Однако программа напечатает NOT EQUAL 0.3. Данная «ошибка вычисления» встречается в большинстве современных языков программирования и обусловлена погрешностью представления этих чисел. Если повысить число знаков дробной части в выводе, мы увидим, что 0.1 + 0.2 == 0.30000000000000004. Подробнее об этом можно прочитать здесь и в этой статье.

Поскольку операции над числами с плавающей точкой могут содержать погрешность, обычное сравнение через == некорректно. Поэтому правильнее сравнивать модуль разности величин с некой допустимой для нас погрешностью. Модуль дробного числа можно получить с помощью функции std::abs из заголовочного файла cmath. Исходную программу можно было бы переписать так:

#include <cmath>
#include <iostream>

int main() {
    double delta = 0.000001;

    double x = 0.1, y = 0.2;
    double sum = x + y;

    if (std::abs(sum - 0.3) < delta) {
        std::cout << "EQUAL ";
    } else {
        std::cout << "NOT EQUAL ";
    }

    std::cout << sum << "n";
}

Теперь программа выведет EQUAL 0.3.

Оператор switch

Рассмотрим простейший калькулятор, считывающий число, затем знак арифметической операции, а затем другое число и печатающий результат. Напишем сначала программу с помощью if и else.

#include <cstdint>
#include <iostream>

int main() {
    int64_t a, b;
    char operation;
    std::cin >> a >> operation >> b;

    int64_t result = 0;
    if (operation == '+') {
        result = a + b;
    } else if (operation == '-') {
        result = a - b;
    } else if (operation == '*') {
        result = a * b;
    } else if (operation == '/' || operation == ':') {
        result = a / b;
    } else if (operation == '%') {  // остаток от деления
        result = a % b;
    }

    std::cout << result << "n";
}

Вопросы для самопроверки

Что будет, если ввести 2 / 3?

  • Так как всё вычисление происходит в целых числах, то напечатается 0. Деление целых положительных чисел в C++ — это всегда неполное частное.

Что будет, если ввести 2 @ 3?

  • Обработку значка @ мы не предусмотрели. Программа напечатает 0, но тут необходимо напомнить, что у локальных переменных типа int нет дефолтных значений, и если бы мы не присвоили изначально result = 0, то программа напечатала бы какое-то неизвестное заранее число, лежащее в ячейках памяти, в которых поселился result.

Перепишем эту программу через оператор switch. Этот оператор следует рассматривать как условный прыжок на соответствующую метку в зависимости от значения выражения.

#include <cstdint>
#include <iostream>

int main() {
    int64_t a, b;
    char operation;
    std::cin >> a >> operation >> b;

    int64_t result;
    switch (operation) {
        case '+':
            result = a + b;
            break;  // если не написать этот break, программа просто пойдёт дальше в код следующего блока case
        case '-':
            result = a - b;
            break;
        case '*':
            result = a * b;
            break;
        case '/':
        case ':':
            result = a / b;
            break;
        case '%':
            result = a % b;
            break;
        default:  // здесь обрабатывается случай, когда ни один case не сработал.
            result = 0;
    }

    std::cout << result << "n";
}

Выражения внутри скобок оператора switch и в блоках case должны быть простого целочисленного или символьного типа. В приведённой выше программе значение + относится к типу char. Использование сложных типов (например, строк) приведёт к ошибке компиляции:

int main() {
    std::string name;
    std::cin >> name;
    switch (name) {  // ошибка компиляции
        case "Alice":
           std::cout << "Hello, Alice!n";
           break;
    }
}

Оператор goto

Есть шутка, что оператор безусловного перехода goto — это ругательное слово из четырёх букв. Безусловные переходы ломают иерархичность программы, затрудняют чтение и отладку. Доказано, что любую программу можно переписать без оператора goto. Поэтому во многих современных языках goto отсутствует.

Однако в C++ этот оператор есть по следующим причинам:

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

Мы познакомимся с его синтаксисом, но дальше использовать нигде не будем — и вам не советуем.

int main() {
    again:  // метка — это произвольное имя с двоеточием

    std::cout << "How old are you?n";
    int age;
    std::cin >> age;

    if (age < 0 || age >= 128) {
        std::cout << "Wrong age...n";
        goto again;  // безусловный прыжок в место, помеченное меткой
    }

    std::cout << "Your age is " << age << ".n";

    // ...
}

Здесь вводится метка again, на которую осуществляется переход, если возраст введён некорректно. Ниже мы покажем, как можно избавиться от оператора goto.

С помощью оператора goto нельзя выйти из функции или зайти в неё, а также нельзя перепрыгнуть через объявления переменных (кроме тривиальных случаев):

#include <iostream>

int main() {
    goto label;
    int x = 42;
    label:  // ошибка компиляции!
    std::cout << x << "n";
}

Цикл while

В C++ существует несколько видов циклов. Цикл while — это цикл с предусловием. Перед очередной итерацией проверяется условие, и если оно истинно, то цикл продолжается. Рассмотрим пример печати таблицы квадратов чисел от 1 до 10:

#include <iostream>

int main() {
    int n = 1;
    while (n <= 10) {
        std::cout << n << "t" << n * n << "n";  // выводим число и его квадрат через табуляцию
        ++n;
    }
}

Здесь мы намеренно разделяем числа и их квадраты не пробелом, а знаком табуляции t. В консоли такой вывод будет выглядеть выровненным по колонкам с фиксированной шириной:

1	1
2	4
3	9
4	16
5	25
6	36
7	49
8	64
9	81
10	100

Цикл do-while

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

#include <iostream>

int main() {
    int n = 1;
    do {
        std::cout << n << "t" << n * n << "n";
        ++n;
    } while (n <= 10);
}

Без особых причин пользоваться этим видом циклов не стоит, старайтесь использовать циклы while или for.

Цикл for

Цикл for — самый гибкий. Он записывается так:

for (initialization; condition; action) {
    // тело цикла
}

Как правило, с циклом ассоциируется некоторый параметр, который меняется от итерации к итерации, а цикл выполняется до тех пор, пока некоторое условие на этот параметр истинно.

Начальное значение такого параметра можно задать в разделе initialization, условие — в condition, а действие над параметром, выполняющееся после каждой итерации, — в action.

Напечатаем таблицу квадратов через цикл for:

#include <iostream>

int main() {
    for (int i = 1; i <= 10; ++i) {
        std::cout << i << "t" << i * i << "n";
    }
}

Напомним, что ++i — традиционная краткая форма записи для выражения i = i + 1.

Цикл for эквивалентен такому циклу while:

{
    initialization;
    while (condition) {
        // тело цикла
        action;
    }
}

Цикл range-based for

Этот цикл применим к контейнерам разной природы (массивам, векторам, спискам и т. д.), с которыми мы познакомимся позже. Пока рассмотрим его на примере строк. Цикл позволяет удобно проитерироваться по символам строки, не используя индексов. В этом примере мы считываем строку и печатаем отдельно все символы строки и их ASCII-коды:

#include <iostream>
#include <string>

int main() {
    std::string line;
    std::getline(std::cin, line);
    for (char symbol : line) {
        std::cout << symbol << "t" << static_cast<int>(symbol) << "n";
    }
}

Здесь оператор static_cast преобразует символ к числовому типу int, чтобы получить его код. Результат для строки Hello, world! выглядит так:

H	72
e	101
l	108
l	108
o	111
,	44
 	32
w	119
o	111
r	114
l	108
d	100
!	33

Обратите внимание, что std::string хранит внутри байты. Если вы вводите символы русского алфавита и у вас используется кодировка UTF-8, ставшая де-факто стандартом, то эти символы будут кодироваться парами байтов. И при такой итерации вы увидите отдельные байты, а не символы.

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

Циклы могут быть вложенными. Напечатаем таблицу умножения:

#include <iostream>

int main() {
    for (int i = 1; i <= 10; ++i) {
        for (int j = 1; j <= 10; ++j) {
            std::cout << i * j << "t";
        }
        std::cout << "n";
    }
}

Результат:

1	2	3	4	5	6	7	8	9	10	
2	4	6	8	10	12	14	16	18	20	
3	6	9	12	15	18	21	24	27	30	
4	8	12	16	20	24	28	32	36	40	
5	10	15	20	25	30	35	40	45	50	
6	12	18	24	30	36	42	48	54	60	
7	14	21	28	35	42	49	56	63	70	
8	16	24	32	40	48	56	64	72	80	
9	18	27	36	45	54	63	72	81	90	
10	20	30	40	50	60	70	80	90	100	

Операторы break и continue

Оператор break досрочно заканчивает текущий цикл. Оператор continue прыгает в самый конец тела цикла и, если условие цикла позволяет, переходит на следующую итерацию.

Типичный пример использования оператора break — выход из формально бесконечного цикла:

while (true) {
    // ...
    if (condition) {
        break;
    }
    // ...
}

Кстати, рассмотрим другие способы записать бесконечный цикл.

Через цикл do-while:

do {
    // ...
} while (true);

Через цикл for:

for (;;) {
    // ...
}

Напишем программу, которая считывает числа с клавиатуры до тех пор, пока пользователь не введёт ноль, а затем печатает их сумму:

#include <iostream>

int main() {
    int sum = 0;
    while (true) {
        int x;
        std::cin >> x;
        if (x == 0) {
            break;
        }
        sum += x;
    }
    std::cout << sum << "n";
}

(Здесь, конечно, неявно предполагается, что и сами числа, и результат суммирования помещаются в тип int, и в ходе вычислений не происходит переполнений.)

Считывание до конца ввода

В предыдущем примере мы считывали числа до тех пор, пока на вход не поступит ноль. Это не очень удобно. Предположим, что вместо ввода с клавиатуры мы читали бы эти числа из файла. Это легко сделать, перенаправив файл на стандартный ввод при запуске программы из консоли:

./a.out < input.txt

Следующий цикл считывает числа до тех пор, пока поступающие данные не закончатся:

#include <iostream>

int main() {
    int sum = 0;
    int x;
    while (std::cin >> x) {
        sum += x;
    }
    std::cout << sum << "n";
}

Здесь вместо условия цикла подставлено выражение std::cin >> x. Кроме считывания x это выражение преобразуется к логическому типу, показывающему, есть ли ещё данные в потоке ввода.

При вводе данных не из файла, а с клавиатуры можно сымитировать конец ввода комбинацией клавиш Ctrl+D в Linux и macOS или Ctrl+Z в Windows.

Аналогично можно прочитать строки до конца ввода с помощью std::getline:

#include <iostream>
#include <string>

int main() {
    std::string name;
    while (std::getline(std::cin, name)) {
        std::cout << "Hello, " << name << "!n";
    }
}

Циклы

Здравствуйте, дорогие читатели! Вот мы с вами и подошли к изучению циклов. Циклы в Паскаль. Что это такое? Как этим пользоваться? Для чего они нужны? Именно на эти вопросы я сегодня и отвечу.
Если вы читали этот урок, то знаете, что существует три вида алгоритмов: линейный, разветвляющийся и циклический. Мы с вами уже знаем, как реализовывать линейные и разветвляющиеся алгоритмы на Паскале. Приступим к изучению последнего типа алгоритмов.
В языке Pascal, как и в большинстве языков программирования, существует три типа циклических конструкций.

Циклы

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

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

Задача 1. Вывести все числа от 1 до числа, введенного с клавиатуры.

Как вы, наверное, уже поняли из названия, while — это цикл, в котором условие стоит перед телом. Причем тело цикла выполняется тогда и только тогда, когда условие true; как только условие становится false, выполнение цикла прекращается.

While имеет формат:

while < условие> do <оператор 1>;  {Пока … делай ….}

Данный цикл подходит только для одного оператора, если же вы хотите использовать несколько операторов в своем коде, вам следует заключить их в операторные скобки — begin и end;.

Решение задачи.

program example_while; 

var
  i, N: integer; { объявляем переменные }

begin
  i := 1; { Присваиваем i значение 1 }
  readln(N); { Считываем последнее число }
  while i <= N do {Как только i станет больше N, цикл прекратится (можно было бы написать просто <, но пришлось бы добавлять 1 к N) }
  begin {Открываем операторные скобки}
    write(i, ' '); {Выводим i}
    Inc(i);  {увеличиваем i на один.}
  end; { закрываем скобки }
end.

Repeat, или цикл с постусловием

Repeat  — полная противоположность while. Repeat — это цикл, в котором условие стоит после тела. Причем оно выполняется тогда и только тогда, когда результат условия false; как только логическое выражение становится true, выполнение цикла прекращается.

Repeat имеет формат:

repeat { повторяй … }
<оператор 1>;
< оператор 2>;

until {до…} <условие>

Begin и end не требуются.

Решение задачи.

program example_repeat;

var
  i, N: integer;{ объявляем переменные }

begin
  i := 1; { Присваиваем i значение 1 }
  readln(N); { Считываем последнее число }
  repeat {после repeat не требуется begin и end }
    write(i, ' '); {Выводим i}
    Inc(i);  {увеличиваем i на один.}
  until i = N + 1; {Например, i = 11, а N = 10. Цикл прекратится, так условие стало true.}
end.

For, или цикл с параметром

For — это  цикл, в котором тело выполняется заданное количество раз.

Существует две формы записи этого цикла:

Первая форма

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

После каждой итерации значение <счетчик1> будет увеличиваться на 1.

<значение1> — это начальное значение счетчика. Это может быть переменная или число.
<конечное_значение> : как только значение <счетчик1> станет больше <конечное_значение>, выполнение цикла прекратится.

Если требуется написать несколько операторов в теле цикла, используем begin и end.

И <счетчик1>, и <конечное_значение>, и <значение1> —  переменные целого типа.

Чаще всего в качестве счетчика используется переменная i.

Вторая форма

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

После каждой итерации значение <счетчик2> будет уменьшатся на 1.

<значение2> — это начальное значение счетчика.
<конечное_значение> : как только значение <счетчик2> станет меньше <конечное_значение>, выполнение цикла прекратится.

Два важных примечания:

  1. Цикл повторяется, пока значение значение счетчика лежит в отрезке [значение ; конечное_значение].
  2. Изменять значение счетчика внутри тела нельзя!  Вот что выводит компилятор:

for

Решение задачи:

 
program example_for;

var
  i, N: integer;

begin
  read(N); {предположим, что мы ввели 10}
  for i := 1 to N do write(i, ' '); {количество итераций - 10 - 1 + 1 = 10}
end.

Согласитесь,  данный код проще и лаконичнее, чем все предыдущие. И цикл for — не совсем обычный цикл, в нем нет логического условия. Поэтому цикл с параметром в программировании называют синтаксическим сахаром. Синтаксический сахар — это дополнения синтаксиса языка программирования, которые не добавляют новых возможностей, а делают использование языка более удобным для человека.

Давайте решим пару задач.

For1. Даны целые числа K и N  (N > 0). Вывести N раз число K.

Организовываем простой цикл от 1 до требуемого числа.

program for1;

var
  K, N, i: integer;

begin
  read(K, N);
  for i := 1 to N do write(K, ' '); {Пишем К через пробел }
end.

For2. Даны два целых числа A и B (A < B). Вывести в порядке возрастания все целые числа, расположенные между A и B (включая сами числа A и B), а также количество N этих чисел.

Так как A < B, то цикл должен будет выводить все числа от А до B. Чтобы сосчитать количество чисел, используем формулу: <конечное_значение> — <начальное_значение> + 1.

program for2;

var
  A, B, i, count: integer;

begin
  read(A, B);
  for i := A to B do write(i, ' '); {выписываем числа от меньшего к большему}
  count := B - A + 1; {считаем количество чисел}
  writeln;
  write( 'Количество чисел - ', count);
end.

For9. Даны два целых числа A и B (A < B). Найти сумму квадратов всех целых чисел от A до B включительно.

Организовываем такой же цикл, как и в предыдущей задаче, но одновременно суммируем квадраты всех чисел. Чтобы высчитать квадрат, используем функцию Sqr.

program for9;

var
  A, B, i, S: integer;

begin
  read(A, B);
  S := 0; {PascalABC делает это автоматически, но если у вас другой компилятор советуем обнулять переменные вручную}
  for i := A to B do S := S + Sqr(i);  {складываем все квадраты}
  writeln;
  write( 'Сумма квадратов - ', S);
end.

For13°. Дано целое число N (> 0). Найти значение выражения 1.1 – 1.2 + 1.3 – … (N слагаемых, знаки чередуются). Условный оператор не использовать.

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

program for13;

var
  N, A, i: integer;
  S: real;

begin
  Write('N = ');
  readln(N); 
  S := 1.1; 
  A := 1; {Сначала положительное}
  for i := 2 to N do {первую итерацию цикла мы уже произвели, поэтому начинаем отсчет с 2}
  begin 
   A := -A; {Теперь отрицательное}
   S := S + A * (1 + i / 10);  {Складываем}
  end;
  Writeln(S:5:1); {Отдадим под дробную часть одно знакоместо}
end.

While1°. Даны положительные числа A и B (A > B). На отрезке длины A размещено максимально возможное количество отрезков длины B (без наложений). Не используя операции умножения и деления, найти длину незанятой части отрезка A.

Каждый раз вычитаем B из А, пока А — В  >= 0.

program while1;

var
  A, B: integer;

begin
  readln(A, B);
  while (A - B) >=  0 do A := A - B; {Пока разница положительная, вычитаем. Необходимо предусмотреть вариант с кратностью А и B, поэтому >=}
  write(A);
end.

While4°. Дано целое число N (> 0). Если оно является степенью числа 3, то вывести True, если не является — вывести False.

Действуем следующим образом: пока N делится нацело на три, делим N нацело. Затем, если N = 1 — число является степенью тройки; если N <> 1, тогда число — не степень тройки. Для того чтобы решить эту задачу, требуется знать, что такое div и   mod,  и как работают логические выражения.

program while4;

var
  N: integer;

begin
  readln(N);
  while N mod 3 = 0 do N := N div 3; {Пока остаток от деления на три равен нулю, делим N нацело } 
  writeln(N = 1); {логическое выражение}
end.

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

#Руководства

  • 4 апр 2023

  • 0

Они есть практически в каждом языке программирования, но в Python с ними работать приятнее всего. Как, впрочем, и со всем остальным.

Иллюстрация: Катя Павловская для Skillbox Media

Иван Стуков

Журналист, изучает Python. Любит разбираться в мелочах, общаться с людьми и понимать их.

Код в Python обычно выполняется последовательно: первая строка, потом вторая, третья и так далее. Но некоторые конструкции позволяют нарушать этот порядок, чтобы совершать более сложные операции.

Например, циклы выполняют один и тот же блок кода несколько раз. В Python есть два основных вида циклов: while и for. О них и поговорим.

  • Как работают циклы
  • Цикл while в Python
  • Цикл for в Python
  • Функция range()
  • Однострочный цикл: генератор списков
  • Прерывание цикла: ключевое слово break
  • Пропуск части цикла: ключевое слово continue
  • Последнее действие в цикле: ключевое слово else
  • Бесконечный цикл
  • Как сделать аналог do while в Python
  • Вложенные циклы в Python

Любой цикл состоит из двух обязательных элементов:

  • условие — начальный параметр; цикл запустится только при его выполнении и закончится, как только условие перестанет выполняться;
  • тело — сама программа, которая выполняется внутри цикла.

Схематически его можно представить так:

Инфографика: Майя Мальгина для Skillbox Media

В синтаксисе Python в конце строки с условием ставится двоеточие, а всё тело выделяется отступом (табуляцией или четырьмя пробелами).

программа до цикла
условие:
	первая строка тела
	вторая строка тела
программа после цикла

While — наиболее простой и понятный вид цикла. Его ещё называют циклом с предусловием.

x = 1
while x < 5:
    print(x)
    x += 1  # Означает то же самое, что x = x + 1
>>> 1
>>> 2
>>> 3
>>> 4

С языка Python на русский программу можно перевести так: «Пока икс меньше пяти, печатай икс и прибавляй к нему единицу».

Но в простоте while кроется и опасность: его легко сделать бесконечным. Например, если в коде выше мы уберём x += 1, то получится вот так:

# Этот код будет выполняться бесконечно
x = 1
while x < 5:
    print(x)

Здесь с переменной x ничего не происходит. Она всегда равна единице, поэтому условие цикла никогда не перестанет выполняться. Соответственно, он никогда не завершится.

Чтобы избежать таких ситуаций, при использовании while нужно следить: перестанет ли когда-нибудь выполняться условие? Ещё можно использовать оператор break — о нём мы расскажем чуть позже.

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

На каждой итерации цикла программа как бы спрашивает: «Остались ли в объекте ещё элементы, по которым я не прошла?»

Допустим, у нас есть список с числами: [14, 101, -7, 0]. Мы можем использовать его вместе с for, чтобы напечатать каждый элемент по отдельности.

num_list = [14, 101, -7, 0]
for number in num_list:
    print(number)
>>> 14
>>> 101
>>> -7
>>> 0

Здесь переменная number обновляется при каждом новом витке цикла. Сначала она хранит в себе первый элемент, потом второй, и так — пока список не закончится.

Как и любую другую переменную, мы могли назвать number как угодно. Часто используют буквы i, j и k. Если внутри цикла мы ни разу не обращаемся к этой переменной, то среди питонистов её принято обозначать символом нижнего подчёркивания _.

Когда нужно применить for к числовому промежутку, его можно задать диапазоном. Для этого используют функцию range(). В неё можно передать от одного до трёх аргументов.

Если аргумент один, то сформируется диапазон от нуля до числа, предшествующего значению аргумента.

for i in range(3):
    print(i)
>>> 0
>>> 1
>>> 2

Если аргумента два, то сформируется диапазон от значения первого аргумента до числа, предшествующего значению второго аргумента.

for i in range(23, 26):
    print(i)
>>> 23
>>> 24
>>> 25

Если аргумента три, то первые два работают, как в прошлом случае. Третий же означает шаг, с которым числа следуют друг за другом.

for i in range(10, 20, 3):
    print(i)
>>> 10
>>> 13
>>> 16
>>> 19

Если в теле цикла for выполняется всего одно действие, синтаксис Python позволяет сократить его запись до:

i for i in iterable_object

Это синтаксический сахар, который не добавляет новой функциональности, но влияет на внешний вид кода. Так можно легко и быстро генерировать списки.

num_list = [i for i in range(1, 11)]
print(num_list)
>>> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

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

print([i for i in range(1, 11) if i % 2 == 0])
>>> [2, 4, 6, 8, 10]

Конструкция if i % 2 == 0 означает: «если при делении i на 2 остаток равен 0».

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

print([i ** 2 for i in range(1, 11) if i % 2 == 0])
>>> [4, 16, 36, 64, 100]

Главное при таком подходе — сильно не увлекаться. Если код тяжело прочесть и понять (например, когда к i применяется сразу несколько функций и методов и вдобавок задаётся сложное условие), то лучше разбить его на несколько строк. Понятность важнее лаконичности.

Бывают случаи, когда нужно завершить цикл принудительно, даже если его условие всё ещё выполняется. В таких случаях используют ключевое слово break.

Возьмём строку Hi, loop! и будем выводить каждый её символ. Если встретим запятую, досрочно завершим цикл.

string = 'Hi, loop!'
for i in string:
    if i == ',':
        break
    print(i)
>>> H
>>> i

Если же в строке запятой не будет, то цикл пройдёт по каждому её символу — и только потом завершится.

string = 'Hi loop!'
for i in string:
    if i == ',':
        break
    print(i)
>>> H
>>> i
>>>  
>>> l
>>> o
>>> o
>>> p
>>> !

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

Возьмём числа от 1 до 10 включительно и выведем из них только те, которые не делятся ни на 2, ни на 3.

for i in range(1, 10):
    if i%2 == 0 or i%3 == 0:
        continue
    print(i)
>>> 1
>>> 5
>>> 7

Как видим, если срабатывает условие if (то есть если число делится на 2 или на 3 без остатка), то оставшаяся часть тела не работает — и i не печатается.

Обычно ключевое слово else употребляют в связке с if, но у него есть и другое применение. Его можно использовать вместе с while или for. В таком случае else-код выполнится после того, как пройдут все витки цикла.

Если же цикл досрочно прервётся из-за break, то часть программы в else не выполнится.

Вспомним наш код со строкой Hi, loop! и добавим к нему else.

string = 'Hi, loop!'
for i in string:
    if i == ',':
        break
    print(i)
else:
    print('Цикл завершился без break')
>>> H
>>> i

В строке была запятая, сработал break — не выполнилось else-условие. Теперь уберём из неё запятую и посмотрим, что получится.

string = 'Hi loop!'
for i in string:
    if i == ',':
        break
    print(i)
else:
    print('Цикл завершился без break')
>>> H
>>> i
>>>  
>>> l
>>> o
>>> o
>>> p
>>> !
>>> Цикл завершился без break

Цикл прошёл все свои итерации, завершился самостоятельно, и поэтому код в else выполнился. Он также будет работать, если цикл не совершил ни одного витка.

while 1 == 0:
    print('Эта строка никогда не выполнится')
else:
    print('Цикл завершился без break')
>>> Цикл завершился без break

Иногда использовать бесконечный цикл может быть хорошей идеей. Например, мы пишем игру: она должна работать до тех пор, пока игрок из неё не выйдет. В этом случае в условии выхода нужно будет прописать break.

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

# Способ №1 — «пока истинно»
while True:
	pass  # pass — оператор-заглушка, который ничего не делает

Если сделать while False, то цикл, наоборот, никогда не начнётся.

# Способ №2 — «пока проверяемое значение — любое ненулевое число»
while 1:
	pass
while -4:
	pass
while 2023:
	pass

Если сделать while 0, то цикл никогда не начнётся.

# Способ №3 — «пока проверяемое значение — непустой элемент»
while 'string':
	pass
while [False, 'list', 0]:
	pass

Если после while поставить пустой элемент — например, строку str() или список list(), то цикл никогда не начнётся.

# Способ №4 — корректное уравнение
while 1 == 1:
	pass
while 0 != 1:
	pass

Альтернативный подход — поместить после while переменную, в которой лежит подходящее условие. Например:

# Способ №1
condition = True
while condition:
	pass
# Способ №2
condition = 1
while condition:
	pass
# Способ №3
condition = 'string'
while condition:
	pass

В таких случаях для выхода из цикла можно не использовать оператор break, а заменить значение в переменной condition на False, 0, None или любой пустой элемент. Цикл закончит последний виток и завершится, потому что условие больше не будет выполняться.

Такой подход применяется, когда нужно завершить цикл из других мест программы: например, из функции или вложенного цикла. Ещё одно отличие: так как цикл завершается «естественно», без оператора break, в нём выполнится else-код (если он есть).

condition = True
x = 0
while condition:
    print(x)
    x += 1
    if x == 3:
        condition = False
else:
    print('Цикл завершился без break')
>>> 0
>>> 1
>>> 2
>>> Цикл завершился без break

В некоторых языках программирования есть ещё один вид цикла — с постусловием. Он всегда проходит хотя бы один виток и только после этого проверяет, выполняется ли условие. Вот его схема:

Инфографика: Майя Мальгина для Skillbox Media

В Java и C++ такое достигается с помощью конструкции do while, но в Python её нет. Зато можно сделать аналог. Для этого нужно использовать бесконечный цикл, а внутри его тела прописать условие завершения.

x = 12
while True:
    x += 1
    print(x)
    if x > 5:
        break
>>> 13

Каким бы ни было значение x, такой цикл пройдёт хотя бы один виток. А это и есть постусловие.

Циклы в Python можно вкладывать друг в друга — то есть в теле одного цикла вызывать другой. Логика программы при этом усложняется.

Инфографика: Майя Мальгина для Skillbox Media

Можно вкладывать друг в друга сколько угодно циклов. При этом для каждого нового уровня вложенности нужно увеличивать отступ. Выглядит это так:

while condition:
    pass
    while inner_condition:
        pass
    pass

Напишем программу, которая будет выводить номер итерации внешнего и внутреннего цикла.

for i in range(3):
    print(f'Итерация внешнего цикла: {i}')
    for j in range(2):
        print(f'Итерация внутреннего цикла: {j}')
>>> Итерация внешнего цикла: 0
>>> Итерация внутреннего цикла: 0
>>> Итерация внутреннего цикла: 1
>>> Итерация внешнего цикла: 1
>>> Итерация внутреннего цикла: 0
>>> Итерация внутреннего цикла: 1
>>> Итерация внешнего цикла: 2
>>> Итерация внутреннего цикла: 0
>>> Итерация внутреннего цикла: 1

  • Циклы — один из основных инструментов любого Python-разработчика. С их помощью всего за пару строчек кода можно совершить сразу множество повторяющихся действий.
  • Циклы состоят из условия и тела. Код в теле выполняется только до тех пор, пока соблюдено условие.
  • В Python есть два вида циклов: while и for. В while условие задаётся явным образом. В for перебирается каждый элемент коллекции.
  • К обоим видам можно применять разные операторы: break для прерывания, continue для пропуска части тела, else для совершения последнего действия перед выходом из цикла.
  • Циклы можно делать бесконечными (тогда программа никогда не завершится или завершится только при выполнении определённого условия) и вкладывать друг в друга.

Нейросети вам помогут.
Большой вебинар по нейросетям. 15 экспертов, 7 топ-нейросетей. Научитесь использовать ИИ в своей работе и повысьте эффективность.

Узнать больше

Цикл заставляет интерпретатор JavaScript многократно выполнять один и тот же блок кода, называемый телом цикла. Каждое отдельное исполнение инструкций в теле цикла называется итерацией. В JavaScгipt доступны четыре инструкции циклов: while, do/while, for и for/in.

Цикл while

Инструкция while (англ. до тех пор, пока) создает цикл с предусловием. В скобках после слова while указывают некоторое логическое выражение или значение. Цикл начнется если значение этого выражения равно true и будет работать до тех пор, пока это условие не обратится в false. Общий синтаксис этого цикла выглядит так:

while (условие) {
  инструкция
}

Циклы while|for

Следующий цикл while исполняется, пока значение переменной i меньше 3:

После окончания третьей итерации условие i < 3 больше не является истинным, поэтому цикл завершается.

Для создания бесконечного цикла в качестве условия достаточно задать булево значение true:

while (true) {
  инструкция
}

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

Цикл do…while

Инструкция do…while (англ. делай до тех пор, пока) отличается от цикла while тем, что в do…while сначала выполняется тело цикла, а затем проверяется условие продолжения цикла. Из-за такой особенности do…while называют циклом с постусловием. Таким образом, если условие do…while заведомо ложное, то хотя бы один раз блок операторов в теле цикла do…while всё равно выполнится.

Инструкция do…while представляет собой конструкцию из двух операторов, используемых совместно. Синтаксис этой конструкции следующий:

do {
  // тело цикла
} while (условие);

Пример do…while:

Этот цикл продолжается, пока переменная i меньше 4. Она равна 0 в начале цикла и увеличивается на 1 на каждой итерации.

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

Цикл for

Инструкция for – это вариант цикла с предусловием, который состоит из трех необязательных выражений, заключенных в круглые скобки и разделенных точками с запятой, за которым следует оператор (обычно оператор блока), который должен выполняться в цикле. Она имеет следующий синтаксис:

for (инициализация; выражение; обновление) {
  // ... тело цикла ...
}

Описание синтаксиса:

  1. Инициализация. Присваивается первоначальное значение переменной, обычно – счетчика. Выполняется только один раз в начале выполнения оператора. Областью действия этой переменной будет тело цикла.
  2. Выражение – булево выражение, которое вычисляется на каждой итерации цикла. Представляет собой условие продолжения работы оператора цикла. После того, как значение счетчика достигнет указанного предела, цикл завершится.
  3. Обновление – это значение, на которое будет увеличиваться или уменьшаться счетчик цикла. Вычисляется по завершении каждой итерации цикла. Чтобы оно было полезным, как и выражение инициализации, оно должно иметь побочные эффекты. В общем случае таким побочным эффектом служит операция присваивания, инкремента или декремента.

Пример цикла for:

Рассмотрим выполнение этого цикла более подробно:

  1. Инициализация: Переменная-счетчик, в данном случае х, инициализируется значением 1. Выполняется один-единственный раз, при заходе в цикл.
  2. Выражение: x < 4 – это условие продолжения цикла for, оно проверяется перед каждой итерацией и при входе в цикл на истинность. Если это так, то выполняются инструкции тела цикла (в данном случае – инструкция alert( x + » » );).
  3. Обновление: x++ – изменяет значение переменной-счетчика. Выполняется после тела на каждой итерации, но перед проверкой условия x < 4.
  4. Тело цикла: alert( x + » » ) – тело цикла обрамляется фигурными скобками, если тело цикла состоит из одной операции, то фигурные скобки можно опустить.

Иными словами, поток выполнения цикла: Инициализация → (если условие выражения true → тело цикла → обновление (x++)) → (если условие выражения true → тело цикла → обновление (x++)) → … и так далее, пока верно условие – x < 4.

Циклы for могут быть более сложными, чем в приведенных выше примерах. В некоторых циклах на каждой итерации может изменяться одновременно несколько переменных. В таких циклах часто применяется оператор «запятая» – он позволяет объединить несколько выражений инициализации и инкрементирования в одно, например:

Использование for без блоков

Все три выражения в заголовке цикла for являются необязательными.

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

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

Можно опустить все три блока. Для избежания зацикливания используйте break для завершения цикла, а также изменяйте (увеличивайте или уменьшайте) переменную-счётчик, так чтобы условие для оператора break в какой-то момент сработало:

Примечание: Любое из выражений в цикле for может отсутствовать, однако сами точки с запятой обязательно должны присутствовать, иначе будет синтаксическая ошибка.

Цикл for…in

Цикл for…in используется для перебора всех свойств из объекта в случайном порядке и имеет следующий синтаксис:

for (variable in object) {
  инструкция /* ... делать что-то с object[variable] ... */
}

В качестве nеременной (variable) можно подставить имя переменной или инструкцию var, объявляющую одну переменную. Переменной перед началом каждой итерации цикла присваивается в виде строки имя одного из свойств объекта. Как и в цикле for, оператор var здесь не обязателен, но его рекомендуется использовать, чтобы переменная была локальной. Справа от ключевого слова in указывается объект, свойства которого будут перебираться циклом. Если переменная, представляющая объект, будет иметь значение null или undefined цикл не выполнится ни разу. И как обычно, инструкция – это инструкция или блок инструкций, образующих тело цикла.

Пример итерации по свойствам объекта:

Как отмечалось ранее, если имя свойства хранится в переменной, то обратиться к нему можно только через квадратные скобки (myCar[prop]), а не через оператор «точка».

Свойства объектов в JavaScript не упорядочены, поэтому порядок возврата их имен в цикле for…in предсказать сложно. Все перечислимые свойства будут возвращены, но порядок их вывода может зависеть от браузера.

Согласно стандарта ECMAScript, если имя свойства – нечисловая строка, то такие свойства всегда перебираются в том же порядке, в каком присваивались. Так получилось в примере выше при выводе свойств объекта myCar.
С другой стороны, если в качестве имени свойства выступает число или строка, которая может быть преобразована в числовой фомат, то браузеры осуществлят сортировку таких свойств в целях внутренней оптимизации. Вывод таких имен свойств объекта не будет соответствовать их оригинальному расположению.

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

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

Пример вложенного цикла:

Теперь попытаемся разобраться, как это работает. Первый (внешний) цикл после каждой итерации увеличивает значение переменной i, а второй (внутренний) – переменной j. За одну итерацию внешнего цикла внутренний выполняется девять раз. По условию (i < 10) внешний цикл выполнится 9 раз. Соответственно вложенный цикл будет выполнятся тоже 9 раз, а код внутри него – 9*9 итого 81 раз.

Иными словами, код читаем так: натыкаемся на внешний цикл, делаем первый проход, во время прохода натыкаемся на еще один цикл (внутренний), делаем девять проходов по нему, каждый раз выводя текущее значение переменной j. Выводим значение i и далее возвращаемся в начало внешнего цикла для второго прохода и так 9 раз.

Операторы break и continue

Циклом можно управлять с помощью операторов break и continue.

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

В следующем примере создаётся счётчик, значения которого должны изменяться от 1 до 99, однако оператор break прерывает цикл после 4 итераций:

Для вложенных циклов оператор break используется с меткой, с помощью которой завершается работа «меченой» инструкции. Метка позволяет выйти из любого блока кода. Метка имеет вид "имя_метки:", имя должно быть уникальным. Она ставится перед циклом или блоком инструкций, которые нужно завершить с помощью break:

Указание имени метки (без двоеточия) за ключевым словом break приводит к выходу из цикла или инструкции. Между ключевым словом break и именем метки не допускается перевод строки. Вызов break inner завершит вложенный цикл, а break outer ищет ближайший внешний цикл с такой меткой и переходит в его конец.

Оператор continue прерывает текущее выполнение цикла и переходит к выполнению следующего шага этого цикла. При этом, цикл while возвращается непосредственно к своему условию, а цикл for сначала вычисляет выражение инкремента, а затем возвращается к условию.

Рассмотрим пример:

В теле цикла инструкция if с помощью оператора (%) проверяет, является ли число четным. Если да, итерация цикла завершается до увеличения переменной num, но цикл продолжается со следующей итерации со значением i, увеличенным на единицу. Затем цикл выполняется до естественного завершения при значении i, равном 10. Переменная num подсчитывает количество итераций цикла. Окончательное значение num равно 5, а не 9, потому что четные операции инкремента пропускаются из-за оператора continue.

Оператор continue, как и break, можно использовать вместе с «помеченными» инструкциями для
возврата к конкретному месту в коде. Чаще всего это делается во вложенных циклах, например:

В этом примере для внешнего цикла for добавлена метка outer_mask. Каждый цикл включает 5 итераций, то есть инструкция num++ предположительно должна быть выполнена 25 раз, после чего переменная num должна быть равна 25. Оператор continue завершает выполнение внутреннего цикла, начиная новую итерацию внешнего. Она выполняется, когда j равно 3, то есть пропускаются две итерации внутреннего цикла, из-за чего num в итоге имеет значение 23.


Задачи

  • Число «задом наперед»

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

    Показать решение

    Решение:

    1. Найдем остаток от деления на 10 исходного числа num1. Получим его последнюю цифру digit.
    2. Добавим эту цифру к новому числу num2.
    3. Разделим нацело на 10 исходное число num1 и округлим до целых. Тем самым избавимся от последней цифры в нем. Полученное число сохраним в num1.
    4. Снова найдем остаток от деления на 10 того, что осталось от первого числа num1. Запомним эту цифру.
    5. Умножим на 10 второе число. Тем самым увеличим его разрядность до двух и сдвинем первую цифру в разряд десятков.
    6. Добавим к полученному второму числу запомненную ранее цифру digit из первого числа.
    7. Будем повторять перечисленные действия пока исходное число не уменьшится до нуля, т.е. пока не избавимся от всех его разрядов.
  • Сумма свойств объекта

    Есть объект users в которм перечислен возраст участников. Напишите код, который выведет суммарный возраст всех участников. Решите задачу через цикл for…in.

    
    var users = {
      "John": 28,
      "Mark": 30,
      "David": 25,
      "Richard": 42
    };
    
    /* ...ваш код... */
    

    Показать решение

  • Найти сумму четных цифр числа

    Пользователь вводит натуральное число. Найти сумму четных цифр, входящих в его состав.

    Показать решение

    Решение:

    1. В переменную sum будем суммировать все четные числа.
    2. Пока значение введенного числа (n) больше нуля выполнять пункты 3 – 5.
    3. Извлекать последнюю цифру числа (n) (путем нахождения остатка от деления на 10) и проверять ее на четность (путем нахождения остатка от деления на 2).
    4. Если цифра четная, то добавлять ее к sum.
    5. Избавиться от последней цифры числа путем ее деления нацело на 10.
    6. Вывести значение sum в консоль. Перейдите во вкладку Console инструментов разработчика ( Ctrl+Shift+J / Cmd+Shift+J ).
  • Повторять цикл, пока пользователь не введёт 0

    Напишите цикл, который предлагает prompt ввести число. Если посетитель ввёл число – попросить ввести ещё раз, и так далее.
    Цикл должен спрашивать ввести число пока либо посетитель не введёт 0, либо не нажмёт кнопку Cancel (ESC). После ввода нуля, показать на экран количество чисел, которые были введены, их общую сумму и среднее арифметическое.

  • Сумма нечётных чисел в диапазоне

    Необходимо суммировать все нечётные целые числа в диапазоне, который введёт пользователь с клавиатуры.

  • Равнобедренный треугольник из символов

    Нарисовать равнобедренный треугольник из символов *. Высоту выбирает пользователь. Например, при высоте = 6, на экране треугольник должен выглядеть так:

    Равнобедренный треугольник

  • Найти наибольшую цифру натурального числа

    Пользователь вводит с клавиатуры натуральное число. Найдите его наибольшую цифру и выведите её через alert.
    Например, введено число 987560. Наибольшая цифра в нем 9.

    Показать решение

    Решение:

    1. Переменная n – заданное число, а переменная m – максимальная цифра в этом числе.
    2. Допустим, что последняя цифра числа и есть максимальная. Извлечем ее используя оператор нахождения остатка при делении на 10. Присвоим значение переменной m.
    3. Избавимся от последней цифры с помощью операции деления на 10 и округления при помощи побитового оператора.
    4. Далее в цикле будем извлекать с конца числа поочерёдно каждую его цифру и сравнивать со значением m. Если очередная цифра будет больше, чем максимальное значение, то будем присваивать ее переменной m.
    5. Также в цикле будем каждый раз избавляться от последней, уже учтенной, цифры. Цикл завершит свою работу, когда переменная n станет равной нулю, т. е. после того, когда будут перебраны все цифры числа.
    6. В конце кода через alert выведем значение m на экран. Это и будет наибольшая цифра введенного числа.
 

Рассмотрим третью алгоритмическую структуру — цикл.
Циклом называется блок кода, который для решения задачи требуется повторить несколько раз.

Каждый цикл состоит из

  • блока проверки условия повторения цикла
  • тела цикла
 

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

В языке Си следующие виды циклов:

  • while — цикл с предусловием;
  • do…while — цикл с постусловием;
  • for — параметрический цикл (цикл с заданным числом повторений).

Общая форма записи

while (Условие)
{
  БлокОпераций;
}

Если Условие выполняется (выражение, проверяющее Условие, не равно нулю), то выполняется БлокОпераций, заключенный в фигурные скобки, затем Условие проверяется снова.
Последовательность действий, состоящая из проверки Условия и выполнения БлокаОпераций, повторяется до тех пор, пока выражение, проверяющее Условие, не станет ложным (равным нулю). При этом происходит выход из цикла, и производится выполнение операции, стоящей после оператора цикла.

Пример на Си: Посчитать сумму чисел от 1 до введенного k

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

#define _CRT_SECURE_NO_WARNINGS // для возможности использования scanf
#include <stdio.h>
int main() {
  int k;  // объявляем целую переменную key
  int i = 1;
  int sum = 0; // начальное значение суммы равно 0
  printf(«k = «);
  scanf(«%d», &k);   // вводим значение переменной k
  while (i <= k)     // пока i меньше или равно k
  {
    sum = sum + i; // добавляем значение i к сумме
    i++;           // увеличиваем i на 1
  }
  printf(«sum = %dn», sum); // вывод значения суммы
  getchar(); getchar();
  return 0;
}

Результат выполнения
Цикл while
При построении цикла while, в него необходимо включить конструкции, изменяющие величину проверяемого выражения так, чтобы в конце концов оно стало ложным (равным нулю). Иначе выполнение цикла будет осуществляться бесконечно (бесконечный цикл).

Пример бесконечного цикла

1
2
3
4

while (1)
{
  БлокОпераций;
}

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

Например, если в приведенном выше коде программы ввести k=-1, то получим результат
Цикл while может не выполниться ни разу

Цикл с постусловием do…while

Общая форма записи

do {
  БлокОпераций;
while (Условие);

Цикл do…while — это цикл с постусловием, где истинность выражения, проверяющего Условие проверяется после выполнения Блока Операций, заключенного в фигурные скобки. Тело цикла выполняется до тех пор, пока выражение, проверяющее Условие, не станет ложным, то есть тело цикла с постусловием выполнится хотя бы один раз.

Использовать цикл do…while лучше в тех случаях, когда должна быть выполнена хотя бы одна итерация, либо когда инициализация объектов, участвующих в проверке условия, происходит внутри тела цикла.

Пример на Си. Проверка, что пользователь ввел число от 0 до 10

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

#define _CRT_SECURE_NO_WARNINGS // для возможности использования scanf
#include <stdio.h>
#include <stdlib.h> // для использования функции system()
int main() {
  int num;             // объявляем целую переменную для числа
  system(«chcp 1251»); // переходим на русский язык в консоли
  system(«cls»);       // очищаем экран
  do {
    printf(«Введите число от 0 до 10: «); // приглашение пользователю
    scanf(«%d», &num); // ввод числа
  } while ((num < 0) || (num > 10)); // повторяем цикл пока num<0 или num>10
  printf(«Вы ввели число %d», num); // выводим введенное значение num — от 0 до 10
  getchar(); getchar();
  return 0;
}

Результат выполнения:
Цикл do...while

Параметрический цикл for

Общая форма записи

for (Инициализация; Условие; Модификация)
{
  БлокОпераций;
}

for — параметрический цикл (цикл с фиксированным числом повторений). Для организации такого цикла необходимо осуществить три операции:

  • Инициализация — присваивание параметру цикла начального значения;
  • Условие — проверка условия повторения цикла, чаще всего — сравнение величины параметра с некоторым граничным значением;
  • Модификация — изменение значения параметра для следующего прохождения тела цикла.
 

Эти три операции записываются в скобках и разделяются точкой с запятой ;;. Как правило, параметром цикла является целочисленная переменная.
Инициализация параметра осуществляется только один раз — когда цикл for начинает выполняться.
Проверка Условия повторения цикла осуществляется перед каждым возможным выполнением тела цикла. Когда выражение, проверяющее Условие становится ложным (равным нулю), цикл завершается. Модификация параметра осуществляется в конце каждого выполнения тела цикла. Параметр может как увеличиваться, так и уменьшаться.

Пример на Си: Посчитать сумму чисел от 1 до введенного k

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

#define _CRT_SECURE_NO_WARNINGS // для возможности использования scanf
#include <stdio.h>
int main() {
  int k;  // объявляем целую переменную key
  int sum = 0; // начальное значение суммы равно 0
  printf(«k = «);
  scanf(«%d», &k);   // вводим значение переменной k
  for(int i=1; i<=k; i++) // цикл для переменной i от 1 до k с шагом 1
  {
    sum = sum + i; // добавляем значение i к сумме
  }
  printf(«sum = %dn», sum); // вывод значения суммы
  getchar(); getchar();
  return 0;
}

Результат выполнения
Цикл while
В записи цикла for можно опустить одно или несколько выражений, но нельзя опускать точку с запятой, разделяющие три составляющие цикла.
Код предыдущего примера можно представить в виде

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#define _CRT_SECURE_NO_WARNINGS // для возможности использования scanf
#include <stdio.h>
int main() {
  int k;  // объявляем целую переменную key
  int sum = 0; // начальное значение суммы равно 0
  printf(«k = «);
  scanf(«%d», &k);   // вводим значение переменной k
  int i=1;
  for(; i<=k; i++) // цикл для переменной i от 1 до k с шагом 1
  {
    sum = sum + i; // добавляем значение i к сумме
  }
  printf(«sum = %dn», sum); // вывод значения суммы
  getchar(); getchar();
  return 0;
}

Параметры, находящиеся в выражениях в заголовке цикла можно изменить при выполнении операции в теле цикла, например

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

#define _CRT_SECURE_NO_WARNINGS // для возможности использования scanf
#include <stdio.h>
int main() {
  int k;  // объявляем целую переменную key
  int sum = 0; // начальное значение суммы равно 0
  printf(«k = «);
  scanf(«%d», &k);   // вводим значение переменной k
  for(int i=1; i<=k; ) // цикл для переменной i от 1 до k с шагом 1
  {
    sum = sum + i; // добавляем значение i к сумме
    i++;           // добавляем 1 к значению i

  }
  printf(«sum = %dn», sum); // вывод значения суммы
  getchar(); getchar();
  return 0;
}

В цикле for может использоваться операция запятая, — для разделения нескольких выражений. Это позволяет включить в спецификацию цикла несколько инициализирующих или корректирующих выражений. Выражения, к которым применяется операция запятая, будут вычисляться слева направо.

Пример на Си:

1
2
3
4
5
6
7
8
9
10
11
12
13

#define _CRT_SECURE_NO_WARNINGS // для возможности использования scanf
#include <stdio.h>
int main() {
  int k;  // объявляем целую переменную key
  printf(«k = «);
  scanf(«%d», &k);   // вводим значение переменной k
  for(int i=1, j=2; i<=k; i++, j+=2) // цикл для переменных
  {                                  // (i от 1 до k с шагом 1) и (j от 2 с шагом 2)
    printf(«i = %d   j = %dn», i, j); // выводим значения i и j
  }
  getchar(); getchar();
  return 0;
}

Результат выполнения
Цикл for

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

В Си допускаются вложенные циклы, то есть когда один цикл находится внутри другого:

for (i = 0; i<n; i++)  // внешний цикл — Цикл1
{     
  for (j = 0; j<n; j++)   // вложенный цикл — Цикл2
  {
    ;        // блок операций Цикла2
  }
  // блок операций Цикла1;
}

Пример: Вывести числа от 0 до 99, по 10 в каждой строке

1
2
3
4
5
6
7
8
9
10
11
12
13
14

#define _CRT_SECURE_NO_WARNINGS // для возможности использования scanf
#include <stdio.h>
int main() {
  for(int i=0; i<10; i++) // цикл для десятков
  {                                  
    for (int j = 0; j < 10; j++) // цикл для единиц
    {
      printf(«%2d «, i * 10 + j); // выводим вычисленное число (2 знакоместа) и пробел
    }
    printf(«n»); // во внешнем цикле переводим строку
  }
  getchar(); // scanf() не использовался,
  return 0;  // поэтому консоль можно удержать одним вызовом getchar()
}

Результат выполнения
Вложенные циклы: вывод чисел от 0 до 99

Рекомендации по выбору цикла

При выборе цикла необходимо оценить необходимость проверки условия при входе в цикл или по завершении прохождения цикла.
Цикл с постусловием удобно применять в случаях, когда для проверки условия требуется вычислить значение выражения, которое затем будет размещено в теле цикла (см. выше пример ввода числа от 0 до 10).
Цикл c предусловием используется в случае если все переменные, участвующие в выражении, проверяющем условие, проинициализированы заранее, но точное число повторений цикла неизвестно или предполагается сложная модификация переменных, участвующих в формировании условия повторения цикла.
Если цикл ориентирован на работу с параметром, для которого заранее известно число повторений и шаг изменения, то более предпочтительным является параметрический цикл. Очень удобно использовать параметрический цикл при работе с массивами для перебора элементов.

Операторы прерывания и продолжения цикла break и continue

В теле любого цикла можно использовать операторы прерывания цикла — break и продолжения цикла — continue.

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

Пример на Си: Вывести числа от 0 до 99 ниже главной диагонали

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#define _CRT_SECURE_NO_WARNINGS // для возможности использования scanf
#include <stdio.h>
int main() {
  for(int i=0; i<10; i++) // цикл для десятков
  {                                  
    for (int j = 0; j < 10; j++) // цикл для единиц
    {
      if (j > i) // если число единиц больше числа десятков в числе
        break// выходим из вложенного цикла и переходим к новой строке
      printf(«%2d «, i * 10 + j); // выводим вычисленное число (2 знакоместа) и пробел
    }
    printf(«n»); // во внешнем цикле переводим строку
  }
  getchar(); // scanf() не использовался,
  return 0;  // поэтому консоль можно удержать одним вызовом getchar()
}

Результат выполнения
Оператор break

Пример на Си: Вывести числа от 0 до 99 исключая числа, оканчивающиеся на 5 или 8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#define _CRT_SECURE_NO_WARNINGS // для возможности использования scanf
#include <stdio.h>
int main() {
  for(int i=0; i<10; i++) // цикл для десятков
  {                                  
    for (int j = 0; j < 10; j++) // цикл для единиц
    {
      if ((j == 5) || (j == 8)) // если число единиц в числе равно 5 или 8,
        continue;             // переходим к следующей итерации цикла
      printf(«%2d «, i * 10 + j); // выводим вычисленное число (2 знакоместа) и пробел
    }
    printf(«n»); // во внешнем цикле переводим строку
  }
  getchar(); // scanf() не использовался,
  return 0;  // поэтому консоль можно удержать одним вызовом getchar()
}

Результат выполнения
Оператор continue

При вложенных циклах действия операторов break и continue распространяется только на самую внутреннюю структуру, в которой они содержатся.

Оператор безусловного перехода goto

Общая форма записи

goto Метка;
. . .
Метка : Операция;

Выполнение оператора goto вызывает передачу управления в программе операции, помеченной Меткой. По сути Метка является идентификатором адреса операции, которой должно быть передано управление. Для отделения Метки от Операции используется двоеточие — :.
Метка может располагаться в программе как до оператора goto, так и после него. Имена Меток образуются по тем же правилам, что и имена переменных.

Пример на Си: Вывести все целые числа от 5 до 0.

1
2
3
4
5
6
7
8
9
10
11
12

#define _CRT_SECURE_NO_WARNINGS // для возможности использования scanf
#include <stdio.h>
int main() {
  int k = 5;
M1: if (k < 0) // если k<0,
    goto M2;   // переходим на метку M2 (выходим из программы)
  printf(«%d «, k); // выводим значение k
  k—;              // уменьшаем k на 1
  goto M1;          // переходим на метку M1 (повторяем операции выше)
M2: getchar();
  return 0;
}

Результат выполнения
Оператор goto

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

Назад: Язык Си

Понравилась статья? Поделить с друзьями:

Новое и полезное:

  • West 6100 инструкция на русском языке
  • Wesper чиллер инструкция по эксплуатации
  • Wespe heizung master 12 инструкция
  • Wespe elite инструкция по применению
  • Wert rus газовая колонка инструкция

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии