1. Вступ
Коли людина тільки починає програмувати, вона часто мислить так: «мені ж просто треба зберігати значення — чому не можна зробити один універсальний тип number і не морочитися?». Це нормально: мозок економить енергію. Але C++ — мова, яка вимагає конкретики. Тип у C++ — це не «прикраса», а домовленість: скільки памʼяті потрібно, які значення допустимі, як працюють введення й виведення та які операції взагалі мають сенс.
Уявіть, що ви розкладаєте речі в різні коробки. Для печива — коробка з кришкою, для супу — каструля, для повітря —… ну, повітря не зберігають, воно просто зникає, як мотивація в пʼятницю ввечері. Типи — це різні «контейнери». І якщо ви спробуєте налити суп у коробку з-під печива, результат буде передбачувано сумним.
Сьогодні ми розберемо пʼять базових типів, які трапляються постійно:
- int — звичайні цілі числа зі знаком,
- long long — цілі числа більшого діапазону,
- unsigned — цілі числа без мінуса,
- double — дробовий тип,
- char — один символ.
Паралельно введемо дуже важливу ідею: діапазон значень (межі того, що тип може зберігати).
Розміри типів
На відміну від багатьох мов програмування, цілочисельні типи в C++ не мають фіксованого розміру. Це зроблено для того, щоб компілятор міг якнайкраще узгодити машинний код програми з платформою (ОС + процесор).
Одну й ту саму програму на C++ можна скомпілювати для 16-, 32- і 64-розрядних процесорів, під macOS, Windows, Linux тощо. І в усіх цих випадках цілочисельні типи даних можуть відрізнятися — так історично склалося.
Спочатку в C++ було три цілочисельні типи:
- int — цілочисельний тип
- short int (або short) — короткий цілочисельний тип (удвічі коротший за int)
- long int (або long) — довгий цілочисельний тип (удвічі довший за int)
Але згодом додали ще довший цілочисельний тип — long long int, або long long.
Зараз їхні «стандартні» розміри виглядають так:
| Тип | Windows x64 | macOS x64 |
|---|---|---|
|
2 байти | 2 байти |
|
4 байти | 4 байти |
|
4 байти | 8 байт |
|
8 байт | 8 байт |
Замість типу long краще використовувати long long — він гарантовано не менший за int.
Як обирати тип під задачу
Дуже хочеться обирати тип за принципом «який коротше записується» або «який я бачив у прикладах». Але в реальному коді тип — це частина сенсу. Якщо ви бачите в коді bool isAdmin, то майже без коментарів розумієте, що там лише два стани. Якщо бачите char grade, очікуєте літеру на кшталт 'A' або 'B'. А якщо все звести до int, вийде «звалище»: 0 може означати «ні», «помилка», «не знайдено», «перший елемент» або «ще нічого не вводили».
2. Цілочисельні типи: int, long long, unsigned
int: базова робоча «цеглина» для цілих чисел
int — це найуживаніший цілочисельний тип, із якого зазвичай починають. Коли ви рахуєте кількість задач, номер дня, лічильник у циклі, температуру в градусах (якщо без дробів) або баланс очок у грі, майже завжди вистачить int.
Важливо розуміти дві речі. По-перше, int зберігає цілі числа й уміє працювати з мінусом. По-друге, int не нескінченний: у нього є межі. Саме це підводить нас до поняття діапазону. Але про діапазони — трохи нижче. Поки що мислимо практично: int — це «нормальний вибір за замовчуванням» для цілих значень розумного розміру.
Невеликий фрагмент для нашого StudyBuddy:
#include <iostream>
int main() {
int tasksSolvedToday = 0;
std::cin >> tasksSolvedToday;
std::cout << tasksSolvedToday << '\n'; // наприклад: 7
}
Тут tasksSolvedToday — це «кількість», і за змістом вона ціла. Уже на цьому кроці тип допомагає: ви не зможете випадково записати туди «3.14» як дріб — компілятор цього не дозволить, і це добре.
long long: коли значення справді великі
Майже в кожному проєкті настає момент, коли звичайного int стає замало. Зазвичай це трапляється не одразу, а коли ви починаєте накопичувати значення: сумарну кількість секунд за рік, загальну кількість переглядів, загальний обсяг даних, підсумкові очки за сезон, кількість операцій у логах — тобто все, що може зрости значно більше, ніж «звичайна цифра на вході».
long long — це тип для великих цілих чисел. Він теж уміє працювати з мінусом, але головне — здатен зберігати значно більші значення, ніж int. Нам не потрібно зараз запамʼятовувати точні межі, але корисно засвоїти саму ідею: long long — для серйозних речей.
Додамо в StudyBuddy «накопичений підсумок задач» — нехай користувач введе, скільки задач він розвʼязав «за весь час», а програма порахує новий підсумок:
#include <iostream>
int main() {
long long totalTasksBefore = 0;
int tasksToday = 0;
std::cin >> totalTasksBefore >> tasksToday;
long long totalAfter = totalTasksBefore + tasksToday;
std::cout << totalAfter << '\n'; // наприклад: 1050
}
Зверніть увагу на важливу думку: вхідне значення «за день» може бути малим, але підсумок — великим. Це дуже поширена ситуація. І вона не про формули, а про коректний вибір типу.
unsigned: «без мінуса» як частина домовленості
Будь-який цілочисельний тип у C++ можна зробити беззнаковим, якщо додати перед ним ключове слово unsigned. Тип unsigned int (часто пишуть просто unsigned) означає: «ціле число без відʼємних значень». Тобто діапазон unsigned зміщується в бік більших додатних чисел, бо місце під мінус не потрібне.
Звучить ідеально для «кількостей»: кількості задач, кількості користувачів, кількості спроб. Але на практиці є важливий нюанс. У реальному коді мінус інколи потрібен не тому, що «в житті буває -5 задач», а як сигнал — наприклад, «помилка» або «не знайдено». Ми поки не будуємо такі складні контракти, тому правило просте: використовуйте unsigned лише тоді, коли ви впевнені, що відʼємні значення за змістом неможливі й мінус не знадобиться як спеціальний сигнал.
У StudyBuddy додамо «скільки днів поспіль я навчаюся» — це гарний кандидат на невідʼємне значення:
#include <iostream>
int main() {
unsigned streakDays = 0;
std::cin >> streakDays;
std::cout << streakDays << '\n'; // наприклад: 12
}
На цьому етапі достатньо запамʼятати: unsigned підкреслює «невідʼємність» на рівні типу. Але це не «магічний захист від усіх бід», а просто суворіша домовленість.
3. Типи для «дробів» і «символу»: double і char
double: коли числа бувають із дробовою частиною
Якщо int і long long — це про цілі значення, то double — про числа з дробовою частиною. Щойно в задачі зʼявляється щось на кшталт середнього значення, відсотка, коефіцієнта, температури з десятими частками або грошової суми з копійками, вам уже недостатньо цілого типу.
double зберігає дійсні числа, тобто числа з рухомою комою. Це означає, що він уміє представляти значення на кшталт 3.14, 0.5, -12.75. Але за цю гнучкість доводиться платити: усередині такі числа зберігаються не ідеально точно, а в двійковому представленні, яке може давати невеликі похибки.
Додамо в StudyBuddy середню продуктивність за тиждень:
#include <iostream>
int main() {
double averageTasksPerDay = 0.0;
std::cin >> averageTasksPerDay;
std::cout << averageTasksPerDay << '\n'; // наприклад: 5.75
}
Зверніть увагу на 0.0 — це підкреслює, що ми працюємо саме з дійсним числом.
Чому не можна просто взяти int і «ділити акуратно»? Бо під час ділення цілих чисел дробова частина відкидається. Наприклад, 7 / 2 у цілих дасть 3, а не 3.5. Якщо вам важлива точність результату для дробів, потрібен саме double.
Важливо також розуміти: double — не «нескінченно точний калькулятор». Наприклад, число 0.1 у двійковій системі не подається точно, тому операції на кшталт 0.1 + 0.2 можуть давати результат 0.30000000000000004. Це не «помилка компілятора», а особливість представлення чисел із рухомою комою.
Практичне правило для початківця:
- якщо ви рахуєте цілі кількості (штуки, дні, елементи) — використовуйте int або long long;
- якщо ви рахуєте середні значення, відсотки, коефіцієнти, дроби — використовуйте double.
Тип double — це домовленість: «тут можливі дробові значення». І, як і у випадку з іншими типами, він допомагає зробити код зрозумілішим уже на рівні оголошення змінної.
char: один символ і різниця між 'A' і "A"
char — це тип для зберігання одного символу. Він записується в одинарних лапках: 'A', '?', '7'. Це принципово відрізняється від рядка "A" (рядок — це текст, потенційно з багатьох символів; ми його вже знаємо як std::string).
Корисна звичка для початківця: коли бачите одинарні лапки, думайте «один символ». Коли подвійні — «рядок» або «текст».
У StudyBuddy ми попросимо користувача ввести «оцінку продуктивності» однією літерою, наприклад A, B, C:
#include <iostream>
int main() {
char grade = 'C';
std::cin >> grade;
std::cout << grade << '\n'; // наприклад: A
}
char добре підходить, коли дані справді «однолітерні»: код відповіді Y/N, оцінка A/B/C, команда q для виходу, роздільник, один символ категорії.
Усередині тип char просто зберігає код символу і, по суті, є цілочисельним типом. У C++ з ним можна виконувати математичні операції.
5. Діапазони значень
Тепер — найважливіша й трохи філософська частина сьогоднішньої лекції. Але ми подамо її максимально практично.
Компʼютер зберігає дані в памʼяті. Памʼять скінченна. Отже, і кількість різних значень, які можна записати в змінну, теж скінченна. Звідси випливає проста думка: у кожного цілочисельного типу є мінімальне та максимальне значення. Це і є діапазон.
У побуті це схоже на лічильник кілометражу в старих машинах: він не нескінченний. Коли цифри закінчуються, він «перевертається» (а інколи просто ламається). Із типами ідея приблизно та сама: якщо число виходить за межі, поведінка стає неправильною. Ми не будемо зараз розбирати тонкощі того, «як саме неправильно», — це окрема тема. Але вам важливо вже сьогодні звикнути до думки: тип обирають так, щоб значення точно вміщалися.
Щоб було зручніше орієнтуватися, ось практична таблиця «як це зазвичай виглядає на сучасних системах». Це не обіцянка, що «скрізь саме так», а радше здоровий орієнтир для мислення:
| Тип | Що зберігає | Приклад діапазону значень |
|---|---|---|
|
|
false / true (0 або 1) |
|
один символ | −128 … 127 |
|
цілі зі знаком | −2 147 483 648 … 2 147 483 647 |
|
цілі без знака | 0 … 4 294 967 295 |
|
великі цілі зі знаком | −9 223 372 036 854 775 808 … 9 223 372 036 854 775 807 |
|
дробові зі знаком | приблизно ±1.7 × 10308 (із ~15 знаками точності) |
Ідея, яку варто забрати з собою: якщо ви рахуєте «підсумок», «загальну кількість», «накопичену суму» або «кількість секунд за довгий період», то найчастіше це кандидат на long long. Якщо ви зберігаєте «прапорець» або «так/ні», то це bool. Якщо «одна літера» або «одна команда», то це char.
6. Розміри типів і sizeof
Ми вже говорили, що цілочисельні типи в C++ не мають суворо фіксованого розміру. Їхній розмір залежить від платформи та компілятора. Але як дізнатися реальний розмір типу на конкретній машині?
Для цього існує оператор sizeof. Він повертає розмір типу або змінної в байтах.
Найпростіший приклад:
#include <iostream>
int main() {
std::cout << sizeof(int) << '\n';
std::cout << sizeof(long long) << '\n';
std::cout << sizeof(double) << '\n';
std::cout << sizeof(char) << '\n';
}
Ви можете отримати, наприклад:
4
8
8
1
Це означає:
- int займає 4 байти
- long long — 8 байт
- double — 8 байт
- char — 1 байт
7. Типові помилки під час вибору базових типів
Помилка № 1: зберігати логічні стани в int і плодити «магічні числа».
Початківець часто пише int ok = 1;, int ok = 0;, а потім в іншому місці раптом додає if (ok == 2). Проблема тут не в тому, що компілятор не зрозуміє, а в тому, що людина перестає розуміти код. Якщо станів рівно два, bool повідомляє про це прямо на рівні типу й не дає вам «випадково» створити третій стан.
Помилка № 2: використовувати char як «короткий рядок».
Іноді хочеться зберігати текст "OK" або "Hi" у char, бо «ну це ж усього два символи». Але char — це рівно один символ. Якщо вам потрібен текст, навіть із двох літер, це вже рядок (std::string). Дуже корисно щоразу ловити себе на запитанні: «мені потрібен один знак чи текст?».
Помилка № 3: обирати unsigned «бо кількість же не буває відʼємною», а потім усе одно виявляється потрібен мінус.
Життя підступне: сьогодні ви зберігаєте «кількість задач», а завтра вам потрібен сигнал «не введено», «помилка», «не знайдено». І раптом мінус стає зручним. На початку краще не перетворювати unsigned на релігію: використовуйте його, коли впевнені, що відʼємні значення не потрібні ані за змістом, ані як службовий сигнал.
Помилка № 4: зберігати накопичені підсумки в int, бо «поки вистачає».
Це класична пастка. Поки тестові дані маленькі, усе добре. Потім ви робите підсумок «за рік», «за весь час», «для всіх користувачів», і число раптом перестає вміщатися. Саме тому для підсумків і сум часто заздалегідь беруть long long: це недорога страховка, яка економить години пошуку дивних помилок.
Помилка № 5: думати, що діапазони — це «якась теорія», і повністю їх ігнорувати.
Діапазони — це не академічна тема, а прямий наслідок того, що памʼять скінченна. Якщо тип не здатен зберігати потрібні значення, програма починає поводитися неправильно. Навіть якщо ви поки не вмієте «обчислювати межі в голові», достатньо звички ставити собі запитання: «а це число може стати дуже великим?» — і тоді обирати тип свідомо.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