Управляющие структуры

Простой оператор C ++ – это каждая из отдельных инструкций программы, таких как объявления переменных и выражения, описанные в предыдущих разделах. Они всегда заканчиваются точкой с запятой ( ;) и выполняются в том же порядке, в котором они отображаются в программе.Но программы не ограничиваются линейной последовательностью операторов. Во время своего процесса программа может повторять сегменты кода или принимать решения и бифуркацию. С этой целью C ++ предоставляет инструкции управления потоком, которые служат для указания того, что должно быть сделано нашей программой, когда и при каких обстоятельствах.

Многие из инструкций управления потоком, описанные в этом разделе, требуют обобщения (под) оператора как часть его синтаксиса. Этот оператор может быть либо простым выражением C ++, либо как одна команда, заканчивающаяся точкой с запятой (;) – или составной оператор. Составной оператор представляет собой группу операторов (каждая из которых завершается своей точкой с запятой), но все сгруппированы в блок, заключенный в фигурные скобки: {}:

{ statement1; statement2; statement3; }

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

Выводы выбора: if и else (условные конструкции)

ifИспользуется ключевое слово , чтобы выполнить инструкцию или блокировать, если, и только если условие выполняется. Его синтаксис таков:if (condition) statement

здесь conditionвыполняется выражение, которое оценивается. Если это conditionтак, statementвыполняется. Если оно ложно, statementоно не выполняется (оно просто игнорируется), и программа продолжается сразу после всего оператора выбора.
Например, следующий фрагмент кода печатает сообщение (x is 100), только если значение, хранящееся в xпеременной, действительно равно 100:

1
2
if (x == 100)
  cout << "x is 100";

Если xне точно 100, это утверждение игнорируется, и ничего не печатается.

Если вы хотите включить более одного оператора, выполняемого при выполнении условия, эти утверждения должны быть заключены в фигурные скобки ( {}), образуя блок:

1
2
3
4
5
if (x == 100)
{
   cout << "x is ";
   cout << x;
}

Как обычно, отступы и разрывы строк в коде не влияют, поэтому приведенный выше код эквивалентен:

 
if (x == 100) { cout << "x is "; cout << x; }

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

if (condition) statement1 else statement2

statement1statement2

1
2
3
4
if (x == 100)
  cout << "x is 100";
else
  cout << "x is not 100";

Это печатает x is 100, если действительно x имеет значение 100, но если это не так, и только если это не так, оно печатает x is not 100вместо этого.
Несколько структур if + else могут быть объединены с целью проверки диапазона значений. Например:

1
2
3
4
5
6
if (x > 0)
  cout << "x is positive";
else if (x < 0)
  cout << "x is negative";
else
  cout << "x is 0";

Это отображает, является ли x положительным, отрицательным или нулевым, объединяя две структуры if-else. Опять же , было бы также возможно выполнить более одного оператора в случае, группируя их в блоки , заключенные в фигурные скобки: {}.

Операторы итерации (повторения. циклические конструкции)

Циклы повторяют утверждение определенное количество раз или пока выполняется условие. Они вводятся с помощью ключевых слов whiledoи for.

Цикл while

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

while (expression) statement

statementexpressionstatementexpression

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// custom countdown using while
#include <iostream>
using namespace std;

int main ()
{
  int n = 10;

  while (n>0) {
    cout << n << ", ";
    --n;
  }

  cout << "liftoff!\n";
}
10, 9, 8, 7, 6, 5, 4, 3, 2, 1, подъем!

Первый оператор в mainнаборах n равен 10. Это первое число в обратном отсчете. Затем начинается цикл while: если это значение удовлетворяет условию n>0(что n больше нуля), тогда выполняется блок, который следует за условием, и повторяется до тех пор, пока условие ( n>0) остается истинным.

Весь процесс предыдущей программы можно интерпретировать в соответствии со следующим сценарием (начиная с main):

  1. n присваивается значение
  2. whileПроверяется условие ( n>0). На данный момент есть две возможности:
    • условие истинно: оператор выполняется (к шагу 3)
    • условие равно false: игнорировать оператор и продолжать после него (к шагу 5)
  3. Выполнить инструкцию: (печатает значение и уменьшается на 1)
    cout << n << ", ";
    --n;
    nn
  4. Конец блока. Вернитесь автоматически к шагу 2.
  5. Продолжить программу сразу после блока:
    распечатать liftoff!и завершить программу.

