+---------------------------+
|.-------------------------.|
|| kee_reel@blog:~/ru $ cd ||
|| ссылки контакты         ||
|| c c++ linux opengl sql  ||
|| python сети             ||
||                         ||
|.-------------------------.|
+-::---------------------::-+
.---------------------------.
 // /oooooooooooooooooooooo\\ \\ 
 // /oooooooooooooooooooooooo\\ \\ 
//-------------------------------\\
\\-------------------------------//


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 в природе:

Круговорот 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

П

Блок-схема

Нарисуй на бумаге или в онлайн-редакторе блок схему для только что сделанной тобой задачи (можешь опираться на блок-схему в начале статьи).

Заключение

Итого, ты изучил:

  • Блок-схемы
  • Булевые значения и операторы
  • Таблицы истинности
  • Ответ на хитрую задачу на собеседовании
  • Операторы сравнения
  • Условия
  • Вложенные условия

Это очень важный этап развития тебя, как программиста. Условия используются везде, и если ты понял их сейчас, то ты сможешь в будущем легко перенести это знание на другие языки программирования.

Если что – пиши, я помогу и постараюсь объяснить лучше.

Дальше мы рассмотрим основную рабочую силу твоих программ – циклы.


▲ В начало ▲