§8 Инструкция if. Полное и неполное ветвление. Вложенные инструкции if. Инструкция switch

Условная инструкция if

Из прошлого занятия вам, должно быть, стало понятным, что без логики в программе невозможно решать сложные задачи, в которых требуется выполнять инструкции в зависимости от условий. Из жизненного опыта нам известно, что даже элементарные бытовые действия мы выполняем после определенных размышлений.
1234x600
В языке C++ существуют специальные инструкции управления, которые прерывают линейное выполнение алгоритма и направляют дальнейшее его выполнение по тому пути, который выбран в результате решения поставленного условия.
Условная инструкция if является инструкцией управления, которая позволяет реализовать алгоритмическую структуру ветвление.

Синтаксис:
if (выражение)
{
   Инструкция_1; // Если условие true
}
else 
{ 
    Инструкция_2; // Если условие false
}

Ветвление полное и неполноеЕсли выражение в условии принимает значение true (или отличное от нуля), то выполняется инструкция Инструкция1. Если условие принимает значение false (или равно 0), то выполняется инструкция Инструкция2. Выражение в условии может быть логическим выражением или любым выражением скалярного типа (т. е. целое число, число с плавающей точкой, символьная величина или указатель). Если результатом вычисления выражения является ненулевое значение, то в С++ такой результат интерпретируется как true, в противном случае (т. е. 0) – false. Инструкция if имеет две формы: полная и неполная. В неполном ветвлении ветвь “на иначе” отсутствует:

if (Выражение) 
    Инструкция; 

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

Программа cpp-8.1

Неполное ветвление. Определить является ли число N кратным числу K.

#include <iostream>
using namespace std;

int main() {
    int N, K;
    cout << "N = "; cin >> N;
    cout << "K = "; cin >> K;
    if (N % K == 0) 
        cout << N << " кратно " 
             << K << endl;
    return 0;
}
Блок-схема к программе cpp-8.1

11
Неполные ветвления используются в программах так же часто, как и полные. Каскад ветвлений – тоже не редкость.

Программа cpp-8.2

На вход программе подаются 4 числа определить количество положительных чисел в исходном наборе. Если таких чисел нет, то сообщить об этом.

#include <iostream>
using namespace std;

int main() {
    int a, b, c, d, i = 0;
    cout << "a = "; cin >> a;
    cout << "b = "; cin >> b;
    cout << "c = "; cin >> c;
    cout << "d = "; cin >> d;
    if (a > 0) ++i;
    if (b > 0) ++i;
    if (c > 0) ++i;
    if (d > 0) ++i;
    if (i) cout << "Количество положительных "
                   "чисел равно " << i << endl;
    if (!i) cout << "Положительных чисел - нет!" << endl; 
    return 0;
}

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

Программа cpp-8.3

Полное ветвление. Введены два числа. Определить порядковый номер большего из них.

#include <iostream>
using namespace std;

int main() {
    int a, b;
    cout << "a = "; cin >> a;
    cout << "b = "; cin >> b;
    if (a > b) 
        cout << 1 << endl;
    else
        cout << 2 << endl;
    return 0;
}
Блок-схема к программе cpp-8.3

12

Составная инструкция (блок)

В том случае, если в ветвях if более одной инструкции, то данный набор инструкций называется составной инструкцией или блоком, который должен заключаться в фигурные скобки:

if (Выражение) 
{
    Блок1; 
} 
else 
{
    Блок2;
}

Существует несколько стилей представления кода в котором присутствуют блоки. Для компактности кодинга рекомендуется использовать следующий стиль:

if (expr) {
    stm_1;
} else { 
    stm_2;
}

Пример задачи. Даны два действительных числа a и b. Возвести в третью степень большее из них и в четвертую степень меньшее. Вывести новые значения a и b.

Программа cpp-8.4
#include <iostream>
#include <cmath>
using namespace std;

int main() {
    double a, b;
    cout << "a = "; cin >> a;
    cout << "b = "; cin >> b;
    if (a > b) {
        a = pow(a, 3);
        b = pow(b, 4);
    } else {
        a = pow(a, 4);
        b = pow(b, 3);
    }
    cout << "a = " << a << "\n"
         << "b = " << b << endl;
    return 0;
}

Обратите внимание, что блок не завершается точкой с запятой.

Вложенные инструкции if

Одна инструкция if может быть вложена в другую инструкцию if. C++ поддерживает очень большую глубину вложенности, но на практике редко возникают случаи, когда глубина вложенности превосходит 3 или 4. С увеличением числа вложенных друг в друга if код перестает быть читаемым и понятным. Также возрастает вероятность ошибки и найти ее будет проблематично.
Пример задачи. Дана точка A с координатами x и y. Определить какой координатной четверти принадлежит A.

Программа cpp-8.5.1
#include <iostream>
using namespace std;

