Дополнение к главе 1. Переменные и поиск ошибок


Объявление, обмен значений и таблицы трассировки

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

Объявление и присваивание

Важно различать объявление переменной (declaration) и присваивание ей значения (assignment).

Правильный пример:

1
2
int x;      // Объявление
x = 10;     // Присваивание

Частая ошибка:

1
2
int y;
y = y + 1; // Ошибка: у локальной переменной y ещё нет начального значения

Во второй программе возникнет ошибка Use of unassigned local variable 'y' — «Использование локальной переменной y, которой не присвоено значение». Чтобы вычислить y + 1, нужно сначала прочитать прежнее значение y, а программа его ещё не задала.

Исправьте пример, присвоив y начальное значение:

int y = 0;
y = y + 1;
Console.WriteLine(y); // 1

Visual Studio отмечает ошибки, которые мешают компиляции — переводу программы в исполняемый вид. Откройте список ошибок и прочитайте сообщение вместе с номером строки. Не ограничивайтесь красным подчёркиванием: текст сообщения подсказывает причину.

Сообщение Visual Studio об использовании переменной без присвоенного значения

Дополнительное видео на иврите: как читать ошибки Visual Studio

Видео показывает, как использовать сообщения Visual Studio для исправления ошибок компиляции. Просмотр необязателен; основной приём описан выше.

Обмен значений двух переменных

Представьте две чашки: в чашке A зелёный чай, а в чашке B — чёрный. Как поменять их содержимое, не смешивая чай?

Понадобится третья, пустая чашка temp:

  1. Перелейте содержимое A в temp.
  2. Перелейте содержимое B в освободившуюся A.
  3. Перелейте содержимое temp в освободившуюся B.

При обмене значений в программе такую же роль играет временная переменная. Она сохраняет значение, которое иначе было бы потеряно после присваивания.

Прочитайте два целых числа в переменные a и b, поменяйте значения местами и выведите результат. Сначала попробуйте самостоятельно.

Решение с временной переменной

Этот фрагмент заменяет метод Main внутри класса Program из предыдущей главы.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static void Main()
{
    Console.WriteLine("Введите первое число:");
    int a = int.Parse(Console.ReadLine());

    Console.WriteLine("Введите второе число:");
    int b = int.Parse(Console.ReadLine());

    Console.WriteLine($"До обмена: a = {a}, b = {b}");

    int temp = a;  // Сохраняем исходное значение a
    a = b;         // Копируем значение b в a
    b = temp;      // Копируем исходное значение a в b

    Console.WriteLine($"После обмена: a = {a}, b = {b}");
}

Например, для a = 5 и b = 3 после обмена получится a = 3 и b = 5.

Запись $"До обмена: a = {a}, b = {b}" использует интерполяцию строк. Знак $ перед кавычками позволяет помещать выражения в фигурные скобки: вместо {a} в строку подставится значение a. Это ещё один способ объединить текст и значения без нескольких знаков +.

Сравните обе формы:

Console.WriteLine("a = " + a + ", b = " + b);
Console.WriteLine($"a = {a}, b = {b}");

В упражнениях 1.2 есть похожая задача. Посмотрите, как понятные имена переменных помогают прочитать алгоритм.

Почему следующий код не выполняет обмен?

a = b;
b = a;
Проверить объяснение

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

Что такое таблица трассировки

Таблица трассировки показывает, как меняются значения переменных при выполнении команд. Она помогает предсказать результат, найти ошибку и понять назначение алгоритма.

Проследите за такой программой. Номера в левом столбце таблицы соответствуют номерам строк в примере:

1
2
3
4
5
6
7
8
9
10
11
static void Main(string[] args)
{
    int a = 5;       // Начальное значение a
    int b = 3;       // Начальное значение b

    a = a + b;
    b = a - b;
    a = a - b;

    Console.WriteLine($"a = {a}, b = {b}");
}
Строка a b
3 5
4 3
6 8
7 5
8 3

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

Итоговый вывод:

a = 3, b = 5

Как сформулировать назначение алгоритма

После трассировки ответьте: какую задачу решает программа? Перечисление команд («сначала складывает, потом вычитает…») ещё не объясняет общий результат.

Назначение программы

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

Обозначим исходные значения буквами A и B:

  1. После a = a + b; в a находится A + B.
  2. После b = a - b; в b находится (A + B) − B, то есть A.
  3. После a = a - b; в a находится (A + B) − A, то есть B.

Для обычных программ способ с temp понятнее и не требует сложения. При сложении больших чисел можно выйти за диапазон int; поведение тогда зависит от режима проверки переполнения. В этом примере используются небольшие значения.

Попробуйте выполнить трассировку для a = 9, b = 2, а затем для двух равных чисел. Предскажите вывод до запуска.

Дополнительно: поиск на сайте и оформление кода в документе

Для поиска материала используйте ключевые слова, например Console.ReadLine, char или название темы. Видео ниже — на иврите, просмотр необязателен.

Если вы храните решения в Google Docs, оставляйте отступы и используйте моноширинный шрифт, чтобы структура кода была видна. Дополнение Code Blocks может помочь с оформлением, но для выполнения программы оно не требуется: запускайте код в среде C#.

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

Содержание курса