Вещь, которую следует учитывать с while-loop, состоит в том, что цикл должен заканчиваться в какой-то момент, и поэтому оператор должен каким-то образом изменить значения, проверенные в состоянии, чтобы заставить его стать ложным в какой-то момент. В противном случае цикл будет продолжаться циклически. В этом случае цикл включает в себя --n, что уменьшает значение переменной, которая оценивается в условии ( n) на единицу – это в конечном итоге сделает условие ( n>0) ложным после определенного количества итераций цикла. Чтобы быть более конкретным, после 10 итераций nстановится 0, что делает условие более недействительным и завершает цикл while.

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

Цикл do-while

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

do statement while (condition);

conditionstatementstatementcondition

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// echo machine
#include <iostream>
#include <string>
using namespace std;

int main ()
{
  string str;
  do {
    cout << "Enter text: ";
    getline (cin,str);
    cout << "You entered: " << str << '\n';
  } while (str != "goodbye");
}
Введите текст: привет
Вы вошли: привет
Введите текст: кто там?
Вы вошли: кто там?
Введите текст: до свидания
Вы вошли: до свидания

Цикл do-while обычно предпочтительнее, чем цикл while, когда statementнужно выполнить хотя бы один раз, например, когда условие, которое проверено до конца цикла, определяется в самом цикле. В предыдущем примере вход пользователя внутри блока – это то, что будет определять, заканчивается ли цикл. И, таким образом, даже если пользователь хочет закончить цикл как можно скорее, введяПрощай, блок в цикле должен выполняться хотя бы один раз, чтобы запросить ввод, и это условие может быть определено только после его выполнения.

Цикл for

forЦикл предназначен для перебора несколько раз. Его синтаксис таков: как и while-loop, этот цикл повторяется, пока он верен. Но, кроме того, если мы знаем точное количество действий (итераций) цикла, то можем использовать цикл for.  Он работает следующим образом:

for (действие до начала цикла; условие продолжения цикла; действия в конце каждой итерации цикла)
{
инструкция цикла;
инструкция цикла 2;
инструкция цикла N;
}

Вот пример обратного отсчета с использованием цикла for:

1
2
3
4
5
6
7
8
9
10
11
// countdown using a for loop
#include <iostream>
using namespace std;

int main ()
{
  for (int n=10; n>0; n--) {
    cout << n << ", ";
  }
  cout << "подъем!\n";
}
10, 9, 8, 7, 6, 5, 4, 3, 2, 1, подъем!

Три поля для цикла являются необязательными. Их можно оставить пустыми, но во всех случаях требуются знаки с запятой между ними. Например, for (;n<10;)это цикл без инициализации или увеличения (эквивалент цикла while); и for (;n<10;++n)это цикл с увеличением , но без инициализации (возможно, потому, что переменная уже была инициализирована до цикла). Цикл без условия эквивалентен циклу с trueусловием (т. Е. Бесконечным циклом).

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

1
2
3
4
for ( n=0, i=100 ; n!=i ; ++n, --i )
{
   // whatever here...
}

Этот цикл будет выполняться в 50 раз , если ни nили iне изменяются в пределах цикла:

nначинается со значением 0, и iс 100, условие n!=i(то есть, что nне равен i). Поскольку nувеличивается на единицу и iуменьшается на единицу на каждой итерации, условие цикла становится ложным после 50-й итерации, когда оба nи iравны 50.

Диапазон для цикла

В for-loop используется другой синтаксис, который используется исключительно для диапазонов: этот тип цикла повторяется по всем элементам in , где объявляет некоторую переменную, способную принимать значение элемента в этом диапазоне. Диапазоны представляют собой последовательности элементов, включая массивы, контейнеры и любой другой тип, поддерживающий функции

for ( declaration : range ) statement;

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

Пример диапазона для цикла, использующего строки:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// range-based for loop
#include <iostream>
#include <string>
using namespace std;

int main ()
{
  string str {"Hello!"};
  for (char c : str)
  {
    cout << "[" << c << "]";
  }
  cout << '\n';
}
[Здравствуйте][!]

Обратите внимание, что то, что предшествует двоеточие ( :) в цикле for, является объявлением charпеременной (элементы в строке имеют тип char). Затем мы используем эту переменную cв блоке оператора для представления значения каждого из элементов в диапазоне.

Этот цикл является автоматическим и не требует явного объявления любой переменной счетчика.

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