int main() {
    double x, y;
    cout << "x = "; cin >> x;
    cout << "y = "; cin >> y;
    cout << "Точка находится ";
    if (x > 0)
        if (y > 0)
            cout << "в I четверти.";
        else
            cout << "в IV четверти.";
    else
        if (y > 0)
            cout << "во II четверти.";
        else
            cout << "в III четверти.";
    cout << endl;
    return 0;
}

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

Программа cpp-8.5.2
#include <iostream>
using namespace std;

int main() {
    double x, y;
    cout << "x = "; cin >> x;
    cout << "y = "; cin >> y;
    cout << "Точка находится ";
    if (x > 0 && y > 0)
        cout << "в I четверти.";
    else if (x > 0 && y < 0)
        cout << "в IV четверти.";
    else if (x < 0 && y > 0)
        cout << "во II четверти.";
    else
        cout << "в III четверти.";
    cout << endl;
    return 0;
}

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

Инструкция switch

Еще одним способом избежать многократной вложенности или формы “else if” – это использование инструкции switch (“переключатель”). Это, конечно, не означает, что с его помощью можно с легкостью заменить любую инструкцию if с большой глубиной вложенности. Данная инструкция подходит в тех случаях, когда нужно сделать выбор по целочисленному значению. При проектировании графических интерфейсов switch идеально соответствует элементу “радиокнопка” (от англ. radio button), или “переключатель”.
Синтаксис

switch (expression) { 
    case constant_expression1 : statement1; break;
    case constant_expression2 : statement2; break;
    case constant_expressionN : statementN; break;
    default: default_statement; /*необязательно*/
}

Здесь выражение expression – это выражение целочисленного типа или типа enum (с этим типом мы будем знакомиться ниже). Среди блоков case будет выполняться тот блок, в котором метка constant_expression будет равна expression. Использование инструкции break позволяет, после выбора соответствующего блока, выйти из switch (иначе блоки case будут выполняться последовательно). Необязательный блок default будет выполняться в том случае, если ни один из блоков case не будет удовлетворять условию.

Блок-схема


Рассмотрим пример. Составить программу перевода из различных мер объема в кубические метры.

Программа cpp-8.6
#include <iostream>
using namespace std;

int main() {
	int n;
	double d;
	cout << "Введите единицу объема:\n"
			"1 - литры\n"
			"2 - кубический миллиметр\n"
			"3 - кубический сантиметр\n"
			"4 - кубический дециметр\n"
			"5 - имперский галлон\n"
			"6 - кубический дюйм:\n";
	cin >> n;
	cout << "Введите значение величины: ";
	cin >> d;
	switch (n) {
	case 1:
		cout << d * 0.001 << " кубических метров";
		break;
	case 2:
		cout << d * 1.0e-18 << " кубических метров";
		break;
	case 3:
		cout << d * 1.0e-6 << " кубических метров";
		break;
	case 4:
		cout << d * 0.001 << " кубических метров";
		break;
	case 5:
		cout << d * 4.5461e-3 << " кубических метров";
		break;
	case 6:
		cout << d * 1.64e-5 << " кубических метров";
		break;
	}
	return 0;
}

enum (перечисление)

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

enum name {enumerator1 = constexpr , enumerator2 = constexpr , ... };
enum name : type { enumerator1 = constexpr , enumerator2 = constexpr , ... }; 

Вы спросите: “Какое отношение имеют перечисления к условной инструкции?”. Самое что ни на есть прямое! Дело в том, что перечисления очень часто обрабатываются с помощью инструкции switch. Приведем пример программы.

#include <iostream>
using namespace std;

int main() {
    enum Color {aqua, black, blue, gray, green, red, yellow};
    int r;
    cout << "1. aqua,\n"
            "2. black,\n"
            "3. blue,\n"
            "4. gray,\n"
            "5. green,\n"
            "6. red,\n"
            "7. yellow\n"
            "Введите номер именованного значения цвета: ";
    cin >> r;
    cout << "Код цвета в 16-ричном представлении: ";
    switch(r) {
        case aqua   : cout << "#00FFFF" << endl; break;
        case black  : cout << "#000000" << endl; break;
        case blue   : cout << "#0000FF" << endl; break;
        case gray   : cout << "#808080" << endl; break;
        case green  : cout << "#008000" << endl; break;
        case red    : cout << "#FF0000" << endl; break;
        case yellow : cout << "#008000" << endl; break;
        default : cout << "В наборе нет цвета"
                          " с таким именем!" << endl;
    }
    cout << "Что на самом деле скрыто в пременных enum?\n"
         << "aqua     => " << aqua
         << "\nblack  => " << black
         << "\nblue   => " << blue
         << "\nyellow => " << yellow
         << endl;

    return 0;
}

Вывод

1. aqua,
2. black,
3. blue,
4. gray,
5. green,
6. red,
7. yellow
Введите номер именованного значения цвета: 5
Код цвета в 16-ричном представлении: #FF0000
Что на самом деле скрыто в пременных enum?
aqua   => 0
black  => 1
blue   => 2
yellow => 6

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

