Să considerăm următoarea problemă: “Se citesc trei numere naturale. Să se determine suma lor.” Desigur, este o problemă banală, dar haideți să o analizăm și să vedem mai multe soluții!
Folosim trei variabile: a
, b
, c
. Le citim și afișăm suma lor.
#include <iostream> using namespace std; int main() { int a, b, c; cin >> a >> b >> c; cout << a + b + c; return 0; }
Această soluție este asemănătoare cu cea anterioară, dar calculăm suma valorilor într-o variabilă suplimentară.
#include <iostream> using namespace std; int main() { int a, b, c, S; cin >> a >> b >> c; S = a + b + c; cout << S; return 0; }
Vom calcula suma valorilor pe rând. Atenție la inițializarea lui S
cu 0
!!!
#include <iostream> using namespace std; int main() { int a, b, c, S; S = 0; cin >> a >> b >> c; S = S + a; S = S + b; S = S + c; cout << S; return 0; }
Observăm că după ce adunăm la S
valoarea unei variabile, nu o mai folosim. Putem astfel să folosim o singură variabilă în care să citim de trei ori câte un număr și, după fiecare citire, să adunăm la S
valoarea curentă a variabilei.
#include <iostream> using namespace std; int main() { int a, S; S = 0; cin >> a; S = S + a; cin >> a; S = S + a; cin >> a; S = S + a; cout << S; return 0; }
Observă că în soluția anterioară am scris de trei ori aceleași instrucțiuni: cin >> a; S = S + a;
. Trebuie înțeles că ele s-au executat de trei ori, dar valorile pe care le aveau variabilele s
și S
la fiecare pas erau diferite.
Aici intervin structurile repetitive: În loc să scriem de trei ori aceleași instrucțiuni, le vom scrie o singură dată, dar vom cere să fie executate de trei ori!. De exemplu putem folosi instrucțiunea while
:
#include <iostream> using namespace std; int main() { int a, S; S = 0; int i = 1; while(i <= 3) { cin >> a; S = S + a; i++; } cout << S; return 0; }
O altă soluție, folosind instrucțiunea for
:
#include <iostream> using namespace std; int main() { int a, S; S = 0; for(int i = 1 ; i <= 3 ; i ++) { cin >> a; S = S + a; } cout << S; return 0; }
Să începem cu niște definiții – în cele ce urmează vorbim despre numere naturale:
n
divide numărul m
dacă există un număr p
astfel încât n * p = m
. De regulă, este echivalent cu faptul că restul împărțirii lui m
la n
este 0
, în C/C++ m % n
este 0
.n
divide pe m
, spunem că n
este divizor al lui m
, iar m
este multiplu al lui n
.Când scriem un număr, sau când ne gândim la el lucrăm cu o înșiruire de cifre care sunt vizibile în mod direct și au o semnificație clară. În calculator un număr este memorat (și poate fi accesat) ca o entitate distinctă, ca o valoare, nu ca o înșiruire de cifre. De aceea, pentru a determina cifrele unui număr trebuie să folosim anumite operații dintre cele pe care le avem la dispoziție în limbajul de programare folosit.
Să ne gândim la un număr (natural), n = 274
– aici n
este o variabilă de tip int
.
Care dintre cifrele sale poate fi determinată cu o simplă operație aritmetică? Constatăm că putem determina ultima cifră a numărului cu operația C++ % 10
– restul împărțirii la 10
. Într-adevăr, 274 % 10
este 4
, adică ultima cifră (a unităților) a lui 274
.
Cum putem determina cifra zecilor? Sigur, o soluție ar fi n % 100 / 10
. Într-adevăr, n % 100
este 74
, iar 74 /10
este 7
. Ne amintim că, dacă operanzii sunt întregi, operația /
reprezintă câtul împărțirii întregi.
Dar mai există o variantă, mai utilă pe termen lung :). Știm că n % 10
reprezintă cifra unităților lui n
și vrem să determinăm cifra zecilor. Putem să modificăm mai întâi valoarea lui n
, astfel: n = n / 10
, și să determinăm ultima cifră a acestui număr. Este cifra unităților pentru valoarea curentă a lui n
și cifra zecilor pentru valoarea inițială.
int n = 274; cout << n % 10; // se va afisa 4 n = n / 10; // n devine 27 cout << n % 10; // se va afisa 7
Vom numi trunchiere operația prin care se elimină ultima cifră a valorii unei variabile întregi. Pentru a realiza trunchierea, folosim operația de atribuire și împărțirea la 10
: n = n / 10
sau n /= 10
.
Cum aflăm cifra sutelor? Trunchiem încă o dată valoarea lui n
. n
devine 2
, iar n % 10
este 2
, adică cifra sutelor pentru valoarea inițială a lui n
. Mai mult, acum n
are o singură cifră, și printr-o nouă trunchiere devine 0
.
Să tragem câteva concluzii:
n
este n % 10
;n
; ultima cifră a valorii curente este cifra zecilor a valorii inițiale;n
devine 0
. Numărul de trunchieri este în concordanță cu numărul de cifre din valoarea inițială a lui n
.Astfel, se conturează următorul program pentru determinarea cifrelor unui număr:
#include <iostream> using namespace std; int main() { int n; cin >> n; while(n != 0) // cat timp n este nenul - mai are cifre { int uc = n % 10; //determinam ultima cifra a lui n cout << uc << " "; // prelucram ultima cifra n /= 10; // eliminam ultima cifra (trunchiem numarul) } return 0; }
Observații:
n
în ordine inversă, de la ultima spre prima! Pentru n=274
se va afișa:4 7 2
n
se citește valoarea 0
, nu se va afișa nimic, deoarece expresia n != 0
este de la început nulă. Acest lucru are o importanță deosebită în anumite situații – de exemplu dacă s-ar cere numărul de cifre ale lui n
.n
prin procedeul de mai sus, valoarea inițială a lui n
se pierde – devine 0
. Dacă la final avem nevoie de ea, trebuie să o copiem într-o altă variabilă.Să considerăm următorul șir de cifre, în ordine: 2 8 5 3
Cu ele se poate construi un număr, astfel:
R = 0
;R
R
Dacă cifrele se adaugă la sfârșit, procedăm astfel:
R = 0
c = 2
. R = 10 * R + c
, adică R
devine 10 * 0 + 2 = 2
c = 8
. R = 10 * R + c
, adică R
devine 10 * 2 + 8 = 28
c = 5
. R = 10 * R + c
, adică R
devine 10 * 28 + 5 = 285
c = 3
. R = 10 * R + c
, adică R
devine 10 * 285 + 3 = 2853
Dacă cifrele se inserează la început, procedăm astfel:
R = 0
c = 2
. R = R + 1 * c
, adică R
devine 0 + 1 * 2 = 2
c = 8
. R = R + 10 * c
, adică R
devine 2 + 8 * 10 = 82
c = 5
. R = R + 100 * c
, adică R
devine 82 + 100 * 5 = 582
c = 3
. R = R + 1000 * c
, adică R
devine 582 +1000 * 3 = 3582
Ambele metode folosesc de fapt scrierea zecimală a numărului:
3582 = 0 + 1 * 2 + 10 * 8 + 100 * 5 + 1000 * 3
Pe de altă parte:
2853 =
285 * 10 +3 =
(28*10 + 5) * 10 +3 =
((2 * 10 + 8)*10 + 5) * 10 +3 =
(((0 * 10 + 2) * 10 + 8)*10 + 5) * 10 +3
În practică, cifrele cu care se construiește numărul pot să provină din diverse surse. O situație frecventă este construirea unui număr folosind cifrele altui număr cunoscut.
Exemplul 1: Determinarea oglinditului unui număr dat
Prin oglinditul (inversul) unui număr se înțelege un numărul scris cu cifrele numărului inițial, în ordine inversă. De exemplu, oglinditul lui 274
este 472
, iar oglinditul lui 1300
este 31
– numerele nu pot să înceapă cu cifra 0
.
n
numărul dat, și ogl
variabila în care vom calcula rezultatul.ogl = 0
.n
.n
, calculată prin n % 10
va fi adăugată la sfârșitul lui ogl
, prin atribuirea ogl = 10 * ogl + n % 10
.Program C++:
#include <iostream> using namespace std; int main(){ int n; cin >> n; int ogl= 0; while(n){ ogl =10*ogl + n%10; n /= 10; } cout << ogl << endl; return 0; }
Exemplul 2: Se dă un număr natural. Să se modifice acest număr, micșorând cu o unitate fiecare cifră impară. Dacă numărul dat este 275
rezultatul va fi 264
.
Rezolvare: Vom determina cifrele numărului dat și vom construi rezultatul, inserând cifrele la început. Cifrele pare se inserează ca atare, cifrele impare se inserează micșorate.
n
numărul dat și R
rezultatul. Vom utliliza o variabilă suplimentară, p
, pentru a calcula puterile lui 10
.R = 0
, p = 1
n
în variabila uc
, uc = n % 10
.
uc
este par, R = R + p * uc
, apoi p = p * 10
.uc
este impar, R = R + p * (uc - 1)
, apoi p = p * 10
.Program C++
#include <iostream> int main() { int n , R = 0, p = 1; std :: cin >> n; while(n) { int uc = n % 10; if(uc % 2 == 0) R += p * uc; else R += p * (uc - 1); p *= 10; n /= 10; } std :: cout << R << std :: endl; return 0; }
pbInfo.ro contine numeroase probleme care presupun determinarea cifrelor unui număr.
Vezi aici lista lor!
Instrucțiunile sunt porțiuni bine determinate ale unui program care stabilesc comportamentul programului – ce face acesta. Instrucțiunile se execută secvențial, în ordinea în care apar în program, și au un anumit efect. Fiecare instrucțiune (cu o excepție) se termină cu ;.
Se recomandă, deși nu este obligatoriu, ca pe o linie să nu fie mai mult de o instrucțiune, acest lucru sporind lizibilitatea programului. De asemenea, în cazul instrucțiunilor de control, se recomandă ca instrucțiunea subordonată să fie scrisă indentat.
Computerele prelucrează date! Le citesc de la tastatură, le memorează în variabile (sau constante), le afișează pe ecran. Și mai fac cu ele diverse operații. Noi suntem obișnuiți să facem operații aritmetice (adunări, scăderi, etc.), dar în C++ există multe alte operații.
O operație este alcătuită din operanzi și operator. Operanzii reprezintă datele cu care se fac operațiile, iar operatorul este simbolul care stabilește ce operație se face cu operanzii. Din punct de vedere a numărului de operanzi, operațiile (operatorii) pot fi:
-7
, operația de schimbare a semnului unui număr);2+5
);Operanzii pot fi variabile, constante, literali, rezultatele unor funcții, rezultatele altor operații. O operație care are ca operanzi alte operații se numește expresie.
Fiecare operație C++ are un rezultat!
Acest articol analizează o parte a operatorilor C++, cei mai frecvent utilizați:
Aceștia sunt: +
, -
, *
, /
, %
. În exemplele de mai jos, considerăm variabilele:
N = 11
și M = 3
de tip int
X = 11
și Y = -3.5
de tip double
.+
și -
:
+
returnează valoarea operandului-
returnează valoarea operandului cu semn schimbat.Exemple
+ X = 11
- Y = 3.5
- + N = -11
+
: adunarea a două numere;-
: scăderea a două numere;*
: înmulțirea a două numere;/
: împărțirea a două numere;%
: restul împărțirii a două numere întregi (modulo);Adunarea, scăderea și înmulțirea se comportă conform așteptărilor, ca la matematică. Operația de împărțire și operația modulo necesită niște explicații suplimentare.
Împărțirea întreagă și împărțirea zecimală
Operația de împărțire are două moduri de lucru, în funcție de tipul operanzilor.
int
, short
, char
, etc.), se va realiza împărțirea întreagă, iar rezultatul operației /
este câtul împărțirii întregi.float
, double
, long double
), se va realiza împărțirea zecimală, iar rezultatul operației /
este rezultatul acestei împărțiri, “cu virgulă”.Exemple
N / M = 3
X / Y = -3.14286
X / 2.0 = 5.5
M / 2 = 1
M / 2.0 = 1.5
Ultima împărțire este deosebită. Cei doi operanzi au tipuri diferite: M = 3
este de tip int
, iar 2.0
este de tip double
. Aici intervine operația de conversie implicită: în mod automat, valoarea operandului M
se consideră ca fiind de tip double
, împărțirea este împărțire reală și are rezultatul 1.5
.
Operatorul modulo %
Operația modulo are sens numai dacă ambii operanzi sunt de tip întreg – împărțirea cu rest are sens numai în această situație. Iată câteva exemple:
N % M = 2
: restul împărțirii lui 11
la 3
este 2
30 % 10 = 0
Operatorul modulo este util în multe situații. El poate fi utilizat pentru a afla ultima cifră a unui număr natural: ultima cifră a lui 276
este 276 % 10
adică 6
, sau pentru a verifica dacă un număr N
este divizor al lui M
. În caz afirmativ, M % N
este 0
.
Observații suplimentare
0
.10 32 33 34 35 37 46 59
Sunt: <
, >
, <=
, >=
, ==
, !=
.
Un operator relațional stabilește dacă între două numere (operanzii) are loc o anumită relație. Rezultatul acestei operații este adevărat sau fals. Rezultatul operațiilor relaționale poate fi 0
sau 1
:
1
dacă relația este adevărată0
dacă relația este falsăFie N = 11
și M = 3
. Operațiile relaționale sunt:
<
; N < M
este fals, adică 0
>
; N > M
este adevărat, adică 1
<=
; M <= N
este 1
>=
; M >= N
este 0
==
; N == M
este fals, adică 0
!=
; N != M
este adevărat, adică 1
.Una dintre cele mai frecvente erori este folosirea pentru operația de egalitate a operatorului =
, în loc de ==
. Operatorul =
reprezintă operația de atribuire!
O altă eroare frecventă apare la compararea mai multor numere. De la matematică suntem obișnuiți să comparăm numere astfel: a < b < c
– condiția este adevărată dacă numerele sunt în ordine strict crescătoare. În C++, rezultatul acestei operații poate fi diferit de cel așteptat, datorită modului în care se fac operațiile.
De exemplu:
cout << (5 > 4 > 3) ; // 0 (false)
Expresia 5 > 4 > 3
este echivalentă cu (5 > 4) > 3
și se evaluază astfel:
5 > 4
, cu rezultat adevărat (1
)1 > 3
, cu rezultat fals (0
)!!Sunt: !
, ||
, &&
.
Operatorii logici au operanzi de tip valori de adevăr și rezultat valori de adevăr. Istoric, operațiile logice sunt legate de numele matematicianului englez George Boole, cel care a pus bazele acestei ramuri a matematicii și a inventat algebra booleană și calculul propozițional.
În C++, operatorii logici pot fi aplicați oricăror valori numerice, și au ca rezultat una din valorile 0
sau 1
. În exemplele de mai jos vom folosi literalii true
și false
, de tip bool
.
Negația: !
! true
este false
. Orice valoare nenulă negată devine 0
.! false
este true
. 0
negat devine 1
.Disjuncția: ||
false || false → false
false || true → true
true || false → true
true || true → true
Conjuncția: &&
false && false → false
false && true → false
true && false → false
true && true → true
7 11 17 19 28 509
Fie p
și q
două valori booleene (pot fi rezultatele unor expresii, de exemplu). Atunci:
!(p && q) == !p || !q
!(p || q) == !p && !q
Să luăm ca exemplu apartenența unei valori la un interval:
x∈[a,b]
x ≥ a && x ≤ b
!(x ≥ a) || !(x ≤ b)
!(x ≥ a)
este echivalent cu x<a
, obținem:x < a || x > b
x ∈ (-∞,a)∪(b,+∞)
, adică x∉[a,b]
15 18 61 476 529
=
Atribuirea este operația prin care o variabilă primește valoarea unei expresii:
variabila = expresie
Expresia poate avea orice fel de rezultat, dacă tipul său este identic cu al variabilei sau poate fi convertit la tipul variabilei. În cazul tipurilor întregi, reale, bool
, oricare dintre acestea poate fi convertit la la oricare altul, eventual cu trunchierea unor valori.
Exemple:
#include <iostream> using namespace std; int main() { int n , m; // valori aleatorii double x , y; // valori aleatorii n = 5; // valoare lui n devine 5 cout << n << endl; m = n + 2; // valoare lui m devine 7 cout << m << endl; n = n + 3; // valoarea lui n devine 5 + 3, adica 8 cout << n << endl; x = m / 5; // valoarea lui x devine 8 / 5, adica 1. ATENTIE! este impartire intreaga cout << x << endl; y = 5; // valoarea lui y devine 5, de tip double. Are loc conversia lui 5 de tip int la double cout << y << endl; x = m / y; // valoarea lui x devine 1.4, deoarece impartirea este zecimala. Are loc conversia valorii lui m la double, apoi se face impartirea cout << x << endl; return 0; }
Atribuirea este o operație, deci are rezultat! Rezultatul operației de atribuire este chiar variabila care primește valoare.
Nu confundați operația de atribuire =
cu operația de egalitate ==
.
Este posibilă și realizarea unor atribuiri multiple, ca mai jos:
int a , b, c; a = b = c = 10;
Toate variabilele vor primi valoarea 10
.
Următoarea atribuire este mai interesantă:
n = n + 4;
Ea se efectuează astfel (să considerăm, ca exemplu, că valoarea inițială a lui n
este 5
):
n
: n + 4
este 5 + 4
adică 9
n
devine 9
.Notă: În membru stâng al unei atribuiri poate fi nu doar o variabilă, ci o expresie de tip lvalue. Prin lvalue se înțelege left value, adică tocmai o expresie ce poate “în stânga” unei atribuiri. Variabilele sunt expresii lvalue, dar există și altfel de expresii, despre care vom vorbi mai târziu, care sunt lvalue.
Sunt: +=
, -=
, *=
, /=
, %=
, >>=
, <<=
, &=
, ^=
, |=
.
În programare sunt foarte frecvente atribuirile de forma:
x = x * 5;
în care unei variabile i se aplică o anumită operație aritmetică (în exemplul de mai sus *
) iar rezultatul se memorează chiar în acea variabilă. Pentru a facilita scrierea codului în aceste situații, în C++ există atribuirea compusă:
var OP= expresie
, echivalentă cu var = var OP expresie
Astfel, atribuirea x = x * 5
este echivalentă cu x *= 5
.
Interschimbarea este operația prin care valorile a două variabile se sechimbă între ele. De exemplu, dacă variabilele A
și B
au valorile 5
, respectiv 7
, în urma interschimbării B
va avea valoarea 5
și A
va avea valoarea 7
.
Interschimbarea se face prin interschimbări succesive. Există mai multe metode, dar cea mai utilizată este cunoscută sub numele de regula paharelor, deoarece este similară cu modul în care se schimbă conținutul a două pahare. În acest caz este nevoie de încă un pahar, iar în cazul interschibării variabilelor este nevoie de o variabilă auxiliară.
Schema interschimbării este următoarea:
int A = 5 , B = 7; int aux = A; A = B; B = aux; cout << A << " " << B; // 7 5
1196
++
, --
Se numesc operatori de de incrementare (++
) și decrementare (--
).
Prin incrementarea unei variabile se înțelege mărirea valorii sale cu 1
. Similar, prin decrementarea unei variabilă se înțelege micșorarea valorii sale cu 1
.
Operația de incrementare a variabilei X
poate fi:
X ++
. Efectul expresiei este mărirea valorii lui X
cu 1
, iar rezultatul operației este valoarea inițială a lui X
.++ X
. Efectul expresiei este mărirea valorii lui X
cu 1
, iar rezultatul operației este chiar variabila X
.Exemplu pentru postincrementare:
int x = 5 , y = 10; y = x ++; // y primeste valoare lui (x++), adica valoarea initiala a lui x cout << x << " " << y; // 6 5
Exemplu pentru preincrementare:
int x = 5 , y = 10; y = ++ x; // y primeste valoare lui (++x), adica valoarea marita a lui x cout << x << " " << y; // 6 6
Operația de decrementare a variabilei X
poate fi:
X --
. Efectul expresiei este micșorarea valorii lui X
cu 1
, iar rezultatul operației este valoarea inițială a lui X
.-- X
. Efectul expresiei este micșorarea valorii lui X
cu 1
, iar rezultatul operației este chiar variabila X
.?
Operatorul condițional este singurul operator ternar (cu trei operanzi) din C++. Sintaxa lui este:
expresie1 ? expresie2 : expresie3
și se evaluează astfel:
expresie1
expresie1
este nenul (adevărat), se evaluează expresie2
și rezultatul acestei expresii va fi rezultatul operației ?
expresie1
este nul (fals), se evaluează expresie3
și rezultatul acestei expresii va fi rezultatul operației ?
expresie2
și expresie3
trebuie să aibă rezultate de același tip, sau de tipuri compatibile.
Exemplu:
int x; cin >> x; cout << (x % 2 == 0? "par" : "impar");
,
În anumite situații, regulile de sintaxă ale limbajului C++ solicită prezența unei singure operații, dar logica programului cere prezența mai multor operații. Acestea pot fi grupate cu ajutorul operatorului ,
. Sintaxa acestei operații este;
expresie1 , expresie2
Modul de evaluare este:
expresie1
, apoi expresie2
– important, dacă în expresie2
apar variabile care se modifică în expresie1
expresie2
Exemple:
int x , y , z; x = 1 , y = 2 , z = 3; x ++, y = x + 2, z -= x; // este semnificativa ordinea in care s-au evaluat cele trei expresii cout << x << " " << y << " " << z; // 2 4 1
Sunt: &
, |
, ^
, ~
, <<
, >>
.
Operatorii pe biți reprezintă o temă avansată de programare. Ei permit manipularea directă și foarte rapidă a biților care formează reprezentarea în memorie a unei date. Vezi acest articol!
În anumite situații trebuie să considerăm o expresie de un anumit tip ca fiind de alt tip. Acest lucru poate fi realizat prin operatorul de conversie:
(tip_nou) expresie
Exemple:
int x = 2; cout << 7 / x << endl; // 3 - este impartire intreaga cout << 7 / (double) x; // 3.5 - este impartire zecimala
char p = 'a'; cout << (int)p << endl; // 97, codul ASCII al lui 'a' cout << p - 32 << endl; // 65 cout << (char)(p - 32); // A - carcaterul cu codul ASCII 65
sizeof
Operatorul sizeof
este un operator unar care se aplică la un tip de date sau la o expresie. Rezultatul său este numărul de octeți pe care îi ocupă o dată de acel tip, respectiv rezultatul expresiei.
Exemple
cout << sizeof(double) << endl; // 8: o data de tip double ocupa 8 octeti cout << sizeof(3 + 5) << endl; // 4: 3 + 5 este de tip int; o data de tip int ocupa 4 octeti
Limbajul C++ conține și alți operatori, dintre care:
( )
– modificarea priorității unei operații, apel de funcție[ ]
– indexarea unui tablou.
, ->
– acces la membrii unei structuri&
, *
– referențiere (determinarea adresei unei variabile), dereferențiere (accesare variabilei de la o adresă)new
, delete
– alocare și dealocarea memoriei<<
, >>
– inserare și extragere din stream::
operatorul de rezoluțiePrioritatea operatorilor stabilește ordinea în care se evaluează o expresie care conține mai mulți operatori, de diverse feluri – ordinea în care se efectuează operațiile.
Asocierea operatorilor stabilește ordinea în care se evaluează o expresie ce conține mai mulți operatori cu aceeași prioritate. Poate fi de la stânga la dreapta sau de la dreapta la stânga.
Atât prioritatea, cât și asocierea operatorilor poate fi modificată folosind paranteze rotunde ()
Pentru operatorii prezentați mai sus, prioritatea este următoarea:
Nivelul 1 de prioritate. Asociere: stânga dreapta
::
Nivelul 2 de prioritate. Asociere: stânga dreapta
++ --
[]
()
. ->
Nivelul 3 de prioritate. Asociere: dreapta stânga
++ --
~
, negarea logică !
+ -
& *
new delete
sizeof
Nivelul 4 de prioritate. Asociere: stânga dreapta
.* ->*
Nivelul 5 de prioritate. Asociere: stânga dreapta
* / %
Nivelul 6 de prioritate. Asociere: stânga dreapta
+ -
Nivelul 7 de prioritate. Asociere: stânga dreapta
<<
, >>
Nivelul 8 de prioritate. Asociere: stânga dreapta
< > <= >=
Nivelul 9 de prioritate. Asociere: stânga dreapta
== !=
Nivelul 10 de prioritate. Asociere: stânga dreapta
&
Nivelul 11 de prioritate. Asociere: stânga dreapta
^
Nivelul 12 de prioritate. Asociere: stânga dreapta
|
Nivelul 13 de prioritate. Asociere: stânga dreapta
&&
Nivelul 14 de prioritate. Asociere: stânga dreapta
||
Nivelul 15 de prioritate. Asociere: dreapta stânga
= += -= *= /= %= >>= <<= &= ^= |=
?
Nivelul 16 de prioritate. Asociere: stânga dreapta
,
Operațiile de de intrare/ieșire sunt operațiile prin care un program primește date sau afișează rezultate. Aceste operații trebuie privite din perspectiva programului
Practic, datele care intră în program sau ies din program sunt șiruri de caractere pe care programul le primește, respectiv le trimite
Limbajul C++ oferă o modalitate uniformă de a realiza operațiile de intrare/ieșire, indiferent dacă se fac la consolă, în fișiere, sau cu alte dispozitive care prelucrează caractere. Este vorba despre stream sau flux. Stream-ul poate fi privit ca o înșiruire de caractere care sunt trimise într-o ordine bine determinată de la o sursă la o destinație. Programul va insera caractere în stream (dacă este un stream de ieșire, care afișează date) sau va extrage caractere din stream (dacă este un stream de intrare, din care se citesc date).
Biblioteca standard C++ permite lucrul cu mai multe categorii de stream-uri. Dintre acestea vom discuta în continuare despre stream-urile cu consola, dispozitivul standard de intrare-ieșire, altfel spus stream-uri care permit citirea de la tastatură și afișarea pe ecran. Obiectele care permit aceste operații sunt:
cin
– stream standard de intrarecout
– stream standard de ieșirecerr
– stream standard de ieșire pentru eroriclog
– stream standard de ieșire pentru înregistrarea evenimentelorÎn continuare vom vorbi despre cout
și cin
– stream-ul standard de ieșire și de intrare. cerr
și clog
sunt și ele stream-uri de ieșire și funcționează precum cout
; mai mult, de cele mai multe ori fac exact același lucru ca și cout
– afișează pe ecran. Există însă situații când ieșirea produsă de cerr
sau clog
este redirectată către alte dispozitive.
cout
În cele mai multe cazuri, dispozitivul standard de ieșire este ecranul și poate fi accesat cu stream-ul cout
. Pentru aceasta, cout
se folosește împreună cu operatorul de inserție <<
, urmat de data care se va afișa:
cout << "Salut"; // afiseaza pe ecran Salut cout << 17; // afiseaza numarul 17 pe ecran cout << n; // afiseaza pe ecran valoarea variabilei n
Operatorul cout
afișează în stream-ul din stânga valoarea din dreapta. Să observăm că "Salut"
este delimitat de ghilimele, deoarece este o constantă literal de tip șir de caractere, iar n
nu este delimitată de ghilimele, deoarece este o variabilă.
Notă: Dacă textul care urmează după <<
este între ghilimele, se va afișa ca atare. Dacă nu este între ghilimele, se consideră că este o variabilă, și se afișează valoarea ei.
cout << "Salut"; //afiseaza cuvantul Salut cout << Salut; // afiseaza valoare variabilei Salut
Putem afișa mai multe valori în aceeași instrucțiune:
cout << "Ana " << "are" << " mere."; // se va afisa Ana are mere
sau
int nr_mere = 17; cout << "Ana " << "are " << nr_mere << " mere."; // se va afisa Ana are 17 mere
cout
nu adaugă automat sfârșit de linie sau spatii. De exemplu:
cout << "Aceasta este o"; cout << "propozitie mai lunga!";
va afișa:
Aceasta este opropozitie mai lunga!
Pentru a insera spațiu între o
și propoziție
, îl precizăm explicit:
cout << "Aceasta este o "; // este un spatiu dupa o cout << "propozitie mai lunga!";
sau
cout << "Aceasta este o"; cout << " propozitie mai lunga!"; // la inceput este un spatiu
Dacă vrem să afișăm pe linii diferite procedăm astfel:
cout << "Aceasta este o\n"; cout << "propozitie mai lunga!";
O altă variantă este să folosim manipulatorul endl
pentru a întrerupe linia. De exemplu:
cout << "Aceasta este o" << endl; cout << "propozitie mai lunga!";
Ambele variante de mai sus vor afișa:
Aceasta este o propozitie mai lunga!
endl
produce un caracter rând nou, exact ca și inserarea lui \n
, dar mai face ceva: endl
golește buffer stream-ului cout
, adică forțează afișarea pe ecran tuturor caracterelor inserate în stream până în acest moment. endl
poate produce întârzieri în execuția programului, deci trebuie folosit cu precauție.
cin
În cele mai multe cazuri, dispozitivul standard de intrare este tastatura și poate fi accesat cu stream-ul cin
. Pentru aceasta, cin
se folosește împreună cu operatorul de extragere >>
, urmat de variabila în care se va memora valoarea extrasă (variabila care se va citi):
int n; cin >> n;
Mai întâi se declară variabila n
, apoi se citește o valoare pentru ea – se extrage din cin
o valoare care se memorează în variabila n
. La execuție, programul așteaptă să se introducă o valoare de la tastatură. De fapt, caracterele introduse sunt transmise programului numai când se apasă tasta ENTER.
Să considerăm următorul program:
#include <iostream> using namespace std; int main() { int n = 7; cout << "n = "; cin >> n; cout << "n este " << n << endl; cout << "patratul lui n este " << n * n << endl; return 0; }
Rezultatul său depinde de valoare introdusă pentru n
. Ar putea fi:
n = 25 n este 25 patratul lui n este 625
Dar dacă se nu se introduce un număr?
n = salut n este 0 patratul lui n este 0
La operația de extragere din cin
contează tipul variabilei de după >>
. Caracterele din stream sunt interpretate în funcție de tipul variabilei. Dacă aceste caractere nu corespund cu tipul variabilei, operația de extragere eșuează. Dacă operația de extragere din stream eșuează:
0
și se setează failbit. Dacă valoarea extrasă depășeste limitele tipului variabilei, aceasta primește valoarea maximă sau minimă a tipului său și se setează failbit – de la C++11.Se pot citi valorile a două sau mai multe variabile în aceeași instrucțiune:
cin >> x >> y;
este echivalent cu
cin >> x; cin >> y;
În ambele cazuri se așteaptă introducerea a două valori; acestea pot fi separate/precedate prin orice fel de caractere albe: spații, TAB-uri, caractere rând nou.
Atenție: Una dintre cele mai frecvente erori este inversarea operatorilor pentru stream-urile cin
și cout
, sau citirea valorii unei constante. Următoarele instrucțiuni sunt greșite:
cout >> "Salut"; cin << n; cin >> "Salut";
Limbajul C++ a fost inventat de către Bjarne Stroustrup în 1979, ca o extindere a limbajului C. Limbajul C a fost inventat în 1969-1973 de către Dennis Ritchie pentru a realiza sistemul de operare Unix. Astfel, aproape toate programele scrise în C pot fi compilate în C++, eventual cu foarte puține modificări.
Limbajele de programare sunt limbaje asemănătoare cu limbajul uman. Conțin cuvinte (destul de puține), semne de punctuație, operații matematice și au reguli de scriere. Programele care rulează pe orice calculator au fost scrise într-un limbaj de programare. Există numeroase limbaje de programare, precum C, C++, Pascal, Java, Python, PHP, Javascript, etc.
Programul scris într-un limbaj de programare se numește program sursă și trebuie traduse într-un limbaj pe care îl înțelege procesorul, numit cod mașină, sau program executabil. Pentru anumite limbaje de programare operația de traducere se numește compilare (cazul lui C, C++, Pascal, etc.), pentru alte limbaje (PHP, Python, Javascript, etc.) operația de traducere se numește interpretare. Traducerea este realizată de un program specializat numit compilator sau interpretor.
Limbajul C++ este un limbaj compilat. Etapele scrierii unui program în C++ sunt:
.cpp
.o
sau .obj
.exe
;Cum scriem un program C++? Avem nevoie cel puțin de un editor de text pentru scrierea sursei și de un compilator C++. Deși fișierul sursă poate fi realizat cu orice editor de text, de cele mai multe ori folosim un IDE. Un IDE pentru C/C++ foarte utilizat este Code::Blocks. Acest articol prezintă modul de instalare a pachetului Code::Blocks pe calculator, împreună cu compilatorul MinGW, iar acest articol prezintă pașii necesari pentru a realiza un program C++ în Code::Blocks.
Să considerăm un prim program C++:
// primul program C++ #include <iostream> int main() { /* primul program C++ il scriem in Code::Blocks */ std :: cout << "Hello world"; return 0; }
Dacă vom compila și rula acest program, pe ecran va apărea:
Hello world
Să analizăm acest program. El este alcătuit din mai multe linii:
#
se numesc directive preprocesor. Ele sunt interpretate înainte de compilarea propriu-zisă, de către un program numit preprocesor. În cazul nostru, directiva #include iostream
, care permite realizarea operațiilor de citire și afișare – la noi afișarea mesajului Hello world
pe ecran.main
/*
primul program C++
il scriem in Code::Blocks
*/
/*
și */
nu influențează comportamentul programului. Ele pot să ocupe mai multe linii, sau pot să apară în interiorul unei linii.Hello world
. Ea este alcătuită din trei părți. std::cout
semnifică dispozitivul standard de ieșire (standard character output) – de cele mai multe ori ecranul calculatorului. A doua parte este operatorul de inserție <<
, care indică faptul că ceea ce urmează este inserat în std::cout
(trimis spre ecran). A treia parte este textul, "Hello world"
, cuprins între ghilimele, care va fi inserat în std::cout
.;
la sfârșitul instrucțiunii. Orice instructiune C++ trebuie să se termine cu ;
, la fel cum orice propoziție în limba română se termină cu caracterul .
(punct).;
la finalul unei instrucțiuni.main
și a programului nostru. Valoarea 0
semnifica faptul că programul s-a încheiat cu succes! return 0;
, acestea nu s-ar mai fi executat.}
reprezintă finalul funcției main
.Să reținem că nu toate liniile programului produc efecte la executarea programului. Unele linii (comentariile) sunt scrise numai pentru a ușura înțelegerea programului de către cel care îl citește/scrie. Mai mult, nu este obligatoriu ca fiecare instrucțiune să fie scrisă pe o singură linie. Următoarele trei exemple de funcție main
au acelați efect:
int main() { cout << "Salut"; return 0; }
int main() { cout << "Salut"; return 0; }
int main() { cout << "Salut"; return 0; }
Să modificăm primul program, astfel încât să afișăm pe ecran două propoziții:
// al doilea program C++ #include <iostream> int main() { std :: cout << "Hello world!"; std :: cout << "Primul program C++!"; return 0; }
La rulare, programul va afișa:
Hello world!Primul program C++!
Să observăm că cele doua propoziții sunt scrie pe același rând al ecranului, chiar dacă au fost scrise cu două instrucțiuni distincte. Dacă dorim ca cele doua propoziții să fie afișate pe linii diferite ale ecranului, folosim std::endl
.
// al doilea program C++ #include <iostream> int main() { std :: cout << "Hello world!" << std::endl; std :: cout << "Primul program C++!"; return 0; }
Acum, programul va afișa:
Hello world! Primul program C++!
În C++, identificatorii sunt grupați în spații de nume – namespaces. Există un spațiu de nume predefinit, cu numele std
, din care fac parte toți identificatorii din biblioteca C++ standard.
cout
, ca și endl
, este un identificator din spațiul de nume std
și pentru a-l putea folosi trebuie folosită expresia std::cout
. Pentru a ne referi mai simplu la identificatorii din spațiul de nume std
se poate folosi instructiunea:
using namespace std;
Astfel, programul anterior poate fi rescris:
// al doilea program C++ #include <iostream> using namespace std; int main() { cout << "Hello world!" << endl; cout << "Primul program C++!"; return 0; }
Comentariile sunt texte care pot să apară în programul sursă și nu sunt luate în considerare la compilare. Ele sunt citite doar de către oameni, pentru a explica anumite secțiuni mai importante din program. Așa cum am văzut mai sus, în C++ sunt două tipuri de comentarii:
Comentariul pe o linie începe de caracterele //
și se termină la finalul liniei. Comentariul de tip bloc începe la /*
, se termină la */
și se poate întinde pe mai multe linii.
Comentariile sunt importante! Trebuie să învățăm să scriem cod pe care să-l înțelegem și peste o zi sau un an, iar prezența comentariilor este un pas înainte.
Tipul de date reprezintă un concept foarte important în C/C++. Orice dată (constantă sau variabilă) este de un numit tip. Tipul datei precizează ce valori poate avea acea dată și ce operații se pot face cu ea.
În C/C++ tipurile de date sunt:
int
float
și double
char
bool
void
Acest articol se referă numai la tipurile simple.
int
int
ocupă (de regulă) 4 octeți; astfel, poate memora valori întregi din \([-2^{31},2^{31}-1]\), adică \([-2.147.483.648,2.147.483.647]\).Exemplu
int n = 100;
În probleme, dacă datele întregi nu depășesc (aproximativ) 2.000.000.000
folosim tipul int
. Pentru datele care depășesc această valoare vom folosi tipul long long
.
float
și double
float
se reprezinta pe 4
octeți;double
se reprezinta pe 8
octeți;Exemplu
float p = 3.14, r = 2.5; double A = p * r * r;
Datele reale pot fi scrise în forma științifică (exponențială):
double x = 1.24E+07; // înseamnă 1.24 * 10^7
1
octetExemplu
char c='A';
În C++, o dată de tip char
nu memorează caracterul, ci un număr corespunzător caracterului. Mai multe detalii aici.
Informații despre pointeri găsiți în acest articol.
bool
Anumite operații care se fac cu datele au ca rezultat valori de adevăr: adevărat sau false.
bool
conține două valori: true
și false
;1
octet;1
și 0
;Exemplu
bool pp = false;
void
nu au valori și nu se pot face cu ele operații;Nu putem declara variabile de tipul void
.
Permit schimbarea modului în care se face reprezentarea internă a unei date. Aceștia sunt:
signed
unsigned
short
long
Pot fi aplicați tipurilor
int
double
char
Tip de date | Reprezentare | Înțeles |
---|---|---|
signed int |
4 octeți cu semn | La fel ca int . Valori întregi din \([-2^{31},2^{31}-1]\), adică \([-2147483648,2147483647]\). |
unsigned int |
4 octeți fără semn | Valori naturale din \([0,2^{32}-1]\), adică \([0 , 4294967295]\). |
long |
4 octeți cu semn | La fel ca int . Echivalent cu long int . |
unsigned long |
4 octeți fără semn | La fel ca unsigned int . Echivalent cu unsigned long int . |
short |
2 octeți cu semn | Valori întregi mici din \([-2^{15},2^{15}-1]\), adică \([-32768,32767]\). Echivalent cu short int . |
unsigned short |
2 octeți fără semn | Valori naturale mici din \([0 , 2^{16}-1]\), adică \([0 , 65535]\). Echivalent cu unsigned short int . |
long long |
8 octeți cu semn | Valori întregi foarte mari din \([-2^{63},2^{63}-1]\). Echivalent cu long long int |
unsigned long long |
8 octeți fără semn | Valori naturale foarte mari din \([0,2^{64}-1]\). Echivalent cu unsigned long long int |
signed char |
1 octet cu semn | Caractere. Valorile numerice sunt din \([-2^{7},2^{7}-1]\), adică \([-128,127]\). |
unsigned char |
1 octet fără semn | Caractere. Valorile numerice sunt din \([0,2^{8}-1]\), adică \([0,255]\). |
long double |
10, 12, 16 | Memorează numere reale mari. Reprezentarea depinde de compilator, dar trebuie să ocupe cel puțin la fel ca double . |
Orice program prelucrează date. Acestea se află în memoria RAM a calculatorului, și pot fi variabile (valoarea datei se poate modifica) sau constante (valoarea nu se poate modifica).
O variabilă reprezintă o locație de memorie unde se află o valoare de un anumit tip. Orice variabilă este caracterizată de:
0
. Acest număr reprezintă adresa acelui byte și se afișează implicit în baza 16
.'_'
– underline. Literele mari sunt considerate diferite de cele mici, astfel că Raspuns
, raspuns
și RASPUNS
reprezintă identificatori diferiți.'_'
, nu este recomandat, pentru a evita anumite conflicte cu identificatori de sistem.31
de caractere sunt semnificative.{...}
) și sunt vizibile doar în acel bloc. Au valori inițiale aleatorii.0
.În C/C++, variabilele trebuie declarate, precizând tipul și identificatorul. Sintaxa este:
Tip_de_date Lista_identificatori
;
unde Tip_de_date
poate fi orice tip C++ corect (citește aici despre tipurile de date), iar Lista_identificatori
este alcătuită din cel puțin un identificator. Dacă sunt mai mulți, se vor separa prin caracterul virgulă ,
.
Exemple:
int a , x;
S-au declarat două variabile, cu numele a
și x
ce vor putea memora valori numere întregi dintr-un interval pe care îl vom studia mai târziu.
La declarare, variabilele pot fi inițializate cu o valoare corespunzătoare tipului de date folosit:
int a = 1, x;
Următorii identificatori C++ sunt corecți: a
, numar
, Numar
, alt_numar
, a2b
, _suma
– nerecomandat, un_nume_de_variabila_foarte_lung
.
Următorii identificatori C++ sunt incorecți:
2a
– începe cu cifră. Identificatorii pot începe cu litere sau '_'
alt numar
– conține caracter interzis: spațiuun-numar
– contine caracter interzis: minusnumăr
– conține litera ă
. Identificatorii pot conține numai litere ASCII – din alfabetul englez.Constantele sunt date care nu-și modifică valoarea în timpul execuției programului. Pot fi constante cu nume, sau constante literale, date direct prin valoarea lor.
Constantele simbolice (cu nume) pot fi precizate în două moduri:
define
. Exemplu:#define MAX 101
const
; ele devin read-only, iar valoarea lor nu mai poate fi modificată. Exemplu:const int MAX = 101;
Notă: la declararea variabilelor read-only este obligatorie inițializarea!
Într-un program pot apărea valori constante, fie că sunt numere, caractere, șiruri de caractere sau de altă natură. Acestea se mai numesc constante literale sau literali.
Reprezintă numere întregi – fără parte fracționară. Pot fi:
10
176
, -54
, 0
;0 1 2 3 4 5 6 7 8 9
;8
0
;015
, 062
;0 1 2 3 4 5 6 7
;16
:
0x
;0x15
, 0x6f
, 0xff
;0 1 2 3 4 5 6 7 8 9 A B C D E F
.O constantă octală nu poate contine cifra 9
. Valoarea 0295
nu este corectă și va produce eroare de compilare!
Reprezintă numere reale și se mai numesc în virgulă mobilă. Separatorul zecimal este caracterul punct '.'
și pot apărea în două forme:
-1.5 14.974
-0.567E+2
înseamnă -0.567*10
+2
, adică -56.7
:
-0.567
reprezintă mantisa;+2
reprezintă exponentul.char
Sunt alcătuite dintr-un singur caracter, delimitat de apostroafe: ‘.
Exemplu
'a', 'B', '~', '?'
O categorie aparte de caractere constă în secvențele ESCAPE. O secvență escape este alcătuită din două caractere, dintre care primul este backslash: \
. Reprezintă caractere care nu pot fi scrise ca atare sau au un înțeles special. Din punct de vedere sintactic sunt caractere, fiind delimitate prin aprostrof. Probabil cea mai cunoscută secvență escape este '\n'
– new line (enter).
Dintre secvențele escape amintim:
'\n'
– Newline'\b'
– Backspace'\f'
– Form feed'\r'
– Return'\t'
– TAB orizontal'\\'
– Backslash'\''
– Apostrof'\"'
– Ghilimele'\?'
– Semn de întrebare'\0'
-Caracterul nulO constantă char
conține exact un caracter. Nu putem avea mai multe caractere între apostroafe, cu excepția secvențelor escape, dar o secvență escape reprezintă un singur caracter!
Sunt delimitate de ghilimele “. Pot să conțină secvențe escape.
Exemple
"numar", "n = ", "Am terminat.\n"
'A'
și "A"
nu reprezintă același lucru: 'A'
este un caracter, iar "A"
este un șir de caractere, format dintr-un singur caracter!
Nu orice cuvânt poate fi utilizat pe post de identificator. Există în C++ o listă de cuvinte care au o semnificație bine determinată și nu pot fi utilizate în alt scop. Ele se numesc cuvinte rezervate (keywords) și sunt următoarele:
alignas |
else |
requires |
1281 1286 1282 1283 1284 1285
În orice sistem de calcul, datele – de orice tip – se memorează sub formă de numere. Mai mult, acestea se reprezintă în baza 2. În consecință, pentru a memora în calculator caractere este necesară utilizarea unei reprezentări a caracterelor prin numere. O astfel de reprezentare este Codul ASCII.
ASCII este o formă de reprezentare în calculator a caracterelor folosită în toate limbajele de programare studiate în liceu, alături eventual de alte reprezentări.
Codul ASCII standard codifică caracterele folosind 7
biți, astfel că permite codificarea a 2
7
=128
caractere. Nu sunt prea multe! De fapt sunt codificate numai literele din alfabetul englez, cifrele de la 0
la 9
, semnele de punctuație și operatorii, precum și alte simboluri. Lipsesc cu desăvârșire literele specifice altor alfabete latine (așa numite litere cu diacritice, precum ar fi ă Ă î Î â Â ș Ș ț Ț ş Ş Ţ ţ
(observăm că sunt două feluri de Ș
și doua feluri de Ţ
, dar despre acest fapt vom discuta în alt articol ), precum și literele din alte alfabete: chirilic, ebraic, arab, chinez, etc. Pentru memorarea acestor litere se poate folosi codul ASCII Extins, sau codul UNICODE.
Prin codul ASCII, fiecărui caracter reprezentat în acest cod i se asociază un număr. Aceste numere (numite chiar coduri ASCII) se găsesc în intervalul 0 .. 127
. Caracterele ASCII se împart în două categorii:
32 126
, inclusiv capetele: aici se regăsesc toate caracterele care au o reprezentare grafică bine determinată:
A ... Z
,a ... z
,0 .. 9
,.,:;!?'"
+ - / * <> = (){}[]
~`@#$%^&_\|
0 .. 31
și 127
. Ele erau folosite mai demult pentru a controla transmiterea datelor. Caracterele neimprimabile nu au o reprezentare grafică bine determinată – în funcţie de sistemul operare folosit, reprezentările grafice ale acestor caractere pot fi foarte diferite, sau chiar să lipsească cu totul. Dintre aceste caractere amintim două, de o importanţă mai mare în limbajele de programare studiate:
0
, numit și caracter nul, notat în C++ cu '\0'
– reprezintă finalul unui șir de caractere în memorie10
, numit Line Feed, notat în C++ cu '\n'
– produce trecerea la rând nou atunci când este afișat pe ecran sau într-un fișier.'A'
are codul 65
, 'B'
are codul 66
, .. , 'Z'
are codul 90
. Două caractere consecutive în alfabet au coduri ASCII consecutive! De asemenea, litera 'a'
are codul 97
, etc.'a' > 'Z'
) și diferenţa între codurile ASCII a două litere (mică – mare) este 32
.'0'
are codul 48
, caracterul '1'
are codul 49
, etc. *Observăm că caracterul '0'
nu are codul ASCII 0
, ci 48
.32
.Imagine preluată de pe Wikipedia.
Formularul de mai jos realizează conversia între un caracter și codul său ASCII. Rezultatele sunt consistente pentru caracterele imprimabile!