Операторы ветвления в языке C: if-else, тернарный, switch

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
        …;

Для более легкого восприятия человеком отступами подчеркнуто, что куда вложено. Однако для компилятора отступы никакой роли не играют, и принадлежность первой ветки 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 обозначаются соответственно парными знаками амперсанда && и вертикальной черты ||. Их приоритет меньше, чем у простых логических операторов, поэтому простые логические операции при их объединении в сложные логические выражения можно не заключать в скобки. Пример сложного логического выражения:

a > 100 && b != 0

Следует отметить, что в чистом Си как такового логического типа данных со значениями true и false нет. Вместо этого используются целые числа. Так в результате выполнения выражений ниже на экран будут выведены числа 0 и 1.

int a = 3, b = 0, c = -4, d = -1;
 
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 12, 13, 18. Ветка default не обязательна.

При выполнении оператора switch, заданное значение в круглых скобках сравнивается с константами. Как только совпадение будет найдено, все последующие вложенные во все case операции начинают выполняться. Другими словами, выполняется не только кейс, где произошло совпадение, но и все нижележащие ветки casedefault тоже), константы которых не совпадают со значением при 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-версия


Основы языка C. Курс




Все разделы сайта