$ sudo teach IT
Модуль 2 · Примитивные операции

Урок 2.5 — Виды ошибок

Ошибки — это нормально. Научимся читать, понимать и исправлять их. Главный навык программиста.

Ошибки — это нормально. Даже опытные программисты с 20-летним стажем пишут код с ошибками. Разница между новичком и профессионалом не в том, что профессионал не делает ошибок, а в том, что он умеет их находить и исправлять. В этом уроке мы разберём три вида ошибок, с которыми ты столкнёшься, и научимся читать сообщения об ошибках — это навык, который сэкономит тебе сотни часов.

⚠️

Три вида ошибок в C#

Все ошибки в программировании делятся на три категории:

🔴
Ошибки компиляции (Compilation Errors) C# не может понять, что ты написал

Программа не скомпилируется. Код даже не запустится. Компилятор подсказывает, в чём проблема. Номер ошибки начинается с CS (C# Sharp). Пример: пропущенная точка с запятой, неверное имя переменной, лишняя скобка.

error CS1002: ; expected

🟡
Ошибки времени выполнения (Runtime Errors) Программа скомпилировалась, но упала во время работы

Код успешно скомпилировался и запустился, но в какой-то момент произошло исключение (exception). Пример: деление на ноль, обращение к несуществующему элементу массива, попытка открыть несуществующий файл. Программа «падает» с красным текстом ошибки.

System.DivideByZeroException: Attempted to divide by zero.

🔵
Логические ошибки (Logic Errors) Программа работает, но делает не то, что нужно

Самые коварные ошибки. Код скомпилировался, запустился, не упал — но выдаёт неправильный результат. Компьютер не знает, что ты хотел сделать. Он просто выполняет инструкции. Если ты написал a + b вместо a * b — программа честно сложит, а не умножит.

Программа работает, но выдаёт 8 вместо 15.

⚠️ Важно: Логические ошибки сложнее всего найти. Компилятор их не видит. Программа не падает. Только ты сам можешь заметить, что результат не совпадает с ожидаемым. Поэтому так важны тесты (мы будем писать их в модуле 12).

🔴

Ошибки компиляции (CS????)

Ошибки компиляции возникают, когда ты нарушаешь синтаксис языка. C# — строго типизированный язык с чётким синтаксисом. Компилятор проверяет код до запуска и сообщает о проблемах. Каждая ошибка имеет код вида CSXXXX.

Рассмотрим самые частые ошибки компиляции у новичков:

1. Пропущенная точка с запятой ;

В C# каждая инструкция должна заканчиваться ;

int x = 5   // ❌ забыли точку с запятой
Console.WriteLine(x);

CS1002: ; expected

2. Использование необъявленной переменной

Переменную нужно объявить до использования.

Console.WriteLine(z);   // ❌ z не объявлена

CS0103: The name 'z' does not exist in the current context

3. Несоответствие типов

C# не позволяет положить строку в int.

int number = "привет";   // ❌ string нельзя в int

CS0029: Cannot implicitly convert type 'string' to 'int'

4. Забыли фигурную скобку }

Фигурные скобки должны быть парными.

