C# में चर और डेटा प्रकार
Переменные и типы данных в C#: полное руководство с примерами
Представь, что ты пишешь кулинарный рецепт. Тебе нужно где-то записать: «100 граммов муки», «2 яйца», «название блюда — Пирог». Переменные в программировании — это точно такие же «ячейки памяти» для хранения данных. Давай разберёмся, как они работают в C#.
Что такое переменная и зачем она нужна
Переменная — это именованная область памяти компьютера, в которой хранится какое-то значение. Представь компьютерную память как огромный склад с ящиками. Каждый ящик имеет:
- Номер (адрес памяти) — компьютер работает с этим
- Название (имя переменной) — программист работает с этим
- Содержимое (значение) — данные, которые хранятся
- Тип ящика (тип данных) — какие данные можно хранить
Без переменных программы были бы практически бесполезны — они не смогли бы запоминать и обрабатывать данные.
Основные типы данных в C#
C# — строго типизированный язык. Это значит, что каждая переменная должна иметь чётко определённый тип данных. Давай познакомимся с основными:
Целые числа: int и другие
Для хранения целых чисел (без дробной части) используется тип int. Это как ящик, в котором можно хранить только целые числа от -2 147 483 648 до 2 147 483 647.
int age = 15; // Возраст
int temperature = -5; // Температура (может быть отрицательной)
int score = 1500; // Очки в игре
int population = 144000000; // Население страны
Console.WriteLine($"Возраст: {age}");
Console.WriteLine($"Температура: {temperature}°C");
// Математические операции с int
int a = 10;
int b = 3;
Console.WriteLine(a + b); // 13
Console.WriteLine(a - b); // 7
Console.WriteLine(a * b); // 30
Console.WriteLine(a / b); // 3 (ЦЕЛОЧИСЛЕННОЕ деление!)
Console.WriteLine(a % b); // 1 (остаток от деления)
Важно! При делении двух целых чисел результат тоже будет целым. 10 / 3 = 3 (не 3.33). Если нужна дробная часть — читай про double ниже.
Есть и другие типы для целых чисел:
byte smallNumber = 255; // 0 до 255 (1 байт)
short mediumNumber = 32000; // -32768 до 32767 (2 байта)
int regularNumber = 1000000; // ~±2 млрд (4 байта)
long bigNumber = 9000000000L; // ~±9 квинтиллионов (8 байт), суффикс L
// Беззнаковые (только положительные)
uint positiveOnly = 4000000000U; // суффикс U
ulong veryBig = 18000000000000000000UL;
Числа с дробной частью: double и float
double height = 1.75; // Рост в метрах
double pi = 3.14159265358979; // Число Пи
double temperature = 36.6; // Температура тела
float lessAccurate = 3.14f; // float требует суффикс f, менее точный
// Пример вычислений
double radius = 5.0;
double area = pi * radius * radius;
Console.WriteLine($"Площадь круга: {area:F2}"); // :F2 — два знака после запятой
// Результат: Площадь круга: 78.54
double vs float: double хранит 15-17 значимых цифр, float — только 7. Используй double по умолчанию, float только когда критична скорость или память.
Тип decimal: точные деньги
Если ты работаешь с деньгами или финансами — всегда используй decimal. Вот почему:
// ПРОБЛЕМА с double при работе с деньгами:
double moneyDouble = 0.1 + 0.2;
Console.WriteLine(moneyDouble); // 0.30000000000000004 — ОШИБКА!
// РЕШЕНИЕ — decimal точен:
decimal moneyDecimal = 0.1m + 0.2m; // суффикс m обязателен
Console.WriteLine(moneyDecimal); // 0.3 — точно!
// Финансовые расчёты
decimal price = 1299.99m;
decimal discount = 0.15m; // 15% скидка
decimal finalPrice = price * (1 - discount);
Console.WriteLine($"Цена со скидкой: {finalPrice:C}"); // :C — формат валюты
Правило: Деньги → decimal. Физика/математика → double. Остальное → int.
Булев тип: bool
Тип bool хранит только два значения: true (истина) или false (ложь). Это как выключатель — или включён, или выключен.
bool isRaining = false;
bool hasHomework = true;
bool isAdult = false;
// Логические операции
bool bothTrue = true && true; // true (И: оба должны быть true)
bool eitherTrue = false || true; // true (ИЛИ: хотя бы один true)
bool notTrue = !true; // false (НЕ: инверсия)
// Часто используется для условий
int playerHealth = 50;
bool isAlive = playerHealth > 0; // true
bool isDead = playerHealth <= 0; // false
Console.WriteLine($"Игрок жив: {isAlive}");
Символьный тип: char
Тип char хранит один символ. Обрати внимание: одинарные кавычки!
char grade = 'A'; // Оценка
char initial = 'Д'; // Инициал (поддерживает Unicode)
char digit = '5'; // Цифра как символ (не число!)
char space = ' '; // Пробел
char newLine = '\n'; // Перевод строки (специальный символ)
Console.WriteLine(grade); // A
// char можно сравнивать
char letter = 'c';
bool isUpperCase = char.IsUpper(letter); // false
bool isLetter = char.IsLetter(letter); // true
char upper = char.ToUpper(letter); // 'C'
Строки: string
Тип string хранит текст — последовательность символов. Двойные кавычки!
string name = "Александр";
string greeting = "Привет, мир!";
string empty = ""; // Пустая строка
string nullString = null; // Нет значения вообще
// Операции со строками
string firstName = "Иван";
string lastName = "Петров";
string fullName = firstName + " " + lastName; // Конкатенация
Console.WriteLine(fullName); // Иван Петров
// Методы строк
Console.WriteLine(name.Length); // 9 — длина строки
Console.WriteLine(name.ToUpper()); // АЛЕКСАНДР
Console.WriteLine(name.ToLower()); // александр
Console.WriteLine(name.Contains("кс")); // True
Console.WriteLine(name.Replace("Але", "Все")); // Всександр
// Проверка пустоты
bool isEmpty = string.IsNullOrEmpty(nullString); // true
bool isWhitespace = string.IsNullOrWhiteSpace(" "); // true
Ключевое слово var: когда тип угадывает компилятор
В C# есть умная функция: если ты инициализируешь переменную сразу при объявлении, компилятор может сам угадать тип. Для этого используется ключевое слово var.
// Явное указание типа (традиционно)
int count = 42;
string message = "Hello";
double price = 9.99;
// Неявная типизация с var (современный стиль)
var count2 = 42; // компилятор видит 42 → int
var message2 = "Hello"; // компилятор видит строку → string
var price2 = 9.99; // компилятор видит 9.99 → double
// var НЕ делает переменную динамической!
var number = 10;
// number = "текст"; // ОШИБКА! number - это int, уже нельзя менять тип
// Полезно для длинных типов
var list = new List(); // вместо List list = new List();
var dict = new Dictionary(); // удобно!
Когда использовать var? Когда тип очевиден из правой части выражения. Когда тип длинный и неудобный. Когда тип — результат LINQ-запроса.
Константы: const и readonly
Иногда нужна переменная, значение которой нельзя изменить — константа.
// const — значение известно при компиляции, нельзя изменить
const double Pi = 3.14159265358979;
const int MaxPlayers = 100;
const string AppName = "МояИгра";
// Попытка изменить константу вызовет ошибку компиляции:
// Pi = 3.14; // Ошибка! Cannot assign to 'Pi' because it is a constant
// readonly — значение задаётся при инициализации или в конструкторе
readonly DateTime startTime = DateTime.Now;
// startTime = DateTime.Now; // Ошибка после инициализации!
Разница: const вычисляется при компиляции, readonly — при запуске программы. Используй const для математических констант и настроек. readonly — для значений, которые могут зависеть от условий запуска.
Nullable типы: когда значения может не быть
Обычный int всегда хранит какое-то число. Но что если число не задано? Например, возраст пользователя в форме — он мог не указать его. Для таких случаев есть nullable типы.
// Обычный int — не может быть null
int regularAge = 25;
// regularAge = null; // ОШИБКА! int не может быть null
// Nullable int — может быть null (не задан)
int? nullableAge = null; // Возраст не указан
int? confirmedAge = 25; // Возраст указан
// Проверка на null
if (nullableAge == null)
{
Console.WriteLine("Возраст не указан");
}
if (confirmedAge.HasValue)
{
Console.WriteLine($"Возраст: {confirmedAge.Value}");
}
// Оператор ?? (null-coalescing) — значение по умолчанию
int displayAge = nullableAge ?? 0; // Если null — используем 0
Console.WriteLine($"Показываем: {displayAge}"); // 0
// Nullable для других типов
double? weight = null;
bool? isVerified = null;
string? nullableString = null; // В C# 8+ строки тоже можно пометить ?
Зачем нужны nullable? В базах данных поля могут быть NULL. В формах пользователь может не заполнить поле. Nullable типы позволяют корректно работать с «отсутствием значения».
Преобразование типов
Иногда нужно преобразовать одно значение в другой тип. В C# это делается несколькими способами:
Неявное преобразование (автоматическое)
// Из меньшего типа в больший — автоматически
int smallNumber = 42;
long bigNumber = smallNumber; // int → long (безопасно, места больше)
float f = smallNumber; // int → float (автоматически)
double d = smallNumber; // int → double (автоматически)
Console.WriteLine(bigNumber); // 42
Явное преобразование (casting)
// Из большего типа в меньший — нужно явное преобразование
double pi = 3.14159;
int intPi = (int)pi; // Явное преобразование — дробная часть ОТБРАСЫВАЕТСЯ
Console.WriteLine(intPi); // 3 (не 3.14!)
long bigNum = 100000L;
int smallNum = (int)bigNum; // Может потерять данные если bigNum > int.MaxValue
// ОПАСНО: переполнение
int maxInt = int.MaxValue; // 2 147 483 647
int overflow = maxInt + 1; // -2 147 483 648 — переполнение!
Преобразование строк в числа
// Строка → число
string ageText = "25";
int age = int.Parse(ageText); // Кидает исключение если строка не число
int age2 = Convert.ToInt32(ageText); // Аналогично
// Безопасный способ с TryParse
string userInput = "abc";
bool success = int.TryParse(userInput, out int result);
if (success)
{
Console.WriteLine($"Число: {result}");
}
else
{
Console.WriteLine("Это не число!");
}
// Число → строка
int number = 42;
string text = number.ToString(); // "42"
string formatted = number.ToString("D5"); // "00042" — 5 цифр с нулями
string hex = number.ToString("X"); // "2A" — шестнадцатеричное
Имена переменных: как называть правильно
// ПРАВИЛЬНЫЕ имена (camelCase для локальных переменных)
int playerHealth = 100;
string userName = "Alex";
double distanceInKilometers = 42.5;
bool isGameOver = false;
// НЕПРАВИЛЬНЫЕ имена (компилятор не примет)
// int 1number = 5; // Нельзя начинать с цифры
// int my-var = 5; // Дефис запрещён
// int class = 5; // class — зарезервированное слово
// Зарезервированные слова нельзя использовать как имена:
// int, string, bool, if, else, for, while, class, return, void...
// Соглашения именования в C#:
int localVariable = 5; // camelCase для локальных
const int MAX_SIZE = 100; // UPPER_CASE для констант (или PascalCase)
string _privateField = "val"; // _camelCase для приватных полей класса
Типичные ошибки с переменными
Ошибка 1: Использование переменной до инициализации
int x;
// Console.WriteLine(x); // ОШИБКА! Use of unassigned local variable 'x'
int y = 0; // Инициализируем нулём
Console.WriteLine(y); // 0 — OK
Ошибка 2: Деление на ноль
int a = 10;
int b = 0;
// int result = a / b; // DivideByZeroException — исключение при выполнении!
// Проверяй перед делением:
if (b != 0)
{
int result = a / b;
Console.WriteLine(result);
}
Ошибка 3: Переполнение int
int big = 2_000_000_000; // Нижние черты можно использовать для читаемости
int bigger = big + big; // Переполнение! Результат отрицательный
// Решение: использовать long
long safeBig = (long)big + big; // Явно преобразуем в long перед сложением
Итого
Что ты узнал в этом уроке:
- ✅ int — целые числа (возраст, счёт, количество)
- ✅ double — числа с дробной частью (рост, вес, координаты)
- ✅ decimal — точные дробные числа (деньги, финансы)
- ✅ bool — истина или ложь (true/false)
- ✅ char — один символ в одинарных кавычках
- ✅ string — текст в двойных кавычках
- ✅ var — компилятор сам определяет тип
- ✅ const — константа, нельзя изменить
- ✅ int? — nullable тип, может быть null (значение отсутствует)
- ✅ Преобразование типов: неявное (автомат), явное (casting), Parse/TryParse
Практический мини-проект: форма регистрации
// Симуляция формы регистрации пользователя
Console.WriteLine("=== Регистрация пользователя ===\n");
// Имя пользователя
string? userName = null;
while (string.IsNullOrWhiteSpace(userName))
{
Console.Write("Имя пользователя (3-20 символов): ");
userName = Console.ReadLine()?.Trim();
if (userName?.Length < 3 || userName?.Length > 20)
{
Console.WriteLine("Имя должно быть от 3 до 20 символов!");
userName = null;
}
}
// Возраст
int? age = null;
while (age is null)
{
Console.Write("Ваш возраст: ");
if (int.TryParse(Console.ReadLine(), out int parsedAge) && parsedAge >= 13 && parsedAge <= 120)
age = parsedAge;
else
Console.WriteLine("Введите корректный возраст (13-120)!");
}
// Email (простая проверка)
string? email = null;
while (email is null)
{
Console.Write("Email адрес: ");
string? input = Console.ReadLine()?.Trim().ToLower();
if (input?.Contains('@') == true && input.Contains('.'))
email = input;
else
Console.WriteLine("Введите корректный email!");
}
// Вывод результата
Console.WriteLine("\n=== Данные зарегистрированы ===");
Console.WriteLine($"Логин: {userName}");
Console.WriteLine($"Возраст: {age} лет");
Console.WriteLine($"Email: {email}");
Console.WriteLine($"Совершеннолетний: {(age >= 18 ? "Да" : "Нет")}");
Console.WriteLine($"Дата регистрации: {DateTime.Now:dd.MM.yyyy HH:mm}");
Таблица всех числовых типов C#
Для удобства — полная таблица числовых типов:
// Тип | Размер | Диапазон | Использование
// --------|--------|-----------------------------|-----------------------
// sbyte | 1 байт | -128 до 127 | Маленькие числа со знаком
// byte | 1 байт | 0 до 255 | Байты, цвета (R,G,B)
// short | 2 байт | -32,768 до 32,767 | Координаты, высоты
// ushort | 2 байт | 0 до 65,535 | Порты (0-65535)
// int | 4 байт | -2,147,483,648 до +2млрд | ОСНОВНОЙ — всё остальное
// uint | 4 байт | 0 до 4,294,967,295 | Счётчики без отрицат.
// long | 8 байт | ~-9.2×10^18 до +9.2×10^18 | Большие числа
// ulong | 8 байт | 0 до ~1.8×10^19 | Очень большие положит.
// float | 4 байт | ~±1.5×10^-45 до ±3.4×10^38 | Игровая графика
// double | 8 байт | ~±5.0×10^-324 до ±1.8×10^308| Научные расчёты
// decimal | 16 байт| ±7.9×10^-28 до ±7.9×10^28 | ДЕНЬГИ и финансы
// bool | 1 байт | true / false | Логика, флаги
// char | 2 байт | U+0000 до U+FFFF | Один Unicode символ
// string | Разный | Текст произвольной длины | Строки
Арифметика с разными типами
// Правила арифметики в C#
// int op int = int (даже результат дроби = целое!)
int a = 7, b = 2;
Console.WriteLine(a / b); // 3, не 3.5!
Console.WriteLine(a % b); // 1 (остаток)
// int op double = double (повышение типа)
int c = 5;
double d = 2.0;
Console.WriteLine(c / d); // 2.5 (c автоматически конвертируется в double)
// Явное преобразование для дробного деления int/int
Console.WriteLine((double)a / b); // 3.5
Console.WriteLine(a / (double)b); // 3.5
// Математические функции (System.Math)
Console.WriteLine(Math.Abs(-42)); // 42 — абсолютное значение
Console.WriteLine(Math.Sqrt(16)); // 4 — квадратный корень
Console.WriteLine(Math.Pow(2, 10)); // 1024 — степень
Console.WriteLine(Math.Round(3.7)); // 4 — округление
Console.WriteLine(Math.Floor(3.9)); // 3 — округление вниз
Console.WriteLine(Math.Ceiling(3.1)); // 4 — округление вверх
Console.WriteLine(Math.Max(5, 10)); // 10 — максимум
Console.WriteLine(Math.Min(5, 10)); // 5 — минимум
Console.WriteLine(Math.Log(Math.E)); // 1 — натуральный логарифм