1
2
for (auto c : str)
  cout << "[" << c << "]";

Здесь тип cавтоматически выводится как тип элементов в str.

Выводы

Операторы  позволяют изменять поток программы, выполняя переходы в определенные местоположения.

Оператор break

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// break loop example
#include <iostream>
using namespace std;

int main ()
{
  for (int n=10; n>0; n--)
  {
    cout << n << ", ";
    if (n==3)
    {
      cout << "countdown aborted!";
      break;
    }
  }
}
10, 9, 8, 7, 6, 5, 4, 3, обратный отсчет отменен!

Утверждение о продолжении

continueЗаявление заставляет программу пропустить остальную часть цикла в текущей итерации, как если бы конец блока операторов был достигнут, в результате чего она , чтобы перейти к началу следующей итерации. Например, давайте пропустим номер 5 в нашем обратном отсчете:

1
2
3
4
5
6
7
8
9
10
11
12
// continue loop example
#include <iostream>
using namespace std;

int main ()
{
  for (int n=10; n>0; n--) {
    if (n==5) continue;
    cout << n << ", ";
  }
  cout << "liftoff!\n";
}
10, 9, 8, 7, 6, 4, 3, 2, 1, подъем!

Утверждение goto

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

Точка назначения идентифицируется меткой , которая затем используется в качестве аргумента для gotoоператора. Этикетка изготовлена из действительного идентификатора с последующим двоеточием ( :).

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

1
2
3
4
5
6
7
8
9
10
11
12
13
// goto loop example
#include <iostream>
using namespace std;

int main ()
{
  int n=10;
mylabel:
  cout << n << ", ";
  n--;
  if (n>0) goto mylabel;
  cout << "liftoff!\n";
}
10, 9, 8, 7, 6, 5, 4, 3, 2, 1, подъем!

Другой оператор выбора: переключатель.

Синтаксис оператора switch немного странный. Его цель – проверить значение среди числа возможных постоянных выражений. Это нечто похожее на конкатенирование if– elseутверждения, но ограниченные постоянными выражениями. Его наиболее типичный синтаксис:

switch (expression)
{
  case constant1:
     group-of-statements-1;
     break;
  case constant2:
     group-of-statements-2;
     break;
  .
  .
  .
  default:
     default-group-of-statements
}

Он работает следующим образом: switchоценивает expressionи проверяет, эквивалентен ли это constant1; если он есть, он выполняется group-of-statements-1до тех пор, пока не найдет breakутверждение. Когда он находит это breakутверждение, программа переходит к концу всего switchоператора (закрывающей скобки).

Если выражение не было равно constant1, оно затем проверяется constant2. Если он равен этому, он выполняется group-of-statements-2до тех пор, пока не breakбудет найдено, когда он перейдет в конец коммутатора.

Наконец, если значение выражения не соответствует какой-либо из ранее указанных констант (их может быть любое количество), программа выполняет инструкции, включенные после default:метки, если она существует (поскольку она является необязательной).

Оба следующих фрагмента кода имеют одинаковое поведение, демонстрируя эквивалент if-else оператора switch:

пример переключения эквивалент if-else
switch (x) {
  case 1:
    cout << "x is 1";
    break;
  case 2:
    cout << "x is 2";
    break;
  default:
    cout << "value of x unknown";
  }
if (x == 1) {
  cout << "x is 1";
}
else if (x == 2) {
  cout << "x is 2";
}
else {
  cout << "value of x unknown";
}

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

Если в приведенном выше примере отсутствует команда break после первой группы для случая 1, программа не будет автоматически переходить в конец блока переключателя после печати x is 1и вместо этого продолжит выполнение операторов в случае два (таким образом, печать такжеx is 2). Затем он будет продолжать делать это до тех пор, пока не breakбудет встречен оператор или конец switchблока. Это делает ненужным заключать утверждения для каждого случая в фигурных скобках {}и может также быть полезным для выполнения одной и той же группы операторов для разных возможных значений. Например:

1
2
3
4
5
6
7
8
9
switch (x) {
  case 1:
  case 2:
  case 3:
    cout << "x is 1, 2 or 3";
    break;
  default:
    cout << "x is not 1, 2 nor 3";
  }

Обратите внимание, что switchэто ограничение сравнивает его вычисленное выражение с метками, которые являются постоянными выражениями. Невозможно использовать переменные как метки или диапазоны, потому что они не являются допустимыми константами C ++.

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

Залишити відповідь