class Program
{
    static void Main()
    {
        Console.WriteLine("Привет");
    // ❌ забыли закрывающую скобку }

CS1513: } expected

5. Ключевое слово как имя переменной

Нельзя называть переменную int, class, if и т.д.

int int = 10;   // ❌ int — ключевое слово

CS1519: Invalid token '=' in class, struct, or interface member declaration

6. Пропущенный using System;

Console.WriteLine живёт в пространстве имён System.

class Program {
    static void Main() {
        Console.WriteLine("Привет");  // ❌ нужен using System;
    }
}

CS0103: The name 'Console' does not exist in the current context

💡 Как читать ошибку компиляции: В Visual Studio или Rider ошибка подчёркивается красной волнистой линией. В терминале (dotnet build) ты увидишь: Program.cs(5,13): error CS1002: ; expected. Это значит: файл Program.cs, строка 5, позиция 13. CS1002 — код ошибки. «; expected» — описание. Всегда начинай исправление с первой ошибки — часто она тянет за собой десятки других.

🟡

Ошибки времени выполнения (исключения)

Программа скомпилировалась, запустилась, но во время работы что-то пошло не так — возникает исключение (exception). Программа «падает» и выводит красный текст с информацией об ошибке. Это называется stack trace (трассировка стека).

Самые частые исключения у новичков:

➗
DivideByZeroException Деление на ноль
int a = 10;
int b = 0;
int result = a / b;   // ❌ DivideByZeroException!

System.DivideByZeroException: 'Attempted to divide by zero.'

💡 В C# деление целого числа на ноль вызывает исключение. Но деление double на ноль даёт Infinity, -Infinity или NaN.

📦
NullReferenceException Обращение к объекту, который равен null
string text = null;
int length = text.Length;   // ❌ NullReferenceException!

System.NullReferenceException: 'Object reference not set to an instance of an object.'

💡 Это самое частое исключение в C#. Всегда проверяй, не равен ли объект null, перед тем как вызвать его метод.

🔢
FormatException Неверный формат при преобразовании
string input = "abc";
int number = int.Parse(input);   // ❌ FormatException!

System.FormatException: 'Input string was not in a correct format.'

💡 Поэтому мы используем TryParse — он не выбрасывает исключение, а возвращает false.

📋
IndexOutOfRangeException Выход за границы массива
int[] numbers = { 10, 20, 30 };
Console.WriteLine(numbers[5]);   // ❌ IndexOutOfRangeException!

System.IndexOutOfRangeException: 'Index was outside the bounds of the array.'

💡 Массивы нумеруются с 0. Если в массиве 3 элемента, индексы 0, 1, 2. Индекс 5 — вне диапазона.

📁
FileNotFoundException Файл не найден
string text = File.ReadAllText("nofile.txt");   // ❌ FileNotFoundException

System.IO.FileNotFoundException: 'Could not find file...'

💡 Как читать stack trace: Красный текст ошибки содержит цепочку вызовов — от места, где исключение возникло, до места, где оно было поймано (или до Main, если не поймано). Читай снизу вверх: самая нижняя строчка — это место, где произошла ошибка. Строка содержит имя файла, номер строки и позицию.

🔵

Логические ошибки

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

Пример 1: Неправильная формула

Нужно вычислить среднее арифметическое двух чисел:

int a = 5;
int b = 7;
int average = a + b / 2;        // ❌ 5 + (7/2) = 5 + 3 = 8
int averageCorrect = (a + b) / 2;  // ✅ (5+7)/2 = 12/2 = 6

Console.WriteLine(average);        // 8 (неправильно!)
Console.WriteLine(averageCorrect); // 6

💡 Из-за приоритета операторов деление выполнилось раньше сложения. Скобки решают.

Пример 2: Путаница с = и ==

= — присваивание, == — сравнение. Перепутать легко.

int x = 5;
if (x = 10)     // ❌ присваивание! x становится 10, условие всегда true
    Console.WriteLine("x равен 10");

if (x == 10)    // ✅ сравнение
    Console.WriteLine("x равен 10");

💡 В C# компилятор предупредит о if (x = 10) — выдаст предупреждение CS1718. Но это не ошибка, код скомпилируется.

Пример 3: Границы циклов и массивов

«Ошибка на единицу» (off-by-one error) — классика.

int[] numbers = { 10, 20, 30, 40 };

// Хотели вывести все элементы:
for (int i = 0; i <= numbers.Length; i++)  // ❌ <= должно быть <
    Console.WriteLine(numbers[i]);          // IndexOutOfRangeException на i=4

// Правильно:
for (int i = 0; i < numbers.Length; i++)
    Console.WriteLine(numbers[i]);

Как искать логические ошибки?

