Inainte de a examina modul in care calculatoarele iau decizii, este important sa intelegem notiunea de date. La urma urmelor, toate informatiile stocate intr-un calculator se reduc la o serie formata din 1 si 0. Ceea ce da sens informatiilor rezulta din capacitatea de organizare a acesteia in componente semnificative, numite tipuri de date.
Cand ati invatat matematica, nu trebuia sa va preocupati de tipuri. Un numar este un numar si nimic altceva. Toate aceste expresii sunt identice din punct de vedere matematic:
3 3.0 trei 2+1
Dar limbajele de calculator si sistemele sunt altceva decat matematica pura. Nu este suficient sa aveti o valoare ; trebuie sa aveti si un mod de a o stoca. In tutorialele anterioare ne-am referit la variabila ca la o "caseta magica" , dar este mai corect sa spunem ca o variabila este un cos care poate contine date. Dar, ca toate cosurile, nu este infinita. Nu poate stoca decat o cantitate limitata de informatii.
Spre deosebire de lumea matematicii pure, lumea calculatoarelor este una in care datele reprezinta, deseori, o resursa pretioasa.
Dincola de suprafata, formatul intre si cel in virgula mobila nu sunt deloc asemanatoare. In majoritatea cazurilor, diferentele sunt invizibile pentru utilizator ; este suficient sa folositi tipul de care aveti nevoie si lasati detaliile in seama programului C++. Uneori, insa, compilatorul va va avertiza cu privire la "conversii" sau "pierderi de date" , cazuri in care este util sa stiti la ce se refera.
Iata modul de stocare a unei valori, in speta 150, in format intreg si in virgula mobila. ( Am facut cateva presupuneri simplificatoare. De fapt, formatele in virgula mobila folosesc o reprezentare binara, nu zecimala. )
Bitul de semn s indica daca numarul este pozitiv sau negativ, valoarea 0 indicand un numar nenegativ.
Campul exponent este cel care face diferenta intre formatul in virgula mobila si cel intreg, determinand si plusul de flexibilitate al primului format. Sa consideram problema stocarii valorii 10 la puterea 18. Iata cum arata numarul :
1 000 000 000 000 000 000
Aceasta valoarea nu poate fi stocata intr-o variabila intreaga. Nu exista suficient spatiu. Dar o variabila in virgula mobila poate stoca usor o asemenea valoare ; totul se reduce la utilizarea unui camp exponent suficient de mare. ( Exponentul va fi 18 in cazul in care calculatorul foloseste formatul zecimal. In formatul binar, adica acela folosit in realitate de catre calculator, valoarea exponentului este de cateva ori bune mai mare decat aceasta ) . Iata un mod concis de reprezentare a acestui numar in C++ :
1e18
Ideea este ca trebuie sa folositi tipul corect de date pentru fiecare aplicatie in parte. Pentru a stoca un numar fara virgula, puteti folosi, daca doriti, stocarea in format virgula mobila ( ca si numarul 150 din exemplul de mai sus ) . Dar acest format necesita mai mult spatiu si este mai complex decat formatul intreg. Practic, calculatorul este pus la o treaba mai grea decat trebuie. Este mai bine sa folositi formatul intreg atunci cand lucrati numai cu numere fara virgula, cu conditia ca acestea sa se gaseasca in intervalul standard al numerelor intregi ( aproximativ doua miliarde, adica doua mii de milioane ).
In unele situatii rare, un camp in format virgula mobila nu poate stoca un intreg cu precizie. Aceasta se intampla numai la valori intregi foarte mari. Iata un alt motiv pentru a evita utilizarea formatului in virgula mobila atunci cand lucrati numai cu numere fara virgula.
O variabila de tip intreg se declara folosind o sintaxa asemanatoare cele utilizate la declararea unei variabile de tip double. Tipul int este o valoare intreaga standard (care ocupa patru octeti pe aproape orice calculator actual).
int nume_variabila ;
Valorile constante sunt, de asemenea, stocate in format intreg sau in virgula mobila. Prezenta unui punct zecimal ( virgula ) determina stocarea automata a valorii in format virgula mobila. Un numar precum 1. 141592 necesita, evident, formatul in virgula mobila si, ca atare, este stocat in forma double. Dar, intrucat contine un punct zecimal, numarul 3.0 este, de asemenea, stocat in format double. Daca se foloseste notatia 3, va fi stocat in format int.
Si acest lucru este important, deoarece C++ va fi "amabil" si va efectua conversiile de date fara reclamatii, insa numai daca poate proceda astfel fara potentiale pierderi de date. De exemplu, o constanta int trebuie convertita in virgula mobila inainte de a fi salvata in format double.
double x ; x = 3 ; // OK: converteste din int.
In acest caz, compilatorul C++ nu protesteaza, deoarece formatul double poate stoca orice valoare care poate fi stocata in formatul int.
Dar , in exemplul urmator, o valoare in virgula mobila ( 3.7 ) trebuie convertita intr-un intreg. Compilatorul executa conversia dorita, dar emite un mesaj de avertizare in care se spune ca este posibila pierderea de date.
int n ; n = 3.7 ; // Atentie: conversie din double in int.
Aici, rezultatul este ca portiunea fractionara 0.7 se pierde, iar valoarea 3 este stocata in variabila n.
Mai putin evident este faptul ca instructiunea urmatoare - care pare foarte nevinovata - are ca rezultat acelasi avertisment, deoarece portiunea "0" are semnificatia unui format in virgula mobila. Pentru compilatorul de C++, orice conversie din formatul in virgula mobila in cel intreg este considerata automat ca suspecta.
n = 3.0 ; // Atentie: conversie din double in int
In ciuda avertismentului, programul continua sa functioneze corect in acest caz, deoarece 3.0 este echivalent din punct de vedere matematic cu 3. Insa majoritatea programatorilor prefera sa se debaraseze de avertismentele din partea compilatorului. Sunt agasante si dau impresia persistenta ca ceva este in neregula.
In acest caz, modalitatea de a scapa de avertismente consta in a specifica o conversie fortata, care cere compilatorului sa converteasca in tipul int. Intrucat, in acest caz, conversia se executa deliberat, compilatorul presupune ca stiti ce faceti si nu emite avertismentul.
n = static_cast<int> ( 3.0 ) ;
Sau , mai bine, puteti transforma constanta intr-un intreg, nu intr-un numar in virgula mobila ; atunci nu este nici o problema, deoarece nu faceti decat sa atribuiti o constanta in format int unei variabile de acelasi format.
n = 3 ;
Ca veni vorba, forma generala a operatorului static_cast este urmatoarea :
static_cast<tip>( expresie )
Operatorul static_cast preia expresia specificata si returneaza o expresie noua, cu aceeasi valoare matematica, dar de tipul indicat.
Exista numerosi operatori de conversie fortata acceptati de versiunile standard de C++ . Operatorul static_cast este cel mai comun dintre acestia ; utilizarea sa este simpla. Ceilalti au utilizari mai specializate.
Luarea deciziilor intr-un program
Luarea deciziilor intr-un program are un caracter limitat. Un calculator poate sa execute numai instructiuni care sunt perfect clare si precise.
Intr-un fel, este un lucru bun ; din alte puncte de vedere, este o provocare. Vestea buna este ca un calculator va face intotdeauna exact ce i se spune. Vestea proasta este ca un calculator va face intotdeauna ce i se spune, indiferent cat de stupid este. Din nou, aceasta este una dintre regulile capitale ale programarii - poate cea mai importanta :
* Un calculator poate executa numai instructiuni perfect clare.
In cazul proceselor decizionale, aceasta inseamna ca un calculator nu cunoaste conceptele de judecata sau discernamant. Calculatorul nu poate decat sa execute reguli precise din punct de vedere matematic - de exemplu, sa compare doua valori pentru a vedea daca sunt egale.
Singurul domeniu in care specialistii in calculatoare sugereaza ca un calculator poate dispune de ceea ce se poate numi discernamant este acela al inteligentei artificiale ( IA ). Dar aceasta este exceptia care confirma regula. Un program sofisticat de luare a deciziilor este alcatuit din mii sau poate chiar milioane de instructiuni individuale, fiecare dintre acestea fiind simpla, precisa si clara.
If si if-else
Cea mai simpla metoda de a programa o comportare este sa spui : " Daca A este adevarat, atunci executa B." Acesta este efectul instructiunii if din C++. Iata forma simpla a sintaxei instructiunii if :
if ( conditie ) instructiune
Exista si forme mai complexe ale acestei instructiuni, despre care vom discuta imediat. Dar, pentru inceput, sa consideram o instructiune if care compara doua variabile x si y. ( Vom presupune ca aceste variabile au fost declarate anterior, conform necesitatilor. )
if ( x == y ) cout << "x este egal cu y. " ;
Ciudat. Aici sunt doua semne egal ( == ) in loc de unul singur ( = ) . Nu este nici o greseala. In aceasta situatie, C++ are doi operatori diferiti : un semn egal indica atribuirea, care copiaza valori intr-o variabila, in timp ce doua semne egal indica verificarea egalitatii.
Observatie : Pe masura ce faceti progrese, veti descoperi ca utilizarea atribuirii ( = ) acolo unde se dorea, de fapt, testarea egalitatii ( == ) reprezinta una dintre cele mai comune erori. Problema este ca se permite folosirea atribuirii ( = ) in interiorul unei conditii, dar atribuirea nu executa o actiune corecta.
Si daca,in loc de a executa o singura instructiune ca raspund la o conditie, doriti sa executati o serie intreaga de operatii? Raspunsul consta in utilizarea unei instructiuni compuse ( cunoscuta si sub numele de "bloc de instructiuni " ) :
if ( x == y ) { cout << " x este egal cu y. " << endl ; cout << " Nu-i asa ca-i dragut? " ; ele_sunt_egale = true ; }
Semnificatia acestei sintaxe este ca fie executa toate aceste instructiuni, fie nu se executa nici una. In situatia in care conditia ( x egal cu y, in acest caz ) nu este adevarata, controlul programului executa un salt dincolo de sfarsitul instructiunii compuse - cu alte cuvinte, la prima instructiune de dupa acolada de inchidere ( } ) .
Acoladele de deschidere, respectiv de inchidere ( { } ) determina inceputul, respectiv sfarsitul instructiunii compuse. Aceasta instructiune se poate include in sintaxa instructiunii if datorita unei alte reguli cardinale :
* O instructiune compusa se poate folosi oriunde se utilizeaza o instructiune scrisa in sintaxa C++.
Din punct de vedere tehnic, o instructiune compusa nu este decat o instructiune ca oricare alta. Observati ca instructiunea compusa nu se incheie cu punct si virgula ( ; ) . Numai instructiunile care o compun se termina astfel. Aceasta este una dintre exceptiile de la regula caracterului punct si virgula, despre care am vorbit in tutorialul anterior.
Iata din nou sintaxa instructiunii if :
if ( conditie ) instructiune
Aplicand regula de baza pe care am enuntat-o anterior, in loc de instructiune putem insera o instructiune compusa :
if ( conditie ) { instructiuni }
unde instructiuni poate reprezenta zero sau mai multe instructiuni.
Se mai pot specifica si actiuile care trebuie executate in cazul in care conditia nu este adevarata. Dupa cum probabil ghiciti, aceasta varianta foloseste cuvantul-cheie else ( altfel ).
if ( conditie ) instructiune1 else instructiune2
Ca de obicei, instructiune1, instructiune2 sau ambele pot fi instructiuni compuse. Acum avem sintaxa completa a instructiunii if.
Iata un scurt exemplu.
if ( x == y ) cout << " x este egal cu y " ; else cout << " x NU este egal cu y " ;
Acest program poate fi rescris astfel incat sa utilizeze instructiuni compuse, chiar daca acest lucru nu este absolut necesar :
if ( x == y ) { cout << " x este egal cu y " ; } else { cout << " x NU este egal cu y " ; }
Toate liniile de program cuprinse intr-o sintaxa if sau if-else pot fi scrise in acest mod, motiv pentru care acoladele apar intotdeauna, chiar daca blocurile de instructiuni rezultante cuprind fiecare cate o singura instructiune. Personal nu folosesc aceasta metoda , fiindca necesita munca suplimentara, chiar daca unii programatori o recomanda calduros.
Avantajul metodei prezentate ( care foloseste mereu instructiuni compuse in sintaxa if ) este acela ca se poate reveni si adauga o instructiune sau doua intre acolade, fara ca prin aceasta programul sa devina incorect. De regula, eu adaug acoladele dupa necesitati, dar poate preferati aceasta abordare mai precauta. Labels: programare-c++
Responses
0 Respones to "Introducere in Limbajul de Programare C++. Notiuni de baza. PARTEA 2"
Trimiteți un comentariu