Управление потоком в C++

C++Beginner
Практиковаться сейчас

Введение

В этом практическом занятии вы изучите инструкции управления потоком в C++. Вы научитесь использовать инструкции if-else, switch, while, do-while и for.

Предварительный просмотр содержания

Есть три основных конструкции управления потоком - последовательная, условная (или решение) и циклическая (или итеративная). Последовательная структура: процесс выполнения идет сверху вниз по строкам. Условная структура использует инструкцию if-else для проверки, удовлетворяет ли утверждение определенным конкретным условиям, и затем делает выбор. Циклическая структура используется для повторного выполнения некоторых логических операций.

image desc

Последовательное управление потоком

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

Условное управление потоком

Существует несколько типов условных операторов: if-then, if-then-else, вложенный if (if-elseif-elseif-...-else), switch-case и условное выражение.

#include <iostream>
using namespace std;

int main(){

 int mark;

 cout<<"Введите число [0-100]: ";
 cin>>mark;
    // if
    if (mark >= 50) {
       cout << "Поздравляем!" << endl;
       cout << "Продолжайте в том же духе!" << endl;
    }

    cout<<"Введите число [0-100]: ";
 cin>>mark;
    // if-else
    if (mark >= 50) {
       cout << "Поздравляем!" << endl;
       cout << "Продолжайте в том же духе!" << endl;
    } else {
       cout << "Постарайтесь лучше!" << endl;
    }

 cout<<"Введите число [0-100]: ";
 cin>>mark;
    // вложенный if
    if (mark >= 80) {
       cout << "A" << endl;
    } else if (mark >= 70) {
       cout << "B" << endl;
    } else if (mark >= 60) {
       cout << "C" << endl;
    } else if (mark >= 50) {
       cout << "D" << endl;
    } else {
       cout << "F" << endl;
    }

    // switch-case
    char oper;
    int num1 = 1, num2 = 2, result = 0;
    cout<<"Введите символ [+ - / *]: ";
    cin>> oper;
    switch (oper) {
       case '+':
          result = num1 + num2;
          break;
       case '-':
          result = num1 - num2;
          break;
       case '*':
          result = num1 * num2;
          break;
       case '/':
          result = num1 / num2;
          break;
       default:
          cout << "Неизвестный оператор" << endl;
    }
    cout<<num1<<oper<<num2<<"="<<result;
    return 0;
}

Вывод:

Введите число [0-100]: 50
Поздравляем!
Продолжайте в том же духе!
Введите число [0-100]: 40
Постарайтесь лучше!
Введите число [0-100]: 85
A
Введите символ [+ - / *]: +
1+2=3
image desc

Условный оператор: Условный оператор - это тернарный (с тремя операндами) оператор, в форме booleanExpr? trueExpr : falseExpr. В зависимости от booleanExpr он вычисляет и возвращает значение trueExpr или falseExpr.

// возвращает либо "ПРОЙДЕН" либо "НЕ ПРОЙДЕН", и выводит в cout
cout << (mark >= 50)? "ПРОЙДЕН" : "НЕ ПРОЙДЕН" << endl;

max = (a > b)? a : b;   // правая часть возвращает a или b
abs = (a > 0)? a : -a;  // правая часть возвращает a или -a

Скобки: Вы можете опустить фигурные скобки { }, если в блоке есть только одна инструкция. Например,

if (mark >= 50)
   cout << "ПРОЙДЕН" << endl;   // Только одна инструкция, можно опустить { }, но не рекомендуется
else {                       // несколько инструкций, нужны { }
   cout << "НЕ ПРОЙДЕН" << endl;
   cout << "Постарайтесь лучше!" << endl;
}

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

Управление потоком цикла

Опять-таки, существуют несколько типов циклов: for-цикл, while-do, и do-while.

// for-цикл
int sum = 0;
for (int number = 1; number <= 100; ++number) {
   sum += number;
}

// while-do
int sum = 0, number = 1;
while (number <= 100) {
   sum += number;
   ++number;
}

// do-while
int sum = 0, number = 1;
do {
   sum += number;
   ++number;
} while (number <= 100);

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

/*
 * Сумма от 1 до заданной верхней границы и вычисление их среднего значения.
 */
#include <iostream>
using namespace std;

int main() {
   int sum = 0;     // Сохраняет накопленную сумму
   int upperbound;
   cout << "Введите верхнюю границу: ";
   cin >> upperbound;

   // Сумма от 1 до верхней границы
   for (int number = 1; number <= upperbound; ++number) {
      sum += number;
   }
   cout << "Сумма равна " << sum << endl;
   cout << "Среднее значение равно " << (double)sum / upperbound << endl;

   // Сумма только нечетных чисел
   int count = 0;     // Количество нечетных чисел
   sum = 0;           // Сброс суммы
   for (int number=1; number <= upperbound; number=number+2) {
      ++count;
      sum += number;
   }
   cout << "Сумма нечетных чисел равна " << sum << endl;
   cout << "Среднее значение равно " << (double)sum / count << endl;
}