  • Вывод промежуточных результатов. Вставь Console.WriteLine() в ключевых местах и смотри, что получается.
  • Debug (точка останова). В Visual Studio / Rider поставь точку останова (красная точка слева от строки) и смотри значения переменных в отладчике.
  • Тесты. Напиши маленькие тесты для каждой функции. Если функция должна возвращать 6 при входных данных 2 и 3 — проверь это.
  • Объясни код вслух. Буквально: сядь и расскажи коду (или игрушечной утке), что он делает. Очень часто ошибка находится в процессе объяснения.
🔍

Как читать сообщения об ошибках

Сообщения компилятора и исключения пугают новичков. Но на самом деле они — твой лучший друг. Они содержат всю информацию для исправления ошибки. Научись их читать.

Разбор ошибки компиляции

Program.cs(7,5): error CS1002: ; expected
Program.cs Файл, в котором ошибка
(7,5) Строка 7, позиция 5
error CS1002 Код ошибки (CS = C# Sharp)
; expected Описание: ожидалась точка с запятой

Разбор stack trace исключения

Unhandled exception. System.DivideByZeroException: Attempted to divide by zero.
at Program.Main() in /Users/user/Projects/App/Program.cs:line 8
System.DivideByZeroException Тип исключения
Attempted to divide by zero Описание: попытка деления на ноль
at Program.Main() ... line 8 Где произошла ошибка (метод, файл, строка)

💡 Золотое правило: Прочитай всю ошибку от начала до конца. Не паникуй. В 90% случаев ошибка говорит прямо, что не так. «; expected» — очевидно, нужна точка с запятой. «Type or namespace definition, or end-of-file expected» — скорее всего, забыл закрывающую скобку }. Научись видеть в ошибке подсказку, а не приговор.

🌐

Как гуглить ошибки

Умение искать решение в интернете — один из самых важных навыков программиста. Все ошибки, которые ты встретишь, уже кто-то встречал до тебя. Вот стратегия поиска:

1. Скопируй точный текст ошибки

Не пересказывай своими словами. Скопируй весь текст ошибки. В идеале — код ошибки (CS1002) или имя исключения (DivideByZeroException).

2. Используй правильные ключевые слова

Гугли: C# CS1002, C# NullReferenceException, C# int.Parse FormatException. Добавь dotnet или .NET для актуальных результатов.

3. Читай StackOverflow

StackOverflow — главный сайт для программистов. Чаще всего первый результат поиска — вопрос с SO. Читай ответы с зелёной галочкой (принятый ответ).

4. Читай официальную документацию Microsoft

Документация Microsoft (learn.microsoft.com) — лучший источник. Статьи на русском: learn.microsoft.com/ru-ru/dotnet/. Если знаешь английский — используй английскую версию, она всегда новее.

5. Используй ChatGPT/Copilot

Современные AI-помощники отлично справляются с поиском ошибок. Скопируй код и текст ошибки — AI объяснит причину и предложит исправление. Но не копируй слепо — сначала пойми, что было не так.

⚠️ Лайфхак: как задавать вопросы про код

Когда просишь помощи (у коллеги, на StackOverflow, у AI), всегда показывай:

