Как составить программу с оператором цикла

В этой главе мы познакомимся с операторами ветвления 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.

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

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

  • 8 июн 2020

  • 14

Разбираемся, как сократить повторяющийся код в C++ и сэкономить время.

 vlada_maestro / shutterstock

Евгений Кучерявый

Пишет о программировании, в свободное время создаёт игры. Мечтает открыть свою студию и выпускать ламповые RPG.

Это шестая часть из серии статей «Глубокое погружение в C++». В прошлый раз мы узнали, как использовать функции и процедуры. Сейчас поговорим о циклах while, do-while и for.

Циклы — это разновидность условных конструкций. Они позволяют выполнять команды несколько раз, если определённое утверждение верно. Например, с помощью циклов можно пять раз вывести на экран какую-нибудь надпись или посчитать сумму всех чисел.

Запись цикла while выглядит так:

Этот код выполняется следующим образом:

  1. Программа проверяет, верно ли утверждение.
  2. Выполняются инструкции в теле цикла.
  3. Программа возвращается к пункту 1.

То есть пока утверждение верно (i < 100), цикл будет повторять одни и те же действия. Цикл, который пять раз выводит сообщение «Hello, World!»:

int i = 0;

while(i < 5)
{
    std::cout << "Hello, World! n";
    i++;
}

Посмотрим на вывод:

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

Один шаг цикла называется итерацией, а счётчик — итератором. Поэтому чаще всего для счётчика создаётся переменная i.

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

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

Когда нам нужно вмешаться в работу цикла, мы используем операторы break и continue.

Оператор break прерывает выполнение цикла:

int sum = 0;
int maxSum = 50;
int i = 0;

while(i < 100)
{
    sum += i;

    i++;

    if(sum >= maxSum)
    {
   	 break;
    }
}

std::cout << "i = " << i << "nsum = " << sum << "n";

Этот цикл должен посчитать сумму всех чисел от одного до ста. Но мы указали максимальное значение для переменной sum, поэтому цикл прервётся, как только sum станет больше maxSum.

Компилятор умеет отличать оператор break в конструкции switch от оператора break, который прерывает циклы. Поэтому можно спокойно писать вот такой код:

int action = 0;
bool end = false;

//Этот цикл будет бесконечным, если его не прервать изнутри
while(true)
{
    std::cout << "Exit? n1 - Yesn0 - NonAction: ";
    std::cin >> action;

    switch(action)
    {
   	 case 1:
   		 std::cout << "Good bye!n";
   		 end = true;
   		 break;
   	 case 0:
   		 std::cout << "Try again!n";
    }

    if(end)
    {
   	 break;
    }
}

Вот как это будет работать:

Важно! Оператор break внутри конструкции switch не может прервать цикл.

Иногда нам нужно пропустить одну итерацию и перейти к следующей. Для этого используем оператор continue.

int i = 0;

while(i < 100)
{
    i++;

    //
    if(i % 3 == 0)
    {
   	 continue;
    }

    std::cout << " " << i;
}

std::cout << "n";

Этот цикл выведет все числа от одного до ста, кроме тех, которые делятся на три без остатка.

Цикл do-while похож на while, но он сначала выполняет одну итерацию и только потом проверяет верность утверждения:

while(false)
{
    //Ничего не выводится
    std::cout << "Hello! n";
}

do
{
    //Надпись будет выведена один раз
    std::cout << "Bye! n";
}
while(false);

Вот результат:

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

Вот пример такого цикла:

int sum = 0;

for(int i = 0; i < 200; i++)
{
    sum += i;
}

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

В результате мы получим сумму всех чисел от 1 до 200:

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

for(int i = 0; i < 10; i++)
{
    //Обратите внимание, что во вложенном цикле должен использоваться другой итератор. В данном случае j вместо i
    for(int j = 0; j < 10; j++)
    {
   	 std::cout << " + ";
    }
    std::cout << "n";
}

