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

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



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

Название «тернарный» произошло от латинского 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
Целые числа фиксированного размера