Тернарный оператор и оператор запятая

Теги: Тернарный оператор, оператор ?, вложенный тернарный оператор, оператор запятая, запятия си, порядок выполнения тернарного оператора, порядок выполнения оператора запятая, ошибка оператор запятая.



Тернарный оператор и оператор запятая

Название «тернарный» произошло от латинского ternarius – тройной. Оператор принимает три аргумента. Если первый аргумент истина, то возвращается второй аргумент, если ложь, то возвращается третий.

Синтаксис оператора

<условие> ? <аргумент 2> : <аргумент 3>

Например, пользователь вводит два числа. Присвоить переменной значение наименьшего.

#define _CRT_SECURE_NO_WARNINGS
#include <conio.h>
#include <stdio.h>

void main() {
        int a, b, c;

        scanf("%d %d", &a, &b);

        c = (a > b) ? b : a;

        printf("%d", c);
        _getch();
}

Другой пример: вывести модуль числа

#define _CRT_SECURE_NO_WARNINGS
#include <conio.h>
#include <stdio.h>

void main() {
        int a;

        scanf("%d", &a);

        printf("%d", a > 0 ? a : -a);
        _getch();
}

Здесь тернарный оператор используется вместо аргумента функции printf.

Оператор ? может быть вложенным. Например, найдём среднее из трёх чисел:

#include <conio.h>
#include <stdio.h>

void main() {
        int a = 1;
        int b = 2;
        int c = 3;
        int mid;

        mid = (a > b) ? (a > c) ? (c > b) ? c : b : a : (b > c) ? (c > a) ? c : a : b;

        printf("%d", mid);
        _getch();
}

Видно, что в этом примере тернарный оператор становится нечитаемым. Поэтому не используйте вложенные тернарные операторы и заменяйте их на обычные ветвления

#include <conio.h>
#include <stdio.h>

void main() {
        int a = 1;
        int b = 2;
        int c = 3;
        int mid;

        if (a > b) {
                if (a > c) {
                        if (c > b) {
                                mid = c;
                        } else {
                                mid = b;
                        }
                } else {
                        mid = a;
                }
        } else {
                if (b > c) {
                        if (c > a) {
                                mid = c;
                        } else {
                                mid = a;
                        }
                } else {
                        mid = b;
                }
        }

        printf("%d", mid);
        _getch();
}

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

#include <conio.h>
#include <stdio.h>

void main() {
        int x = 0;

        //Выведет 200, так как ++ постфиксный
        printf("%d\n", x++ ? 100: 200);
        //Выведет 1, так как после проверки x был увеличен
        printf("%d\n", x);

        x = 0;
        //Выведет 100, так как сначала будет увеличен x
        printf("%d\n", ++x ? 100 : 200);
        printf("%d\n", x);

        x = 0;
        printf("%d\n", ++x ? x++ : x++);
        //Выведет 2, так как будет выполнено первое условие
        //и x будет инкрементирован повторно
        printf("%d\n", x);
        
        _getch();
}

Оператор '?' в некоторых случаях можно компактно записать как оператор switch:

#define _CRT_SECURE_NO_WARNINGS
#include <conio.h>
#include <stdio.h>

int main(int argc, char **argv) {
        unsigned day_of_week;
        char const * name;

        printf("day of week: ");
        scanf("%u", &day_of_week);

        name = day_of_week == 1 ? "Monday" :
                   day_of_week == 2 ? "Tuesday" :
                   day_of_week == 3 ? "Wednesday" :
                   day_of_week == 4 ? "Thursday" :
                   day_of_week == 5 ? "Friday" :
                   day_of_week == 6 ? "Saturday" :
                   day_of_week == 7 ? "Sunday" :
                   "Wrong day of week";
        printf("%s", name);
        _getch();
}

Оператор запятая.

Оператор «,» принимает два аргумента, выполняет первый, после этого выполняет второй и возвращает его значение. Например:

#include <conio.h>
#include <stdio.h>

void main() {
        int a, b, c;

        c = (a = 3, b = 4);
        printf("%d", c);

        _getch();
}

В данном примере c будет равно 4. Выражение

(a = 3, b = 4)

вернёт 4. Очевидно, что если убрать скобки, то c станет равным 3, так как запятая в этом случае будет разделять c = a = 3 и b = 4, с присвоится значение 3, а 4 будет возвращено оператором запятая, но потеряется. То есть выражение

c = a = 3, b = 4;

эквивалентно

(c = a = 3), (b = 4);

Если написать

c = (a = 3, b = 4, d = 5);

то будет возвращено значение 5.

В выражении

#include <conio.h>
#include <stdio.h>

void main() {
        int c;

        c = 1, 2, 3, 4, 5;
        printf("%d", c);

        _getch();
}

с будет равно 1, так как этот код эквивалентен такому

((((c = 1), 2), 3), 4), 5;

Такое поведение оператора запятая часто приводит к следующей ошибке. Вместо десятичной точки

a = 1.5;

пишут

a = 1,5;

Таким образом, переменная a будет иметь значение 5.

Для оператора «,» гарантированно выполнение по порядку, слева направо. Оператор запятая поэтому используется в условиях, когда нужно выполнить несколько действий или получить значение. Например

#include <conio.h>
#include <stdio.h>

int foo(int a) {
        return a % 5 + a*a;
}

void main() {
        int i = 0;
        int mod;
        
        while (mod = foo(i), mod < 100) {
                printf("%d ", i);
                i++;
        }

        _getch();
}

Часто запятая используется в цикле for, так как позволяет задавать несколько значений или выполнять несколько значений за раз. Пример – переворачивание массива.

#include <conio.h>
#include <stdio.h>

#define SIZE 10

void main() {
        int arr[SIZE] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        int i, j, tmp;
        
        for (i = 0, j = SIZE - 1; i < SIZE / 2; i++, j--) {
                tmp = arr[i];
                arr[i] = arr[j];
                arr[j] = tmp;
        }

        for (i = 0; i < SIZE; i++) {
                printf("%d ", arr[i]);
        }

        _getch();
}
Q&A

Всё ещё не понятно? – пиши вопросы на ящик email
Целые числа фиксированного размера