Вывод:

Введите верхнюю границу: 15
Сумма равна 120
Среднее значение равно 8
Сумма нечетных чисел равна 64
Среднее значение равно 8
image desc

Прерывание циклического потока - 'break' и 'continue'

Инструкция break прерывает и выходит из текущего (самого вложенного) цикла.

Инструкция continue прерывает текущую итерацию и продолжает следующую итерацию текущего (самого вложенного) цикла.

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

Следующая программа выводит составные числа между 2 и верхней границей.

/*
 *  Выводит составные числа от 1 до верхней границы.
 */
#include <iostream>
#include <cmath>
using namespace std;

int main() {
   int upperbound;
   cout << "Введите верхнюю границу: ";
   cin >> upperbound;
   for (int number = 2; number <= upperbound; ++number) {
      // Не является простым, если есть делитель между 2 и sqrt(number)
      int maxFactor = (int)sqrt(number);
      for (int factor = 2; factor <= maxFactor; ++factor) {
         if (number % factor == 0) {   // Делитель?
            cout << number << " ";
            break;   // Найден делитель, нет необходимости искать больше делителей
         }
      }
   }
   cout << endl;
   return 0;
}

Вывод:

Введите верхнюю границу: 20
4 6 8 9 10 12 14 15 16 18 20
image desc

Перепишем вышеуказанную программу, чтобы вывести все простые числа. Для этого используется флаг boolean под названием isPrime, который указывает, является ли текущее number простым числом. Затем он используется для управления печатью.

/*
 *  Выводит простые числа от 1 до верхней границы.
 */
#include <iostream>
#include <cmath>
using namespace std;

int main() {
   int upperbound;
   cout << "Введите верхнюю границу: ";
   cin >> upperbound;
   for (int number = 2; number <= upperbound; ++number) {
      // Не является простым, если есть делитель между 2 и sqrt(number)
      int maxFactor = (int)sqrt(number);
      bool isPrime = true;  // Флаг boolean, указывающий, является ли number простым числом
      for (int factor = 2; factor <= maxFactor; ++factor) {
         if (number % factor == 0) {   // Делитель?
            isPrime = false;   // number не является простым числом
            break;   // Найден делитель, нет необходимости искать больше делителей
         }
      }
      if (isPrime) cout << number << " ";
   }
   cout << endl;
   return 0;
}

Вывод:

Введите верхнюю границу: 100
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
image desc

Изучите следующую программу, использующую break и continue.

/* A mystery series */
#include <iostream>
using namespace std;

int main() {
   int number = 1;
   while (true) {
      ++number;
      if ((number % 3) == 0) continue;
      if (number == 53) break;
      if ((number % 2) == 0) {
         number += 3;
      } else {
         number -= 3;
      }
      cout << number << " ";
   }
   cout << endl;
   return 0;
}

Вывод:

5 4 2 7 11 10 8 13 17 16 14 19 23 22 20 25 29 28 26 31 35 34 32 37 41 40 38 43 47 46 44 49 53 52
image desc

Завершение программы

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

exit(): Вы можете вызвать функцию exit(int exitCode) из <cstdlib> (портированной из C's "stdlib.h"), чтобы завершить программу и вернуть управление операционной системе. По соглашению, возвратный код 0 указывает на нормальное завершение; в то время как не нулевой exitCode (-1) указывает на аномальное завершение. Например,

abort(): Заголовочный файл <cstdlib> также предоставляет функцию abort(), которая может быть использована для аномального завершения программы.

if (errorCount > 10) {
   cout << "слишком много ошибок" << endl;
   exit(-1);  // Завершить программу
              // ИЛИ abort();
}

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

Следующая диаграмма иллюстрирует вложенный for-цикл, то есть внутренний for-цикл внутри внешнего for-цикла.

image desc
/*
 *  Выводит треугольную фигуру.
 */
#include <iostream>
using namespace std;

int main() {
   int size = 8;
   for (int row = 1; row <= size; ++row) {     // Внешний цикл для вывода всех строк
      for (int col = 1; col <= size-row+1; ++col) {  // Внутренний цикл для вывода всех столбцов каждой строки
         cout << "## ";
      }
      cout << endl;   // Строка завершена, перемещаем курсор на следующую строку
   }

   return 0;
}

Вывод:

## ## ## ## ## ## ## #
## ## ## ## ## ## #
## ## ## ## ## #
## ## ## ## #
## ## ## #
## ## #
## #
#
image desc

Следующая конструкция часто используется:

while (true) { ...... }

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

Резюме

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