  • Сам код (не скриншот, а текст)
  • Текст ошибки (полностью)
  • Что ты ожидал (входные данные → ожидаемый результат)
  • Что получил (входные данные → реальный результат)
  • Что уже попробовал (покажи, что ты не ленивый)
🧩

Большой пример — ошибки в реальной программе

Давай разберём программу, в которой намеренно допущены ошибки всех трёх типов. Попробуй найти их до того, как прочитаешь комментарии.

C# · Программа с ошибками
using System;

class Program
{
    static void Main()
    {
        // ОШИБКА КОМПИЛЯЦИИ #1: пропущена точка с запятой
        Console.WriteLine("Добро пожаловать в калькулятор!")
        //                                    ↑ ошибка CS1002

        Console.Write("Введите первое число: ");
        string input1 = Console.ReadLine();

        Console.Write("Введите второе число: ");
        string input2 = Console.ReadLine();

        // ОШИБКА КОМПИЛЯЦИИ #2: необъявленная переменная
        Console.WriteLine($"Вы ввели {num1} и {num2}");
        //                         ↑ ошибка CS0103

        // ОШИБКА ВРЕМЕНИ ВЫПОЛНЕНИЯ: если ввести не число
        int a = int.Parse(input1);
        int b = int.Parse(input2);
        // Если input1 = "abc" → FormatException!

        // ЛОГИЧЕСКАЯ ОШИБКА: неправильная формула
        int sum = a + b;
        int average = a + b / 2;
        //              ↑ деление выполнится раньше сложения!
        // Нужно: (a + b) / 2

        // ОШИБКА ВРЕМЕНИ ВЫПОЛНЕНИЯ: деление на ноль
        int ratio = a / b;
        // Если b = 0 → DivideByZeroException!

        Console.WriteLine($"Сумма: {sum}");
        Console.WriteLine($"Среднее: {average}");
        Console.WriteLine($"Отношение: {ratio}");
    }
}

Теперь та же программа, но исправленная:

C# · Исправленная версия
using System;

class Program
{
    static void Main()
    {
        Console.WriteLine("Добро пожаловать в калькулятор!");

        Console.Write("Введите первое число: ");
        string input1 = Console.ReadLine();

        Console.Write("Введите второе число: ");
        string input2 = Console.ReadLine();

        // Безопасное преобразование с TryParse
        if (int.TryParse(input1, out int a) && int.TryParse(input2, out int b))
        {
            int sum = a + b;
            int average = (a + b) / 2;  // скобки исправляют логическую ошибку

            Console.WriteLine($"Вы ввели {a} и {b}");
            Console.WriteLine($"Сумма: {sum}");
            Console.WriteLine($"Среднее: {average}");

            // Проверка деления на ноль
            if (b != 0)
            {
                int ratio = a / b;
                Console.WriteLine($"Отношение: {ratio}");
            }
            else
            {
                Console.WriteLine("Отношение: нельзя делить на ноль");
            }
        }
        else
        {
            Console.WriteLine("Ошибка: нужно ввести числа, а не текст!");
        }
    }
}
💡 Обрати внимание: в исправленной версии мы использовали TryParse (убирает FormatException), проверили деление на ноль (убирает DivideByZeroException), поставили скобки в формуле (убирает логическую ошибку) и не забыли точки с запятой. Все три типа ошибок обработаны.
📝

Практическое задание

Вот программа с 5 ошибками (всех трёх типов). Найди и исправь их:

using System

class Program
{
    static void Main()
    {
        Console.Write("Сколько вам лет? ");
        string input = Console.ReadLine()

        int age = int.Parse(input);

        if (input.Length > 2)
            Console.WriteLine("Вы выглядите молодо для своего возраста!")

        int months = age * 12;
        int decades = age / 10;
        int futureYear = 2050 - age;

        Console.WriteLine($"Вам {age} лет");
        Console.WriteLine($"Это {months} месяцев");
        Console.WriteLine($"Это {decades} десятилетий");
        Console.WriteLine($"В 2050 году вам будет {futureYear}");
    }
}
👀 Показать ответ
using System;  // ✔️ добавлена точка с запятой после using System

class Program
{
    static void Main()
    {
        Console.Write("Сколько вам лет? ");
        string input = Console.ReadLine(); // ✔️ точка с запятой

        // ✔️ Добавлена проверка TryParse (была логическая ошибка:
        //    если ввести "abc" — FormatException)
        if (!int.TryParse(input, out int age))
        {
            Console.WriteLine("Ошибка: введите число!");
            return;
        }

        // ✔️ Исправлено условие: input.Length > 2 работает, но лучше
        //    проверять сам возраст. Если age > 100 — тогда "выглядите молодо"
        if (age > 100)
            Console.WriteLine("Вы выглядите молодо для своего возраста!");

        int months = age * 12;
        int decades = age / 10;
        int futureYear = 2050 - age; // ✔️ ЛОГИЧЕСКАЯ ОШИБКА!
        // Было: 2050 - age. Если age=20, то futureYear=2030.
        // А должно быть: 2026 + (100 - age) — сколько лет до 100 + текущий год
        // Или просто: сколько лет будет в 2050 = 2050 - 2026 + age.

        Console.WriteLine($"Вам {age} лет");
        Console.WriteLine($"Это {months} месяцев");
        Console.WriteLine($"Это {decades} десятилетий");
        Console.WriteLine($"В 2050 году вам будет {2050 - 2026 + age}");
    }
}
📌

Что важно запомнить

1️⃣
Ошибки компиляции — нарушение синтаксиса. Код не запускается. Код ошибки CSXXXX. Исправляй первую ошибку — она часто вызывает остальные.
2️⃣
Ошибки времени выполнения (исключения) — программа падает во время работы. Читай stack trace: тип исключения, описание, место в коде (файл, строка).
3️⃣
Логические ошибки — код работает, но выдаёт не то. Самые опасные. Отладчик, Console.WriteLine и тесты — твои главные инструменты.
4️⃣
Как читать ошибку: Файл(строка,позиция): тип ошибки: описание. Никогда не игнорируй ошибки — они говорят тебе правду.
5️⃣
Гугли ошибки по коду (CSXXXX) или имени исключения. Читай StackOverflow и официальную документацию Microsoft.
6️⃣
Always validate input. TryParse, проверка на null, проверка на ноль. Защити программу от дурака.

Тест: 2.5: Виды ошибок

5 вопросов

Преобразование типов

Premium