Operatori și expresii în C++
Pentru a opera cu variabile și constante, vom folosi operatori. În funcție de numărul operanzilor, un operator poate fi unar, binar sau ternar. O expresie este o înșiruire de variabile, constante și operatori. Majoritatea expresiilor pot fi evaluate de compilator, returnând o valoare.
Operatorul de atribuire
Operatorul de atribuire (=
) are rolul de a atribui o valoare unei variabile. De exemplu, după execuția instrucțiunii de mai jos, variabila x
va avea valoarea 618
. Întotdeauna operația de atribuire se desfășoară de la dreapta la stânga.
x = 618;
Operandul din dreapta poate fi de asemenea o variabilă, de exemplu:
a = b;
În cazul acesta, variabila a
primește valoarea variabilei b
. Așadar, nicio modificare ulterioară a lui b
nu va afecta valoarea lui a
.
int a = 1;int b = 2;
a = b;// Acum a are valoarea 2, iar b tot 2.
Operatorul de atribuire returnează valoarea atribuită primului operand.
b = 1 + (a = 9); // b devine 10.// Întâi a primește valoarea 9, iar apoi// lui b i se atribuie valoarea (1 + 9).
De aceea, putem atribui mai multor variabile aceeași valoare în modul următor:
variabila1 = variabila2 = ... = variabilaN = valoare;
Operatorul de atribuire se mai numește operator de asignare. A nu se confunda cu operatorul ==
, care testează egalitatea dintre operanzi!
Operatori aritmetici
Operatorii aritmetici efectuează operații matematice asupra operanzilor:
Operator | Descriere | Efect |
---|---|---|
+ | adunare | Returnează suma operanzilor. |
- | scădere | Returnează diferența dintre operanzi. Primul este descăzutul, iar al doilea scăzătorul. |
* | înmulțire | Returnează produsul dintre operanzi. |
/ | împărțire | Returnează rezultatul împărțirii primului operand la al doilea. Dacă ambii sunt întregi, se va efectua împărțirea întreagă (se returnează câtul), altfel cea reală. |
% | modulo | Returnează restul împărțirii primului operand la al doilea. Ambii operanzi trebuie să fie întregi. |
Cum în matematică împărțirea la 0
nu are sens (nici măcar dacă deîmpărțitul este 0
), x / 0
și x % 0
vor genera o eroare.
La fel ca în matematică, în evaluarea unei expresii se ține cont de ordinea efectuării operațiilor. La finalul articolului veți găsi o listă completă cu ordinea evaluării operatorilor din C++.
1 + 2 * 3 % 4 - 5 / 6 // Se evaluează la 3.
Tot ca în matematică, putem folosi paranteze rotunde ca să delimităm o parte din expresie pentru a-i crește prioritatea, sau doar pentru a o evidenția. În C++ nu putem folosi decât paranteze rotunde. Exemplu:
((1 + 2) * 3) - 4 // Corect, se evaluează la 5.(1 + 2) * (3 + 4 // Greșit, a doua paranteză nu a fost închisă.
Operatori relaționali
Operatorii relaționali sunt folosiți pentru a testa o relație dintre valorile a două expresii. În C++, operatorii relaționali sunt:
Operator | Descriere |
---|---|
== | egal |
!= | diferit |
< | mai mic |
> | mai mare |
<= | mai mic sau egal |
>= | mai mare sau egal |
Acești operatori returnează o valoare booleană. Exemple:
1 == 2 // false1 < 3 // true2 != 2 // false3 >= 3 // true
Testul de egalitate pentru numere reale
Cum numerele reale sunt stocate folosind virgulă mobilă, de la un anumit punct se pierde precizia. Adică, teste de genul 0.000001 == 0
vor fi evaluate uneori drept true
.
De aceea, dacă trebuie să testăm egalitatea dintre două numere reale, e bine să implementăm o funcție de genul:
inline bool equals(double a, double b) { double dif = a - b; double abs = dif < 0 ? -dif : dif; // modulul diferenței
// Dacă diferența dintre cele două numere este suficient // de mică, vom considera că sunt egale. return abs < 0.000001;}
Operatori logici
În C++ există 3 operatori logici: !
(NOT, negație), &&
(AND, conjuncție) și ||
(OR, disjuncție). În evaluarea expresiilor ce conțin acești operatori, operanzii sunt reduși mai întâi la o valoare booleană, adică pentru o valoare nenulă se va folosi true
, iar pentru una nulă, false
. De ce spun o valoare nulă, și nu 0
direct? Nu pentru toate tipurile de date valoarea nulă este 0
; de exemplu, pentru pointeri este nullptr
.
Operatorul !
returnează valoarea booleană opusă celei la care se evaluează operandul. Exemple:
!(2 != 2) // true!(3 == 3) // false!false // true!true // false!x // true dacă x este nul, false dacă x este nenul
Operatorul &&
returnează true
dacă ambii operanzi sunt true
, altfel false
.
a | b | a && b |
---|---|---|
true | true | true |
true | false | false |
false | true | false |
false | false | false |
Exemple:
618 && 819 // true123 && 0 // false1 == 1 && 6 < 4 // falsefalse && false // falsex && x % 10 == 0 // true dacă x are ultima cifră 0 și e nenul
Operatorul ||
returnează true
dacă cel puțin unul dintre operanzi este true
, altfel false
.
a | b | a || b |
---|---|---|
true | true | true |
true | false | true |
false | true | true |
false | false | false |
Exemple:
true || false // true2 < 1 || 1 == 2 // falsefalse || 2 < 1 && 3 == 3 // false
// true dacă x reprezintă un an bisect:x % 400 == 0 || x % 100 && x % 4 == 0
Când vrem să testăm dacă trei variabile de același tip sunt egale, folosim operatorul &&
:
a == b == c // Nu va produce efectul dorit.// Se evaluează întâi a == b, obținându-se true sau false.// Dacă se obține true, se va evalua 1 == c, altfel 0 == c.a == b && b == c // Asta, în schimb, este ceea ce ne dorim.
Pentru a reține și mai ușor valorile returnate de cei doi operatori, putem asimila conjuncția cu înmulțirea dintre 0
și 1
, iar disjuncția cu adunarea dintre 0
și 1
, unde 0
este false
și 1
este true
.
Evaluarea expresiilor ce conțin &&
și ||
este foarte eficientă în C++. Într-o conjuncție, dacă operandul stâng este false
, cel drept este ignorat, deoarece indiferent de valoarea lui, rezultatul va fi false
. Similar, dacă într-o disjuncție operandul stâng este true
, celălalt este ignorat și se returnează direct valoarea true
.
Legile lui De Morgan
De Morgan a enunțat două legi logice foarte simple despre negarea unei propoziții compuse, sau a unei expresii în cazul nostru:
!(a && b) == !a || !b!(a || b) == !a && !b
Acestea pot fi demonstrate dând valori binare lui a
și b
(sunt doar 4 combinații).
Operatorul ternar condițional ?:
Sintaxa unei expresii ce conține acest operator este:
expresie ? expresie1 : expresie2
Se evaluează expresie
, și dacă aceasta este adevărată, se returnează expresie1
, iar dacă nu, expresie2
. Exemplu:
int maxim, a, b;cin >> a >> b;maxim = a > b ? a : b;
Operatori pe biți
Acești operatori lucrează la nivelul biților din reprezentarea întregilor. Operațiile pe biți sunt folosite pentru optimizarea multor algoritmi. Am abordat subiectul pe larg în acest articol.
Operator | Descriere |
---|---|
& | AND |
| | OR |
^ | XOR |
~ | NOT |
<< | SHIFT LEFT (SHL) |
>> | SHIFT RIGHT (SHR) |
Operatori compuși de atribuire
Operatorii compuși de atribuire (+=
, -=
, *=
, /=
, %=
, >>=
, <<=
, &=
, ^=
, |=
) ne ajută să scriem mai puțin cod, dar și optimizează operațiile efectuate asupra variabilelor. Exemple:
x += y; // x = x + y;x /= y; // x = x / y;x -= a + b // x = x - (a + b);
De ce acești operatori sunt eficienți? De exemplu, în x = x + y
, întâi se calculează x + y
, iar apoi se atribuie această valoare lui x
, pe când în x += y
, adunarea se efectuează direct pe x
.
Operatorii de incrementare și decrementare
Incrementarea reprezintă adunarea lui 1
unui număr, iar decrementarea, scăderea lui 1
din acesta. De multe ori avem nevoie de efectuarea uneia dintre aceste operații înainte sau după altă operație, și de aceea acești operatori pot fi folosiți atât sub formă de prefix, cât și de sufix.
În expresia x = ++a
, întâi a
se incrementează, iar apoi lui x
i se atribuie valoarea lui a
. În schimb, în expresia x = a++
, întâi x
primește valoarea lui a
, iar apoi a
se incrementează. Similar pentru operatorul de decrementare (--
). Exemple:
x = 618;y = ++x;// Acum x == 619 și y == 619.
x = 618;y = x++;// Acum x == 619 și y == 618.
Dacă vrem să incrementăm variabila a
, putem folosi la fel de bine oricare dintre cele 4 instrucțiuni de mai jos, mai ales că de ceva timp compilatoarele sunt atât de inteligente încât înlocuiesc bucăți de cod cu cele mai eficiente variante ale lor din punct de vedere semantic (dar asta nu înseamnă că optimizează și complexitatea algoritmilor).
++a;a++;a += 1;a = a + 1;
Operatorul de casting (conversie a tipului)
Operatorul de casting convertește o valoare de un anumit tip în altul. Acest operator se pune înaintea expresiei respective și are sintaxa (tip)
. Exemple:
double a = 1.618;int b = (int) a; // Acum b == 1.
Dintr-un tip real într-unul întreg, conversia se face prin trunchiere, nu prin rotunjire. Deci atât 1.99
, cât și 1.01
, convertite la int
, vor deveni 1
.
În C++, cast-ul se mai poate efectua folosind notația funcțională tip(expresie)
.
int x = int(3.14);
Operatorul sizeof()
Am întâlnit deja acest operator în Variabile și tipuri de date în C++. Operatorul sizeof()
poate lua ca parametru un tip sau o variabilă, și returnează mărimea în bytes a acestuia. Rezultatul este determinat întotdeauna înaintea execuției programului.
int x = sizeof(bool); // x primește valoarea 1.
Operatorul virgulă
Operatorul virgulă este folosit pentru a separa mai multe expresii, concatenându-le. Operatorul va returna valoarea celei mai din dreapta expresii.
a = (b = 3, ++b); // Acum a == 4 și b == 4.
De obicei, acest operator este folosit când vrem să scriem o singură instrucțiune care să facă mai multe operații, într-o structură for
de exemplu.
Ordinea evaluării operatorilor
Mai există niște operatori în limbajul C++, dar despre aceștia voi discuta în articolele următoare. Iată lista completă a operatorilor C++, de la cei cu cea mai mare prioritate în jos:
Grup | Operator | Descriere | Evaluare |
---|---|---|---|
Rezoluție | :: | rezoluție | stânga-dreapta |
Operatori sufix | ++ -- | sufix de incrementare/ decrementare | stânga-dreapta |
() | apel de funcție | ||
[] | subscript | ||
. -> | acces către membru | ||
Operatori prefix | ++ -- | prefix de incrementare/ decrementare | dreapta-stânga |
~ ! | NOT pe biți, NOT logic | ||
+ - | prefix unar (semnul unui număr) | ||
& * | referențiere, dereferențiere | ||
new delete | alocare/ dealocare de memorie | ||
sizeof() | dimensiune în bytes | ||
(type) | casting | ||
Pointer către membru | .* ->* | acces către pointer al membrului | stânga-dreapta |
Înmulțire, împărțire | * / % | produs, raport, rest | stânga-dreapta |
Adunare, scădere | + - | sumă, diferență | stânga-dreapta |
Shiftări pe biți | << >> | shiftare la stânga/ dreapta | stânga-dreapta |
Operatori relaționali | < > <= >= | operatori de comparație | stânga-dreapta |
Operatori de egalitate | == != | egal, diferit | stânga-dreapta |
AND pe biți | & | AND pe biți | stânga-dreapta |
XOR pe biți | ^ | XOR pe biți | stânga-dreapta |
OR pe biți | | | OR pe biți | stânga-dreapta |
Conjuncție | && | AND logic | stânga-dreapta |
Disjuncție | || | OR logic | stânga-dreapta |
Operatori de atribuire | = *= /= %= += -= >>= <<= &= ^= |= | operatori (compuși) de atribuire | dreapta-stânga |
?: | operatorul condițional ternar | ||
Concatenare | , | compunerea expresiilor | stânga-dreapta |
Următorul articol din seria de tutoriale C++ este Citirea datelor din consolă și din fișiere în C++. Dacă aveți întrebări despre operatori și expresii în C++, adresați-le mai jos