Управляющие операторы
Тема 2 Управляющие операторы
2.1 Базовые конструкции структурного программирования
В теории программирования доказано, что программу для решения задачи любой сложности можно составить только из трех структур, называемых следованием, ветвлением и циклом. Их называют базовыми конструкциями структурного программирования.
Следованием называется конструкция, представляющая собой последовательное выполнение двух или более операторов (простых или составных).
Ветвление задает выполнение либо одного, либо другого оператора в зависимости от выполнения какого-либо условия.
Цикл задает многократное выполнение оператора.
Особенностью базовых конструкций является то, что любая из них имеет только один вход и один выход, поэтому конструкции могут вкладываться друг в друга произвольным образом.
Рисунок 2.1 Базовые конструкции структурного программирования
Целью использования базовых конструкций является получение программы простой структуры. Такую программу легко читать, отлаживать и при необходимости вносить в нее изменения.
Любое выражение, завершающееся точкой с запятой, рассматривается как оператор, выполнение которого заключается в вычислении выражения.
2.2 Операции отношения и логические операции
Операции отношения (<, <=, >, >=, ==, !=) сравнивают первый операнд со вторым. Операнды могут быть арифметического типа или указателями. Результатом операции является значение true или false. Операции сравнения на равенство и неравенство имеют меньший приоритет, чем остальные операции сравнения. Например: x >=0, y != 10, z == 0.
ВНИМАНИЕ! Обратите внимание на разницу между операцией проверки на равенство ( == ), результатом которой является true или false, и операцией присваивания ( = ), результатом которой является значение, присвоенное левому операнду.
Логические операции (&&,||, ^). Операнды логических операций И (&&), ИЛИ (||), ИСКЛЮЧАЮЩЕЕ ИЛИ (^) должны иметь тип, допускающий преобразование к типу bool, при этом операнды в одной операции могут быть различных типов. Результатом операции является true или false.
Результат операции логическое И имеет значение true только если оба операнда имеют значение true. Результат операции логическое ИЛИ имеет значение true, если хотя бы один из операндов имеет значение true. Результат операции логическое ИСКЛЮЧАЮЩЕЕ ИЛИ имеет значение true, если один из операндов имеет значение true, а второй false. Логическое отрицание ( !) дает в результате значение false, если операнд есть true, и значение true, если операнд равен false. Операнд может быть арифметического типа. В этом случае выполняется неявное преобразование в тип bool. Логические операции выполняются слева направо. Если значения первого операнда достаточно, чтобы определить результат операции, второй операнд не вычисляется.
Таблица результатов операций И, ИЛИ, ИСКЛЮЧАЮЩЕЕ ИЛИ, НЕ
(A и B операнды)
A |
B |
A && B |
A || B |
A ^ B |
! A |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
1 |
0 |
1 |
1 |
1 |
1 |
0 |
0 |
1 |
1 |
0 |
1 |
1 |
1 |
1 |
0 |
0 |
Примеры выражений с логическими операциями:
x > 0 && y <=10
( a < -1 && b > 0 ) || c != 100
Условная операция ( ?:). Эта единственная в С++ тернарная операция (имеет три операнда), ее формат:
операнд_1 ? операнд_2 : операнд_3
Операнды вычисляются слева направо. Результат вычисления первого операнда должен быть типа, который можно преобразовать к типу bool. Если результат равен true, то результатом выполнения всей условной операции будет значение второго операнда, иначе третьего операнда. Их типы могут быть различными.
Пример: пусть требуется, чтобы некоторая целая величина увеличивалась на 1, если ее значение не превышает n, а иначе принимала значение 1. Это можно записать с помощью одной строки кода:
i = ( i < n ) ? i + 1 : 1;
2.3 Операторы ветвления. Условный оператор if
Условный оператор if используется для разветвления процесса вычислений на два направления. Схема алгоритма оператора приведена на рисунке 2.1. Формат оператора:
if ( выражение ) оператор_1; [ else оператор_2;]
Сначала вычисляется выражение, которое может иметь арифметический тип или тип указателя. Если оно не равно нулю, т.е. равно true, то выполняется первый оператор, иначе второй. После этого управление передается на оператор, следующий за условным. Одна из ветвей может отсутствовать.
Если в какой-либо ветви требуется выполнить несколько операторов, их необходимо заключить в блок. Блок может содержать любые операторы, в том числе описания и другие условные операторы.
Примеры:
if ( a < 0) b = 1; |
if ( a < b && (a >d || a == 0 ) ) b++; else { b *= a; a = 0;} |
if (a < b) if (a < c ) m = a; else m = c; else if ( b < c ) m = b; else m = c; |
В примере 1 отсутствует ветвь else. Подобная конструкция называется "пропуск оператора", поскольку присваивание либо выполняется, либо пропускается в зависимости от выполнения условия.
Если требуется проверить несколько условий, их объединяют знаками логических операций. Например, выражение в примере 2 будет истинно в том случае, если выполнится одновременно условие a < b и одно из условий в скобках. Если опустить внутренние скобки, будет выполнено сначала логическое И, а потом ИЛИ.
Оператор в примере 3 вычисляет наименьшее значение из трех переменных.
По синтаксису оператора if в его ветвях должно быть не более одного оператора. Если же их больше, то они должны быть объединены в блок с помощью фигурных скобок или с помощью операции «запятая» (,).
Пример. Производится выстрел по мишени, изображенной на рисунке 3.2. Определить количество очков.
Рисунок 3.2 Мишень
#include <stdio.h>
int main( )
{
float x, y;
int kol;
printf ( "\n Введите координаты выстрела ");
scanf ("%f", &x);
scanf ("%f", &y);
if ( x * x + y * y < 1 )
kol = 2;
else
if ( x*x + y*y < 4 )
kol = 1;
else
kol = 0;
printf ( "\n Очков: %d", kol );
}
2.4 Операторы ветвления. Оператор множественного выбора switch
Оператор switch (переключатель) предназначен для разветвления процесса вычислений на несколько направлений. Формат оператора:
switch ( выражение )
{
case константное_выражение_1: операторы 1;
case константное_выражение_2: операторы 2;
...
case константное_выражение_n: операторы n;
[default: операторы ;]
}
Выполнение оператора начинается с вычисления выражения (оно должно быть целочисленным), а затем управление передается case-метке операторам, помеченным константным выражением, значение которого совпало с вычисленным, после чего последовательно выполняются все остальные ветви, если выход из переключателя явно не указан.
Все константные выражения должны иметь разные значения, но быть одного и того же целочисленного типа. Несколько меток могут следовать подряд. Если совпадения не произошло, выполняются операторы, расположенные после слова default (а при его отсутствии управление передается следующему за switch оператору).
Если в какой-то из case-меток отсутствует оператор break, то выполнятся также операторы в следующей case-метке и так далее до тех пор, пока где-то не встретится оператор break.
Пример (программа реализует простейший калькулятор на 4 действия):
#include <stdio.h>
int main( )
{
int a, b, res;
char op;
printf ( "\n Введите 1-й операнд: ");
scanf ("%d", &a);
printf ( "\n Введите знак операции: ");
scanf ("%c", &op);
printf ( "\n Введите 2-й операнд: ");
scanf ("%d", &b);
bool f = true;
switch (op)
{
case '+': res = a + b; break;
case '-': res = a - b; break;
case '*': res = a * b; break;
case '/': res = a / b; break;
default: printf ("\n Неизвестная операция"); f = false;
}
if ( f )
printf ("\n Результат: %d", res);
}
Выход из переключателя обычно выполняется с помощью операторов break или return.
2.5 Операторы цикла
Операторы цикла используются для организации многократно повторяющихся вычислений.
Для организации цикла необходима переменная, называемая параметр цикла или управляющая переменная цикла. Любой цикл состоит из:
- начальных установок или блока инициализации параметра цикла;
- тела цикла, то есть тех операторов, которые выполняются несколько раз;
- блока модификации параметра цикла;
- проверки условия выхода из цикла, которая может размещаться либо до тела цикла (тогда говорят о цикле с предусловием), либо после тела цикла (цикл с постусловием).
Рисунок 3.3 Два вида циклов
Один проход цикла называется итерацией. Целочисленные параметры цикла, изменяющиеся на целое число на каждой итерации, называются счетчиками цикла.
Нельзя передавать управление извне внутрь цикла. Выход из цикла возможен как при выполнении условия выхода, так и по операторам break, return или безусловного перехода goto.
2.6 Цикл с предусловием (while)
Цикл с предусловием реализует схему алгоритма, приведенную ниже, и имеет вид:
while ( выражение ) оператор;
Например:
i = 1; while (i < N) { тело цикла; i++; } |
Выражение определяет условие повторения тела цикла, представленного простым или составным оператором. Если выражение не равно 0 (истинно), выполняется оператор цикла, после чего опять вычисляется выражение. Если при первой проверке выражение равно 0 (ложно), цикл не выполнится ни разу. Тип выражения должен быть арифметическим или приводимым к нему.
Пример (программа печатает таблицу значений функции y=x2+1 во введенном диапазоне):
#include <stdio.h>
int main( )
{
float Xn, Xk, Dx;
printf ("Введите диапазон и шаг изменения аргумента: ");
scanf ("%f%f%f", &Xn, &Xk, &Dx);
float X = Xn; //начальные установки цикла
while ( X <= Xk ) //проверка условия выхода
{
printf ("\n %5.2f %5.2f", X, X*X + 1); //тело
X += Dx; //модификация
}
}
2.7 Цикл с постусловием (do while)
Цикл с постусловием реализует схему алгоритма, приведенную ниже, и имеет вид:
do оператор while выражение;
i = 1; do { тело цикла; i++; } while (i < N); |
Сначала выполняется простой или составной оператор, составляющий тело цикла, а затем вычисляется выражение. Если оно не равно 0 (истинно), тело цикла выполняется еще раз, и так далее, пока выражение не станет равным нулю (ложно) или в теле цикла не будет выполнен какой-либо оператор передачи управления. Тип выражения должен быть арифметическим или приводимым к нему.
Пример (программа осуществляет проверку ввода):
#include <stdio.h>
int main( )
{
char answer;
do
{
printf ("\n Купи слоника!");
scanf ("%c", &answer);
}
while (answer != 'y');
}
2.8 Цикл for
Цикл for реализует схему алгоритма, приведенную ниже, и имеет вид:
for ( блок инициализации; блок проверки условия; блок модификации)
тело цикла;
Пример:
for ( int i = 1; i <= L; i++ ) тело цикла; |
Блок инициализации используется для объявления и присвоения начальных значений величинам, используемым в цикле. В этой части можно записать несколько операторов, разделенных запятой.
Блок проверки условия определяет условие выполнения цикла: если оно не равно 0 (истинно), цикл выполняется.
Блок модификации выполняется после каждой итерации цикла и служит обычно для изменения параметров цикла. В части модификаций можно записать несколько операторов через запятую.
Простой или составной оператор представляет собой тело цикла. Любая из частей оператора for может быть опущена (но точки с запятой надо оставить на своих местах!). В любой части можно использовать операцию "запятая" (последовательное вычисление), например:
for (int i = 1, s = 0; i <= 100; i++)
s += i; // сумма чисел от 1 до 100
Пример (программа печатает таблицу значений функции y=x2+1 во введенном диапазоне):
#include <stdio.h>
int main( )
{
float Xn, Xk, Dx;
printf ("Введите диапазон и шаг изменения аргумента: ");
scanf ("%f%f%f", &Xn, &Xk, &Dx);
for (float X = Xn; X <= Xk; X += Dx)
printf ("\n %5.2f %5.2f", X, X*X + 1);
}
2.9 Вложенные циклы
Каждый из операторов цикла может быть вложен в любой другой в произвольной последовательности. Глубина вложенности циклов не ограничена. Она определяется только алгоритмом решаемой задачи.
Ниже приведён пример вложенных циклов for
for ( int i = 1; i <= N; i++ ) for ( int j = 1; j <= M; j++ ) тело цикла; |
Этот фрагмент программы работает следующим образом. Для одного значения параметра внешнего цикла i (например, i = 1 ) параметр внутреннего цикла j изменяется в диапазоне от минимального до максимального значения (от 1 до M). Только после этого параметр i увеличивается на единицу. Таким образом, тело цикла выполнится N * M раз.
Другие варианты вложенных циклов работают аналогично: параметр внешнего цикла меняется медленно, а внутреннего быстро. Их рекомендуется освоить самостоятельно. Для этого схему алгоритма внутреннего цикла необходимо вставить целиком вместо блока тело цикла.
2.10 Операторы передачи управления
В С++ есть пять операторов, изменяющих естественный порядок выполнения вычислений:
- оператор выхода из цикла и переключателя break;
- оператор перехода к следующей итерации цикла continue;
- оператор возврата из функции return;
- оператор безусловного перехода goto;
- оператор генерации исключения throw.
Оператор выхода break используется для немедленного завершения оператора цикла или switch. Выполнение передается следующему после завершенного оператору.
Рассмотрим его использование на примере открытого итеративного цикла for. На примере вычисления суммы чисел от 1 до 100.
int i = 1, sum = 0;
for ( ; ; )
{
if( i > 100) break;
sum += i;
i++;
}
Оператор перехода к следующей итерации цикла continue пропускает все операторы, оставшиеся до конца тела цикла, и передает управление на модификацию параметров цикла (в случае цикла for ) и начало следующей итерации.
Рассмотрим его использование на примере вычисления суммы 1 / x, если x изменяется в диапазоне [-5, 5].
#include <stdio.h>
int main( )
{
float X, Sum = 0;
for ( X = -5; X <= 5; X++)
{
if(X == 0)
continue;
Sum = Sum + 1 / X;
printf ("\n Sum = %f", Sum);
}
Оператор возврата из функции return завершает выполнение функции и передает управление в точку ее вызова. Мы рассмотрим его вместе с функциями в соответствующей теме.
Оператор безусловного перехода goto имеет формат:
goto метка;
В теле той же функции должна присутствовать ровно одна конструкция вида:
метка: оператор;
Оператор goto передает управление на помеченный оператор. Метка это обычный идентификатор, областью видимости которого является функция, в теле которой он встречается.
Использование оператора безусловного перехода оправдано в двух случаях:
- принудительный выход вниз по тексту программы из нескольких вложенных циклов или переключателей;
- переход из нескольких мест функции в одно (например, если перед выходом из функции необходимо всегда выполнять какие-либо действия).
В остальных случаях для записи любого алгоритма существуют более подходящие средства.
Исключительную ситуацию (или просто исключение ) генерирует либо программист с помощью оператора throw, либо сама среда выполнения. Это происходит, когда во время выполнения программы возникают какие-либо ошибки, например, деление на ноль или переполнение. Механизм обработки исключений, реализованный в С++, позволяет реагировать на подобные ошибки и таким образом избегать аварийного завершения программы. Он будет рассмотрен в другой теме.
Управляющие операторы