Получаем результат:

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

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

Научитесь: Профессия Разработчик на C++ с нуля
Узнать больше

План урока:

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

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

Операторы цикла

Решение задач с использованием операторов while, repeat, for

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

В жизни людей очень часто встречаются циклы. Будь то жизнь маленького ребёнка или взрослого человека, а то и пожилых людей. Эти циклы можно расписать как выполнение одних и тех же действий, пока выполняется определённое условие. К примеру, взрослый человек находится на работе до момента, когда наступит время его ухода. И так изо дня в день, однако, есть и исключения в виде выходных. В жизни детей можно привести такой пример, как обязанность каждый день ходить в школу до момента, когда наступят выходные или каникулы.

Циклические алгоритмы – это алгоритмы, в которых некоторая часть операций повторяется многократно.

Цикл – конструкция с оператором, который повторяется определённое или неопределённое заранее количество раз. Действия, выполняющиеся последовательно внутри цикла, называют телом цикла.

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

Циклы разделяют на три типа в зависимости от метода организации повторений:

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

1 cikly razdelyaut na tri ripa

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

Выбрав среду программирования Паскаль необходимо познакомиться с операторами, с помощью которых можно разработать программу с циклом. Ими являются while, repeat, for. Оператор while был разобран ещё на прошлом уроке, однако забывать о нём нельзя.

Цикл с предусловием

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

2 cikl s predusloviem

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

Цикл с постусловием – это алгоритм циклической структуры, в котором проверка условия продолжения осуществляется после выполнения тела цикла.

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

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

3 cikl s postusloviem4 cikl s postusloviem drugoi variant 

Цикл с заданным числом повторений

Этот вид цикла вместо логического условия выполнения использует параметр (счетчик) – специальную переменную, которая на каждом шаге цикла получает очередное значение из определенного диапазона. Цикл повторяется до тех пор, пока не будут перебраны все элементы диапазона. Таким образом, определяя диапазон, мы определяем заранее заданное число повторений.

4 cikl s postusloviem drugoi variant

Операторы цикла

Для программирования циклических алгоритмов и корректного выполнения программ с их использованием, необходимо знать операторы цикла. Чаще всего, в языке Паскаль используют операторы цикла: for, repeat и while. Разберем их подробнее.

Оператор while

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

6 uslovie operatora

Если переводить его дословно, то можно сказать, что он работает по принципу «пока <условие> выполнять действие <оператор 1>», а заканчивается при переходе программы на слово end. Перед выполнением операторов внутри цикла условие обязательно проверяется и уже дальше, в зависимости от его истинности, программа либо выполняет тело цикла, либо переходит к последующим операторам.

Решение задач с использованием оператора while

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

Задача 1. На вход подаются целые числа. До тех пор, пока не будет введено число, которое больше 17, программа должна вывести сумму полученного числа и числа 8. Когда вводимое число будет больше 17, то после выполнения программы цикл завершается.

Решение.

7 kod na vhod podautsya celye chisla

Шаг 1. Для начала необходимо дать программе название.

Шаг 2. Учитывая, что на вход подаётся целое число, указать тип данных, в данном случае – integer.

Шаг 3. Запись командного блока. Нужно написать слово, обозначающее начало, begin.

Шаг 4. Нужно дать переменной a значение 1, чтобы цикл начался автоматически.

Шаг 5. Запись цикла. Поскольку известно условие окончания работы, для этой задачи необходимо написать «пока a меньше или равно 17» и сделать переход к последующим операторам путём написания составного цикла.

Шаг 6. Первоначальный вывод программы. Необходимо написать то, что программа будет выдавать в первую очередь. В данном случае, она будет запрашивать целое число, запрос так и пишется: «Введите целое число: » .

Шаг 7. Запись необходимых операторов. Используя оператор readln программа считывает данные и переводит курсор на новую строку. Далее она производит операции над поступившими данными.

