Fiecare variabilă din C++ are un tip, iar tipul decide trei lucruri: ce valori poate reține variabila, câtă memorie ocupă și cum se comportă în calcule. La BAC informatică nu ți se cere să știi pe de rost numărul de octeți al fiecărui tip, dar trebuie să alegi corect între int și long long, să știi când o împărțire dă rezultat real și cum se comportă char în expresii.
Tipurile întregi: int și long long
Pe compilatoarele folosite în mod obișnuit (GCC, Code::Blocks, Visual Studio), valorile sunt:
| Tip | Memorie | Interval aproximativ |
|---|---|---|
int | 4 octeți | de la -2 147 483 648 la 2 147 483 647 (cam ±2·109) |
unsigned int | 4 octeți | de la 0 la 4 294 967 295 |
long long | 8 octeți | cam ±9,2·1018 |
short | 2 octeți | de la -32 768 la 32 767 |
Regula practică pentru citirea enunțului: un număr cu cel mult 9 cifre încape sigur în int, pentru că 999 999 999 este mai mic decât 2 147 483 647. Un număr cu 10 cifre s-ar putea să nu încapă, iar unul cu cel mult 18 cifre cere long long.
Atenție și la rezultatele calculelor, nu doar la datele de intrare. Dacă citești până la un milion de numere de cel mult 9 cifre și le aduni, suma poate ajunge la aproximativ 1015, deci variabila sumă trebuie să fie long long, chiar dacă fiecare număr încape în int.
Depășirea (overflow): greșeala care nu dă eroare
Când un calcul cu int depășește intervalul, programul nu se oprește și nu afișează niciun mesaj: pur și simplu obții o valoare greșită, de cele mai multe ori negativă. Exemplul clasic este factorialul: 12! = 479 001 600 încape în int, dar 13! = 6 227 020 800 nu mai încape. În long long încape până la 20! = 2 432 902 008 176 640 000; 21! depășește și acest tip.
O capcană mai subtilă:
int x = 100000;
long long p = x * x; // GREȘIT: x * x se calculează în int și depășește
long long q = 1LL * x * x; // CORECT: 1LL * x este long long, deci produsul la fel
Tipul variabilei din stânga nu contează pentru calculul din dreapta. Expresia x * x se evaluează cu tipul operanzilor (ambii int), iar abia rezultatul deja stricat se copiază în p. De aceea, ori declari x direct long long, ori forțezi conversia ca în a doua linie.
Tipurile reale: double și float
double ocupă 8 octeți și reține aproximativ 15–16 cifre semnificative; float ocupă 4 octeți și are doar în jur de 7 cifre semnificative. La BAC folosește double ori de câte ori ai nevoie de zecimale (medii, rapoarte, rădăcini).
Numerele reale sunt reținute aproximativ. De aceea 0.1 + 0.2 == 0.3 are valoarea false în C++. Când compari valori reale rezultate din calcule, evită ==; dacă poți, lucrează cu întregi. De exemplu, în loc să verifici sqrt(n) == (int)sqrt(n) pentru pătrat perfect, calculează r = sqrt(n) ca întreg și verifică r * r == n.
Tipul char: un caracter este, de fapt, un număr
O variabilă char ocupă un octet și reține codul ASCII al unui caracter. Câteva coduri utile: '0' are codul 48, 'A' are 65, 'a' are 97, spațiul are 32. Literele mari și cele mici sunt la distanță de 32: 'a' - 'A' == 32.
Pentru că un char este un număr, poți face calcule cu el:
c - '0'transformă caracterul-cifră'7'în valoarea numerică 7c - 'a' + 'A'transformă o literă mică în literă mare (la fel cac - 32)c >= 'a' && c <= 'z'verifică dacăceste literă micăchar d = 'a' + 2;pune îndcaracterul'c'
Diferența dintre afișări contează la grile: cout << 'a' + 1; afișează 98, pentru că rezultatul expresiei este de tip int, pe când cout << (char)('a' + 1); afișează b.
Tipul bool
bool are doar două valori: true și false. La afișare cu cout apar ca 1 și 0. Orice valoare numerică nenulă convertită la bool devine true, iar 0 devine false. Asta explică de ce if (n % 2) este echivalent cu if (n % 2 != 0).
Tipul bool este potrivit pentru funcțiile care răspund cu „da” sau „nu”, de exemplu bool prim(int n), și pentru vectorii de marcaje (ciurul lui Eratostene, vectori de apariții), unde ocupă un singur octet pe element.
Conversiile automate pe care le face compilatorul
Când într-o expresie apar tipuri diferite, compilatorul convertește operanzii la tipul „mai larg”, după câteva reguli simple:
charșiboolsunt promovate laintîn calcule:'A' + 1esteintintcombinat culong longdălong long- orice întreg combinat cu
doubledădouble:5 / 2.0 = 2.5 - la atribuirea unui real într-un întreg, zecimalele se pierd prin trunchiere:
int a = 3.99;pune 3 îna, iarint b = -3.99;pune -3
Iată un program scurt pe care îl poți rula ca să vezi toate aceste efecte:
#include <iostream>
using namespace std;
int main()
{
int a = 7, b = 2;
double r = 3.99;
char c = 'a';
cout << a / b << "\n"; // 3
cout << a / 2.0 << "\n"; // 3.5
cout << (int)r << "\n"; // 3
cout << c + 1 << "\n"; // 98
cout << (char)(c + 1) << "\n"; // b
cout << (5 > 3) << "\n"; // 1
long long f = 1;
for (int i = 1; i <= 20; i++)
f = f * i;
cout << f << "\n"; // 2432902008176640000
return 0;
}
long long pus din prudență nu costă puncte; o depășire, da.Cum alegi tipul, pe scurt
- Numere naturale sau întregi de cel mult 9 cifre:
int. - Sume mari, produse, factoriale, numere de 10–18 cifre:
long long. - Medii, rapoarte, rezultate cu zecimale:
double. - Caractere și prelucrări de text:
char(și tablouri decharpentru șiruri). - Rezultate de tip da/nu și marcaje:
bool.
De reținut
- ●
intține până la aproximativ 2,1·109; orice număr cu cel mult 9 cifre încape. - ●
long longține până la aproximativ 9,2·1018; folosește-l pentru sume, produse și factoriale. - ● Depășirea nu dă eroare: produce valori greșite.
x * xse calculează în tipul luix. - ●
chareste un cod ASCII:'0'= 48,'A'= 65,'a'= 97. - ● Un real atribuit unui întreg pierde zecimalele; o valoare nenulă convertită la
booldevinetrue.