---
course: ОАиП
lecture: 2
title: "Лекция №2. Типы данных. Операции. Базовый ввод / вывод."
---

# Лекция №2. Типы данных. Операции. Базовый ввод / вывод.

## §2.1 Определение переменной и константы

**Переменная (variable)**

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

**Константа**

– это средство, позволяющее программисту определить элемент, которому не позволено изменяться.

**Литеральные константы (или просто «литералы»)**

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

Например:

text

```text
bool myNameIsAlex = true; // true – это логический литерал
int x = 5; // 5 – это целочисленный литерал
int y = 2 * 3; // 2 и 3 – это целочисленные литералы

// C++
cout << ‘a’; // a – символьный литерал

// C#
Console.WriteLine("hello"); // hello – это строковый литерал
```

Строковые литералы заключаются в двойные кавычки, а символьные литералы – в одинарные кавычки.

## §2.2 Объявление переменных для получения доступа и использования памяти

Если при написании программы разработчику необходимо сохранять промежуточный результат, то он использует **переменные**.

При программировании на таких языках, как С++ и С#, для хранения значений определяют **переменные**. Определение переменной очень просто и осуществляется по следующему шаблону:

text

```text
ТИП_ПЕРЕМЕННОЙ ИМЯ_ПЕРЕМЕННОЙ;
```

или

text

```text
ТИП_ПЕРЕМЕННОЙ ИМЯ_ПЕРЕМЕННОЙ = ИСХОДНОЕ_ЗНАЧЕНИЕ;
ТИП_ПЕРЕМЕННОЙ ИМЯ_ПЕРЕМЕННОЙ(ИСХОДНОЕ_ЗНАЧЕНИЕ);
```

**Атрибут «ТИП\_ПЕРЕМЕННОЙ»** указывает компилятору характер данных, который может хранить переменная, и компилятор резервирует для этого необходимое пространство.

**Атрибут «ИМЯ\_ПЕРЕМЕННОЙ»** является более осмысленной заменой для адреса области в памяти, где хранится значение переменной.

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

cpp

```cpp
#include <iostream>
using namespace std;
int main ()
{
   cout << "Умножение двух чисел:" << endl;
   cout << "Введите первое число: ";

   int First = 0;

   cin >> First;
   cout << "Введите второе число: ";

   int Second = 0;
   cin >> Second;
 
   // Умножение двух чисел, сохранение результата в переменной
   int MultiplicationResult = First * Second;

   // Отображение результата
   cout << First << " x " << Second;

   cout << " = " << MultiplicationResult << endl;

   return 0;
}
```

Результат выполнения программы:

text

```text
Умножение двух чисел: 12
Введите первое число: 5
Введите второе число: 2
5 x 2 = 10
```

**Имена переменных** важны для написания хорошего, понятного и удобного в сопровождении кода.

Имена же переменных задаются согласно следующим правилам:

