Operatori și expresii în C++

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:

OperatorDescriereEfect
+adunareReturnează suma operanzilor.
-scădereReturnează diferența dintre operanzi. Primul este descăzutul, iar al doilea scăzătorul.
*înmulțireReturnează produsul dintre operanzi.
/împărțireReturnează 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ă.
%moduloReturnează 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:

OperatorDescriere
==egal
!=diferit
<mai mic
>mai mare
<=mai mic sau egal
>=mai mare sau egal

Acești operatori returnează o valoare booleană. Exemple:

1 == 2 // false
1 < 3 // true
2 != 2 // false
3 >= 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.

Floating point error

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.

aba && b
truetruetrue
truefalsefalse
falsetruefalse
falsefalsefalse

Exemple:

618 && 819 // true
123 && 0 // false
1 == 1 && 6 < 4 // false
false && false // false
x && 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.

aba || b
truetruetrue
truefalsetrue
falsetruetrue
falsefalsefalse

Exemple:

true || false // true
2 < 1 || 1 == 2 // false
false || 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.

OperatorDescriere
&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:

GrupOperatorDescriereEvaluare
Rezoluție::rezoluțiestânga-dreapta
Operatori sufix++ --sufix de incrementare/ decrementarestânga-dreapta
()apel de funcție
[]subscript
. ->acces către membru
Operatori prefix++ --prefix de incrementare/ decrementaredreapta-stânga
~ !NOT pe biți, NOT logic
+ -prefix unar (semnul unui număr)
& *referențiere, dereferențiere
new deletealocare/ dealocare de memorie
sizeof()dimensiune în bytes
(type)casting
Pointer către membru.* ->*acces către pointer al membruluistânga-dreapta
Înmulțire, împărțire* / %produs, raport, reststânga-dreapta
Adunare, scădere+ -sumă, diferențăstânga-dreapta
Shiftări pe biți<< >>shiftare la stânga/ dreaptastânga-dreapta
Operatori relaționali< > <= >=operatori de comparațiestânga-dreapta
Operatori de egalitate== !=egal, diferitstânga-dreapta
AND pe biți&AND pe bițistânga-dreapta
XOR pe biți^XOR pe bițistânga-dreapta
OR pe biți|OR pe bițistânga-dreapta
Conjuncție&&AND logicstânga-dreapta
Disjuncție||OR logicstânga-dreapta
Operatori de atribuire= *= /= %= += -= >>= <<= &= ^= |=operatori (compuși) de atribuiredreapta-stânga
?:operatorul condițional ternar
Concatenare,compunerea expresiilorstâ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 :smile:

Mulțumesc că ai citit acest articol.
Dacă vrei să susții blogul, poți cumpăra un abonament de 2$.

patreon

Lasă un comentariu!

0 comentarii