Шаг 8. Запись суммы. Исходя из условия задачи необходимо сделать так, чтобы программа выводила сумму входящего числа и числа 8. Осуществить это можно используя оператор writeln.

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

Шаг 10. Проверка правильности записи алгоритма. В конце программного блока, после слова end нельзя забывать точку, её обязательно нужно поставить.

Оператор repeat

Оператор цикла repeat until используется для создания циклического алгоритма с постусловием. Его схема выглядит так:

8 operator cikla repeat until

Дословно оператор Паскаля repeat можно перевести как «повторяй <оператор 1>, до <условие>». В зависимости от истинности условия, либо происходит переход на повторение «оператора 1», либо осуществляется выход из цикла к последующим операторам.

Оператор repeat имеет два важных отличия от оператора while:

  • в операторе repeat сначала выполняется тело, а затем проверяется условие;
  • в операторе repeat прописывается условие завершения цикла, тогда как в операторе while – условие его продолжения.

Решение задач с использованием оператора repeat

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

Решение.

9 kod pridumat algoritm i napisat programmu

Шаг 1. Название программы. В данном случае — «задача 1».

Шаг 2. Учитывая, что на вход подаются целые числа, требуется указать тип данных – integer.

Шаг 3. Командный блок. Запись начального слова begin.

Шаг 4. Вывод запроса программы. Поскольку программе необходимо целое число, нужно попросить пользователя ввести его. Осуществляется это с помощью процедуры writeln и текста «Введите целое число, которое больше 1: ».

Шаг 5. Необходимо присвоить переменной i значение 1 для того, чтобы последовательность начиналась с натурального числа.

Шаг 6. Запись цикла. Учитывая, что используется цикл с постусловием, необходимо сначала записать оператор, который будет повторяться, затем увеличить i на 1, чтобы образовывалась последовательность, и уже после этого прописать условие повторения. В данной задаче цикл перестаёт повторяться тогда, когда переменная i принимает значение больше введённого числа, которое является последним членом последовательности.

Шаг 7. Проверка программы на правильность в выводе. В результате своей работы программа должна вывести последовательность натуральных чисел от 1 до n, через пробел.

Оператор for

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

10 operator for

Дословно его можно перевести как «для переменной в значении от начального к конечному выполнять <оператор 1> ».

Решение задач с использованием оператора for

Рассмотреть пример с оператором for можно при написании короткого алгоритма для следующей задачи.

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

Решение.

11 reshenie zadach s ispolzovaniem operatora for

Шаг 1. Необходимо дать программе название.

Шаг 2. Поскольку на вход числа не подаются, тип указывается в зависимости от данных, которые изначально находятся в программе. В данном случае – это целые числа. 

Шаг 3. Запись блока с командами алгоритма.

Шаг 4. Перебор последовательности чисел осуществляется в цикле for, в котором счетчик i пробегает значения от 1 до 10, а расчет и вывод квадратов осуществляется в процедуре write.

Решение задач с использованием операторов while, repeat, for

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

Решение

12 reshenie zadach algoritm programmy

13 razrabotat algoritm programmy

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

Шаг 1. Нужно назвать программу.

Шаг 2. Так как пользователь не вводит никаких данных, то их можно ввести в сам код программы. Тип используемых данных в данном случае – это integer.

Шаг 3. Написание команд. Изначально нужно сделать так, чтобы программа вывела название того, для чего она предназначена. В данной задаче это «Таблица умножения на 9».

Шаг 4. Запись цикла for. С помощью него программа будет последовательно умножать числа от 1 до 10 на 9 и составлять таблицу умножения путём вывода каждого значения по схеме «9x, i, =, p», где i – умножаемое на 9 число, p – результат произведения 9 и i.

Шаг 6. Программа завершает свою работу. Необходимо проверить правильность выведенных данных и, если это необходимо, поправить код для более корректной работы.

