C. Условия
Время чтения: 9 минут
Условие (condition) – это механизм, позволяющий выполнить действие, только если выполняется определённое условие.
Вот пример определения условия:
int x;
scanf("%d", &x);
if(x > 100)
{
printf("Число %d больше 100\n", x);
}
else if(x == 100)
{
printf("Число %d равно 100\n", x);
}
else
{
printf("Число %d меньше 100\n", x);
}
Чтобы лучше понять что происходит, я нарисую блок-схему.
Блок-схема – это просто графическая схема, которая описывает какой-то алгоритм. С её помощью можно описать сам алгоритм, не заморачиваясь с написанием программы на каком-либо языке программирования.
Алгоритм – это последовательность действий.
Вот блок-схема для кода выше:
Сделано с помощью draw.io онлайн редактора блок-схем
В блок-схемах всё очень просто – нужно просто двигаться по стрелкам от “начала” к “концу” и отвечать на вопросы, если их задают. Вопросы в этих схемах и являются условиями, про которые я говорю.
Надеюсь этим я объяснил смысл условий.
Теперь я расскажу, почему на вопросы/условия можно отвечать только “да” или “нет”…
Булевые операции и операции сравнения
В математике есть раздел, который называется “булевая алгебра”. Из неё в программирование пришли вот такие понятия:
- Значение истина, которое обозначается числом 1
- Значение ложь, которое обозначается числом 0
- Оператор НЕ (¬) – этот унарный оператор инвертирует значение
- Оператор ИЛИ (∨) – этот бинарный оператор возвращает истина если хоть один из операндов равен истина
- Оператор И (∧) – этот бинарный оператор возвращает истина если все операнды равны истина
Для описания всевозможных результатов булевых операций используются таблицы истинности:
Булевые операции
В языке Си эти понятия обозначаются так:
- истина: любое целое или вещественное значение не равное 0
- ложь: целое или вещественное значение равное 0
- НЕ: ! (символ восклицательного знака)
- ИЛИ: || (два символа вертикальный слеш)
- И: && (два символа имперсант)
Несмотря не то, что значение истина в Си можно обозначить как любое число не равное 0 – обычно программисты используют значение 1.
Операции НЕ, ИЛИ, И всегда возвращают или 0 (ложь), или 1 (истина).
Вот пример использования этих операций:
// Использую тип char, чтобы не занимать лишнюю память -- ведь нужны только значения 0 и 1
char thisIsTrue = 1;
char thisIsFalse = 0;
// Отрицание со значением истина
char result = !thisIsTrue;
printf("!1 = %d\n", result); // !1 = 0
// Отрицание со значением ложь
result = !thisIsFalse;
printf("!0 = %d\n", result); // !0 = 1
// Операция ИЛИ
result = thisIsFalse || thisIsTrue;
printf("0 || 1 = %d\n", result); // 0 || 1 = 1
result = thisIsFalse || 0;
printf("0 || 0 = %d\n", result); // 0 || 0 = 0
// Операция И
result = thisIsFalse && thisIsTrue;
printf("0 && 1 = %d\n", result); // 0 && 1 = 0
result = 1 && thisIsTrue;
printf("1 && 1 = %d\n", result); // 1 && 1 = 1
// Не забываем что всё кроме 1 тоже считается истиной!
result = !51;
printf("!51 = %d\n", result); // !51 = 0
result = 0 || 522;
printf("0 || 522 = %d\n", result); // 0 || 552 = 1
result = 62.2 && 23;
printf("62.2 && 23 = %d\n", result); // 62.2 && 23 = 1
Хитрая задача на собеседовании
В связи с тем, что булевые операции всегда возвращают или 1, или 0, программисты придумали хитрую задачку, которую любят задавать на собеседованиях.
Сейчас я её покажу, объясню, и ты никогда на ней не провалишься :)
На собеседовании тебе дают такой код:
int a = 42;
a = !!a;
printf("%d", a);
И спрашивают – “Что выведет программа?”.
Давай развернём операцию “!!a” на отдельные этапы выполнения:
- Сначала выполняем крайний правый “!”: !a -> !42 -> 0
- Затем выполняем оставшийся “!” на то, что получилось после предыдущего этапа: !0 -> 1
Ответ на собеседовании: выведется 1.
Операции сравнения
Ещё в языке Си есть операции сравнения, которые ничем не отличаются от аналогичных в математике:
- Равно: ==
- Не равно: !=
- Больше: >
- Больше или равно: >=
- Меньше: <
- Меньше или равно: <=
Эти операции, так же как и булевые операции, возвращают булевое значение 0 (ложь) или 1 (истина).
Вот пример использования этих операций:
char ten = 10;
char hundred = 100;
// Равно
char result = ten == hundred;
printf("10 == 100 = %d\n", result); // 10 == 100 = 0
// Не равно
result = ten != hundred;
printf("10 != 100 = %d\n", result); // 10 != 100 = 1
// Больше
result = ten > hundred;
printf("10 > 100 = %d\n", result); // 10 > 100 = 0
// Меньше или равно
result = ten <= hundred;
printf("10 <= 100 = %d\n", result); // 10 <= 100 = 1
Комбинируем булевые операции, операции сравнения и арифметические операции
Зачастую тебе нужно будет комбинировать между собой несколько операторов, чтобы описать какую-то логику.
Вот пример задания: “Проверить что число чётное и меньше 100”. Вот как бы я написал:
int x;
scanf("%d", &x);
char isOk = !(x % 2) && x < 100;
printf("Число подходит (1 - да, 0 - нет): %d\n", isOk);
Что такое “!(x % 2) && x < 100”? Это
- x % 2 – остаток от деления числа на 2: если число чётное, то остаток будет 0, а если нечётное, то 1
- !(x % 2) – булевая операция НЕ над результатом выражения (x % 2): если результат будет 0 (чётное), то результат будет 1
- x < 100 – сравнение числа со 100: если число меньше, то результат будет 1, а если больше или равно, то 0
- !(x % 2) && x < 100 – булевая операция И над результатами левой и правой части: если число чётное И меньше 100, то вернётся 1
Для ясности, подставлю конкретное число 42, и упрощу его вплоть до результата:
!(42 % 2) && 42 < 100
!(0) && 1
1 && 1
Можете тоже подставлять конкретные числа, чтобы проще было понять логику внутри сложных операций.
Возвращаемся к тому, с чего начали
…вот поэтому, ответом на условие может быть только ответ “да” или “нет” :)
Ещё раз напишу код с условием из начала статьи:
int x;
scanf("%d", &x);
if(x > 100)
{
printf("Число %d больше 100\n", x);
}
else if(x == 100)
{
printf("Число %d равно 100\n", x);
}
else
{
printf("Число %d меньше 100\n", x);
}
В условии пишется выражение, которые возвращает значение 0 (ложь) или 1 (истина). Далее в фигурных скобках содержится блок кода, который выполнится если выражение будет истинным:
// if(выражение)
if(x > 100)
// Начало блока
{
printf("Число %d больше 100\n", x);
// Конец блока
}
Если выражение внутри равно истина (не равно 0), то мы выполняем блок кода внутри этого условия, и заканчиваем.
Если выражение внутри ложно то надо проверить, идёт ли после этого if конструкция else:
- Если else нет – мы закончили
- Если else есть – переходим к следующему условию
Предположим, что первое условие у нас не выполнилось – теперь мы перешли к следующему. Здесь такой же if, но с другим условием:
else if(x == 100)
{
printf("Число %d равно 100\n", x);
}
Проверяем, есть ли после него else – ага, есть.
Тут уже нет условия, поэтому мы просто выполняем блок кода внутри:
else
{
printf("Число %d меньше 100\n", x);
}
Конструкция else без условия:
- Не обязательна (можно оставить только if)
- Должна находиться после конструкции if
- После неё нельзя использовать другие конструкции if или else
Получается такой вот круговорот if в природе:
Вложенные условия
Коротенько, но важно – внутри любого условия могут быть другие условия.
Смотри:
int x;
scanf("%d", &x);
if(x != 100)
{
if(x > 100)
{
printf("Число %d больше 100\n", x);
}
else
{
printf("Число %d меньше 100\n", x);
}
}
else
{
printf("Число %d равно 100\n", x);
}
Результат выполнения этого кода, идентичен результату выполнения кода из предыдущего раздела – просто тут я перенёс два условия под первое условие, чем изменил внутреннюю логику программы.
В твоей практике периодически будут возникать ситуации, когда тебе будет сложно правильно составить конструкцию из условий – в этом случае нарисуй на бумаге блок-схему алгоритма, который хочешь написать.
Тернарный оператор
Иногда, если уловие небольшое, его можно записать с помощью тернарного оператора “?:”.
Тернарный он потому, что в нём 3 операнда: A ? B : C. Сложение, например, это бинарный оператор, там 2 операнда: A + B.
Рассмотрю на примере такой задачи:
- Создаются две целочисленных переменных X и Y
- С клавиатуры вводится значение переменной X
- Если X больше 100, то Y = X * X
- Если X равен 100, то Y = X
- В остальных случаях (X меньше 100), то Y = X * 2
Вот как я бы расписал это с помощью if:
int X, Y;
scanf("%d", &X);
if(x > 100)
{
Y = X * X;
}
else if(x == 100)
{
Y = X;
}
else
{
Y = X * 2;
}
printf("Y = %d\n", Y);
А вот как с помощью тернарного оператора “?:”
int X, Y;
scanf("%d", &X);
// Если x > 100, то в Y вернётся X * X
// Иначе мы пойдём в это выражение ( x == 100 ? X : (X * 2) )
// В нём тот же смысл - если x == 100, то вернётся X
// Иначе вернётся X * 2
Y = x > 100 ? (X * X) : ( x == 100 ? X : (X * 2) );
printf("Y = %d\n", Y);
С этим оператором читать становится сложнее, но запись короче. Используй его по необходимости.
Условный оператор switch case
В случаях, когда у тебя есть переменная, которая:
- Может принимать ограниченное множество значений
- Тебе надо для разных значений, сделать разные действия
Используй switch case:
int day_of_week;
printf("Введите номер дня недели: ");
scanf("%d", &day_of_week);
switch(day_of_week) {
case 1:
printf("Понедельник\n");
break;
case 2:
printf("Вторник\n");
break;
case 3:
printf("Среда\n");
break;
case 4:
printf("Четверг\n");
break;
case 5:
printf("Пятница\n");
break;
case 6:
printf("Суббота\n");
break;
case 7:
printf("Воскресенье\n");
break;
default:
printf("Такого дня нет\n");
}
Здесь в switch пишется выражение, которое будет сравниваться со значениями в описанных case.
Если указанное выражение не подходит ни под какой case, то мы попадём в default. default является опциональным, и можно его не указывать.
Код для каждого случая надо писать между “case X:” и “break;”.
Задания на закрепление
Простенькая задачка на условия и выражения внутри них
С клавиатуры вводится целое число. В ответ программа выводит один из ответов:
- “Чётное” – если число чётное
- “Нечётное” – если число нечётное
- “Ответ на главный вопрос жизни, вселенной и всего такого” – если это число равно 42
П
Блок-схема
Нарисуй на бумаге или в онлайн-редакторе блок схему для только что сделанной тобой задачи (можешь опираться на блок-схему в начале статьи).
Заключение
Итого, ты изучил:
- Блок-схемы
- Булевые значения и операторы
- Таблицы истинности
- Ответ на хитрую задачу на собеседовании
- Операторы сравнения
- Условия
- Вложенные условия
Это очень важный этап развития тебя, как программиста. Условия используются везде, и если ты понял их сейчас, то ты сможешь в будущем легко перенести это знание на другие языки программирования.
Если что – пиши, я помогу и постараюсь объяснить лучше.
Дальше мы рассмотрим основную рабочую силу твоих программ – циклы.