В этой главе вы научитесь выбирать действия с помощью if и else, составлять логические выражения и использовать остаток от деления для проверки чётности и работы с цифрами числа.
Как хранить решения нескольких задач
Решения удобно организовать в Visual Studio так, чтобы к каждому можно было вернуться. Возможны три варианта:
- Несколько методов в одном файле. Из
Mainвызывайте метод нужной задачи. - Несколько классов в одном проекте. Дайте каждому классу понятное имя и вызывайте нужный метод из
Main. - Несколько проектов в одном решении (Solution). Перед запуском выберите нужный запускаемый проект.
Пока вы работаете с одной задачей, достаточно одного проекта и одного Main. Не вставляйте несколько методов Main с одинаковой сигнатурой в один класс.
Дополнительно: видео об организации решений на иврите
В необязательном видео показаны три способа организации задач:
Условный оператор if
Условный оператор выполняет действие только тогда, когда заданное условие истинно.
1
2
3
4
5
int score = 85;
if (score >= 60) // Выражение в скобках — логическое выражение
{
Console.WriteLine("Экзамен сдан!");
}
Выражение score >= 60 проверяет, не меньше ли оценка 60. Если результат true («истина»), выполняется блок в фигурных скобках. Если результат false («ложь»), этот блок пропускается.
Первая таблица трассировки с условием
Когда в коде есть условие, добавьте в таблицу трассировки столбец с результатом логического выражения: true или false. Пронумеруйте строки кода и записывайте номер выполненной строки в первом столбце. Если значение переменной не изменилось, её ячейку можно оставить пустой.
Проследим выполнение при начальном значении score = 72:
1
2
3
4
5
6
7
8
9
int score = 72;
bool passed = false;
if (score >= 60)
{
passed = true;
}
Console.WriteLine(passed);
| Строка | score |
passed |
score >= 60 |
Вывод |
|---|---|---|---|---|
| 1 | 72 | |||
| 2 | false | |||
| 4 | true | |||
| 6 | true | |||
| 9 | True |
Строки 5 и 7 содержат только фигурные скобки: отдельные строки таблицы для них обычно не нужны. Значение bool в исходном коде записывается как true, а Console.WriteLine выводит его как True.
Попробуйте сами
Напишите программу, которая получает две оценки ученика по программированию: за первое и второе полугодие. Если вторая оценка выше первой не менее чем на 5 баллов, выведите сообщение «Есть прогресс!».
Проверьте случаи, когда разница равна 4, 5 и 6 баллам, а также случай, когда вторая оценка ниже первой.
Две ветви: if и else
else задаёт действие на случай, когда условие ложно. Из двух ветвей выполняется ровно одна.
1
2
3
4
5
6
7
8
9
int score = 55;
if (score >= 60) // Здесь условие ложно
{
Console.WriteLine("Экзамен сдан!");
}
else // Поэтому выполнится строка 8, а строка 4 будет пропущена
{
Console.WriteLine("Экзамен не сдан. Попробуйте ещё раз.");
}
Несколько вариантов: else if и else
1
2
3
4
5
6
7
8
9
10
string color = "Green";
if (color == "Red")
Console.WriteLine("Красный цвет");
else if (color == "Green")
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Зелёный цвет");
}
else
Console.WriteLine($"Цвет: {color}");
Условия проверяются сверху вниз. После первой подходящей ветви остальные пропускаются. else выполняется, если ни одно из предыдущих условий не подошло.
Пример с решением: возрастная группа
Напишите программу, которая получает возраст и выводит:
- «Несовершеннолетний», если возраст меньше 18;
- «Взрослый», если возраст от 18 до 64 включительно;
- «Пожилой», если возраст не меньше 65.
Решение
1
2
3
4
5
6
7
8
9
10
11
12
public static void Main()
{
Console.Write("Введите возраст: ");
int age = int.Parse(Console.ReadLine());
if (age < 18)
Console.WriteLine("Несовершеннолетний");
else if (age <= 64)
Console.WriteLine("Взрослый");
else
Console.WriteLine("Пожилой");
}
В ветви else if не нужно повторять проверку age >= 18: если мы дошли до неё, первое условие уже оказалось ложным.
Операторы сравнения и логические операторы
| В математике | В C# | Вид | Значение | Пример |
|---|---|---|---|---|
| \(=\) | == |
Сравнение | Равно | if (x == y) { … } |
| \(\neq\) | != |
Сравнение | Не равно | if (x != y) { … } |
| \(>\) | > |
Сравнение | Больше | if (x > y) { … } |
| \(<\) | < |
Сравнение | Меньше | if (x < y) { … } |
| \(\ge\) | >= |
Сравнение | Больше или равно | if (x >= y) { … } |
| \(\le\) | <= |
Сравнение | Меньше или равно | if (x <= y) { … } |
| \(\land\) | && |
Логический | И | if (a > 0 && b > 0) { … } |
| \(\lor\) | || |
Логический | ИЛИ | if (a == 0 || b == 0) { … } |
| \(\lnot\) | ! |
Логический | НЕ | bool ok = !isReady; |
Логические выражения и тип bool
Логическое выражение (logical expression) имеет значение true или false. Например, age >= 18 сравнивает возраст с числом 18.
Переменная типа bool хранит одно из этих двух значений. В неё можно записать результат сравнения:
Console.WriteLine("Введите два числа, каждое на отдельной строке:");
int num1 = int.Parse(Console.ReadLine());
int num2 = int.Parse(Console.ReadLine());
bool found = (num1 == num2);
if (found)
Console.WriteLine("Числа равны!");
else
Console.WriteLine("Числа не равны.");
Ещё один пример:
int age = 18;
bool isAdult = age >= 18; // Результат сравнения true записывается в isAdult
В строке выше = выполняет присваивание, а >= — сравнение. Сначала вычисляется выражение справа, затем его результат сохраняется в переменной.
Примеры выражений; здесь предполагается, что переменные уже объявлены:
// Простое сравнение: истинно, если x положительно
x > 0
// Логическое И: истинно, если x положительно и чётно
(x > 0) && (x % 2 == 0)
// a не равно b, и при этом c больше d или e не больше f
(a != b) && ((c > d) || (e <= f))
Это примеры выражений, а не готовые инструкции программы: используйте их внутри if или справа от = при присваивании переменной типа bool.
Остаток от деления: оператор %
Оператор % возвращает остаток от деления. Например, 10 % 3 равно 1, потому что \(10 = 3 \cdot 3 + 1\). Он помогает проверять чётность, делимость и выделять цифры числа.
В C# знак % не вычисляет проценты. Например, 20 % 6 даёт остаток 2, а не шесть процентов от двадцати.
int number = 7;
if (number % 2 == 0)
{
Console.WriteLine("Чётное число");
}
else
{
Console.WriteLine("Нечётное число");
}
При number = 7 программа выведет:
Нечётное число
Составные условия
С помощью логических операторов можно объединять проверки:
&&— И: обе проверки должны датьtrue;||— ИЛИ: хотя бы одна проверка должна датьtrue;!— НЕ: меняетtrueнаfalseи наоборот.
В следующей учебной модели условие требует подходящего возраста и наличия водительских прав:
1
2
3
4
5
6
7
8
9
10
11
int age = 25;
bool hasLicense = true;
if (age >= 18 && hasLicense)
{
Console.WriteLine("Условия для вождения выполнены");
}
else
{
Console.WriteLine("Условия для вождения не выполнены");
}
hasLicense уже имеет тип bool, поэтому можно написать && hasLicense без дополнительного сравнения с true.
Переменные-флаги
Флаг — логическая переменная, которая запоминает состояние. Например, found хранит, найдено ли нужное число:
1
2
3
4
5
6
7
8
9
10
11
12
bool found = false;
int number = 5;
if (number == 5)
{
found = true;
}
if (found)
{
Console.WriteLine("Число найдено");
}
Фигурные скобки и оформление кода
В предыдущих примерах открывающая фигурная скобка стоит на новой строке. Этот стиль называется Allman; используйте его для единообразия с примерами курса.
В других материалах вы можете встретить стиль K&R, где открывающая скобка стоит на той же строке, что и условие. Смысл кода не меняется:
bool found = false;
int number = 5;
if (number == 5) {
found = true;
}
if (found) {
Console.WriteLine("Число найдено");
}
Если после условия выполняется ровно одна инструкция, фигурные скобки можно опустить. Отступ и перенос строки делают код понятнее, но сами по себе не создают блок. При добавлении второй инструкции нужны скобки.
bool found = false;
int number = 5;
if (number == 5)
found = true;
if (found)
Console.WriteLine("Число найдено");
Для проверки равенства используйте ==. Один знак = означает присваивание. Например, if (number = 5) не скомпилируется: условие должно иметь тип bool.
Первый if в этом примере можно заменить присваиванием результата сравнения:
1
2
3
4
5
6
7
bool found = false;
int number = 5;
found = number == 5; // В found записывается true
if (found)
Console.WriteLine("Число найдено");
Палиндром: решение и таблица трассировки
Напишите программу, которая получает положительное трёхзначное целое число num и сообщает, является ли оно палиндромом. Палиндром одинаково читается слева направо и справа налево. Например, 363 — палиндром, а 563 — нет.
Решение и трассировка
1
2
3
4
5
6
7
8
9
10
11
12
Console.Write("Введите положительное трёхзначное число: ");
int num = int.Parse(Console.ReadLine());
int units = num % 10; // Последняя цифра
int hundreds = num / 100; // Первая цифра; деление целочисленное
if (units == hundreds)
{
Console.WriteLine($"{num} — палиндром");
}
else
{
Console.WriteLine($"{num} — не палиндром");
}
Таблица трассировки для ввода 363:
| Строка | num |
units |
hundreds |
units == hundreds |
Вывод |
|---|---|---|---|---|---|
| 1 | Введите положительное трёхзначное число: | ||||
| 2 | 363 | ||||
| 3 | 363 | 3 | |||
| 4 | 363 | 3 | 3 | ||
| 5 | 363 | 3 | 3 | true | |
| 7 | 363 | 3 | 3 | 363 — палиндром |
Таблица помогает проследить выполнение на бумаге и объяснить назначение программы. Проверка выполняется в строке 5, а сообщение выводится отдельной инструкцией в строке 7.
Для ввода 563 запишем только изменившиеся значения:
| Строка | num |
units |
hundreds |
units == hundreds |
Вывод |
|---|---|---|---|---|---|
| 1 | Введите положительное трёхзначное число: | ||||
| 2 | 563 | ||||
| 3 | 3 | ||||
| 4 | 5 | ||||
| 5 | false | ||||
| 11 | 563 — не палиндром |
Частые ошибки и проверка понимания
Лишняя точка с запятой после if
В следующем коде сообщение «Успех» выводится всегда:
if (num > 5);
Console.WriteLine("Успех");
Точка с запятой сразу после условия образует пустую инструкцию. Последующий вывод уже не относится к if. Код может скомпилироваться, поэтому проверяйте разные значения, обращайте внимание на предупреждения Visual Studio и используйте автоматическое форматирование.
Отдельные if и цепочка else if
В конструкции if/else выполняется ровно одна из двух ветвей. Если написать несколько независимых if подряд, могут выполниться несколько ветвей или ни одной. В цепочке if/else if выполняется не более одной ветви; завершающий else обеспечивает вариант на случай, когда все условия ложны.
У каждой проверки должны быть обе части
В C# нельзя записать диапазон как if (3 < x < 5). Правильно:
if (x > 3 && x < 5)
Console.WriteLine("Число внутри диапазона");
Запись if (myResult < 5 || > 8) тоже неверна. Нужна полная проверка по обе стороны ||:
if (myResult < 5 || myResult > 8)
Console.WriteLine("Число вне отрезка от 5 до 8");
Приоритет логических операторов
&& имеет более высокий приоритет, чем ||, подобно тому как умножение выполняется раньше сложения. Скобки могут изменить результат:
int a = 5, b = 6, c = 7, d = 8, e = 9, f = 10;
bool result1 = a == b && c > d || e <= f; // true
bool result2 = a == b && (c > d || e <= f); // false
bool result2b = (a == b) && ((c > d) || (e <= f)); // То же, что result2
Для result1 ложная левая часть объединяется через ИЛИ с истинным e <= f, поэтому результат — true. Для result2 первое сравнение a == b ложно, поэтому всё выражение с И даёт false.
Дополнительно: материалы на иврите
Эти материалы необязательны; основные объяснения и практика доступны на русском:
Следующие шаги
Практика 3.1: простые условия — задания и решения