Когда в алгоритме некоторое действие нужно выполнить несколько раз, используются циклы. В программирование цикл — это многократное повторение определенных инструкций. Циклы состоят из заголовка и тела. Заголовок содержит в себе условия, которые определяют работу цикла, а тело – повторяющиеся действия. В этом уроке рассмотрим:

  • цикл со счетчиком (с параметром);
  • цикл с предусловием;
  • цикл с постусловием.
  • вложенные циклы/a>.

Их алгоритмы выполнения различны, но есть и общее: после выполнения тела цикла, проверяется условие, и в зависимости от него работа цикла заканчивается, либо снова выполняется тело.

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

Цикл с параметром, известный также как цикл со счетчиком, используется при известном количестве повторений. Он имеет две формы записи. В любом случае он выполняет следующий после него оператор (как правило, это составной оператор заключенный в «операторные скобки» Begin..End), каждый раз изменяя переменную цикла с шагом 1

For <счетчик>:=< начальное значение> To <конечное значение> Do <тело цикла>;

For <счетчик>:=<начальное значение> Downto <конечное значение> Do <тело цикла>;

Счетчик – это переменная порядкового типа. Начальное и конечное значение должны быть того же типа, что и счетчик. Тело выполняется до тех пор пока условие истинно.

Условия выполнения цикла проверяются перед выполнением блока операторов. Если переменная цикла больше максимального значения (при to) или меньше минимального (downto), то цикл FOR не выполняется.

Формы записи, представленные выше, отличаются словами To и Downto. Если Вы используете цикл с To, то значение счетчика с каждым шагом будет увеличиваться на единицу, а если с Downto, то уменьшаться. Из этого следует, что в первом варианте начальное значение не должно превышать конечное, во втором — верно противоположное. В программе ниже, указанное пользователем количество раз, будут выводиться символы.

program for_primer;
uses crt;
var i, x: integer;
begin
  write('X=');
  readln(x);
  for i:=1 to x do
    write('a');
readkey;
end.

Здесь тело цикла не заключено в Begin-End, так как оператор всего один. Но если их будет больше, то операторные скобки обязательны. Стоит также отметить, что счетчик по выходу из цикла не будет иметь определенного значения, но если цикл закончиться раньше положенного, то счетчик сохранит последнее, записанное в него значение.

Другой пример — вычисление суммы чисел от A до B:

Program Summa;
Var a, b, S: Integer;
Begin
  ClrScr;
  Write('a = ');
  Readln(a);
  Write('b = ');
  Readln(b);
  S:=0;
  For I:=a To b Do
    S:=S + I;
  Writeln ('Cумма = ', S);
  ReadLn
End. 

2 While – цикл с предусловием

Оператор While – начинает описание цикла с предусловием. Такой вид цикла нужен, в тех алгоритмах, где число повторений неизвестно заранее. В общем виде он выглядит так:

While <выражение> Do <тело цикла>;

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

Пример программы написанный с использованием цикла While:

program while_primer;
uses crt;
var i, x, limit: integer;
begin
  write('Предел=');
  readln(limit);
  write(' Числа Фибоначчи: ');
  i:=1; x:=1;
  while i<=limit do
  begin
    write(i,' ');
    i:=i+x;
    x:=i-x;
  end;
  readkey;
end.

В данном коде использовался составной оператор Begin-End, так как операторов в теле цикла несколько.

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

Главной особенностью цикла с постусловием (часто встречается название: цикл-ДО) является выполнение его тела минимум один раз. Это связано с тем, что условие записывается в конце и соответственно вначале выполнится тело, а затем провериться условие. Формально он выглядит так:

Repeat
  <тело цикла>
Until <условие>

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

program repeat_primer;
uses crt;
var i, otvet: integer;
begin
  i:=1;
  repeat
    i:=i+1;
    write(i,'+',i,'*2=');
    read(otvet);
  until otvet<>i+i*2;
  readkey;
