Операторы ветвления
if-else
В языке программирования C синтаксис оператора ветвления if-else выглядит так:
if (логич_выражение) выражение1; else выражение2;
Как и в других языках ветка else не является обязательной.
В языке С в простых логических выражениях используются следующие знаки операторов: >, <, >=, <=, ==, !=.
В случае если тело той или иной ветки состоит из нескольких выражений, разделяемых точкой с запятой, тело заключается в фигурные скобки:
if (логич_выражение) { выражение1; выражение2; … } else { выражениеN; … }
В C можно использовать вложенные конструкции if-else. При этом рекомендуют вкладывать во внешнюю ветку else, а не if, т.к. это позволяет избегать неоднозначности толкования инструкции. Посмотрите на такую конструкцию:
if (…) if (…) …; else …; else if (…) …; else …;
Для более легкого восприятия человеком отступами подчеркнуто, что куда вложено. Однако для компилятора с языка C отступы никакой роли не играют, и принадлежность первой ветки else не очевидна. Ее можно было бы ошибочно отнести к первому if, в результате чего второе else было бы вообще неуместным, т.к. не относилось бы ни к какому if. В данном случае такой ошибки не будет, т.к. компилятор руководствуется правилом: ветка else относится к ближайшему к ней сверху if, у которого еще нет ветки else. Именно поэтому здесь первое else относится ко второму if (т.к. оно к нему ближе), а второе else к первому if, т.к. второе if уже "покрыто" предыдущим else. Теперь посмотрите вот на такую конструкцию:
if (…) if (…) …; else if (…) …; else …;
Программист отступами показал, что он хочет, чтобы первое else относилось к внешнему if. Однако компилятор, руководствуясь правилом отнесения веток else, расценит программу вот так (если перевести на удобство чтения ее программистом):
if (…) if (…) …; else if (…) …; else …;
При этом программа будет делать не то, что хотел программист: если в выражении при первом if будет возвращаться ложь, то ни один else просто не сработает. Однако в таких сложных случаях есть выход — это использование фигурных скобок, даже если тело условной инструкции состоит всего из одного выражения:
if (…) { if (…) …; } else if (…) …; else …;
В таком случае программа будет восприниматься компилятором именно так, как задумал программист.
Чаще всего на практике используется подобная конструкция множественного ветвления:
if (…) { … } else if (…) { … } else if (…) { … } else { … }
Здесь с точки зрения компилятора каждое else относится к предыдущему if, но выравнивание делается таким, как будто в Си есть условный оператор множественного ветвления. Результат работы конструкции таков, что выполняется хотя бы одна ветка. И как только она выполняется, вся конструкция завершает работу.
Условное выражение
В языке программирования C существует сокращенная запись инструкции if-else в виде условного выражения, которое относится к тернарным операторам. Результат такого выражения может быть присвоен переменной:
(логич_выражение) ? выражение1 : выражение2
Переводится это так. Если логич_выражение вернуло истину, то все выражение возвращает выражение1; если логич_выражение вернуло ложь, то все выражение возвращает выражение2. Например:
x = 12; y = 16; z = (x > y) ? x - 1 : y - 1;
Здесь z получит значение 15. Такое условное выражение бывает очень удобно, однако область его применения ограничена простейшими случаями ветвления, т. к. невозможно создавать сложные "тела" в такой конструкции.
Операторы И (&&) и ИЛИ (||)
Как известно логическое выражение может быть сложным. Логические операторы И и ИЛИ в языке программирования C обозначаются соответственно парными знаками амперсанда (&&) и вертикальной черты (||). Их приоритет меньше, чем у простых логических операторов, поэтому простые логические операции при их объединении в сложные логические выражения можно не заключать в скобки. Пример сложного логического выражения на языке C:
a > 100 && b != 0
Проверьте и объясните, что выводит функция printf(), если ей передать простые или сложные логические выражения. Например:
printf("%d\n", a == b && c < d); printf("%d\n", c < d);
Оператор switch
При организации множественного выбора, когда проверяется значение переменной на соответствие тому или иному значению, бывает удобно использовать не условный оператор if-else, а оператор переключения switch. Его синтаксис можно описать так:
switch (целочисленная_переменная) { case константа1: операции; case константа2: операции; …. default: операции; }
В скобках после слова switch может стоять не только переменная, но и выражение, результат выполнения которого возвращает целое значение (может быть символ). Константы при case также могут быть результатом выполнения выражений. Константы можно группировать в одном case (например, case 12, 13, 18
). Ветка default не обязательна.
При выполнении оператора switch, заданное значение в круглых скобках сравнивается с константами. Как только совпадение будет найдено, все последующие вложенные во все case операции начинают выполняться. Другими словами, выполняется не только кейс, где произошло совпадение, но и все нижележащие ветки case (и default тоже), константы которых не совпадают со значением при switch. Например, в результате выполнения вот такой программы:
int a = 1; switch (a) { case 0: printf("%d ", 0); case 1: printf("%d ", 1); case 2: printf("%d ", 2); default: printf("%d ", -1); } printf("\n");
на экране будет выведено:
1 2 -1
, т. к. как только совпадение было обнаружено, все нижеследующие инструкции были выполнены.
Чтобы этого не происходило, в конце операций, принадлежащих определенному case, дописывают оператор break, который осуществляет принудительный выход из всей конструкции (в данном случае switch). Например:
int a=1; switch (a) { case 0: printf("%d\n", 0); break; case 1: printf("%d\n", 1); break; case 2: printf("%d\n", 2); break; default: printf("%d\n", -1); }
выведет только единицу, т. к. выполнение всей инструкции switch прервется после выполнения инструкции break при case 1.
Курс с решением части задач:
pdf-версия, android-приложение