enum Test {a, b, c = 10, d, e = 1, f, g = f + c};

Значения счетчиков будут равны: a = 0, b = 1, c = 10, d = 11, e = 1, f = 2, g = 12

Примеры решения задач
  • 1. Логический тип данных. Составить программу, печатающую значение true, если указанное высказывание является истинным, и false в противном случае: число N является четным двузначным числом
  • #include <iostream>
    #include <iomanip>
    using namespace std;
    
    int main() {
    	int N;
    	bool b;
    	cout << "N = "; cin >> N;
    	b = N / 100 == 0 && N / 10 != 0 && N % 2 == 0;
    	// b = !(N / 100) && N / 10 && !(N % 2);
    	cout << boolalpha << b << endl;
    	return 0;
    }

    В комментарии компактная запись с опущенными операциями сравнения, но с применением инверсии.
    Манипулятор boolalpha – вывод логических величин в текстовом виде (например, false вместо 0).

  • 2. Ветвление неполное. Взять число n по модулю, если это число отрицательное
  • #include <iostream>
    #include <cmath>
    using namespace std;
    
    int main() {
    	int n;
    	cout << "n = "; cin >> n;
    	if (n < 0) 
    		n = abs(n);
    	cout << "|n| = " << n << endl;	
    	return 0;
    }
  • 3. Полное ветвление. Даны вещественные числа a и b, не равные друг другу. Меньшее заменить их средним геометрическим (средним пропорциональным), а большее – их средним арифметическим.
  • #include <iostream>
    #include <cmath>
    using namespace std;
    
    int main() {
    	float a, b;
    
    	cout << "a = "; cin >> a;
    	cout << "b = "; cin >> b;
    
    	if (a > b) {
    		a = (a + b) / 2;
    		b = sqrtf(a * b);
    	} else {
    		a = sqrtf(a * b);
    		b = (a + b) / 2;
    	}
    
    	cout << "a = "
    		 << a
    		 << endl
    		 << "b = "
    		 << b
    		 << endl;
    
    	return 0;
    }
    
  • 4. Каскадные ветвления (ветвления, следующие друг за другом, обычно – неполные). Даны три целых числа. Найти количество положительных чисел в исходном наборе.
  • #include <iostream>
    using namespace std;
    
    int main() {
    	int a, b, c, i = 0;
    
    	cout << "a = "; cin >> a;
    	cout << "b = "; cin >> b;
    	cout << "c = "; cin >> c;
    
    	if (a > 0) ++i;
    	if (b > 0) ++i;
    	if (c > 0) ++i;
    	
    	cout << "Количество положительных чисел равно " << i << endl;
    
    	return 0;
    }
    
  • 5. Вложенные ветвления. Даны три числа. Найти сумму двух наибольших из них.
  • #include <iostream>
    using namespace std;
    
    int main() {
    	int a, b, c;
    
    	cout << "a = "; cin >> a;
    	cout << "b = "; cin >> b;
    	cout << "c = "; cin >> c;
    
    
    	if (a > b)
    		if (b > c)
    			cout << a + b << endl;
    		else
    			cout << a + c << endl;
    	else
    		if (a > c)
    			cout << a + b << endl;
    		else
    			cout << b + c << endl;
    
    	return 0;
    }
    
  • 6. Тернарная операция. Дано целое число. Если оно является положительным, то прибавить к нему 1; в противном случае вычесть из него 2. Вывести полученное число.
  • #include <iostream>
    using namespace std;
    
    int main() {
    	int a;
    
    	cout << "a = "; cin >> a;
    	cout << (a > 0 ?  ++a : a - 2) << endl;
    
    	return 0;
    }
    

Вопросы
  1. Каким должен быть результат логического выражения в инструкции if, чтобы выполнялась ветвь на иначе
  2. Когда используется неполная форма инструкции if?
  3. Почему в условии можно опустить операции сравнения?
  4. В чем опасность использования вместо операции сравнения ==, операцию присваивания (=)?
  5. Приведите примеры когда можно заменить инструкцию if тернарной операцией.
  6. Можно ли заменить (a % 3 == 0) на (!(a % 3))? Аргументируйте свой ответ.
  7. Когда лучше использовать инструкцию switch, а когда инструкцию if?
Темы сообщений
Задания А
  1. Даны целочисленные координаты точки на плоскости. Если точка совпадает с началом координат, то вывести 0. Если точка не совпадает с началом координат, но лежит на оси OX или OY, то вывести соответственно 1 или 2. Если точка не лежит на координатных осях, то вывести 3.
  2. Дано целое число. Вывести его строку-описание вида «отрицательное четное число», «нулевое число», «положительное нечетное число» и т. д.
  3. Даны коэффициенты a, b и c. Найдите вещественные корни квадратного уравнения, если вещественных корней нет – сообщите об этом.
Задания Б
Задания С
Ссылки
1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (Пока оценок нет)
Загрузка...

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Print Friendly, PDF & Email

Обсуждение закрыто.