end.

Программа продолжает работать до тех пор, пока пользователь не допустит ошибку в ответе. Думаю, Вы заметили, что в примере (непосредственно в цикле) составной оператор Begin-End, несмотря на количество операторов не поставлен. Просто его роль выполняют слова repeat и until.

Для переходных манипуляций с циклом обычно используются три оператора:

  • Goto – переходит в отмеченную область;
  • Break – производит безусловный выход из цикла;
  • Continue – осуществляет переход к новой итерации.

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

Циклы в паскаль могут вкладываться друг в друга. Житейский пример: например, у нас есть список студентов, у каждого из которых есть оценки — если мы захотим перебрать все оценки для каждого студента то один цикл (внешний) будет перебираться студентов, а второй (вложенный) — оценки конкретного студента. Обрабатывать списки (массивы) мы научимся дальше.

Рассмотрим вложенные циклы на примере цикла с параметром:

For <счетчик 1>:=<начальное знач.> To <конечное знач.> Do <тело цикла 1>;
For <счетчик 2>:=<начальное знач.> To <конечное знач.> Do <тело цикла 2>;
…
For <счетчик n>:=<начальное знач.> To <конечное знач.> Do <тело цикла n>;

Вернувшись к терминологии, отметим, что в таких структурах одни циклы называются внешними, а другие внутренними. Так цикл 2 относительно цикла 1 является внутренним, а для цикла n он внешний.

Принцип работы вложенных циклов заключается в следующем. Сначала один раз выполняется цикл, идущий первым в программе, затем управление передается следующему циклу (№2), и если после него нет никаких других циклов, то он прокручивается до конца и снова единожды выполняется внешний цикл, иначе, если после цикла №2 стоит еще один вложенный цикл, то №2 выполняется один раз, передавая управление циклу идущему после него. Такой алгоритм продолжается до тех пор, пока самый внешний цикл не выполниться необходимое количество раз.

Предположим у нас есть вложенные циклы for:

for i:=1 to m1 do
for j:=1 to m2 do
…
for k:=1 to mn do

Количество проходов по первому циклу = m1, второму = m2*m1, n-ому = mn*mn-1*mn-2*..*m2*m1. В качестве доказательства предлагаю разобраться в следующей программе.

program counter_performance;
uses crt;
var i, j, k, g, h: integer;
s_i, s_j, s_k, s_g, s_h: integer;
begin
  s_i:=0; s_j:=0; s_k:=0; s_g:=0; s_h:=0;
  for i:=1 to 5 do
  begin
    s_i:=s_i+1;
    for j:=1 to 3 do
    begin
      s_j:=s_j+1;
      for k:=1 to 19 do
      begin
        s_k:=s_k+1;
        for g:=1 to 10 do
        begin
          s_g:=s_g+1;
          for h:=1 to 6 do
            s_h:=s_h+1;
        end;
      end;
    end;
  end;
  write('i=',s_i,' j=',s_j,' k=',s_k,' g=',s_g,' h=',s_h);
  readkey;
end.

Имеются 5 циклов со счётчиками от i до h. В каждом из них при помощи переменных подсчитывается, сколько раз выполняется каждый цикл. Запустив программу на своем компьютере, Вы должны увидеть такой результат:


Результат работы вложенных циклов

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

program nested_loops;
uses crt;
var i, j: integer;
begin
  i:=1; j:=1;
  while i<20 do begin
    while j<i+1 do begin
      write('');
      j:=j+1;
    end;
    j:=1;
    i:=i+1;
    writeln;
  end;
  readkey;
end.

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

Понравилась статья? Поделить с друзьями:
  • Как исправить прямоугольное лицо
  • Как исправить неполадки с интернетом на компьютере
  • Как найти пьесу для театра
  • Как найти личный номер телефона человека
  • Алеадо как найти машину