De ce contează?
Imaginează-ți că primești borcane goale în care să torni apă. Un borcan mic ține o jumătate de litru; dacă torni un litru, dă pe-afară și pierzi restul. Un borcan mare ține zece litri. În C++, fiecare variabilă e un borcan: are o capacitate fixă, stabilită din clipa în care îi spui ce tip are. Dacă alegi borcanul prea mic pentru valoarea ta, numărul „dă pe-afară" — și calculatorul nu țipă, pur și simplu îți dă un rezultat greșit.
Ce este
Un tip de date îi spune calculatorului două lucruri despre o variabilă: ce fel de valori poate ține (numere întregi, numere cu virgulă, caractere) și câtă memorie rezervă pentru ea. Memoria se măsoară în octeți (bytes); fiecare octet are 8 biți, iar cu un număr fix de biți poți reprezenta doar un număr fix de valori distincte.
Asta e ideea centrală: capacitatea unei variabile NU e infinită. Un int ocupă de obicei 4 octeți = 32 de biți. Cu 32 de biți poți număra în jur de 4 miliarde de valori distincte, iar fiindcă jumătate sunt negative, intervalul lui int ajunge cam de la minus 2 miliarde la plus 2 miliarde.
Tipurile simple pe care le folosești zilnic:
- int — numere întregi obișnuite, până la aproximativ 2 miliarde
- long long — numere întregi mari, până la aproximativ 9 trilioane de miliarde
- char — un singur caracter (o literă, o cifră), păstrat de fapt ca un număr mic (codul lui)
- bool — adevărat sau fals (
true/false) - float / double — numere cu virgulă (zecimale);
doublee mai precis
„Cât de mare e un tip" nu e o curiozitate teoretică — e decizia care îți salvează sau îți distruge soluția la concurs. Întrebarea pe care ți-o pui MEREU înainte de a alege int: poate rezultatul (sau o sumă intermediară) să depășească 2 miliarde? Dacă da, ai nevoie de long long. Greșeala nu apare la valori mici de test — apare exact pe testul mare, ascuns, unde pierzi punctajul.
Cum arată
Iată borcanele puse cap la cap. Reține ordinele de mărime, nu cifrele exacte — la concurs îți trebuie reflexul „încape sau nu încape".
| Tip | Dimensiune | Interval aproximativ |
|---|---|---|
bool | 1 octet | doar sau (false / true) |
char | 1 octet | ... (sau codurile ... ) |
int | 4 octeți | aproximativ minus 2 miliarde ... plus 2 miliarde |
long long | 8 octeți | aproximativ minus 9 trilioane de miliarde ... plus 9 trilioane de miliarde |
float | 4 octeți | zecimale, ~7 cifre semnificative |
double | 8 octeți | zecimale, ~15 cifre semnificative |
Observă tiparul: cu fiecare octet în plus, capacitatea nu crește puțin — se dublează pentru fiecare bit adăugat. De aceea long long (8 octeți, 64 de biți) ține valori uriașe față de int (4 octeți, 32 de biți): are de două ori mai mulți biți. Practic, limita lui int e cam 2 miliarde (aproximativ 2*10^9), iar limita lui long long e cam 9 trilioane de miliarde (aproximativ 9*10^18).
Un detaliu care surprinde mulți începători: un char este, în interior, doar un număr mic. Litera 'A' este de fapt numărul 65 (codul ei ASCII), 'B' este 66, iar 'a' este 97. Litera și numărul sunt aceeași valoare, privită în două feluri.
Implementare C++
Programul declară fiecare tip, afișează câtă memorie ocupă (sizeof) și arată faptul că un char e și literă, și număr.
#include <iostream>
using namespace std;
int main() {
// Cate un borcan din fiecare fel:
bool gasit = true; // adevarat sau fals
char litera = 'A'; // un caracter; in interior e numarul 65
int varsta = 16; // intreg obisnuit
long long populatie = 8000000000LL; // 8 miliarde: NU incape in int
double medie = 9.75; // numar cu virgula
// sizeof spune cati OCTETI ocupa fiecare tip:
cout << "sizeof(bool) = " << sizeof(bool) << "\n"; // 1
cout << "sizeof(char) = " << sizeof(char) << "\n"; // 1
cout << "sizeof(int) = " << sizeof(int) << "\n"; // 4
cout << "sizeof(long long) = " << sizeof(long long) << "\n"; // 8
cout << "sizeof(double) = " << sizeof(double) << "\n"; // 8
// Acelasi char, privit in doua feluri:
cout << "litera ca simbol: " << litera << "\n"; // A
cout << "litera ca numar: " << (int)litera << "\n"; // 65
cout << gasit << " " << varsta << " " << populatie << " " << medie << "\n";
return 0;
}Reține (int)litera: e o conversie explicită care îi spune compilatorului „arată-mi caracterul ca pe numărul din spate". Tot așa, dacă scrii char c = 65; apoi afișezi c, vei vedea A. Asta îți permite trucuri utile: ca să afli a câta literă din alfabet e un caracter, scrii litera - 'A' (pentru 'A' dă 0, pentru 'C' dă 2).
De ce se sparge un int — overflow concret
Hai să vedem dezastrul în direct. Vrei să aduni numerele de la 1 la 2 miliarde. Suma reală e uriașă, mult peste limita lui int. Dacă ții suma într-un int, borcanul dă pe-afară.
#include <iostream>
using namespace std;
int main() {
int n = 2000000000; // 2 miliarde: INCA incape in int (limita ~2.1 mld)
int suma_int = n + n; // 4 miliarde: NU mai incape -> overflow!
cout << suma_int << "\n"; // afiseaza ceva ca -294967296 (valoare gresita!)
// Acelasi calcul, cu borcanul mare:
long long suma_ll = (long long)n + n;
cout << suma_ll << "\n"; // 4000000000, corect
return 0;
}Ce s-a întâmplat? n + n ar trebui să fie 4 miliarde, dar int se oprește pe la 2,1 miliarde. Când treci de limită, valoarea „se învârte" la capătul negativ — exact ca un kilometraj de mașină care, după 999999, sare la 000000. Rezultatul -294967296 nu e un mesaj de eroare: e un număr perfect valid, dar complet greșit. Programul rulează liniștit și îți strică răspunsul.
Soluția nu e să „speri" că datele sunt mici. E să-ți pui întrebarea ÎNAINTE: cât de mare poate ajunge rezultatul? Dacă poate trece de 2 miliarde, folosești long long.
Implementare C++ — alegerea corectă
#include <iostream>
using namespace std;
int main() {
long long n;
cin >> n;
// Suma 1 + 2 + ... + n poate fi URIASA: pentru n = 100000 deja
// depaseste 5 miliarde, mult peste limita lui int.
long long suma = n * (n + 1) / 2; // formula lui Gauss
cout << suma << "\n";
// Pentru n = 100000: suma = 5000050000, corect doar in long long.
return 0;
}Greșeala numărul unu la concurs: declari int suma = 0; și aduni multe numere. Fiecare valoare e mică, deci pe testele de probă (numere puține) totul merge — dar pe testul mare, suma trece de 2 miliarde, int-ul face overflow și răspunsul devine un număr negativ aiurea. Pierzi punctajul fără niciun mesaj de eroare.
A doua capcană, subtilă: chiar dacă rezultatul final încape în long long, calculul intermediar se poate sparge. În int a = 50000, b = 50000; long long p = a * b; înmulțirea a * b se face în int ÎNAINTE de a fi pusă în long long, deci dă overflow (2,5 miliarde nu încap). Corect: long long p = (long long)a * b; — forțezi calculul în long long de la primul operand.
Regula de aur: dacă o sumă, un produs sau un rezultat poate depăși aproximativ 2 miliarde, folosește long long peste tot pe lanțul de calcul, nu doar la final.