- Имя переменной не может начинаться с цифры.
- В имени переменной не может быть пробелов, а также специальных символов (вроде ; № # % или /).
- Имя переменной не может совпадать с другими, ранее объявленными именами (функций, переменных и т.д.).

Именами переменных не могут быть также зарезервированные ключевые слова. Например, переменная по имени **return** приведет к ошибке при компиляции.

Если переменные имеют один и тот же тип и записаны в 2 и более строк, то их можно уплотнить до одной строки:

text

```text
int firstValue = 1, secondValue = 2, thirdValue = 3;
```

## §2.3 Область видимости переменной

**Область видимости (scope)**

— это часть программы, в пределах которой имя переменной (или *другой сущности*, например, *функции*) может быть использовано без дополнительных квалификаторов. Другими словами, это где переменная «видна» и доступна для использования.

Понимание области видимости критически важно для:

- Избежания ошибок доступа к несуществующим переменным.
- Предотвращения конфликтов имён.
- Управления временем жизни переменных.
- Написания чистого, модульного и безопасного кода.

В языках C# и C++ выделяют несколько ключевых типов областей видимости:

- **Глобальная** (*global scope*).
- **Локальная** (*local scope*).
- **Блочная** (*block scope*).
- **Пространства имён** (*namespace scope*).
- **Класса** (*class/struct scope*).

### §2.3.1 Глобальные переменные

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

В примере ниже была объявлена **глобальная переменная** *globalVar*, которая показывает доступность в программе.

Объявление глобальных переменных в C++:

cpp

```cpp
#include <iostream>
using namespace std;
 
int globalVar = 42; // Глобальная переменная
 
void func() {
    cout << globalVar << endl; // Доступна
}
 
int main() {
    cout << globalVar << endl; // Доступна
    func();
    return 0;
}
```

Объявление глобальных переменных в C#:

csharp

```csharp
using System;
 
class Program
{
    // Статическое поле класса (аналог глобальной)
    static int globalVar = 42; 
 
    static void Func()
    {
        Console.WriteLine(globalVar); // Доступно
    }
 
    static void Main()
    {
        Console.WriteLine(globalVar); // Доступно
        Func();
    }
}
```

Безосновательное использование **глобальных переменных** обычно считается плохой практикой программирования.

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

### §2.3.2 Локальные переменные

**Локальные переменные**

— это переменные, которые применимы в функции от места ее объявления до конца функции. Областью видимости таких переменных является блоки (и *все их дочерние*), а также их область видимости не распространяется на другие блоки.
Пример использования локальных переменных в C++:

cpp

```cpp
void func() {
    int localVar = 10; // Локальная переменная
    cout << localVar << endl; // ОК
}
 
int main() {
    // cout << localVar; // ОШИБКА: localVar не видна здесь!
    func();
    return 0;
}  
```

Пример использования локальных переменных в C#:

csharp

```csharp
static void Func()
{
    int localVar = 10; // Локальная переменная
    Console.WriteLine(localVar); // ОК
}
 
static void Main()
{
    // Console.WriteLine(localVar); 
    // ОШИБКА: не существует в этом контексте
    Func();
} 
```

## §2.4 l – values и r – values

При работе с переменными и присваиванием важно понимать, что можно ставить слева от знака =, а что — только справа. Для этого в программировании используют понятия **l-value** и **r-value**.

Эти термины происходят от английских слов:

- **l-value** – значение, которое может быть слева от «=».
- **r-value** – значение, которое может быть справа от =.

**l-value** называется именованная переменная, которая:

- Существует в памяти.
- Имеет своё имя.
- Может быть изменена.
- Может стоять слева от оператора присваивания.

Проще говоря: **l-value** — это переменная, которую ты создал и можешь использовать много раз.

Для примера **l-value** можно рассмотреть следующий код:

text

```text
int a = 5;
a = 10; // OK: a — l-value, его можно изменить
```

**r-value** называется временное значение, которое:

- Не имеет имени.
- Существует только на момент вычисления.
- Не может стоять слева от =.
- Используется только для чтения или передачи.

Для примера **r-value** можно рассмотреть следующий код:

text

```text
int a = 5;
int b = a + 3; // a + 3 — r-value (результат вычисления) 
```

Здесь **a + 3** даёт результат **8**, но этот **8** — временное значение. У него нет имени, и написать так нельзя:

tetxt

```tetxt
a + 3 = 10; // ОШИБКА! r-value слева — нельзя!
```

## §2.5 Типы данных

**Тип данных в программировании**

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

| Тип данных | C++ | Размер в байт | Диапазон / особенности | C# | Размер (б) | Особенности |
| --- | --- | --- | --- | --- | --- | --- |
| **Целое (32-бит)** | `int` | 4 | ±2.1e9 | `int` | 4 | — |
| **Короткое целое** | `short` | 2 | ±32 768 | `short` | 2 | — |
| **Длинное целое** | `long` | 4 / 8 | зависит от ОС | `long` | 8 | В C# всегда 8 байт |
| **Беззнаковое целое** | `unsigned int` | 4 | 0 до 4.3e9 | `uint` | 4 | — |
| **Длинное беззнаковое** | `unsigned long` | 4 / 8 | зависит от ОС | `ulong` | 8 | В C# всегда 8 байт |
| **Вещественное (одинар.)** | `float` | 4 | ±1.5e⁻⁴⁵ – ±3.4e³⁸ | `float` | 4 | — |
| **Вещественное (двойн.)** | `double` | 8 | ±5.0e⁻³²⁴ – ±1.7e³⁰⁸ | `double` | 8 | — |
| **Высокая точность** | — | — | — | `decimal` | 16 | ±1.0e⁻²⁸ – ±7.9e²⁸ |
| **Логический** | `bool` | 1 | true / false | `bool` | 1 | — |
| **Символ** | `char` | 1 | ASCII (0–255) | `char` | 2 | Unicode (UTF-16) |

### §2.5.1 Тип данных bool

**Тип bool** (от *Boolean* — по имени математика Джорджа Буля) предназначен для хранения логических значений, где **true** — истина, **false** — ложь.

Используется в условиях, циклах, логических выражениях и для управления ходом программы. В C# и в C++ объявляется аналогично:

text

```text
bool isActive = true;
bool isDone = false;
 
if (isActive) {
    // выполнится
}
```

При работе с типом **bool** в С# и С++, важно понимать, что тип **bool** в С++ гибче, но с риском ошибок, так как в С++ разрешены неявные преобразования между числами и **bool**.

cpp

```cpp
bool b1 = 0;      // false
bool b2 = 5;      // true (любое ненулевое — true)

int x = true;     // x = 1
int y = false;    // y = 0
```

Несмотря на то, что это удобно, это может привести к ошибкам:

cpp

```cpp
if (x = 5) 
{ 
    ... 
} // ОШИБКА? Нет — присваивание, но условие true!
```

С# же наоборот, запрещает неявное преобразование:

csharp

```csharp
int x = 5;

// bool b = x;        // ОШИБКА компиляции!

bool b = (x != 0);   // Правильно: явное сравнение
```

Это делает код безопаснее — невозможно случайно написать **if (x = 5)** вместо **if (x == 5)** — такая ошибка не скомпилируется.

В условиях тип данных **bool** работает в двух языках практически аналогично. В С++:

cpp

```cpp
int score = 85;

if (score) {              // эквивалентно: if (score != 0)
    cout << "Успех!";
}
```

а в C#:

csharp

```csharp
int score = 85;

// if (score) { ... }    // ОШИБКА! Нельзя использовать int как условие

if (score > 0) {          // Правильно
    Console.WriteLine("Успех!");
}
```

### §2.5.2 Тип данных char

**Тип char** (от *character* — символ) предназначен для хранения одного символа, например: 'A', '7', '@', ' ' (пробел). Типичное объявление показано ниже:

text

```text
char Userlnput = 'Y'; // инициализированный символ 'Y'
```

Компьютер не понимает букв — он работает с числами. Поэтому каждый символ имеет числовой код. Самая известная таблица соответствия — **ASCII** (*American Standard Code for Information Interchange*). В ней, например: 'A' → 65, 'B' → 66, '0' → 48, пробел ' ' → 32. Именно это позволяет использовать char как целое число — ведь по сути, символ и есть число-код.

Пример работы **ASCII** в C++:

cpp

```cpp
#include <iostream>
using namespace std;
 
int main() {
    char c = 'Z';
    cout << c << endl;        // Вывод: Z
    cout << (int)c << endl;// Вывод: 90 (код символа в ASCII)
    return 0;
}
```

В C# используется **Unicode (UTF-16)**, поэтому:

- Поддерживается кириллица, смайлики, иероглифы и другие символы.
- Каждый char — 2 байта, что позволяет хранить коды от 0 до 65 535 (основной диапазон).

csharp

```csharp
char c = 'Я';
Console.WriteLine(c);        // Вывод: Я
Console.WriteLine((int)c);   
// Вывод: 1071 (код символа в Юникоде)
```

### §2.5.3 Тип данных int

**Тип int** (сокращение от *integer* — целое число) — один из самых часто используемых типов данных. Он предназначен для хранения целых чисел (без дробной части), как положительных, так и отрицательных.

Используется в: счётчиках и индексах, арифметических вычислениях, условиях и циклах, хранении количества, возраста, размеров и т.д.

Объявляется он с С++ и в С# одинаково:

text

```text
int age = 25;
int count = 0;
int temperature = -10;
```

В C++ и C#, при работе с целочисленными типами данных, можно использовать приставки, которые позволяют изменять размер занимаемой памяти и диапазон значений. Эти приставки работают аналогично в обоих языках, хотя есть небольшие различия в их поведении и использовании:

- **short** (*уменьшение размера*) – приставка **short** укорачивает тип данных, к которому она применяется, путём уменьшения размера занимаемой памяти.
- **long** (*увеличение размера*) – приставка **long** удлиняет тип данных, к которому она применяется, путём увеличения размера занимаемой памяти.
- **unsigned** (*расширение диапазона положительных значений*) – проставка **unsigned** увеличивает диапазон положительных значений в два раза, при этом диапазон отрицательных значений в таком типе данных храниться не может. В С++ приставка пишется полностью (*unsigned int* и т.п.), а в С# сокращается до первой буквы (uint и т.п.).

### §2.5.4 Типы данных с плавающей точкой

**Типы данных с плавающей точкой** (*floating-point types*) предназначены для хранения вещественных чисел — то есть чисел с дробной частью.

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

В C++ и C# поддерживаются два основных типа с плавающей точкой: **float** и **double**. В C# также есть дополнительный тип — decimal, предназначенный для высокоточных вычислений.

Объявление переменных разных типов данных с плавающей точкой:

text

```text
float fValue;
double dValue;
decimal decValue;
```

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

text

```text
int n(5); // 5 - это целочисленный тип
double d(5.0); // 5.0 - это тип данных с плавающей точкой (по умолчанию double)
float f(5.0f); // 5.0 - это тип данных с плавающей точкой, "f" от "float"
```

Обратите внимание, литералы типа с плавающей точкой по умолчанию относятся к типу **double**. **f** в конце числа означает тип **float**.

### §2.5.5 Дополнительные типы данных

В C# вводятся также дополнительные типы данных, которые отсутствуют в C++.

| Тип данных | Описание данных | Пример |
| --- | --- | --- |
| `string` | Хранит набор символов | `string hello = "World";` |
| `object` | Может хранить значение любого типа | `object a = 22;` |

## §2.6 Определение размера переменной

Размер переменной зависит от её типа данных и платформы (разрядности системы: 32-бит или 64-бит). Оба языка — C++ и C# — предоставляют встроенные средства для определения размера переменной или типа.

В C++ для определения размера переменной или типа используется оператор **sizeof**. Он возвращает размер в байтах как значение типа **size\_t**.

Синтаксис операции:

cpp

```cpp
sizeof(переменная)
sizeof(тип)
```

Для примера можно расммотреть следующий код:

cpp

```cpp
#include <iostream>
using namespace std;
int main() {
    int x;

    cout << "Размер int: " << sizeof(x) << " байт" << endl;
    cout << "Размер double: " << sizeof(double) << " байт" << endl;
    cout << "Размер char: " << sizeof(char) << " байт" << endl;

    return 0;
}
```

Возможный вывод:

text

```text
Размер int: 4 байт
Размер double: 8 байт
Размер char: 1 байт
```

В C# определение размера типов работает иначе, чем в C++. Основные способы: **sizeof()** — для неуправляемых (unmanaged) типов.

Работает только **в небезопасном режиме** (*unsafe*) и только для простых типов (*int, char, double* и др.).

csharp

```csharp
unsafe
{
    Console.WriteLine("Размер int: " + sizeof(int) + " байт");
    Console.WriteLine("Размер double: " + sizeof(double) + " байт");
    Console.WriteLine("Размер char: " + sizeof(char) + " байт");
}
```

Возможный вывод:

text

```text
Размер int: 4 байт
Размер double: 8 байт
Размер char: 2 байт
```

### §2.7 Неявное определение типов

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

В C++ с использованием ключевого слова **auto** компилятор автоматически выводит тип переменной из значения, которым она инициализируется.

Синтаксис:

text

```text
auto имя_переменной = значение;
```

Например:

cpp

```cpp
auto x = 42;           // x имеет тип int
auto pi = 3.14;        // pi имеет тип double
auto name = "Hello";   // name имеет тип const char*
auto flag = true;      // flag имеет тип bool
```

В C# аналогичную роль выполняет ключевое слово **var**. Оно позволяет вывести тип переменной на этапе компиляции по правой части выражения.

Синтаксис:

text

```text
var имя_переменной = значение;
```

Например:

csharp

```csharp
var age = 25;                    // int
var price = 19.99;               // double
var name = "Alice";              // string
var isActive = true;             // bool
var numbers = new List<int>();   // List<int>
```

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

Если вы не инициализируете переменную, то применение ключевого слова **auto / var** приведет к ошибке при компиляции.

## §2.8 Константа

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

text

```text
const ИМЯ_ТИПА ИМЯ_КОНСТАТНЫ;
```

Пример использования константы:

text

```text
const double PI = 3.14159;
const int DAYS_IN_WEEK = 7;
 
// PI = 3.14;  // ОШИБКА! Нельзя изменить константу
```

Если попытаться убрать комментарий с 4-й строчки, то произойдет ошибка при компиляции примерно с таким сообщением: **«You cannot assign to a variable that is const (Вы не можете присвоить значение переменной, которая является константой)»**.

## §2.9 Арифметические операторы

Арифметические операции производятся над числами. Значения, которые участвуют в операции, называются операндами.

Арифметические операции бывают **бинарными** (*производятся над двумя операндами*) и **унарными** (*выполняются над одним операндом*).

К бинарным операциям относят следующие операции, которые представлены в таблице ниже:

Краткая шпаргалка

`+` — сложение  
`-` — вычитание  
`*` — умножение  
`/` — деление  
`%` — остаток от деления

Оператор деления имеет два режима. Если оба операнда являются целыми числами, то оператор выполняет целочисленное деление (*7 / 4 = 1*), если один или оба операнда – вещественные, то выполнится деление типа с плавающей точкой (*7.0 / 4 = 1,75*).

Также есть две **унарные арифметические операции**, которые производятся над одним числом: «++» (*инкремент* – увеличение на единицу) и «--» (*декремент* – уменьшение на единицу). Каждая из операций имеет две разновидности: префиксная и постфиксная.

## §2.10 Операторы сравнения и присваивания

Существует пять операций присваивания, не считая основную операцию присваивания =:

- += — операция присваивания-сложения (a += 5).
- -= — операция присваивания-вычитания (a -= 5).
- \*= — операция присваивания-умножения (a \*= 5).
- /= — операция присваивания-деления (a /= 5).
- %= — операция присваивания-остатка от деления (a %= 5).

Для примера:

csharp

```csharp
var a = 5;
a += 5;

Console.WriteLine(a); // Выведет 10  
```

Данное сокращение аналогично математическому выражению **5 + 5**. Со всеми остальными знаками работа происходит аналогично, если, например, взять -=, то это аналогично **5 – 5**, поэтому в **3** строчке выведется значение 0.

В арсенале языков программирования С# и C++ существует 6 различных **операторов сравнения**. Так же они могут быть выступать в виде комбинации друг с другом. Так как эти операторы вам знакомы с курса математики, изучение их не должно вызвать проблему.

| Оператор | Символ | Пример | Операция |
| --- | --- | --- | --- |
| **Больше** | `>` | `x > y` | **true**, если x больше y, и **false**, если x меньше y |
| **Меньше** | `<` | `x < y` | **true**, если x меньше y, и **false**, если x больше y |
| **Больше или равно** | `>=` | `x >= y` | **true**, если x больше или равно y, и **false**, если x меньше или равно y |
| **Меньше или равно** | `<=` | `x <= y` | **true**, если x меньше или равно y, и **false**, если x больше или равно y |
| **Равно** | `==` | `x == y` | **true**, если x равно y, и **false**, если x не равно y |
| **Не равно** | `!=` | `x != y` | **true**, если x не равно y, и **false**, если x равно y |

Каждый из этих операторов возвращает логическое значение **true** (*1, истина*) или **false** (*0, ложь*).

## §2.11 Логические операторы

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

В такой ситуации помогают логические операции.

Существует три логические операции:

- Логическая операция **И** — &&.
- Логическая операция **ИЛИ** — ||.
- Логическая операция **НЕ** (*логическое отрицание*) — !.

Логические операции образуют сложное (составное) условие из нескольких простых (двух или более) условий.

csharp

```csharp
using System;
 
class LogicalOperatorsDemo
{
    static void Main()
    {
        bool a = true;
        bool b = false;
 
        Console.WriteLine("Значения:");
        Console.WriteLine($"a = {a}");
        Console.WriteLine($"b = {b}");
        Console.WriteLine();
 
        // --- Логическое И (&&) ---
        // true, только если ОБА значения true
        Console.WriteLine($"a && b = {a && b}");  // false
        Console.WriteLine($"a && true = {a && true}");// true
 
        // --- Логическое ИЛИ (||) ---
        // true, если ХОТЯ БЫ ОДНО значение true
        Console.WriteLine($"a || b = {a || b}");  // true
        Console.WriteLine($"b || b = {b || b}");  // false
 
        // --- Логическое НЕ (!) ---
        // Инвертирует значение
        Console.WriteLine($"!a = {!a}");  // false
        Console.WriteLine($"!b = {!b}");  // true
    }
}
```

## §2.12 Приоритет операций

**Приоритет операций**

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

Чем выше приоритет, тем раньше операция выполняется.

Если операции имеют одинаковый приоритет, порядок определяется ассоциативностью:

- Слева направо: *a - b - c → (a - b) – c*.
- Справа налево: *a = b = c → a = (b = c)*.

| Приоритет | Операция | Описание | Ассоциативность |
| --- | --- | --- | --- |
| **1 (высший)** | `( )` | Скобки | — |
| **2** | `!`, `+`, `-` | Логическое НЕ, унарный плюс / минус | Справа налево |
| **3** | `*`, `/`, `%` | Умножение, деление, остаток | Слева направо |
| **4** | `+`, `-` | Сложение, вычитание | Слева направо |

## §2.13 Определение типа переменной

В процессе разработки иногда необходимо узнать, какого типа на самом деле является переменная, особенно при работе с шаблонами, обобщениями, наследованием или отладкой. Это называется **определением типа переменной**.

C++ предоставляет оператор **typeid** из библиотеки **typeinfo**, который возвращает информацию о типе во время выполнения:

cpp

```cpp
#include <iostream>
#include <typeinfo>
 
int main() {
    int x = 42;
    double d = 3.14;
 
    // "i" или "int"
    std::cout << "Тип x: " << typeid(x).name() << std::endl;   

    // "d" или "double"
    std::cout << "Тип d: " << typeid(d).name() << std::endl;     
}
```

В C# каждый объект наследуется от **Object**, который имеет метод **GetType()**, возвращающий информацию о типе в реальном времени.

csharp

```csharp
1. object obj = "Hello";
2. Console.WriteLine(obj.GetType());  // Вывод: System.String
```

## §2.14 Неявное преобразование типов

**Неявное преобразование типов**

— это автоматическое приведение одного типа данных к другому, без участия программиста и без использования специальных операторов, например, *(int)* в C# и **static\_cast** в С++.

Есть 2 основных способа неявного преобразования типов:

- Числовое расширение.
- Числовая конверсия.

**1. Числовое расширение**

**Числовое расширение**

— это преобразование значения из одного типа данных в другой тип данных большего размера и диапазона значений.

Пример:

```csharp
byte b = 10;
int x = b;  // OK! byte → int (маленькое → большое)
```

**2. Числовая конверсия**

**Числовая конверсия**

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

Например:

```csharp
double d = 3.14;
int x = (int)d;  // Результат: 3 → дробная часть потеряна!
```

## §2.15 Явное преобразование типов

**Явное преобразование (explicit conversion)**

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

**Неявное преобразование** работает только в безопасных случаях (например, *int → double*). Но если:

- Может быть потеря точности (*double → int*),
- Переполнение (*long → int*),
- Несовместимость типов (*string → int*),

тогда нужно явное преобразование — чтобы показать: *«Я осознаю риски»*.

В языке C++ есть 5 видов операций явного преобразования типов:

- Конвертация **C-style**.
- Применение оператора **static\_cast**.
- Применение оператора **const\_cast**.
- Применение оператора **dynamic\_cast**.
- Применение оператора **reinterpret\_cast**.

Подробнее рассмотрим первые два варианта явного преобразования типов.

**1. Конвертация C-style**

В программировании на языке С++ явное преобразование типов данных выполняется с помощью оператора **()**.

Внутри круглых скобок мы пишем тип, в который нужно конвертировать. Этот способ конвертации типов называется конвертацией C-style. Например:

cpp

```cpp
int i1 = 11;
int i2 = 3; 
float x = (float)i1 / i2;
```

**2. Оператор static\_cast**

Оператор **static\_cast** лучше всего использовать для конвертации одного фундаментального типа данных в другой:

cpp

```cpp
int i1 = 11;
int i2 = 3;
float x = static_cast<float>(i1) / i2;
```

Основным преимуществом оператора **static\_cast** является проверка его выполнения компилятором во время компиляции, что усложняет возможность возникновения непреднамеренных проблем.

В C# явное преобразование делается в основном с помощью синтаксиса в скобках, но есть и вспомогательные средства.

**1. Приведение в скобках — основной способ**

csharp

```csharp
double d = 3.14;
int x = (int)d; 
// Результат: 3 (дробная часть отбрасывается)
```

**2. Методы преобразования из Convert**

csharp

```csharp
string s = "123";
int n = Convert.ToInt32(s);  
// Преобразует строку в число
 
double val = 3.9;
int rounded = Convert.ToInt32(val); 
// Округляет до ближайшего целого: 4
```

**3. Методы .Parse() и .TryParse()**

csharp

```csharp
string s = "42";

// Прямое преобразование (если ошибка — исключение)
int num = int.Parse(s);  
 
bool success = int.TryParse(s, out int result);

if (success) {
    Console.WriteLine(result);
}
```

## §2.16 Математические функции

В C# все основные математические функции находятся в статическом классе **System.Math**. Чтобы их использовать, не нужно создавать объект — достаточно писать **Math.ИмяМетода()**.

В таблице представлены распространенные методы класса **System.Math**.

| Метод | Пример | Назначение |
| --- | --- | --- |
| `Math.Sqrt(x)` | `Math.Sqrt(16) -> 4` | Квадратный корень |
| `Math.Pow(x, y)` | `Math.Pow(2, 3) -> 8` | Возведение в степень |
| `Math.Abs(x)` | `Math.Abs(-5) -> 5` | Модуль числа |
| `Math.Round(x)` | `Math.Round(3.7) -> 4` | Округление до целого |
| `Math.Min(a, b)` | `Math.Min(3, 7) -> 3` | Минимум из двух |
| `Math.Max(a, b)` | `Math.Max(3, 7) -> 7` | Максимум из двух |
| `Math.Ceiling(x)` | `Math.Ceiling(3.1) -> 4` | Округление вверх |
| `Math.Floor(x)` | `Math.Floor(3.9) -> 3` | Округление вниз |
| `Math.Sin(x)` | `Math.Sin(Math.PI / 2) -> 1` | Синус угла (в радианах) |
| `Math.Log(x)` | `Math.Log(10) ~ 2.3` | Натуральный логарифм |

Пример использования:

csharp

```csharp
using System;
class MathDemo
{
    static void Main()
    {
        double x = 25;
        double root = Math.Sqrt(x);         // 5
        double power = Math.Pow(x, 0.5);    // тоже 5
        double round = Math.Round(4.6);     // 5
 
        Console.WriteLine($"Корень из {x} = {root}");
        Console.WriteLine($"Округление 4.6 = {round}");
    }
}
```

В C++ математические функции находятся в заголовочном файле **<cmath>** (ранее — **<math.h>**).

После подключения можно использовать функции напрямую (в глобальной области, если использовать **using namespace std;**).

| Функция | Пример | Назначение |
| --- | --- | --- |
| `sqrt(x)` | `sqrt(16) -> 4` | Квадратный корень |
| `pow(x, y)` | `pow(2, 3) -> 8` | Возведение в степень |
| `abs(x)` | `abs(-5) -> 5` | Модуль (для целых) |
| `fabs(x)` | `fabs(-3.5) -> 3.5` | Модуль для float / double |
| `round(x)` | `round(3.7) -> 4` | Округление до целого |
| `floor(x)` | `floor(3.9) -> 3` | Округление вниз |
| `ceil(x)` | `ceil(3.1) -> 4` | Округление вверх |
| `min(a, b)` | `min(3, 7) -> 3` | Минимум из двух |
| `max(a, b)` | `max(3, 7)` | Максимум из двух |

Пример использования:

cpp

```cpp
#include <iostream>
#include <cmath>
using namespace std;

int main() {
    double x = 25;
    double root = sqrt(x);              // 5
    double power = pow(x, 0.5);         // 5
    double rounded = round(4.6);        // 5

    cout << "Корень из " << x << " = " << root << endl;
    cout << "Округление 4.6 = " << rounded << endl;

    return 0;
}
```
