You are on page 1of 42

C este numit un limbaj de programare „de nivel mediu”.

Această etichetă nu este datorată


unei lipse de „putere” a limbajului de programare (din potrivă C este considerat de mulţi ca un
Fundamentele programării şi programare limbaj „prea puternic”) ci mai degrabă a posibilitatea de a accesa funcţii de sistem de nivel
procedurală coborât. Majoritate limbajelor de nivel înalt Pasal, Java etc. presupune faptul că orice ar avea
nevoie programul există deja în limbaj. Un limbaj de nivel coborât (de exemplu un limbaj de
asamblare) furnizează doar un acces la instrucţiunile de bază ale unităţii centrale. Un limbaj de
Curs 1 Introducere în limbaje de programare nivel intermediar ca de exemplu C nu are toate construcţiile găsite în limbajele de nivel înalt
dar furnizează un mod de programare suficient de elegant asemănător unui limbaj de nivel
Obiective: înalt oferind pe de altă parte şi unelte operaţii şi facilităţi întâlnite la limbajele de nivel
coborât.
Acest curs are scopul de a forma o privire de ansamblu asupra programării în general şi a
programării C în particular.
Folosirea limbajului C
C a fost folosit la început pentru a dezvolta sisteme de operare. Practic peste 80% din
Limbaje de programare
Linux este scris în C. De ce? Pentru că programul C generat rulează aproape la fel de rapid ca
Limbajul de programare poate fi definit astfel: cel scris în limbaj de asamblare, dar modul de scriere al programelor este asemănător cu cel al
O unealtă software ce permite unui programator să scrie comenzi într-un format care limbajelor de nivel înalt.
poate fi uşor de înţeles şi reţinut de o persoană şi poate fi tradus într-un cod pe care un Ce fel de programe sunt scrise în C:
calculator îl poate înţelege şi executa. • Sisteme de operare
Există foarte multe limbaje de programare El este apropiat de limbajul natural şi de aceea • Compilatoare de limbaj (compilatoarele de C dar nu numai sunt de obicei scrise in C)
este un excelent mod de a explica un algoritm. Din exemplul de mai sus reiese cu claritate
• Asambloare
finitudinea algoritmului şi eficacitatea acestuia. Este un algoritm generalizat deoarece este
• Editoare de text
conceput pentru a rezolva orice ecuaţie de gradul I. Pentru a putea fi generalizată, orice soluţie
algoritmică are nevoie de a verifica datele din toata plaja posibilă de valori. Algoritmului • Drivere de reţea
trebuie să poată accepta date de intrare, de a le prelucra şi de a le afişa ca rezultate. Aceste • Baze de date sau programe care gestionează baze de date
lucruri nu sunt posibile decât dacă datele pot fi "memorate". Cea mai folosită cale de a • Interpretoare de comenzi
memora şi identifica date este aceea de a folosi variabile. • Programe utilitare
• etc.
Popularitate limbajului C a făcut ca alte limbaje de programare moderne sa fie „inspirate”
De ce să folosim limbajul C? din C ca funcţionalitate sau sintaxă; dintre acestea aş aminti Java şi php dar sunt multe altele.
Limbajul de programare C în ciuda „vârstei” sale destul de înaintate este şi rămâne un
limbaj de succes în rezolvarea oricărei probleme de programare imaginate de cineva, de la Istoric
programe parte integrantă a sistemelor de operare până la programe de inteligenţă artificială, C este un limbaj de uz general, care este asociat de sistemul de operare UNIX (din care a
oferind compilări eficiente pe toate calculatoarele existente de la controlerele roboţilor derivat apoi şi Linux), sistem care foloseşte intensiv acest limbaj fiind în foarte mare măsură
industriali până la supercalculatoare. scris în C.
Acest succes se datorează folosirii unitare si bine structurate a următoarelor concepte Ideile din limbajul C au fost preluate din limbajul BCPL, dezvoltat de Martin Richards.
practice: Fiind precedat de limbajul B scris de Ken Thompson în 1970 la Bell Labs, pentru primul
• O varietate mare si puternică de operatori; sistem UNIX pe calculatore DEC PDP-7.
• O sintaxă elegantă; În 1972 Dennis Ritchie de la Bell Labs scrie limbajul C şi în 1978 publică „The C
• Conceptul de biblioteci standard; Programming Language” de Kernighan & Ritchie având ca rezultat ă revoluţie în lumea
• O accesibilitate sporită la nivel hardware; calculatoarelor.
În 1983, American National Standards Institute (ANSI Institutul Naţional de Standarde
• Posibilitatea facilă de a optimiza codul pentru fiecare bucăţică de program în parte
American) stabileşte o definire clară a termenelor pentru limbajul C, rezultatul fiind definirea
• Portabilitate între calculatoare;
standardului ANSI pentru C supranumit "ANSI C", care apoi a fost completat în 1988.

1
Curs 2 Noţiunea de algoritm El este apropiat de limbajul natural şi de aceea este un excelent mod de a explica un
algoritm. Din exemplul de mai sus reiese cu claritate finitudinea algoritmului şi eficacitatea
Def.1. Un algoritm este o succesiune de paşi finită, cu punct unic de intrare şi de acestuia. Este un algoritm generalizat deoarece este conceput pentru a rezolva orice ecuaţie de
ieşire, care conduce într-un timp finit la rezolvarea unei clase de probleme. gradul I. Pentru a putea fi generalizată, orice soluţie algoritmică are nevoie de a verifica datele
din toata plaja posibilă de valori. Algoritmului trebuie să poată accepta date de intrare, de a le
Def2. Algoritmul este un mod prin care o transformare este descrisa sistematic şi prelucra şi de a le afişa ca rezultate. Aceste lucruri nu sunt posibile decât dacă datele pot fi
condiţional în desfăşurarea sa. "memorate". Cea mai folosită cale de a memora şi identifica date este aceea de a folosi
Transformarea impune de obicei folosirea unor valori numite date de intrare sau parametrii variabile.
de intrare pe care algoritmul le transformă în rezultate sau date de ieşire. O variabilă este o zonă identificabilă de memorie a cărei valoare poate fi modificată
Algoritmii au următoarele caracteristici: prin acţiunile algoritmului.
Caracteristicile variabilelor sunt
• identificarea de obicei realizată printr-un nume (format dintr-o înşiruire de litere şi cifre).
Date Algoritm Date Numele unei variabile dacă există se numeşte identificator;
de de • tip de date. Este indicat ca să se cunoască ce fel de date vor fi memorate de către variabilă.
intrare ieşire Unele limbaje de programare (în special interpretoarele) admit existenţa unui tip de date
variabil adică variabila poate în perioada sa de definiţie să-şi modifice tipul.
• generalizare: adică sunt concepuţi pentru a rezolva cu succes mai multe probleme care au
• zonă de memorie care va conţine valoarea la un moment dat a variabilei. Dimensiunea
o cale de rezolvare asemănătoare
rezervată pentru o variabilă este de obicei în funcţie de tipul de dată pe care îl conţine.
• determinism: adică obţinerea de rezultate identice pentru valori de intrare identice
Localizarea exactă a zonei de memorie este de obicei cunoscută doar în momentul execuţiei
• finitudine: procesul de prelucrare se termină după un număr finit de paşi; (există cazuri în programului.
care programele scrise nu respectă această condiţie ceea ce conduce la buclă infinită) Variabila îşi poate schimba valoarea pe parcursul parcurgerii algoritmului, dar la un
• claritate: toate acţiunile sau condiţionările din algoritm sunt clar specificate moment dat o variabilă nu poate avea decât o singură valoare. Valoarea variabilei poate fi
Exemplu1: utilizata de către algoritm prin intermediul numelui: oriunde apare numele unei variabile se
Rezolvarea unei ecuaţii de gradul I. înţelege de fapt valoarea pe care aceasta o are la momentul respectiv.
Analiza problemei: Forma generala a unei ecuaţii de gradul I este ax+b=0. Prin tip de date se înţelege gruparea datelor asemănătoare ca domeniu de definiţie sub
Date de intrare: a şi b. un nume numit identificator de tip de date.
Date de ieşire: rădăcina calculata x a ecuaţiei sau un mesaj ("nu exista În general, tipurile de date utilizate în informatica sunt submulţimi ale mulţimilor
soluţie" sau "Există o infinitate de soluţii") cunoscute din matematica. Limitarea plajei de valori este datorată caracterului finit al zonei de
Procesul prelucrării datelor de intrare poate fi descris astfel: memorie folosite memorare. De exemplu, în limbajul C++ sunt utilizate, printre altele,
PAS 1. Se citesc valorile coeficienţilor a, b; următoarele tipuri:
PAS 2. Dacă a=0 şi b=0 atunci se afişează "Există o infinitate
de soluţii"; int: valori întregi intre -32767 şi 32768 (memorare pe 2octeţi);
PAS 3. Dacă a=0 şi b<>0 atunci se afişează "nu exista soluţie"; long int: valori întregi intre -2147483648 şi 2147483647 (memorare pe 4octeţi)
PAS 4. Dacă a<>0 atunci soluţia este x=-b/a;
PAS 5. Afişează valoarea lui x; Obs. Compilatoarele C moderne memorează tipul int pe 4 octeţi, iar un întreg cu semn
Pentru a reprezenta un algoritm putem alege orice model care repezită dezideratele arătate reprezentat pe 2 octeţi se numeşte short int.
mai sus. Algoritmul din exemplul anterior a fost reprezentat prin pseudocod. Unii autori considera inclusă în definiţia tipului de date şi mulţimea operatorilor şi
Pseudocodul este un mod de a descrie liber (fără îngrădiri) a unui algoritm. funcţiilor care se pot aplica elementelor tipului respectiv. De exemplu, pentru un tip întreg,
exista operaţii specifice: împărţirea întreagă şi modul aritmetic (restul împărţirii întregi).
Prin constantă înţelegem o valoare fixă, care nu se modifică de-a lungul aplicării unui
algoritm.
Constantele se reprezintă uzual printr-o valoare efectiva:
3, -2, -123, 9452 sunt constante întregi
3.456, 2.000, 3.4000E+10 sunt constante reale
'a', 'B', '&' sunt constante de tip caracter
2
'ecuaţia are o infinitate de soluţii !' este o constanta şir de caractere

Modalităţi de reprezentare a algoritmilor 6. Blocul de decizie


Nu Da
Schema logică Nu
C
Da
C
Cea mai utilizata metoda de scriere a algoritmilor, cel puţin pentru începătorii în
programare, este aceea a utilizării schemelor logice, care descriu operaţiile ce pot fi aplicate Blocul de decizie evaluează valoarea de adevăr a condiţiei C şi, dacă aceasta este
datelor prin simboluri grafice numite blocuri. adevărata se trece pe ramura DA, iar dacă este falsă pe ramura NU.
Sunt utilizate următoarele blocuri: 6. Conectori
1.Blocul START: Conectarea blocurilor ce formează o schema logica se realizează cu ajutorul unor săgeţi,
START Este blocul care indica începutul oricărei scheme logice şi este folosit o acestea indicând şi sensul de efectuare a operaţiilor ce compun schema logică.
singura dată (orice schema logica are un început unic). De asemenea, pentru a putea reuni mai multe săgeţi se
2.Blocul STOP folosesc cerculeţe. Cerculeţele mici fără text încorporat au rolul
STOP Este blocul care încheie schema logica şi este, de asemenea, unic. de a uni estetic mai multe linii (conectori). Cerculeţele mai mari
având încorporate de obicei o literă din alfabetul grecesc pot
α avea rolul de a indica o continuare a schemei logice pe o altă
3.Blocul de citire α
Blocul de citire corespunde operaţiei de introducere a datelor, în timpul căreia se aşteaptă pagină sau se folosesc pentru a elimina săgeţile lungi inestetice.
ca utilizatorul să introducă valori concrete, ce vor fi stocate în zona de memorie alocata
variabilelor prezente după comanda CITEŞTE. Scheme logice structurate
Cu alte cuvinte, pentru fiecare variabila al cărui Schema logică poate fi definită ca o succesiune de blocuri de tipurile prezentate mai
CITEŞTE nume este precizat în blocul de citire se cere sus, cu următoarele caracteristici:
introducerea unei valori. a. conţine un singur bloc Start şi un singur bloc Stop;
b. în fiecare bloc intra o singura săgeata şi, cu excepţia blocului de decizie, iese o singura
4. Blocul de scriere săgeata (blocurile au o singura intrare şi o singura ieşire)
c. exista cel puţin un “traseu” ce pleacă din blocul Start şi mergând în sensul săgeţilor se
ajunge în blocul Stop;
Blocul de scriere corespunde operatei de afişare a
valorii unei variabile sau a unui mesaj. După comanda secvenţa Execuţie Execuţie d. blocul de decizie poate
SCRIE condiţionată simplă condiţionată
SCRIE se precizează o lista cu numele variabilelor a conţine, pe cele doua ramuri, orice
completă
căror valoare va fi afişată şi a mesajelor. combinaţie de blocuri dintre cele
A1
prezentate;
Nu Da Nu Da O schema logica ce are aceste
5.Blocul de calcul C C
A2 proprietăţi reprezintă un algoritm
variabila  expresie A A2 A1 structurat.
Blocul de calcul corespunde operaţiei numite atribuire, care are ca efect calcularea
valorii expresiei şi memorarea valorii obţinute în zona de memorie alocata variabilei var.
Schimbarea valorii unei variabile se poate realiza fie prin utilizarea unei atribuiri, fie prin
citirea valorii prin intermediul unei operaţii de citire. Există şi un bloc de calcul de forma care Sunt posibile următoarele combinaţii de operaţii ce descriu tipuri de scheme logice
indică o acţiune complexă (grafic indicat prin dublarea marginilor laterale), de obicei o structurate:
procedură. Uzual informaţiile din blocul de calcul sunt sub forma unor atribuiri variabila  1. Secvenţa înseamnă de fapt două sau mai multe acţiuni care se vor desfăşura una în
expresie care se traduc prin modificarea valorii variabilei cu valoarea dată de calculul continuarea celeilalte (adică acţiunea A2 se va realiza doar după încheierea acţiunii A1)
expresiei.
3
2. Execuţii condiţionate. Ele sunt de două feluri. Simplă, în cazul în care acţiunea apare doar VOCABULARUL (LEXICUL): mulţime de cuvinte acceptate ca făcând parte din
pe ramura Da, respectiv completă, în cazul în care apar acţiuni pe ambele ramuri ale condiţiei limbaj
C. Se numeşte UNITATE LEXICALA cea mai mica "îmbinare" de caractere din
Condiţia simpla se exprimă prin: vocabular, care are un înţeles.
Dacă C atunci A Exista un set de reguli privind combinarea unităţilor lexicale în cuvinte şi a cuvintelor în
sau în engleză "fraze" (reguli de SINTAXA), respectarea regulilor ducând la obţinerea unor construcţii
If C then A corecte. SEMANTICA unui limbaj se refera la înţelesul structurilor obţinute prin combinarea
iar cea completă se exprimă prin cuvintelor acceptate de limbaj.
Dacă C atunci A1 altfel A2 În vocabular avem:
sau în engleză cuvinte cheie = cuvinte sau prescurtări ale unor cuvinte din limba engleza, ce
If C then A1 else A2 reprezintă elemente de limbaj participând la crearea unor construcţii sintactic corecte
Buclă cu Buclă cu 3. Bucle, care se folosesc pentru execuţia repetată (de exemplu comenzi sau instrucţiuni).
test iniţial test final a unei acţiuni până în momentul în care condiţia Cuvintele cheie sunt tratate diferit de restul textului din program de aceea ele trebuie
devine falsă. Există două tipuri de bucle, cu test cunoscute şi folosite doar în modul şi locul în care ele au fost definite.
iniţial în care secvenţa este test-acţiune, si bucle cu identificatori = nume folosite pentru variabile, tipuri de date şi funcţii definite de
test final în care secvenţa este de tip acţiune-test utilizator.
Da A Un identificator este format dintr-un şir de caractere care începe cu o litera şi poate conţine
C Bucla cu test iniţial se exprimă prin: litere, cifre şi caracterul "_" (underscore). Identificatorul, în funcţie de limbajul în care este
atât timp cât C execută A folosit nu poate conţine în general spatii sau apostrof, virgula, ghilimele ... Identificatorii nu
A Da pot coincide cu cuvintele cheie.
Nu C sau în engleză
while C do A Prin PROGRAM se înţelege o succesiune de comenzi(instrucţiuni) de prelucrare a
iar cea cu test final se Nu exprimă prin datelor, scrise intr-un limbaj de programare.
execută A atât timp cât C Programul este memorat intr-o entitate numita fişier sursa (este un fişier text).
sau în engleză Prelucrările dintr-un program C++ sunt grupate în FUNCŢII. Rezolvarea unei probleme se
do A while C face prin utilizarea unor funcţii definite în limbaj şi / sau a unor funcţii scrise de programator,
Să revenim puţin asupra operaţiei de atribuire, operaţie care se efectuează într-un bloc de atunci când funcţiile deja existente nu sunt suficiente. Funcţiile pe care limbajul le pune la
calcul şi care implică definirea mai multor termeni: dispoziţia utilizatorului sunt grupate, după tipul de prelucrare oferit, în mai multe fişiere
numite "biblioteci" (fişiere HEADER). Pentru a putea utiliza o funcţie trebuie să se specifice
la începutul programului numele bibliotecii care conţine funcţia respectiva.
Prezentarea generală a noţiunii de limbaj de Orice program C++ trebuie să conţină o funcţie numita "main" (un fel de “program
programare principal”), instrucţiunile conţinute de aceasta fiind cele prelucrate atunci când programul este
lansat în execuţie.
Am văzut în secţiunea precedenta cum pot fi reprezentaţi algoritmii prin utilizarea Pentru a se putea obţine rezultatele prelucrării datelor cu ajutorul programelor, trebuiesc
pseudocodului sau a schemelor logice, insă prelucrarea automata a datelor presupune scrierea parcurse următoarele faze:
algoritmului intr-o forma ce poate fi înţeleasă de calculatorul electronic. Algoritmii vor fi
• scrierea programului (editarea textului sursa);
scrişi intr-un “limbaj de programare”, care va conţine operaţii asemănătoare celor despre care
• compilarea programului (=verificarea corectitudinii sintactice şi semantice a textului sursa
am amintit, numite acum instrucţiuni.
şi prelucrarea sa fişier obiect)
Limbajul de programare conţine:
ALFABETUL: o mulţime de simboluri pentru scrierea cuvintelor din limbaj. • editarea legăturilor (fişierul / fişierele obiect obţinute în urma compilării sunt transformate
Majoritatea limbajelor de programare folosesc alfabetul latin specific limbii engleze, cifre intr-un fişier executabil, adică într-un fişier care poate fi lansat în execuţie prin simpla scriere
arabe, simboluri matematice etc. organizate sub forma unei codificări ASCII. Codificarea a numelui sau la prompt-ul sistemului de operare;
ASCII este de fapt o echivalarea a fiecărui simbol uzual folosit cu o valoare numerică (iniţial Numim mediu de programare un program care permite asistarea programatorului în
în intervalul [0, 127]). Înţelegerea acestei codificări de altfel intens folosită nu numai în toate fazele de elaborare a unui program, scris intr-un limbaj de programare (editare,
programare este fundamentală în a înţelege modul în care se memorează datele în calculator. depanare, compilare, execuţie).
În paragraful următor vor fi prezentate elementele de baza ale limbajului C.

4
Lista cuvintelor cheie ale limbajului C depinde de tipul de compilator folosit pentru
Prezentarea generala a limbajului C++ mediul Borland C++ este:
auto break case char const continue default do double else
Alfabetul enum extern float for goto if int long register return short
signed sizeof static struct switch typedef union unsigned void
Alfabetul limbajului este format din acele simboluri utilizate la reprezentarea volatile while
entităţilor unui program, adică a unitarilor lexicale. Identificatorii definiţi de utilizator nu trebuie să coincidă cu cuvintele rezervate. În
Reamintim ca, prin unităţi lexicale înţelegem cele mai mici entităţi cu valoare semantica limbajul C++ se mai adaugă câteva cuvinte cheie, care vor fi descrise la momentul oportun (în
(adică au o semnificaţie), prin combinarea cărora rezulta construcţiile sintactice ("propoziţii şi capitolul rezervat programării orientate obiect).
fraze").
Alfabetul limbajului C se compune din următoarele categorii de simboluri:
• Literele mari şi mici ale alfabetului englez şi caracterul de subliniere "_" (eng. Comentarii
underscore) Comentariile sunt acele şiruri de caractere utilizate la explicarea programelor sursa,
• Cifrele arabe: 0-9 delimitate prin caractere speciale care determina ignorarea lor de către compilator.
• Semne de punctuaţie: ; , ‘ " Un comentariu este o construcţie de forma /* … */ ca de exemplu:
• Alte caractere: /* şir
+, -, *, / de
(, ), {, }, [, ], \, caractere */
~, ^, <, >, =, ?, !, #, &, sau de forma // … ca de exemplu:
Literele şi cifrele, precum şi caracterul underscore, de multe ori asimilat în mulţimea // şir de caractere comentariu până la sfârşit de linie
literelor, sunt utilizate pentru construirea identificatorilor şi cuvintelor cheie, după reguli ce unde prin şir de caractere se înţelege o secvenţa de caractere din setul caracterelor
vor fi descrise în paragrafele corespunzătoare. În limbajul C se face diferenţa dintre literele reprezentabile, mai puţin combinaţia */. Nu se admit comentariile imbricate (adică un
mici şi majusculele corespunzătoare, deci identificatorul "a" va fi diferit de identificatorul "A". comentariu în alt comentariu). Comentariul poate fi scris pe mai multe linii dacă este scris în
prima formă. A doua formă este specifică pentru C++ şi permite scrierea unor comentarii ce
nu depăşesc o linie.
Identificatori
Identificatorul reprezintă nume pe care le atribuim variabilelor, constantelor,
funcţiilor, tipurilor de date definite de utilizator.
Tipuri de date
Un identificator este o secvenţa de litere, cifre şi caracterul underscore, primul caracter Definiţia noţiunii de tip de dată cuprinde, pe lângă mulţimea de valori a tipului, şi alte
trebuind să fie litera sau underscore. Folosiţi cu multa precauţie identificatori care încep cu aspecte:
underscore, pentru a nu intra în conflict cu numele rutinelor sistem, a căror ortografiere nu se • dimensiunea memoriei alocate
cunoaşte (numele rutinelor sistem încep întotdeauna cu "_"). • mulţimea operaţiilor ce acţionează asupra elementelor tipului
Regulile de formare a identificatorilor sunt aceleaşi cu regulile din Pascal. Un identificator • timpul de viata asociat datei, dat de clasa de memorie
poate avea, teoretic, o lungime arbitrara, dar în general doar primele 31 de caractere sunt luate Aceste tipuri de date le vom folosi în continuare deoarece acesta defineşte o foarte
în considerare de compilator (iarăşi depinde de compilator). importantă proprietate a constantelor cât şi a variabilelor folosite în programare. Tipurile de
Compilatorul de C face distincţie între literele mici şi cele mari din numele identificatorilor date sunt:
(eng case sensitive) astfel că identificatorii următori sunt toţi diferiţi între ei: • tipuri de baza: tipuri predefinite în limbaj;
nume, Nume, NuME, NUMe o caracter (char) - memorează un singur caracter scris în codificare ASCII
Exemple (virgula are rol de separare): (memorare pe 1octet) – pentru C tipul char poate fi de asemenea asimilat unui tip
i, j, abc, tablouDeCaractere, tablou_de_caractere, _, _1, întreg de dimensiunea unui octet.
o diferite variante de tipuri întregi întreg (int), care vor memora date întregi având de
Cuvinte rezervate (eng. keywords) la valori în intervalul [32767, 32768] (memorare pe 2octeţi) până la valori memorate
pe 4 octeţi.
Numele rezervate instrucţiunilor, tipurilor predefinite şi sintaxei de definire a funcţiilor
şi tipurilor de date se numesc cuvinte cheie.

5
o real (float, double, long double) folosite pentru a memora valori raţionale ân limite unsigned int depinde de întreg fără semn [0, 65535] sau [0, 4294967295]
foate largi de reprezentare, unde precizia (numărul de cifre posibil de reprezentat( implementare [UINT_MIN, UINT_MAX]
2 sau 4 octeţi
devine de asemenea importantă. 4 Octeţi complement faţă
long [-2147483648,2147483647]
• tipuri derivate: tipuri definite de utilizator; long int de 2 [LONG_MIN , LONG_MAX]
o enumerare signed long
signed long int
o referinţa
unsigned long 4 Octeţi întreg fără semn [0,4294967295]
o structurate: unsigned long [ULONG_MIN, ULONG_MAX]
o tablou int
o structura Primul tip este tipul caracter. O variabila de acest tip va avea ca valoare codul ASCII
o uniune asociat caracterului respectiv. De exemplu, dacă unei variabile i se atribuie caracterul ’a’,
variabila va conţine valoarea 97 (numărul de ordine al caracterului ’a’ în codul ASCII).
Tipuri de date predefinite Tipul întreg cel mai des utilizat în programe este int, dar numărul de Byte (octeţi) pe care
Tipurile de baza definite în limbajul C sunt: întreg, real şi caracter. Exista insa mai multe se memorează valorile de acest tip diferă de la o implementare la alta a limbajului C (în
tipuri întregi şi reale, în funcţie de numărul de biţi pe care se pot memora valorile şi dacă funcţie de tipul calculatorului). Astfel, tipul int este echivalent cu short int sau long int, în
valorile sunt cu sau fără semn. În plus, unele dintre aceste tipuri diferă de la o implementare la funcţie de implementare.
alta a limbajului (în funcţie de calculatorul pe care se lucrează). În tabelul următor sunt Celelalte tipuri întregi sunt obţinute prin folosirea prefixului signed sau unsigned, indicând
prezentate tipurile fundamentale, memoria necesara stocării valorilor de acel tip şi limita dacă valorile respective sunt cu semn (conţin şi valori negative), respectiv fără semn ( valori
valorilor ce pot fi memorate intr-o variabilă de acel tip. naturale).
Exemplu: Un program C pentru a identifica tipurile de date folosite de compilatorul curent
Tipuri de date întregi #include <stdio.h>
Tipuri întregi de date #include <limits.h>
Tipul Dimensiune Tip Limita valorilor definită mai volatile int char_min = CHAR_MIN;
memorie reprezentare clar de <limits.h>
char 1 Octet (Byte) Complement faţă [-128,127] sau [0, 255] int main(void){
de 2 sau întreg [CHAR_MIN,CHAR_MAX] printf("\n\n\n\n\n Tipuri Caracter\n");
fără semn. printf("Numărul de biti pt un caracter: %d\n", CHAR_BIT);
Identifică un printf("Dimensiunea caracterului este: %d byte\n",
caracter ASCII int)sizeof(char));
signed char 1 Octet (Byte) [-128,127] sau printf("Signed char: [%d,%d]\n", SCHAR_MIN, SCHAR_MAX);
[SCHAR_MIN,SCHAR_MAX] printf("Unsigned char: [0,%u]\n", (unsigned int)UCHAR_MAX);
unsigned char 1 Octet întreg fără semn [0, 255] sau printf("Implicit char este: ");
[UCHAR_MIN,UCHAR_MAX] if (char_min < 0)
int depinde de complement faţă [-32768,32767] sau printf("signed\n");
implementare de 2
[-2147483648,2147483647] else if (char_min == 0)
(pentru printf("unsigned\n");
[INT_MIN , INT_MAX]
compilatoarele else
vechi 2octeţi printf("non-standard\n");
pentru cele
moderne 4octeţi) printf("\n Tipuri short\n");
short int 2 Octeţi complement faţă [-32768,32767] sau printf("Dimensiune short int: %d bytes\n",
de 2 [SHRT_MIN, SHRT_MAX] (int)sizeof(short));
2 Octeţi complement faţă printf("Signed short min: [%d,%d]\n",SHRT_MIN, SHRT_MAX);
signed short int [-32768,32767] sau printf("Unsigned short min: [0,%d]\n",
de 2 [SHRT_MIN, SHRT_MAX] (unsigned int)USHRT_MAX);
unsigned short 2 Octeţi întreg fără semn [0, 65535] sau
int [USHRT_MIN, USHRT_MAX] printf("\n Tipuri Int \n");
printf("Dimensiunea pentru int: %d bytes\n",
(int)sizeof(int));

6
printf("Signed int: [%d,%d]\n",INT_MIN, INT_MAX); Exemple: pentru simplitate voi considera o reprezentare a datelor pe un octet (altfel spus pe 8
printf("Unsigned int [0,%u]\n",(unsigned int)UINT_MAX);
biţi) cu semn. O reprezentare a datelor pe 16biţi, 32 de biţi etc. se realizează simulat cu cea
printf("\n Tipuri Long Int\n"); descrisă de exemplele mele numai că numărul de biţi diferă.
printf("Dimensiunea pentru long int: %d bytes\n",
(int)sizeof(long));
printf("Signed long: [%ld,%ld]\n",LONG_MIN, LONG_MAX);
printf("Unsigned long: [0,%lu]\n",ULONG_MAX);
Echivalent
Valoare de
return 0; Hexazecimal Octal Reprezentare Observaţii
reprezentat
} de la 00 la ff de la 000 la 377
Din tabel se observa ca nu exista un tip logic, aşa cum este el definit în alte limbaje de 0 00 000 00 0 0 0 0 0 0 0 este un număr pozitiv deoarece are bitul
semn 0
programare. În limbajul Pascal, tipul logic (BOOLEAN) e definit ca mulţimea cu valorile Valorile se cadrează la dreapta
1 01 001 00 0 0 0 0 0 1
{False, True} împreuna cu operatorii logici cunoscuţi (şi, sau , negaţia logica). În limbajul C
nu s-a definit acest tip dar se foloseşte următoarea convenţie: o expresie este considerată 10 0a 012 00 0 0 1 0 1 0
adevărată dacă valoarea obţinuta la evaluarea ei este nenulă (are o valoare diferită de 0 127 7f 177 01 1 1 1 1 1 1 cea mai mare valoare pozitivă
exprimată prin valoarea 1) şi falsă (are valoarea 0) în caz contrar. Variabilele care se vor folosi -1 Ff 377 11 1 1 1 1 1 1 Se obţine scăzând 1 din reprezentarea lui 0
ca variabile logice vor fi declarate de tip întreg. 0 0 0 0 0 0 0 0-
Tipul char se foloseşte în C pentru a identifica fie o valoare de reprezentare a unui 000 0 0 0 0 1
caracter ASCII fie pentru a reprezenta o valoare întreagă cu un domeniu de valori foarte mic 111 1 1 1 1 1
(256 valori diferite reprezentate pe 1Byte sau Octet).Tipul char diferă de tipul caracter din -128 80 200 1 0 0 0 0 0 0 0 Reprezentarea celei mai mici valori negative
Pascal (unde caracterele nu se „amestecă” cu valorile întregi), în C caracterele fiind de fapt
Avantajul reprezentării în complement faţă de doi a valorilor întregi cu semn este acela că
întregi, care desemnează codul ASCII corespunzător.
operaţiile aritmetice pentru valorile cu semn faţă de cele fără semn sunt identice (abstracţie
făcând de faptul că apar „depăşiri” de reprezentare prin transporturi dincolo de prima cifră a
Complement faţă de 2 reprezentării).
Complementul faţă de 2 reprezintă o modalitate foarte folosită pentru a reprezenta valori
cu semn în memorie. Tipuri de date reale
Pentru a face o reprezentare a unor numere cu semn în memoria calculatorului trebuie să
Tipuri reale de date conform standardului IEEE 754 (mantisă şi exponent)
pornim de la următoarele premize:
Tipul Dimensiune Limite de reprezentare Precizie în cifre
• în calculator se poate reprezenta un număr finit de valori într-o zonă de memorie de
memorie semnificative
dimensiune prestabilită. Regula este că într-un spaţiu de memorie având x buţi vom
float 4 Octeţi [1.175494*10-38 , 3.402823*10+38] 7
putea reprezenta 2x (2 la puterea x) valori distincte. Astfel pe 8 biţi reprezentăm
28=256 valori, pe 16biţi 216=65536 valori etc. double 8 Octeţi [2.225073*10-308, 1.7976931*10+308] 15
long double 10 Octeţi [3.37*10-4932, 1.18*10+4932] 19
• dacă vom dori reprezentarea unor date cu semn atunci trebuie să alocăm jumătate din
spaţiul de reprezentat pentru valorile pozitive şi jumătate pentru cele negative Ultimele trei tipuri din tabel sunt tipuri reale, diferenţa dintre ele constând în cantitatea de
memorie utilizata, intervalul de valori şi precizia memorării valorilor (numărul de zecimale
• semnul de reprezentare (pozitiv sau negativ) trebuie să fie cunoscut
reţinute). Valorile reale se reprezintă conform notaţiei din standardul IEEE 754 (folosind
• calculele realizate cu valorile memorate trebuie sa fie cât mai simple.
semnul, mantisa şi exponentul). De exemplu, pentru tipul float se utilizează reprezentarea
Modalitatea de reprezentare a datelor cu semn la care s-a ajuns şi este foarte cunoscută se
în simpla precizie, folosind un bit de semn, 7 biţi pentru exponent şi 24 de biţi pentru mantisa.
numeşte complement faţă de 2. Această modalitate de memorare foloseşte următoarele reguli:
Aceasta reprezentare are un exponent în limita a 10-37 şi 1038 cu 6 - 7 zecimale precizie.
• primul bit din reprezentare se numeşte bitul de semn şi prin convenţie bitul de semn
Pentru mai multe detalii referitoare la modul de memorare a datelor reale consultaţi
are valoarea 0 pentru numere pozitive şi 1 pentru cele negative
subcapitolul constante reale.
• valorile pozitive sunt memorate ca şi valori direct obţinute ca transformări în baza 2 a
valorilor date cadrate la dreapta şi completate cu zerouri nesemnificative în partea
stângă
• valorile negative sunt obţinute din cele pozitive fiind rezultatul scăderii valorii
pozitive din reprezentarea valorii zero (vezi exemplele de mai jos).
7
Tipul de date void Constanta Tip constantă Tip dată Reprezentare binară
întreagă
O alta caracteristica aparte o constituie introducerea tipului void, pentru a desemna 12 zecimală cu semn short int 00 0 0 0 0 0 0 0 0 0 0 1 1 0 0
“nimic” sau “orice tip”, în funcţie de contextul în care este utilizat. În exemplele de până acum
12u zecimală fără semn unsigned 00 0 0 0 0 0 0 0 0 0 0 1 1 0 0
tipul void a fost folosit pentru a indica faptul ca funcţia main nu întoarce nici o valoare. short int
12ul Zecimală fără semn unsigned 0 0 00 0 0 00 0 0 00 0 0 00 0 0 00 0 0 00 0 0 01 1 0 00
long int
Constante 50000 zecimală cu semn long int 0 0 00 0 0 00 0 0 00 0 0 00 1 1 00 0 0 11 0 1 01 0 0 00
(deoarece
O constantă este (de fapt ca şi o variabilă) o zonă de memorie care are un tip şi o valoare. depăşeşte
Spre deosebire de variabilă valoarea unei constante nu se poate modifica în timpul execuţiei reprezentar
programului. Tipul constantei ca şi valoarea sunt determinate de modul în care această ea de
constantă a fost scrisă. Există mai multe tipuri de constante dintre care amintim: 16biţi)
50000u zecimală fără semn unsigned 0 0 00 0 0 00 0 0 00 0 0 00 1 1 00 0 0 11 0 1 01 0 0 00
• Constante întregi long int
• Constante flotante -13 zecimală cu semn unsigned 11 1 1 1 1 1 1 1 1 1 1 0 0 1 1
• Constante caracter short int
-13u eronat deoarece nu eronat
• Constante şir de caractere se pot reprezenta
numere negative
eronat deoarece 9 nu
Constante întregi -192
este o cifră octală
eronat

Noi suntem obişnuiţi cu sistemul de numeraţie zecimal, adică folosim zece simboluri prin 012 Octală fără semn unsigned 00 0 0 0 0 0 0 0 0 0 0 1 0 1 0
care exprimăm valorile numerice (cifrele de la 0 la 9). Calculatorul, din motive tehnice short int
-012 eronat deoarece nu eronat
lucrează în binar (foloseşte doar valorile 0 şi 1) pentru a reprezenta valorile. Valorile binare se pot reprezenta
sunt destul de greu de memorat şi folosit, de aceea programatorii folosesc frecvent numere negative
reprezentarea în octal (baza 8) sau hexazecimal (baza 16) a datelor. Limbajul C fiind mai 0x12 hexazecimală fără unsigned 00 0 0 0 0 0 0 0 0 0 1 0 0 1 0
apropiat ca alte limbaje de codul maşină şi fiind folosit pentru a descrie sisteme de operare semn short int
0xaa2b hexazecimală fără unsigned 11 0 0 1 1 0 0 0 0 1 0 1 1 0 1
permite utilizarea nu numai a valorilor scrise zecimal dar şi octal sau hexazecimal. semn short int
O constantă întreagă zecimală cu semn se scrie în C fără nici un prefix sau sufix. 0XAbCdE hexazecimală fără unsigned 0 0 00 0 0 00 0 0 01 0 1 01 0 1 11 1 0 01 1 0 11 1 1 00
Constantele sunt reprezentate fie pe 16 biţi (dacă valoarea variabilei este în intervalul de semn long int
reprezentare a unei valori de tip short int adică [-32768,32767], sau reprezentare pe 32 de -0x12 eronat deoarece nu eronat
se pot reprezenta
biţi dacă fie depăşeşte intervalul de definire pentru short int (dar valoarea ei este in hexazecimal numere
intervalul unui long int [-2147483648, 2147483647]) sau valoarea este postfixată cu negative
caracterul L sau l (de exemplu 12345678, 23l sau 123L).
O constantă întreagă zecimală fără semn se scrie în C folosind sufixul u sau U.
Constantele sunt reprezentate fie pe 16 biţi (dacă valoarea variabilei este în intervalul de Constante flotante
reprezentare a unei valori de tip unsigned short int adică [0,65535], sau reprezentare
O constantă flotantă se foloseşte pentru a reprezenta un număr raţional şi este compusă din
pe 32 de biţi dacă fie depăşeşte intervalul de definire pentru unsigned short int (dar
maxim trei componente plus eventual un indicator de tip:
valoarea ei este in intervalul unui long int [0, 4294967295]) sau valoarea este postfixată
• parte întreagă – o constantă zecimală
de caracterele ul, lu, UL, sau LU (de exemplu 12345678u, 23ul sau 123LU).
• parte fracţionară – un indicator separator de parte zecimală (reprezentat printr-un
O constantă întreagă octală este o valoare fără semn scrisă în baza 8 (o succesiune de cifre
punct zecimal) urmat eventual de mai multe cifre zecimale
de la 0 la 7) începând obligatoriu cu valoarea 0 (zero). De exemplu 0123 este o constantă
• exponent – un indicator de exponent (litera e sau E), urmată de o valoare
octală iar 123 este o constantă zecimală. Ca şi constanta zecimală, constanta octală poate fi
zecimală cu semn care reprezintă o putere a lui 10 la care este înmulţită valoarea.
reprezentată pe 16biţi sau (dacă are o valoare mare sau este postfixată cu litera l sau L) pe
Oricare dintre cele trei părţi poate lipsi dar, la scrierea unei astfel de contante trebuie ţinut
32de biţi.
cont de faptul că obligatoriu trebuie să fie prezentă fie partea fracţionară, fie partea de
Exemple:
exponent fie indicatorul lor.
8
În C exista trei tipuri de date reale (float, double şi long double), în consecinţă există 2. 11 biţi exponent (pentru a reprezenta exponenţi negativi există o valoare – pentru
posibilitatea de a folosi trei tipuri de constante reale: dublă precizie 1023 (210-1) – care trebuie scăzută din exponent pentru a indica
• constanta double – se reprezintă pe 64biţi, nu are sufix deci este implicită în C valoarea exactă a exponentului.
• constanta float – se reprezintă pe 32biţi şi are sufixul f sau F 3. 52 biţi pentru a memora partea zecimală normalizată a valorii de reprezentat (53 biţi
• constanta long double – se reprezintă pe 80 de biţi şi are sufixul l sau L precizie reală) adică cca. 15 cifre zecimale.
Tipul long double are o reprezentare pe 80 biţi. Modul de reprezentare conţine:
Reprezentarea datelor flotante conform IEEE 754-2008. 1. 1 bit de semn (0 reprezintă un număr pozitiv, 1 un număr negativ)
2. 15 biţi exponent (pentru a reprezenta exponenţi negativi există o valoare – pentru
Tipul float Conţine precizie 214-1 – care trebuie scăzută din exponent pentru a indica valoarea exactă a
1. 1 bit de semn (0 reprezintă un număr pozitiv, 1 un număr negativ) exponentului.
2. 8 biţi exponent (pentru a reprezenta exponenţi negativi există o valoare (eng. bias) – 3. 64 biţi pentru a memora partea zecimală normalizată a valorii de reprezentat (65 biţi
pentru simplă precizie 127 – care trebuie scăzută din exponent pentru a indica precizie reală) adică cca. 19 cifre zecimale.
valoarea exactă a exponentului. Observaţii:
3. 23 biţi pentru a memora partea zecimală normalizată a valorii de reprezentat (24 biţi 1. Cele trei reprezentări reale sunt destul de complicate dar de multe ori dorim sa folosim
precizie reală) această parte se mai numeşte şi mantisă. în calcul numere raţionale deci utilizarea lor este pe deplin justificată.
Precizia reală este dată de faptul că în mod implicit primul bit al unei reprezentări este 2. Calculatoarele personale moderne folosesc procesoare ce realizează calcule în virgulă
totdeauna 1 (şi nu este direct reprezentat) flotantă folosind o reprezentare a datelor pe 80 de biţi (deci precizie de long
Exemplu: 25 se reprezintă astfel: double).
• Valoarea sa normalizată este 25(10)=11001(2) = 1,1001*24
• Deducem că:
• Semnul 0 deoarece numărul este pozitiv Constantă caracter
• Exponentul este 127(bias) + 4 = 131 reprezentat ca 10000011 în baza 2 Există multe programe sau subprograme care sunt scrise cu scopul de a prelucra text.
• Mantisa este 1,1001 din care cifra supraunitară nu se scrie deci 1001 Unitatea fundamentală a textului este caracterul. Caracterul este o modalitate simplă şi
deci în final numărul este: elegantă de a reprezenta literele, cifrele sau alte simboluri care apar într-un text într-o formă
0 10 0 000 1 110 0 100 0 000 0 000 0 000 0 000 0 Adică în hexazecimal 41c8 0000 codificată numeric prin aceasta simplificându-se mult prelucrarea şi memorarea acestuia.
Cel mai intens folosi mod de a codifica literele şi celelalte simboluri din text este
Exemple: standardizat pentru limba engleză (americană) şi se numeşte ASCII. Din păcate această
Valoare standardizare nu ţine cont de simbolurile specifice altor ţări (care nu folosesc literele engleze),
Reprezentare există preocuparea la nivel internaţional de a realiza standarde internaţionale cere să includă şi
Constanta Reprezentare binară Observaţii
Zecimală hexazecimală caracterele acestor ţări dar din păcate acest lucru este departe de a fi realizat la un nivel
flotantă
1 1.f 3f80 0000 0 01 1 1 11 1 1 00 0 00 00 00 00 00 00 0 00 0 0 00 0 Mantisa are acceptabil de către toată lumea.
valoarea 0 Setul ASCII cuprinde 128 de caractere realizând o codificare iniţială pe 7 biţi. Pentru că
-2 -2.f c000 0000 1 10 0 0 00 0 0 00 0 00 00 00 00 00 00 0 00 0 0 00 0 marea majoritate a calculatoarelor reprezintă datele în multipli de 8 biţi (sau octeţi sau Byte)
≈3.4028234*1038 3.4028234e38f 7f7f ffff 0 11 1 1 11 1 0 11 1 11 11 11 11 11 11 1 11 1 1 11 1 Cea mai putem spune că reprezentarea unui caracter (folosită de fapt şi de C este pe 8 biţi).
mare valoare Observaţii
1/3 0.3333333f 3eaa aaab 0 01 1 1 11 0 1 01 0 10 10 10 10 10 10 1 01 0 1 01 1 Valoare
rotunjită
• Pentru informaţii suplimentare studiaţi anexa
0 0.f 0000 0000 0 00 0 0 00 0 0 00 0 00 00 00 00 00 00 0 00 0 0 00 0 Caz special • Există unele versiuni foarte noi de C (în special folosite în mediul grafic) care
-0 -0.f Ciudat dar
recunosc şi folosesc o reprezentare pe 16 biţi a unui caracter dar aceste versiuni nu
8000 0000 1 00 0 0 00 0 0 00 0 00 00 00 00 00 00 0 00 0 0 00 0
posibil sunt dezbătute pe cuprinsul acestui curs.
+∞ 7f80 0000 0 11 1 1 11 1 1 00 0 00 00 00 00 00 00 0 00 0 0 00 0 Plus infinit Caracterele ASCII sunt împărţite în:
-∞ ff80 0000 1 11 1 1 11 1 1 00 0 00 00 00 00 00 00 0 00 0 0 00 0 Minus • caractere grafice (adică acele caractere care pot fi reprezentate printr-un simbol
infinit grafic) intervalul [33,126]
Tipul double are o reprezentare pe 64 biţi. Modul de reprezentare conţine: • precum şi caractere negrafice care cuprind valorile {[0,32], 127}
1. 1 bit de semn (0 reprezintă un număr pozitiv, 1 un număr negativ) O constantă caracter în C va avea valoarea corespunzătoare codului ASCII al caracterului
ASCII pe care îl reprezintă.
9
O constantă caracter va fi memorată ca un întreg (va avea tipul int). Constantă şir de caractere
O constantă de tip caracter în C poate fi definită ca o construcţie lexicală incluse între
două caractere ’(apostrof). O succesiune de zero au mai multe caractere care sunt incluse între ghilimele formează
Construcţia lexicală dintre apostroafe poate fi: o constantă şir de caractere sau mai pe scurt un şir de caractere.
• un caracter dacă acesta este un simbol grafic cu excepţia caracterului \ (backslash) Fiecare dintre caracterele ce compun şirul poate fi un caracter ca şi cele descrise la
sau ’ care sunt tratate special de către compilator constantă caracter.
Practic limbajul C va descrie şirul de caractere ca un tablou de caractere care conţine toate
• un caracter \ urmat de un alt caracter sau literă caz în care caracterul are o
caracterele scrise în şir precum şi caracterul ’\0’ (supranumit caracterul null) care in C indică
semnificaţie specială (vezi tabelul de mai jos).
terminarea şirului de caractere.
• una sau mai multe (maxim 3) cifre octale (numită secvenţă escape) care sunt
Exemple:
interpretate ca o valoare octală pentru a descrie un caracter din tabelul ASCII. O Reprezentare
secvenţă escape poate depăşi intervalul normal de definire a unei reprezentări Şir de caractere
ASCII Hexazecimal Octal
Byte Observaţii
ASCII ([0,127]) ajungând şi în intervalul [128,255] (o extindere pe 8 biţi a ”” NUL 00 000 1 Şir nul de caractere
codului ASCII) astfel valoare poate fi în octal între 0 şi 377. ”a” a NUL 61 00 141 000 2
Exemple 41 42 43 00 061 062 063 000 4
”123” 1 2 3 NUL
Constantă Cod Cod Denumire Utilizare ”\123” 53 00 123 000 2 Cele 3 cifre sunt
S NUL
Caracter ASCII ASCII caracter interpretate ca o valoare
zecimal octal ASCII octal
’\\’ 49 57 Backslash Pentru a putea scrie caracterul backslash ”\1234” S 4 NUL 53 44 00 123 063 000 3 Cele 3 cifre sunt
interpretate ca o valoare
’\’’ 39 47 Apostrof Pentru a putea crea o constantă caracter cu ASCII octal a 4-a ramâne
valoarea apostrof 4
’\”’ 34 42 Ghilimele Pentru a putea crea o constantă caracter cu ”ab\0cd” N N 61 62 00 63 141 142 000 143 6 Deşi se alocă 6 octeţi
valoarea ghilimele a bUc dU 64 00 144 000 pentru şir doar primele 2
L L caractere vor fi vizibile,
’a’ 97 141 a Litera a minusculă practic echivalent cu ”ab”
’A’ 65 101 A Litera A majusculă
’0’ 48 60 0 Cifra 0 (zero)
’1’ 41 61 1 Cifra 1 (unu) Constante predefinite
’\a’ 7 7 Bell Calculatorul generează un sunet În C există anumiţi identificatori care de fapt sunt asimilaţi unor constante. Un exemplu
’\b’ 8 10 Backspace Un spaţiu înapoi tipic este PI cunoscut din matematică dar sunt multe astfel de cazuri ca de exemplu
’\t’ 9 11 HT Tabulator orizontal CHAR_MIN şi CHAR_MAX ş.a. care au fost deja definite. Aceşti identificatori sunt asimilaţi
’\n’ 10 12 LF Trecere la linie nouă (în C echivalent cu unor constante dar de fapt modul de descriere şi implementare este total diferit astfel încât
trecere la rând nou) amănunte despre ele voi da în capitolul directive precompilator.
’\v’ 11 13 VT Tabulator vertical – foarte rar folosit
’\f’ 12 14 FF Salt la pagină nouă (la imprimantă) Variabile
’\r’ 13 15 CR Retur de car – revenire la începutul rândului
curent O variabilă este o zonă identificabilă de memorie, modificabilă prin operaţii de
atribuire care are un tip şi o valoare.
’\7’ 7 7 Bell Ca mai sus la Bell
Spre deosebire de variabilă valoarea unei constante nu se poate modifica în timpul
’ \101’ 65 101 A Litera A majusculă
execuţiei programului. În C orice variabilă vom folosi trebuie declarată. Pentru început vom
’ \377’ 255 377 ??? Cea mai mare valoare ASCII posibil de
spune că toate variabilele vor avea un nume şi anume un identificator folosit atât la declarare
reprezentat nu se ştie caracterul reprezentat
cât şi la utilizarea lor. Acest fapt nu este întotdeauna adevărat dar deocamdată ideea că
deoarece depinde de la un SO la altul
variabilele au un nume ne este de foarte mare ajutor în folosirea lor. Limbajul C este unul
’ \401’ Eroare valoare imposibil de reprezentat (nu complicat astfel încât este bine de ştiut faptul că numele unei variabile nu se păstrează în mod
există în tabela ASCII normal în faza de execuţie a programului.
’ \182’ Eroare – e nevoie de cifre octale iar 8 nu e Variabilele se pot clasifica după modul în care se memorează datele în:
una dintre ele
10
• variabile simple – care pot memora o singură valoare. Variabilele care folosesc Exemple de tablouri unidimensionale cu sau fără iniţializări:
tipuri de date predefinite sunt în general simple. int x[10];
• variabile compuse – care memorează mai multe valori de o dată. De multe ori se double tablou[25];
doreşte gruparea mai multor date care au atât separat cât şi împreună semnificaţie. char sir[20]=”Primul program C”;
Limbajul C oferă mai multe metode prin care se pot grupa datele, cele mai int prime[10]={1, 2, 3, 5, 7, 11, 13, 17, 19, 23}
importante tipuri de date complexe fiind tablourile şi structurile. int primePeste100[]={101, 103, 107, 109}

Variabile simple Indicii tablourilor


Pentru a putea utiliza o variabila intr-un program C, este obligatorie declararea acesteia, Pentru a ne referi la un element al unui tablou în C se folosesc indicii. Dacă la definirea
astfel: unui tablou valoarea dintre parantezele dreptunghiulare reprezintă numărul de elemente pe
[clasa_de_memorie]TIP_DE_DATE lista_variabile; care le va avea un tablou, apoi în timpul execuţiei programului elementele unui tablou se
unde: identifică prin tablou[indice], unde tablou înseamnă numele tabloului iar indice al
• clasa_de_memorie specifica locul unde se va aloca memorie pentru variabila şi câtelea element din tablou (începând cu elementul 0 în limbajul C). Indicele unui tablou este
expresia care apare între paranteze drepte după numele tabloului.
durata sa de viata, noţiuni la care vom reveni mai târziu). Specificarea clasei de memorie
Exemple pentru definiţia:
este opţionala;
int prime[10]={1, 2, 3, 5, 7, 11, 13, 17, 19, 23}
• TIP_DE_DATE este orice tip predefinit sau derivat; practic tipul variabilei va indica şi prime[0] are valoarea 1
dimensiunea de memorie alocată pentru variabila respectivă. prime[1] are valoarea 2
• lista_variabile conţine lista variabilelor de acel tip, despărţite prin virgula; prime[2] are valoarea 3
Efectul unei declaraţii este crearea unei zone de memorie ca locaţie a variabilei, prime[3] are valoarea 5 ş.a.
identificarea zonei de memorie cu numele dat variabilei şi eventual iniţializarea variabilei pentru definiţia
(adică atribuirea unei valori iniţiale implicite sau explicite variabilei). char sir[20]=”Primul program C”;
Exemple: sir[0] are valoarea ’P’
int a,b,c; sir[15] are valoarea ’C’
char ch; sir[16] are valoarea ’\0’ sau null
float x,y; În C se pot folosi şi construcţii mai ciudate ca de exemplu se poate folosi indicele pentru o
long int z; constantă şir de caractere ca în exemplele de mai jos:
int g=7; Construcţia ”123456789”[0] este echivalentă cu ’1’ iar ”123456789”[9] este
Observaţie: La declararea variabilei întregi g s-a realizat şi iniţializarea acesteia (adică echivalentă cu ’\n’.
stabilirea unei valori iniţiale).
Variabilele care sunt declarate în interiorul corpului unei funcţii se numesc variabile
locale, iar cele declarate în afara oricărei funcţii din program se numesc variabile globale.
Variabilele globale vor putea fi utilizate în toate funcţiile ce compun programul, iar variabilele Tablouri multidimensionale
locale doar în cadrul funcţiei în care au fost definite, dar aceste amănunte vor fi discutate mai Este posibilă declararea şi folosirea unor tablouri care au două sau mai multe dimensiuni
târziu. numite tablouri multidimensionale, un exemplu cunoscut este acela al matricelor care sunt
tablouri ce au două dimensiuni. Aceste tablouri pentru a fi controlate au nevoie de mai mulţi
indici, de exemplu pentru matrici primul indice se foloseşte pentru a arăta liniile unei matrici
Variabile compuse. Tablouri. iar coloanele sunt indicate de al doilea indice.
Un tablou este o mulţime ordonată de elemente de acelaşi tip la care ne putem referi Exemple:
folosind indici. double matrice [4] [5];
Un tablou unidimensional este echivalentul în programare a unui şir din matematică. Spre defineşte o matrice cu 4 linii şi 5 coloane iar
deosebire de şirurile din matematică în programare şirurile sunt obligatoriu de dimensiune matrice [2] [4]
limitată iar pentru programele scrise în C sau alte limbaje compilate dimensiunea acestor ne indică elementul de pe linia 3 şi coloana 5 a matricei cu numele matrice.
tablouri trebuie să fie cunoscută în momentul declarării lor şi ea rămâne fixă pe toată durata
execuţiei programului.
11
Operatori, operanzi, expresii
O expresie constă din unul sau mai mulţi operanzi legaţi prin operatori.
Operatori
Operand Operatorii constituie unul din conceptele cele mai importante şi mai interesante care stau la
În C mai multe construcţii lexicale pot avea rol de operand. Printre altele un operand poate baza unui limbaj de programare. Limbajul C este vestit pentru marea varietate de operatori pe
fi: care-i pune la dispoziţia programatorului rezultând şi o diversitate de expresii ce se pot forma
• constantă pe baza acestora. După cum se ştie, o expresie este formata din variabile, constante, funcţii şi
• variabilă simplă operatori. În acest paragraf voi aminti câteva din categoriile de operatori ai limbajului C:
• nume de tablou
• nume de structură Operatorii aritmetici:
• numele unui tip de dată
+ adunare, - scădere, * produs, / împărţire, % - restul împărţirii întregi
• numele unei funcţii
++, -- incrementare şi decrementare
• un element al unei structuri
fiecărui operand al unei expresii are două proprietăţi interesante pentru a calcula o expresie şi
anume o valoare prin care participă la calculul expresiei şi un tip prin care compilatorul Operatori
determină tipul rezultat în urma calculului. Operatorul reprezintă o operaţie care se aplica datelor.
Limbajul C este vestit pentru marea varietate de operatori pe care-i pune la dispoziţia
Expresia programatorului rezultând şi o diversitate de expresii ce se pot forma pe baza acestora. După
cum se ştie, o expresie este formata din variabile, constante, funcţii şi operatori. În acest
poate fi definita astfel:
paragraf voi aminti câteva din categoriile de operatori ai limbajului C:
(a) Variabilele şi constantele sunt expresii Există foarte mulţi operatori în C. motivul pentru care avem o varietate mare de operatori
(b) Dacă E1 este expresie atunci op_unar E1 este expresie; (operator prefixat) este acela că C a fost conceput ca un limbaj care sa permită folosirea cât mai bună a codului
(c) Dacă E1 este expresie atunci E1 op_unar este expresie; (operator postfixat) maşină (generat de program) şi a obţine un program executabil cât mai rapid cu putinţă
(d) Dacă E1, E2 sunt expresii, atunci E1 op_binar E2 este expresie; (cerinţe foarte importante pentru componentele unui sistem de operare). Unii operatori sunt
(e) Dacă E1, E2 , E3 sunt expresii, atunci E1 op_ternar1 E2 op_ternar2 E3 este foarte rar găsiţi în alte limbaje de programare, alţii sunt trataţi diferit de alte limbaje de
expresie; programare.
(f) Orice expresie corecta se obţine prin aplicarea paşilor (a)...(e) de un număr finit de ori; Există mai multe moduri prin care putem organiza aceşti operatori. Dintre aceste moduri
Exemple de expresii: 23.4+12/4-a*b+1, c && d || e && f, 1234, -765.34 amintim:
Evaluarea unei expresii = obţinerea unei valori în funcţie de valorile operanzilor ce apar • după numărul de operanzi
în expresie. • operatori unari – au un singur operand Operatorul unar poate fi plasat în dreapta sau
Dacă expresia este numerica, atunci se obţine o valoare numerica, dacă expresia conţine stânga operandului iar pentru diferite paranteze (care sunt considerate de c tot ca
operatori logici şi relaţionali atunci se obţine o valoare logica (adevărat sau fals). În C (sau operatori) atât în stânga cât şi în dreapta operandului
C++) nu există de fapt tipul de date logice ci este valabilă următoarea constatare: • operatori binari – au doi operanzi, primul fiind plasat în stânga operatorului iar celălalt
- Orice valoare numerică egală cu 0(zero) se consideră falsă. operand în dreapta
- Orice valoare numerică diferită de 0(zero) se consideră adevărată. (dacă în urma unei • operator ternar – are trei operanzi. C are un astfel de operator şi anume ?: unde
evaluări de expresie este nevoie de calcularea unei expresii care returnează adevărat atunci de operanzii sunt organizaţi sub forma:
fapt valoarea calculată este 1(unu)). operand ? operand : operand
Exemple: • ordinea de execuţie a operaţiile
1 < 3 este adevărat iar acest adevăr este reprezentat prin valoarea 1. • de la stânga la dreapta – o ordine normală şi obişnuită din matematică care se aplică la
2 > 7 este fals deci este reprezentat prin valoarea 0. majoritatea
• de la dreapta la stânga – o ordine care pare anormală şi neobişnuită dar destul de logică
la o analiză mai atentă
12
• prioritatea operatorilor 16 ?: Ternar Operatorul condiţional DreaptaStânga
• dacă doi operatori (sau mai mulţi) operatori sunt folosiţi natural este ca ordinea în care 17 = *= /= %= += -= >>= Binar Operatorii de atribuire DreaptaStânga
aceştia vor fi aplicaţi să fi semnificativă de exemplu pentru cazul 2+3*4 pot fi două <<= &= ^= !=
ordini de efectuare a operaţiilor astfel (2+3)*4=20 sau 2+(3*4)=14. În matematică (dar 18 , Binar Operatorul virgulă StângaDreapta
şi in limbajul C) dacă nu există paranteze atunci înmulţirea va avea prioritate mai mare În continuare voi prezenta operatorii nu în ordinea din tabel ci grupaţi după felul operaţiilor pe
decât adunarea. care le execută.
În continuare vă voi prezenta un tabel în care vor apărea pentru fiecare dintre operatorii C
toate aceste informaţii de care am vorbit mai sus. Nu toţi operatorii vor fi descrişi în acest
capitol. Motivul este că unii dintre operatori sunt încă prea complicaţi pentru acest capitol dar
Operatori aritmetici
vor fi descrişi în capitolele următoare sau se reperă la programarea obiectuală care nu face Operatorii aritmetici sunt cunoscuţi din matematică şi de aceea ei vor fi prezentaţi primii
obiectul acestei cărţi. aceştia sunt:
Tabel cu operatorii specifici C++ Nivel Operator Tip Descriere ordine
Nivel Operator Tip Descriere ordine 3 +- Unar Operator de semn unar DreaptaStânga
1 :: Unar Operatorul scop folosit StângaDreapta 6 */% Binar Operatori aritmetici StângaDreapta
pentru a identifica multiplicativi
elemente ale unei clase 7 +- Binar Operatori aritmetici de StângaDreapta
2 () [] . -> ++ -- const ++ Unar Pentru ++ respectiv – StângaDreapta adunare
-- ~ ! sizeof new delete operatorul poate fi atât 18 , Binar Operatorul virgulă StângaDreapta
postfixat cât şi prefixat
3 *& Unar Indirectare şi referinţă DreaptaStânga Obs. Operatorii enumeraţi mai sus pot fi utilizaţi în limbajul C şi C++; dacă veţi folosi alte
pentru (pointeri) limbaje uni dintre aceşti operatori pot diferi ca forma de cei prezentaţi de aceea este indicată
+- Unar Operator de semn unar DreaptaStânga studierea documentaţiilor pentru a vedea diferenţele de notaţie. Limbajul C++ defineşte o
4 (tip) Unar Operatorul de forţare a DreaptaStânga mulţime de alţi operatori, care vor fi studiaţi la momentul oportun.
tipului (eng. casting) Atribuirea se desfăşoară astfel:
5 .* ->* Binar Pointer la membru StângaDreapta (a) Se evaluează expresia din partea dreapta a atribuirii;
6 */% Binar Operatori aritmetici StângaDreapta (b) Valoarea obţinută în urma evaluării se memorează în zona de memorie a variabilei cu
multiplicativi numele specificat în partea stângă a atribuirii.
7 +- Binar Operatori aritmetici de StângaDreapta Obs: Vechea valoare a variabilei se pierde în momentul efectuării unei operaţii de
adunare atribuire.
8 << >> Binar Operatori de deplasare StângaDreapta Fie următoarele atribuiri:
i=3;
(eng. shift)
i=i+1;
9 < > <= >= Binar Operatori relaţionali StângaDreapta
Ne punem întrebarea dacă a doua atribuie este corecta. Din punct de vedere matematic, a
10 == != Binar Test de egalitate sau StângaDreapta
doua atribuire este o absurditate însă, din punct de vedere al programării este corecta şi se
inegalitate
realizează astfel:
11 & Binar Operatorul Şi (eng. AND) StângaDreapta (a) a. Se evaluează expresia i+1, iar rezultatul obţinut este 4 (vechea valoare a lui I, 3, la care
pe biţi se adaugă o unitate);
12 ^ Binar Operatorul Sau exclusiv StângaDreapta (b) b. Se stochează în i valoarea 4;
(eng. XOR) pe biţi Exerciţiul 1 : Ce valoare are variabila x după următoarea secvenţa de atribuiri:
13 | Binar Operatorul Sau (eng. OR) StângaDreapta x=3;
pe biţi y=5;
14 && Binar Operatorul logic Şi (eng. StângaDreapta x=x+y;
AND) y=2*y;
15 || Binar Operatorul logic Sau StângaDreapta x=x-y;
(eng. OR) Exerciţiul 2: (Bacalaureat 1999) Se da următoarea secvenţa de atribuiri:
13
a=10; Dacă valoarea obţinuta prin evaluarea expresiei din dreapta atribuirii este de alt tip decât
b=4; tipul variabilei din stânga atunci se încearcă conversia tipului valorii la tipul variabilei. Nu
a=a-b; întotdeauna conversia este posibila, caz în care se va afişa un mesaj de eroare în urma
b=a+b; compilării.
a=b-a; Exemplul 1 : Fie următoarea secvenţa de program:
(a) Ce valori au variabilele a şi b ?
(b) Ce efect au ultimele trei atribuiri ? void main(void){
Teme: Construiţi schema logica pentru rezolvarea ecuaţiei de gradul al II-lea. int a;
float c;

Operatori relaţionali: a=3./2.+9./4.;


cout<<”a=”<<a<<”\n”;
<,> c=3./2.+9./4.;
== egal cout<<”c=”<<c<<”\n”
<= mai mic sau egal /* aceeaşi expresie are valori diferite, în funcţie de tipul
>= mai mare sau egal variabilei din stânga atribuirii */
!= diferit }
Observaţie: Executând programul de mai sus se vor obţine valori diferite pentru variabilele
Operatori logici: a şi c, deşi expresia care apare în dreapta ambelor atribuiri este aceeaşi. Pentru a se obţine
valoarea 3, iar pentru c se obţine 3,75. Explicaţia sta în modul în care se realizează conversiile
&& - şi logic
de tip în cadrul atribuirilor. Valoarea expresiei 3./2.+9./4. este 3.75 dar variabilei a i se va
|| - sau logic
atribui partea întreaga a acestei valori, adică 3. Variabila c este de tip float (număr real),
! - negaţie logica
Operatorii logici şi relaţionali sunt implicaţi în formarea expresiilor cu valoare logica. Spre deci nu va mai fi nevoie de conversia rezultatului evaluării expresiei la tipul variabilei.
exemplu: Exemplul 2:
a<2, 7/5+2<s-1, (x>-3) &&(x<3), !(a==b) void main(void){
float a;
sunt expresii cu valoare logica.
a=5/2;
cout<<a;
Operatori de atribuire. }
În secţiunea precedenta am amintit, vorbind despre reprezentarea algoritmilor prin scheme Observaţie: Executând acest program se va afişa valoarea 2 şi nu valoarea 2.5 aşa cum ar fi
logice, de operaţia de atribuire. În limbajul C se considera ca atribuirea este un operator. fost de aşteptat. Explicaţia este următoarea: operatorul / realizează, atunci când operanzii sunt
Atribuirea are următoarea sintaxa: întregi, împărţirea întreaga, deci vom obţine catul împărţirii întregi dintre 5 şi 2. Exista doua
variabila = expresie; modalităţi de rezolvare a problemei: fie înlocuim expresia cu 5./2. (5.=5.0) fie utilizam
Modul de funcţionare este următorul: operatorul de conversie explicita ( ). Acest nou operator ( numit cast), se utilizează astfel
1. se evaluează expresia; ( tip_de_date) expresie;
2. valoarea obţinuta este stocata în zona de memorie a variabilei, realizându-se eventuale Semnificaţia este următoarea: Se cere convertirea valorii rezultate din evaluarea expresiei
conversii de tip. la o valoare de tipul specificat intre paranteze. În exemplul de mai sus vom înlocui atribuirea
3. valoarea rezultata în urma atribuirii este valoarea atribuita variabilei. cu:
Observaţie: Atribuirea fiind un operator, se considera ca operanzii sunt variabila din partea a=(float) 5/2;
stânga, respectiv expresia din partea dreapta. Orice expresie trebuie să aibă, în urma evaluării (rezultatul expresiei va fi de tip float, deci variabilei a i se va atribui valoarea 2.5).
sale, o valoare (un rezultat). Valoarea expresiei de atribuire este valoarea obţinuta prin Exerciţiu: Fie următorul program, care calculează media aritmetica a trei numere a,b,c ,
evaluarea expresiei din partea dreapta a atribuirii. primele doua introduse de la tastatura.:

14
void main(void){ void main(void){
int a,b,c; int a,b,i=3;
float s; a=++i; //preincrementare a lui i
cin>>a; cout<<a;
cin>>b; b=a--; //postdecrementare
c=a/2+b/3; cout<<”a=”<<a<<”\n”;
s=(a+b+c)/3; cout<<”b=”<<b<<”\n”;
cout<<”Media aritmetica este=”<<s; a+=++b; //atribuire compusa
} cout<<”a=”<<a<<”\n”;
Executaţi acest program şi identificaţi greşelile. Corectaţi greşelile găsite. cout<<”b=”<<b<<”\n”;
}
operatori de atribuire compusa: Observaţie: Când apar expresii de tipul :
++variabila
+=, -=, *=, /=, %= sau
Operatorii de atribuire compusa au fost introduşi pentru a fi utilizaţi în locul atribuirilor de --variabila;
tipul: spunem ca se realizează o preincrementare, respectiv predecrementare. În cazul
preincrementării, variabila va primi ca valoare 1+valoarea iniţială. Dacă preincrementarea
v=v+expresie; apare intr-o expresie se realizează întâi aceasta operaţie şi abia apoi celelalte operaţii care mai
v=v-expresie; apar în expresie (preincrementarea are prioritate mai mare). În atribuirea a = ++i se
v=v*expresie; etc. realizează întâi preincrementarea, în urma căreia i va avea valoarea 4, şi abia apoi se
unde:
realizează atribuirea (a va avea valoarea 4).
• v - variabila În expresia b=a — se realizează o postdecrementare, adică se modifica valoarea variabilei
• expresie-orice expresie corecta în limbajul C a doar după ce s-au efectuat celelalte operaţii din expresie. În cazul nostru, b va primi valoarea
În locul acestor expresii se vor folosi:
lui a (4, în momentul acela) şi abia apoi se va micşora valoarea lui a cu o unitate.
v+=expresie;
v -= expresie; etc. Exerciţiu: Executaţi programul de mai sus şi urmăriţi rezultatele care se obţin.
Mai exista operatori de atribuire compusa, folosindu-se operatorii logici ce acţionează la
Folosirea operatorilor de atribuire compusă sporeşte lizibilitatea programului şi viteza de
nivel de bit, dar despre aceştia vom vorbi intr-o secţiune viitoare. Tot atunci vom discuta şi
execuţie. Dacă atribuirea este de forma:
v=v+1; despre atribuirea multipla.
sau
v=v-1;
se pot utiliza operatorii de incrementare şi decrementare ++ şi --. Expresiile de mai sus se
vor putea scrie: Citirea şi afişarea datelor. Primele programe în
v++;
respectiv C++
v--; Pentru introducerea datelor prin intermediul tastaturii avem nevoie de funcţia cin, iar
Exemplul 3: Se da următorul program: pentru afişarea valorilor sau mesajelor de funcţia cout.
Exemplul 1: Cel mai simplu program este programul care nu realizează nici o prelucrare:

void main (void) {


}
Exemplul 2: Să se afişeze pe ecran un mesaj.

15
#include <iostream.h> • Executând programul de mai sus veţi observa modul de afişare al rezultatului.
void main (void) { • În textul programului au fost introduse mici comentarii, precedate de //, pentru a facilita
cout<< "Acesta este primul program in C!"; înţelegerea textului sursa.
} Exemplul 5: Scrieţi un program care să afişeze următorul meniu:
Observaţii: Băuturi
1. Linia #include <iostream.h> declara ca se va utiliza biblioteca de funcţii cu Bere ………..12500
numele "iostream.h", din care face parte şi funcţia de afişare cout. Vin …………34764
2. Funcţia main() este funcţia principala a unui program C, prelucrările conţinute de Suc…………...5000
aceasta fiind primele efectuate la executarea unui program. Cafea
3. Prelucrările ce apar intr-o funcţie trebuiesc scrise intre { şi } Nes….10000
4. După scrierea unei comenzi (funcţie / instrucţiune) se pune ; Expreso………6000
Exemplul 3: Reluăm exemplul precedent: #include <iostream.h>
#include <iostream.h> void main(void){
void main(void){ cout <<”Bauturi:\n”;
cout<< "Acesta este primul program în C "; cout <<”\t Bere………………12500\n”;
cout<<"\n scris în prima ora de laborator "; cout <<”\t Vin………………..34764\n”;
} cout <<”\t Suc…………………5000\n”;
Observaţii: cout <<”Cafea:\n”;
• Caracterul "\n" are ca efect afişarea a ceea ce urmează pe linia următoare a ecranului cout <<”\t Nes……………….10000\n”;
(adică salt la rândul următor). cout <<”\t Expreso……………6000\n”;
• Mesajul trebuie precedat de << (aceste semne trebuie înţelese ca o direcţie a fluxului de }
date de la textul scris spre funcţia care afişează textul pe ecran) Observaţii: S-a folosit caracterul \t pentru a se “începe” un nou paragraf. Caracterele
Exemplul 4: Să se scrie un program pentru însumarea a doua numere. “\t” şi “\n” fac parte dintre caracterele numite caractere escape, deoarece sunt caractere
#include <iostream.h> neafişabile pe ecran decât prin utilizarea unor simboluri (secvenţe de evitare).
void main(void){
int a; //variabila care va memora primul număr
int b; //variabila care va memora al doilea număr
Instrucţiunea alternativa (if)
int s; // memoreaza suma celor doua numere Până acum am folosit ca exemple programe simple, care conţineau doar funcţiile de intrare
/ ieşire şi operatorul de atribuire. Atunci când elaboram programe ceva mai complexe este
cout <<"Introduceţi primul număr:"; necesar ca, intr-un anumit punct al programului, să decidem continuarea acestuia în funcţie de
cin >> a; o condiţie. În primul laborator am dat ca exemplu de algoritm rezolvarea ecuaţiei de gradul 1
cout <<"Introduceţi al doilea număr:"; (pseudocod şi schema logica). Intr-o schema logica ni se permitea utilizarea unui bloc de
cin >>b; decizie de următorul tip:
s=a+b;
cout<<"Suma "<<a<<"+"<<b<<"="<<c<<"\n";
} NU DA
Observaţii: C
• Se folosesc trei variabile pentru a memora numerele şi suma acestora. Prin "int a" se A B
declara folosirea unei variabile de tip întreg, având numele "a".
• "cin >> a" determina citirea unei valori de la tastatura, valoare ce va fi memorata în
zona de memorie a variabilei "a". Cel care introduce date trebuie să tasteze o valoare
cu semnificaţia: dacă este adevărata condiţia se executa prelucrarea B, altfel se executa
întreagă, altfel semnalându-se eroare.
prelucrarea A.
• Dacă se afişează un mesaj, conţinutul acestuia trebuie pus intre ghilimele. Dacă se doreşte
În limbajul C este utilizata instrucţiunea if, cu următoarea sintaxă:
afişarea valorii unei variabile atunci se scrie, după simbolurile <<, numele acesteia.
16
if (expresie) instrucţiune1; #include <iostream.h>
[else instrucţiune2;} void main (void){
unde: int a,b,c;
• expresie - orice expresie valida în limbajul C int max;
• instrucţiune1, instrucţiune2 - orice instrucţiune corecta din limbajul C ; cout<<”a=”;
Mod de funcţionare: cin>>a;
• se evaluează expresia cout<<”\nb=”;
cin>>b;
• dacă expresia este ne nulă (convenţia pentru adevărat) se executa instrucţiune1
cout<<”\nc=”;
• dacă expresia este nula (falsă) se executa instrucţiune2 cin>>c;
• se trece la următoarea instrucţiune a programului if (a<=b)
Observaţie: alternativa else instrucţiune2 poate să lipsească. if (c<=b)
Exemplul 4: Să se scrie un program pentru calcularea maximului a doua numere. max=b;
#include <iostream.h> else
void main(void){ max=c;
int a,b; else
int max; if (c<=a)
max=a;
cout<<”a=”; else
cin>>a; max=c;
cout<<”\nb=”; cout<<”\nMaximul este=”<<max;
cin>>b; }
if (a<=b) Observaţie: După cum se vede din exemplu, instrucţiune1 şi instrucţiune2 pot
max=b; fi de asemenea instrucţiuni if. Spunem ca sunt instrucţiuni if imbricate. A se observa şi
else
modul cum a fost scris programul, astfel încât să se vadă clar cărei instrucţiuni if ii aparţine
max=a;
cout<<”Maximul celor doua numere este=”<<max<<”\n”; fiecare else.
} Exemplul 6: Se dau trei numere întregi a,b,c. Să se testeze dacă numerele date pot fi
Exemplul 5: Scrieţi un program care calculează maximul a 3 numere. lungimile laturilor unui triunghi.

17
#include <iostream.h> Este indicata aceasta scriere pentru ca sporeşte lizibilitatea programului.
void main (void){ Exemplul 8: Rezolvarea ecuaţiei de gradul I.
int a,b,c; #include <iostream.h>
void main(void)
cout<<”a=”; {
cin>>a; int a,b;
cout<<”\nb=”; float x;
cin>>b;
cout<<”\nc=”; cout<<”\na=”;
cin>>c; cin>>a;
if (a<b+c) cout<<”\nb=”;
if (b<a+c) cin>>b;
if c<a+b) if (a!=0){
cout<<” Numerele pot fi lungimile laturilor unui triunghi x=(float) -b/a;
!”; cout<<”\nx=”<<x;
else }
cout<<”Numerele nu pot fi lungimile laturilor unui else
triunghi !”; if (b==0) cout<<”\n x aparţine lui R “;
else cout<<”Numerele nu pot fi lungimile laturilor unui else cout <<”\n Ecuaţia nu are soluţii”;
triunghi !”; }
else cout<<”Numerele nu pot fi lungimile laturilor unui Observaţie: În cazul în care a este nenul avem de realizat doua operaţii: atribuirea valorii
triunghi !”; -b/a variabilei x şi afişarea valorii rădăcinii. Atunci când se realizează mai multe operaţii
} acestea trebuiesc incluse intre { şi }.
Observaţie: Nu am mai verificat dacă a, b, c sunt pozitive.
Exemplul 7. Reluăm exemplul precedent cu intenţia de a folosi mai puţine instrucţiuni if.
#include <iostream.h> Instrucţiuni iterative
void main (void) Toate problemele prezentate până acum au putut fi rezolvate folosind numai funcţii de
{ citire / scriere, atribuiri şi instrucţiunea de decizie (if). Cele mai multe dintre probleme vor
int a,b,c; necesita structuri de date mai complexe precum şi folosirea unor noi instrucţiuni, care să
permită repetarea de un număr oarecare de ori a unor parţi din algoritm.
cout<<”a=”; Să luam ca exemplu algoritmul de calcul al sumei a 2 numere introduse de la tastatura. El
cin>>a; consta în citirea valorilor pentru cele doua numere şi afişarea sumei acestora. Nu era nevoie
cout<<”\nb=”; decât de doua variabile, cate una pentru fiecare număr. Acest exemplu este doar unul didactic,
cin>>b; în practica ne întâlnindu-se prea des cazuri în care să fie nevoie de a suma doua numere.
cout<<”\nc=”; Generalizarea problemei pentru n numere va modifica substanţial algoritmul nostru. Nu vom
cin>>c; putea folosi cate o variabila pentru fiecare număr introdus deoarece nu cunoaştem exact cate
if ((a<b+c) && (b<a+c) && (c<a+b)) numere avem (n este introdus de utilizatorul programului, altfel algoritmul nu ar mai fi
cout<<”Numerele pot fi lungimile laturilor unui triunghi !”; general). Chiar dacă s-ar şti ca avem, să zicem, 2500 de numere ar fi cam dificil să utilizam
else cout<<”Numerele nu pot fi lungimile laturilor unui 2500 de variabile distincte.
triunghi !”; Problema noastră se poate rezolva simplu dacă utilizam o instrucţiune iterativa (ciclica),
} care să ne permită repetarea de n ori a următoarei secvenţe de operaţii:
Observaţie: Am folosit o singura instrucţiune if, cele trei condiţii anterioare fiind 1. citim o valoare folosind variabila “a”;
conectate prin operatorul ŞI logic. După cum se ştie, dacă avem propoziţiile p,q,r, atunci 2. adunam valoarea citita la rezultatul parţial, memorat în variabila “s”;
propoziţia p&&q&&r va fi adevărata dacă toate propoziţiile componente sunt adevărate şi falsă Instrucţiunile ce descriu aceste prelucrări ciclice sunt compuse din doua părţi:
dacă una dintre propoziţiile componente este falsă. • corpul ciclului, format din prelucrările ce se doresc a fi realizate de mai multe ori;
18
• condiţia, pe baza căreia se stabileşte dacă se vor mai executa prelucrările din ciclu (este #include <iostream.h>
obligatorie executarea prelucrărilor din corpul instrucţiunii de un număr finit de ori); void main()
Corpul ciclului sau condiţia trebuie să conţină acele operaţii care, după efectuarea de un {
număr de ori a corpului instrucţiunii, să determine schimbarea valorii de adevăr a condiţiei, float a;
permiţând încheierea executării instrucţiunii ciclice şi trecerea la următoarele instrucţiuni ale int i,n;
algoritmului. În cazul în care este neglijat acest aspect, programul se va executa la infinit. float suma=0;
Condiţia trebuie să fie o expresie cu valoare logica. Reamintesc faptul ca în limbajul C++
nu exista un tip de date logic, dar se utilizează convenţia ca orice valoare ne nula să fie i=1;
considerata ca adevăr iar valoarea zero ca valoarea fals. În consecinţă, orice expresie cu cout<<"\n Numărul de elemente=";
valoare de tip întreg va putea fi utilizata drept condiţie intr-o instrucţiune iterativa. cin>>n;
În finalul paragrafului o chestiune de terminologie: o execuţie a corpului instrucţiunii while(i<=n){
poarta numele se iteraţie. cout<<"Elementul "<<i<<"este: ";
Instrucţiunile iterative pot fi clasificate, în funcţie de momentul evaluării condiţiei, astfel: cin>>a;
• cicluri cu test iniţial (While şi For)- evaluarea condiţiei se face înaintea fiecărei iteraţii; suma=suma+a; //se mai poate scrie suma+=a
i++;
• cicluri cu test final (Do .. While)- evaluarea condiţiei se face la sfârşitul fiecărei iteraţii;
}
cout<<"Suma este= "<<suma;
Instrucţiunea While }
Instrucţiunea while (“atât timp cat”) este o instrucţiune iterativa cu test iniţial şi are Exemplul 2: Suma primelor n numere naturale.
următoarea sintaxa: #include <iostream.h>
while ( <condiţie>) void main()
instrucţiune; {
unde: int n;
<condiţie> - orice expresie cu valoare întreaga; int i;
int suma=0;
instrucţiune - orice instrucţiune valida a limbajului;
Mod de funcţionare:
cout<<"n=";
• dacă expresia este adevărată se executa prelucrările din ciclu;
cin>>n;
• altfel, se trece la următoarea instrucţiune de după while; i=1;
Cu alte cuvinte, prelucrările din ciclu se executa atât timp cat condiţia este adevărata. Dacă while(i<=n){
expresia este falsă de la început corpul ciclului nu se va executa deloc. suma=suma+i;
Problema propusa în paragraful precedent se poate rezolva astfel: i++;
Exemplul 1 Suma a n numere introduse de utilizator }
cout<<"Suma este: "<<suma;
}
Observaţie: Se poate utiliza o scriere mai compacta, care elimina şi necesitatea utilizării
variabilei i:
while (n--) suma+=n;
Modul de execuţie este următorul:
• valoarea condiţiei este valoarea variabilei n, valoare care scade cu o unitate după fiecare
iteraţie (postdecrementare)
• condiţia devine falsă atunci când valoarea lui n devine zero;

19
Instrucţiunea do .. while Exemplul 3: Reluăm exemplul 1 folosind instrucţiunea for:
#include <iostream.h>
Instrucţiunea do .. while este o instrucţiune iterativa cu test final şi are următoarea void main(){
sintaxa: int i, n;
do float a, suma=0;
instrucţiune;
while (<condiţie>) cin>>n;
Mod de funcţionare: for(i=1;i<=n;i++){
• se executa corpul instrucţiunii; cin>>a;
• se evaluează condiţia: dacă aceasta este adevărata se reia execuţia, altfel se trece la suma+=a;
următoarea instrucţiune din program; }
Deosebirea esenţială faţă de instrucţiunea while este aceea ca expresia se evaluează după cout<<”suma =”<<suma;
iteraţie. }
În cazul în care condiţia este falsă de la început, corpul instrucţiunii se executa o singura Observaţii:
dată. Utilizarea instrucţiunii do .. while este mai puţin frecventa (se foloseşte pentru • Variabila i este utilizata pe post de “contor” al instrucţiunii for, numărând la a câta
acele prelucrări care trebuiesc executate cel puţin o dată). iteraţie s-a ajuns.
Dacă rescriem exemplul 1 utilizând do .. while, obţinem: • Execuţia instrucţiunii for se încheie atunci când numărul de iteraţii devine egal cu n.
…………………………. Iniţializarea lui i cu 1 se realizează o singura dată, la început; i <= n este condiţia de
do{ continuare a execuţiei; i++ se efectuează după fiecare execuţie a ciclului
cin>>a; (postincrementare).
suma+=a; • Aceasta forma a instrucţiunii for este cea mai utilizata. Un alt mod de a descrie execuţia
i++; acesteia este următorul: pentru i de la 1 la n se executa corpul instrucţiunii.
} while(i<=n);
• Nu este obligatoriu ca valoarea lui i să se mărească de fiecare dată cu o unitate.
………………………….
• Nu este obligatorie utilizarea tuturor celor trei expresii din for, dar este obligatorie
scrierea separatorului “;” .
Instrucţiunea for Exemplul de mai sus se poate rescrie astfel:
Una dintre cele mai puternice instrucţiuni iterative ale limbajului C (şi nu numai) este ……………………………
instrucţiunea for, care are următoarea sintaxa: for( ;n--; ){
for (expresie1; expresie2; expresie3) cin>>a;
[instrucţiune]; suma+=a;
unde: }
expresie1, expresie2, expresie3 - expresii valide în C++; ……………………………
instrucţiune - orice instrucţiune a limbajului C++;
Parantezele pătrate semnifica faptul ca instrucţiunea este opţionala; Noţiunea de tablou
Mod de execuţie:
În laboratorul precedent explicam de ce nu putem să utilizam 2500 de variabile distincte
• expresiile au următoarea semnificaţie generala:
atunci când dorim să însumam 2500 de numere. Rezolvarea propusa atunci se baza pe citirea
• expresie1 - expresie de iniţializare; repetata a cate unei valori, folosind o variabila a, urmata de adăugarea acesteia la suma
• expresie2 - condiţia de continuare a execuţiei ciclului; parţiala. Dezavantajul metodei este acela ca nu se pot memora toate valorile citite ci doar
• expresie3 - expresie de actualizare; ultima (citind o valoare intr-o variabila, vechea valoare a acesteia se pierde). Cele mai multe
• atât timp cat expresie2 este adevărata se executa corpul ciclului; programe presupun prelucrări complexe asupra datelor de intrare, deci va fi nevoie să
• de fiecare dată se evaluează expresia de actualizare, care are rolul esenţial de a memoram şirul nostru de numere astfel încât să poată fi utilizat şi în alte prelucrări, nu numai
determina ca, după un număr de iteraţii, expresie2 să devină falsă; pentru calcularea sumei.
• expresie1 se evaluează o singura dată;
20
Pentru a rezolva astfel de situaţii s-a introdus în limbajele de programare noţiunea de #include <iostream.h>
tablou. Tablourile ne permit memorarea unui număr mare de valori utilizând o singura void main(){
variabila. int n; //numărul de elemente
Prin tablou se înţelege un număr de elemente de acelaşi tip, numit tip de baza, stocate intr- int a[50];
o zona compacta de memorie. /* se defineşte o variabila de tip tablou cu maxim 50 de
Un tablou poate fi definit astfel: elemente, deci n va trebui sa fie mai mic decât 50
tip_de_baza nume [dimensiune1] [dimensiune2] … [dimensiune_n]; */
unde: int min; //variabila ce va memora minimul
tip_de_baza = tipul elementelor tabloului; int i; //contor în instrucţiunea for
n = numărul de dimensiuni al tabloului;
[dimensiune_i] = numărul de elemente pe dimensiunea i cout<<”n=”;
cin>>n;
tabloul are dimensiune1*…*dimensiune_n elemente
/* se citesc elementele şirului */
Noţiunea de tablou multidimensional poate fi înţeleasă mai bine după parcurgerea
for(i=0;i<n;i++){
noţiunilor referitoare la vectori şi matrice.
cout<<”a[“<<i<<”]=”;
cin>>a[i];
Tablouri unidimensionale }
Declararea unui tablou unidimensional: // se calculează minimul
tip_de_baza nume[dimensiune]; min=a[0]; /*iniţializam minimul cu primul element din şir */
unde dimensiune specifica numărul de elemente al vectorului. for(i=1;i<n;i++)
De exemplu: if (a[i]<min)
int a[30]; declara un vector ce conţine 30 de elemente de tip int, min=a[i];
cout<<”Minimul este=”<<min; //afişare minim
float b[50]; declara un vector cu 50 elemente reale;
}
“Numerotarea” elementelor se face de la 0 la dimensiune-1, adică cele 30 de elemente ale
După cum se poate observa din programul de mai sus, fiecare element al şirului se poate
primului tablou sunt: a[0], a[1], a[2], …, a[29].
utiliza ca şi cum ar fi o variabila de tip int independenta, deci valoarea unui element al
Spunem ca tabloul este o variabila indexata, deoarece fiecare element al tabloului poate fi
vectorului poate fi modificata independent de celelalte elemente. Să presupunem ca
“găsit” / “utilizat” cunoscând numărul sau de ordine. Vectorul este un şir de valori în care se
utilizatorul introduce pentru n valoarea 4. Iniţial, elementele vectorului nu au o valoare bine
cunoaşte precis care este primul, al doilea, ….,ultimul element. “Numărul de ordine” al unui
definita; putem reprezenta grafic vectorul astfel:
element se numeşte indice.
Să presupunem ca utilizatorul introduce valorile 3, 7, 2, 9 pentru cele patru elemente ale
Exemplul 1: Să se calculeze minimul elementelor unui şir de n numere, utilizând vectori.
vectorului. Reprezentarea vectorului a va fi următoarea:
a[0] a[1] a[2] a[3]
3 7 2 9
Valoarea oricărui element al vectorului poate fi modificata fie printr-o atribuire, fie prin
introducerea unei valori (folosind funcţia cin, de exemplu) de la tastatura. Dacă vom introduce
atribuirea
a[2]=23;
valoarea elementului al treilea din vectorul a nu va mai fi 2 (vechea valoare) ci 23. De
asemenea, dacă se scrie:
cin>>a[2];
valoarea elementului va fi cea introdusa de utilizator de la tastatura.
Exemplul 2: Se considera n numere întregi introduse de la tastatura. Să se afle cate numere
sunt pare şi cate impare.

21
#include <iostream.h> #include <iostream.h>
#include <conio.h> #include <conio.h>
void main() void main(){
{ char cuvant[30];
int n; //numărul de elemente
int v[30]; //vector maxim 30 întregi clrscr();
int pare, impare; cout<<”Introduceti cuvantul:”;
// memorează nr. elementelor pare, impare cin>>cuvant;
int j; //variabila contor pentru for cout<<”Cuvantul introdus este:”<<cuvant;
}
clrscr(); Observaţi cu atenţie cum am declarat variabila ce va memora cuvântul: folosim un vector
//citim numărul de elemente cu elemente de tip caracter. Acest mod de declarare ne permite să lucrăm cu oricare dintre
cout<<”n=”; caracterele ce formează cuvântul. De exemplu, dacă utilizatorul introduce cuvântul salariu,
cin>>n; vectorul nostru de caractere arata cam aşa:
/* se citesc elementele şirului */ Dacă dorim să modificam puţin cuvântul putem scrie:
for(i=0;i<n;i++) cuvant[6]=’i’;
{ şi vom obţine cuvântul salarii.
cout<<”v[“<<i<<”]=”; Exemplul 4: Să se citească un cuvânt şi să se găsească numărul de vocale pe care le conţine.
cin>>v[i];
} #include <iostream.h>
//iniţializam variabilele #include <conio.h>
pare=0; # include <string.h>
impare=0; void main(){
//luam fiecare element din v şi testam dacă acesta este sau nu char c[30];// memorează cuvântului
par int vocale; // numărul vocalelor
for(j=0;j<n;j++) int j;
if (v[j] % 2 = =0)
pare++; clrscr();
else impare++; cout<<”Introduceti cuvantul:”;
//afişam rezultatul cin>>c;
cout<<”Am găsit “<<pare<<” numere pare şi “<<impare; vocale=0;
} //căutam vocalele
În programul de mai sus verificam, pentru fiecare element, dacă acesta se împarte exact la for(j=0;j<strlen(c);j++)
doi, caz în care am mai descoperit un element par. În caz contrar, numărul elementelor impare if ( c[j]==’a’ || c[j]==’e’
se măreşte cu unu. || c[j]==’i’ || c[j]==’o’
Am utilizat operatorul % , numit şi modul aritmetic, care are ca rezultat restul împărţirii lui || c[j]==’u’)
v[j] la 2. vocale++;
Exemplul 3: Să se introducă de la tastatura un cuvânt şi să se afişeze. cout<<”Am gasit “<<vocale<<” vocale.”;
}
Observaţii:
• Am utilizat funcţia strlen, care are ca rezultat numărul de caractere al şirului dat ca
parametru. Funcţia poate fi utilizata doar dacă a fost inclus fişierul header string.h, fişier
ce conţine funcţiile ce acţionează asupra şirurilor de caractere.

22
• “Mecanismul “algoritmului este următorul: se ia cate un caracter din şirul introdus şi se Exemplul 6. (sortare) Se considera un şir cu n elemente reale. Să se aranjeze elementele în
verifica dacă elementul respectiv conţine unul dintre caracterele a, e, i, o, u. De fiecare ordine crescătoare utilizând acelaşi vector.
dată când condiţia este adevărata se incrementează numărul de vocale. #include <iostream.h>
Mai multe despre şirurile de caractere vom spune după capitolul dedicat pointerilor. #include <conio.h>
Exemplul 5 (Căutare secvenţiala) Se considera un şir de n elemente întregi şi un număr void main(){
întreg x. Să se verifice dacă numărul x face parte din şirul considerat. double v[40];
int n;
#include <iostream.h> int j, k;
#include <conio.h>
void main(){ cout<<”n=”;
int v[25]; cin>>n;
int n; for(j=0;j<n;j++){
int x; cout<<”v[“<<j<<”]=”;
int j; cin>>v[j];
int gasit; //variabila logica ce indica dacă x aparţine lui v }
clrscr(); //sortarea crescătoare a şirului v
//citim numărul de elemente for(j=0;j<n-1;j++)
cout<<”n=”; for(k=j+1; k<n;k++)
cin>>n; if (v[j]>v[k]){
/* se citesc elementele şirului */ //interschimbăm valorile v[j] şi v[k]
for(j=0;j<n;j++){ temp=v[j];
cout<<”v[“<<j<<”]=”; v[j]=v[k];
cin>>v[j]; v[k]=temp;
} }
//se citeşte elementul x //afişarea valorilor sortate crescător
cout<<”x=”; for(k=0;k<n;k++)
cin>>x; cout<<v[k]<<”\t”;
gasit=0; }
j=0;
//căutam x în şirul v Tablouri bidimensionale (matrice)
while( (j<n)&&(!gasit)){
if (v[j]==x) gasit=1; Pe lângă vectori, cel mai utilizat tip de tablou de numere este tabloul bidimensional, numit
j++; de cele mai multe ori matrice. Declararea unei matrice se face astfel:
} tip_de_baza nume[dimensiune_1][dimensiune_2];
if(gasit) Exemplu:
cout<<”Elementul aparţine şirului dat !”; double a[10][5]; //tablou cu 10 linii şi 5 coloane de elemente reale
else int a[3][2]; //tablou cu 3 linii şi 2 coloane de elemente întregi
cout<<”Elementul nu aparţine şirului !”; Pentru a putea avea acces la valoarea unui element al matricei, trebuie să precizam linia şi
} coloana pe care se afla acesta. Un element poate fi specificat prin a[i][j], i - reprezentând
Am utilizat instrucţiunea while, condiţia de efectuare a ciclului fiind (j<n) && linia şi j - coloana. În cazul vectorilor citeam o valoare reprezentând numărul de elemente.
(!gasit). Corpul instrucţiunii while se va executa atât timp cat nu s-a ajuns la sfârşitul Pentru matrice vom citi o valoare m - numărul maxim de linii şi o valoare n - numărul maxim
şirului şi elementul x nu a fost găsit în v. Condiţia de mai sus devine falsă în doua cazuri: fie de coloane. O matrice cu m linii şi n coloane va avea m * n elemente.
am epuizat elementele şirului (j a ajuns egal cu n), fie am găsit un element egal cu x. După Dacă m = n atunci matricea se numeşte matrice pătrata de ordin n.
executarea ciclului while testam dacă variabila găsit este ne nula (adevăr), caz în care x Exemplul 7. Să se citească elementele unei matrice şi să se afişeze.
aparţine lui v, altfel x nu aparţine şirului.
23
#include <iostream.h> typedef int matrice[20][20];
#include <conio.h> matrice a, b, c;
void main(){ Am definit un tip de date (tip de date definit de utilizator) ale cărui elemente sunt matrice
int a[20][20]; //matrice cu elemente întregi cu maxim 20 de linii şi coloane cu elemente întregi. Numele noului tip este matrice.
int m, n; // linii, respectiv coloane Declararea variabilelor de acest tip se poate face oriunde în programul în care apare definiţia.
int i, j; //contoare pentru for Definirea unui tip de date se poate face numai prin utilizarea cuvântului cheie typedef înaintea
declaraţiei. Dacă definim mai multe tipuri se va folosi typedef pentru fiecare definiţie.
//citim numărul de linii şi coloane
cout<<”Numărul de linii:”;
cin>>m;
Noţiunea de pointer
cout<<”Numărul de coloane:”; Pointerii au fost introduşi în limbajele de programare pentru a putea rezolva mai eficient
cin>>n; anumite probleme sau pentru a da mai multa claritate anumitor programe.
//se citesc elementele matricei O prima definiţie poate fi următoarea:
for(i=0;i<m;i++) Pointerul este o variabila ce conţine adresa unui obiect.
for(j=0;j<n;j++){ Obiectul a cărei adresa este reţinuta de pointer poate fi:
cout<<”a[“<<i<<”][“<<j<<”]=”; variabila
cin>>a[i][j]; funcţie
} Fie următorul exemplu:
//afişarea elementelor matricei int x;
for(i=0;i<m;i++){ int *px;
for(j=0;j<n;j++) cout<<a[i]][j]<<”\t”; Am definit o variabila de tip întreg x şi o variabila pointer, care poate conţine adresa unei
cout<<”\n”; variabile de tip întreg. Simbolul * ce apare În stânga variabilei px arata ca px este o variabila
} pointer.
} Prin atribuirea
Exemplul 8. Se dau doua matrice cu m linii şi n coloane. Să se calculeze matricea suma. px=&x;
………………………………………………. Pointerul va avea ca valoare adresa de memorie alocata variabilei x (vezi laboratorul nr.1,
int a[20][20], b[20][20], c[20][20]; definiţia variabilei). Operatorul unar & este utilizat pentru a se obţine adresa variabilei x
int m,n; (operator unar = are un singur operand)
int i, j;
Acum putem să lucrăm cu conţinutul variabilei x (adică cu valoarea acesteia) prin
………………………………………………..
//se citesc dimensiunile m, n şi cele doua matrici a şi b intermediul pointerului px, deci indirect, fără să mai folosim variabila x. La prima vedere,
………………………………………………. aceasta modalitate de lucru poate părea dificila şi nu tocmai utila. Necesitatea utilizării
//calculam matricea suma pointerilor va apare cu mai multa claritate în secţiunea dedicata şirurilor de caractere şi
for(i=0;i<m;i++) funcţiilor.
for(j=0;j<n;j++) Exemplul 1. Fie programul următor:
c[i][j]=a[i][j]+b[i][j];
//se afişează matricea c
………………………………………………..
Atunci când lucrăm cu matrice avem nevoie de doi indici: i pentru a parcurge liniile
matricei şi j pentru a parcurge coloanele acesteia. Pentru fiecare valoare a lui i, j ia toate
valorile intre 0 şi n-1, deci se parcurge linia i.
În ultimul exemplu am utilizat trei matrice. Pentru mai multa claritate, putem declara un tip
ale cărui elemente să fie matrice:

24
#include <iostream.h> #include <iostream.h>
void main(){ void main(){
int x,y; double x, y, z;
int *px; double *px, *py, *pz;

cout<<"x="; cin>>x;
cin>>x; cin>>y;
cout<<"y="; px=&x;
cin>>y; py=&y;
px=&x; pz=&z;
cout<<"x are valoarea "<<*px; *pz=*px+*py;
*px=y; cout<<"Suma este: "<<*pz;
cout<<"\nx a devenit "<<x; }
}
În programul de mai sus am introdus valorile variabilelor întregi x şi y, am definit un Pointeri şi tablouri
pointer la variabila x şi am atribuit acestuia adresa de memorie alocat variabilei x. Să
analizam atent linia: În limbajul C, exista o foarte strânsa legătura intre pointeri şi tablouri, astfel ca pointerii şi
cout<<"x are valoarea "<<*px; tablourile sunt tratate la fel. Orice program în care apar tablouri poate fi modificat astfel încât
să folosească pointeri în locul tablourilor. În aceasta secţiune vom discuta despre legătura
Prin *px se înţelege valoarea aflata în zona de memorie a cărei adresa este memorata în
dintre pointeri şi vectori (tablouri unidimensionale).
pointerul px. Valoarea afişată va fi chiar valoarea introdusa pentru x deoarece, înainte de
Fie următoarele declaraţii:
afişare, pointerul px a primit ca valoare adresa variabilei x, adresa la care se afla valoarea int a[20];
acesteia (valoare dobândita prin utilizarea funcţiei cin). int *pa;
Atribuirea *px=y; va modifica valoarea care se afla la adresa memorata de px, valoare Am declarat o variabila a , care este un vector cu maxim 20 elemente întregi şi pa un
care va fi valoarea introdusa de utilizator pentru variabila y. Astfel va fi modificata chiar pointer la o variabila de tip întreg. După cum se ştie, o valoare int are nevoie de 16 biţi pentru
valoarea pe care o are variabila x. a fi memorata, adică 2 Byte (o variabila int poate retine numere întregi intre -32768 şi 32767,
Fireşte ca era mai simplu să folosim atribuirea x=y; care are acelaşi efect şi ne scuteşte de vezi curs Bazele Informaticii). Pentru tabloul a vor fi alocaţi 2*20=40Byte consecutivi în
de-a mai folosi pointeri, insa exemplul este pur didactic. memorie adică, pentru primul element a[0] sunt alocaţi primii 2Byte, pentru a[1] următorii
Operatorul unar * este folosit sub forma *variabila_pointer, valoarea acestei 2Byte,…, pentru a[19] ultimii 2 Byte din cei 40 alocaţi.
expresii fiind valoarea care se găseşte în memorie la adresa memorata de pointerul ce apare ca Fie atribuirea: pa=&a[0];
operand. În concluzie, prin px avem acces la adresa variabilei x, iar prin *px la valoarea După aceasta atribuire, pointerul pa conţine adresa primului element al vectorului, adică
variabilei x. pa pointează la începutul vectorului a.
Vom spune ca un pointer “refera” indirect un obiect sau ca “pointează”(arata) la obiectul Dacă scriem pa=&a[3]; atunci pa va referi elementul al 4-lea din vectorul a, iar *pa va
respectiv. Variabilele pointer pot fi încadrate ca fiind de tip referinţa. conţine valoarea sa.
Exemplul 2. Să se calculeze suma a doua numere reale folosind pointeri. Operaţiile care se pot realiza cu pointeri sunt:
• comparaţia
• adunarea unui pointer cu un întreg
• scăderea unui întreg dintr-un pointer
Doi pointeri pot fi comparaţi folosind operatori relaţionali. În comparaţia:

25
if(p1==p2) Noţiunea de funcţie. Structura şi definirea funcţiilor
cout<<”Adrese identice”;
else Noţiunea de funcţie este o noţiune de mare importanta în informatica, orice limbaj de
cout<<”Adrese diferite”; programare furnizând facilităţi de lucru cu funcţii.
se verifica dacă adresa memorata de p1 este aceeaşi cu adresa reţinuta de p2, unde p1 şi În matematica, funcţia era definita ca fiind tripletul (A, B, f), unde:
p2 sunt pointeri de acelaşi tip. Se poate compara un pointer cu valoarea NULL (sau 0). Un A - domeniul de definiţie;
pointer are valoarea NULL (valoare nedefinita) dacă nu refera nici un obiect. Adunarea unui B - codomeniul sau domeniul de valori;
pointer cu un întreg este definita numai atunci când pointerul refera un tablou (un element al f - lege, convenţie, prin care fiecărui element din domeniul de definiţie i se asociază un
tabloului). Scăderea este definita în acelaşi caz. unic element din codomeniu;
Exemplul 3. Să se citească elementele unui vector şi să se afişeze acestea utilizând pointeri. În informatica, noţiunea de funcţie diferă puţin de modul matematic de abordare. În
#include <iostream.h> limbajul C, orice program trebuie să conţină obligatoriu o funcţie numita main. Dacă
void main(){ prelucrările ce compun programul sunt foarte complexe, utilizarea unei singure funcţii duce la
int a[20]; un program greu de înţeles şi depanat. În acest caz este bine ca problema de rezolvat să fie
int *pa; împărţita în sub probleme prin a căror combinare să se obţină rezolvarea problemei iniţiale.
int i,n; Pentru rezolvarea fiecărei sub probleme se poate utiliza cate o funcţie separata. Funcţia main
(“programul principal”) nu va mai fi de mare întindere, ea conţinând doar apeluri către
cout<<"Numărul de elemente= "; funcţiile deja definite.
cin>>n; Decizia de a folosi o funcţie poate fi luata şi în cazul în care anumite prelucrări trebuiesc
for(i=0;i<n;i++){ realizate de mai multe ori, cum se va vedea şi în exemplul de mai jos.
cout<<"Elementul"<<i<<"="; Exemplul 1. Să se calculeze aria a n triunghiuri, dacă se cunosc lungimile laturilor
cin>>a[i]; acestora.
}
//afişarea vectorului folosind pointeri
pa=&a[0];
for(i=0;i<n;i++){
cout<<*pa<<"\n";
pa++;
}
}
Prima pate a programului nu conţine elemente noi, doar a doua parte meritând atenţie. Mai
întâi iniţializam pointerul pa cu valoarea primului element al vectorului a. Ciclul for conţine
următoarele prelucrări:
• afişează valoarea aflata la adresa indicata de pointer;
• aduna pointerul pa cu 1
Incrementarea pointerului pa are ca efect modificarea adresei memorate în pa. Noua adresa
este adresa zonei de memorie corespunzătoare elementului următor, o adresa cu 2Byte mai
mare decât precedenta. Observam ca mărirea pointerului cu o unitate înseamnă de fapt trecerea
la următorul element din vector.
Dacă vom introduce pentru n o valoare mai mare decât 20 (numărul maxim de elemente
ale vectorului, aşa cum reiese din declaraţie) atunci pointerul pa va depăşi zona de memorie
alocata vectorului şi va referi o adresa la care se pot afla date importante pentru program.
Urmările pot fi imprevizibile, de la blocarea programului până la blocarea sau închiderea
calculatorului !!!

26
#include <iostream.h> {
#include <conio.h> float p,s;
#include <math.h> p=(float)(a+b+c)/2;
float aria(int a, int b, int c){ s=sqrt(p*(p-a)*(p-b)*(p-c));
float p,s; return s;
p=(float)(a+b+c)/2; }
s=sqrt(p*(p-a)*(p-b)*(p-c)); Corpul funcţiei conţine declaraţiile variabilelor utilizate în funcţie şi prelucrările realizate
return s; de funcţie. Variabilele utilizate în funcţia aria, numite şi variabile locale, sunt semi perimetrul
} p şi aria s. Nu declaram variabilele a, b, c (parametrii formali nu se declara în corpul funcţiei)
void main(){ şi nici nu citim valori pentru ele în cadrul funcţiei.
int a,b,c; Orice funcţie care are drept codomeniu un tip diferit de tipul void trebuie să conţină în
float S; corpul funcţiei o instrucţiune
int i,n; return expresie;
unde expresie este orice expresie corecta în C cu valoare de tipul declarat pentru codomeniu.
cout<<"Numărul de triunghiuri= "; Instrucţiunea return este utilizata pentru a semnala faptul ca valoarea funcţiei este
cin>>n; valoarea expresiei.
i=1; În programul principal (funcţia main) se citeşte numărul de triunghiuri n. Instrucţiunea for
for(i=1;i<=n;i++){ va repeta de n ori (pentru fiecare triunghi) următoarele prelucrări:
cout<<"a="; • se citesc valori pentru variabilele a, b, c care reprezintă lungimile laturilor triunghiului
cin>>a; curent;
cout<<"b=";
• se calculează aria triunghiului pentru valorile date;
cin>>b;
cout<<"c="; • se afişează valoarea ariei triunghiului curent;
cin>>c; Modul de utilizare al funcţiei aria este interesant. Atribuirea:
S=aria(a,b,c); S=aria(a,b,c);
cout<<"Aria triunghiului "<<i<< are următorul efect;
" este "<<S<<"\n"; • se evaluează expresia din dreapta atribuirii, expresie ce consta din apelul funcţiei aria
} pentru valorile a, ,b, c
} • evaluarea funcţiei înseamnă executarea prelucrărilor din funcţie pentru valorile
Programul trebuie să calculeze aria a n triunghiuri, deci calculul ariei trebuie realizat de n parametrilor formali a, b, c
ori. Am definit funcţia aria, care calculează aria triunghiului cu lungimile laturilor a, b, c prin • valoarea întoarsa de funcţie este valoarea variabilei s, care apare în return;
formula lui Heron. Structura funcţiei este următoarea: • valoarea este memorata în zona de memorie a variabilei S.
antet: Funcţiile pot fi clasificate astfel:
float aria(int a, int b, int c) • funcţii predefinite = funcţii deja definite de autorii mediului de programare C şi grupate,
care conţine următoarele elemente: în funcţie de utilitatea lor, în biblioteci numite fişiere header. De exemplu, în biblioteca
• tipul rezultatului funcţiei (codomeniul) - rezultatul funcţiei va fi o valoare de tipul declarat; math.h sunt grupate funcţiile matematice, în string.h avem funcţiile de lucru cu şiruri de
• numele funcţiei: - numele nu poate fi identic cu un cuvânt cheie caractere, în iostream.h funcţii pentru introducerea şi afişarea datelor, în malloc.h şi
• lista parametrilor formali - variabilele de care depinde calcularea rezultatului alloc.h funcţii pentru alocarea memoriei…
(“argumentele funcţiei”); pentru fiecare parametru formal se specifica tipul. • funcţii definite de utilizator = funcţii scrise de creatorul unui program pentru acele
• corpul funcţiei: prelucrări pentru care nu exista funcţii predefinite (caz destul de frecvent);
O funcţie poate să aibă drept codomeniu orice tip predefinit scalar (întreg, caracter sau
real), tip compus (uniune sau structura), precum şi pointeri la orice tip. Tipul void înseamnă
ca funcţia nu returnează nici o valoare.
Programatorul poate să strângă funcţiile definite de el intr-un fişier header propriu, care se
poate include în program prin
27
#include “nume_fisier.h”. Funcţia nu întoarce nici o valoare, deoarece nu este necesar (n-are sens să întoarcem vreo
valoare), deci codomeniul va fi tipul void. Din moment ce funcţia nu întoarce vreo valoare,
Apelul funcţiilor şi transferul parametrilor nu se va mai utiliza return.
Exemplul 3. Scrieţi o funcţie care să afişeze un mesaj.
Orice apariţie a numelui funcţiei însoţită de un număr de valori egal cu numărul void mesaj( ){
parametrilor formali se numeşte apel al funcţiei. cout<<”Trăiască Reforma !!!”;
Puteam apela funcţia şi în modul următor: }
cout<<aria(3,4,5); Funcţia mesaj nu întoarce nici o valoare şi nici nu conţine parametrii formali (nu exista
Aceasta instrucţiune are ca efect afişarea ariei triunghiului cu laturile de lungimi 3, 4, 5. valori care să fie necesare execuţiei funcţiei). Apelul funcţiei se va face prin: mesaj();
Observaţi ca nu este obligatoriu ca parametrii din apel să fie variabile, ci pot fi expresii.
exact ca şi pentru funcţia pre definită clrscr( ).
Dacă funcţia noastră ar apărea intr-o expresie ca 23*aria(3,4,5)-
Dacă am dori ca funcţia să afişeze un mesaj dat, obţinem:
2*aria(2,6,6), evaluarea expresiei ar începe cu executarea funcţiei aria pentru valorile 3, void mesaj(char s[80]){
4, 5 şi apoi pentru 2, 6, 6; după ce se obţin rezultatele celor doua apeluri ale funcţiei se cout<<s;
realizează evaluarea celorlalte operatori (înmulţirile şi apoi scăderea). }
Funcţia în care apare un apel al altei funcţii se numeşte funcţie apelanta. Apelul funcţiei poate fi: mesaj("Trăiască pacea şi bunăstarea
Parametrii sunt de doua tipuri: poporului chinez !!!”);
parametri formali: Exemplul 4. Scrieţi o funcţie care stabileşte dacă un număr este prim.
valoare #include <iostream.h>
referinţa (pointer) int este_prim(int n){
parametri efectivi (actuali) int j;
Parametrii sunt utilizaţi pentru a putea transmite din funcţia apelanta valorile necesare int este;
prelucrărilor efectuate de funcţia apelata. Atunci când parametrii formali sunt utilizaţi doar
pentru a transmite valori în funcţia apelata, aceşti parametrii se numesc parametri valoare. este=1; //presupunem ca numărul este prim
Dacă se doreşte transmiterea ca parametru a unei variabile, în scopul modificării valorii for(j=3;j*j<=n;j++)
acesteia astfel încât modificarea să fie disponibila în funcţia apelanta, avem de-a face cu un if(n%j==0) este=0;
parametru formal referinţa (se realizează printr-o variabila de tip pointer). return este;
Pentru a putea apela o funcţie, trebuie să precizam, pe lângă numele acesteia, valorile }
parametrilor pentru care se realizează apelul (parametri actuali). Numărul parametrilor actuali
dintr-un apel de funcţie trebuie să fie acelaşi cu numărul parametrilor formali din definiţia void main(){
funcţiei apelate şi să corespunda ca tip. int număr;
De exemplu, în programul de mai sus, nu puteam apela funcţia aria ca s =
aria(4.56, 5, 5); deoarece primul parametru formal din definiţia funcţiei este definit cout<<”Introduceti numărul=”;
ca de tip int, iar parametrul actual (4.56) este de tip double (incompatibilitate de tip). cin>>număr;
Nu este obligatoriu să existe parametrii formali intr-o funcţie dacă nu este nevoie. De if(este_prim(număr)!=0)
asemenea, nu toate funcţiile întorc o valoare. Aceste aspecte sunt tratate în următoarele cout<<”Numărul este prim !”;
exemple. else
Exemplul 2. Să se scrie o funcţie care afişează pe ecran un număr dat de asteriscuri. cout<<”Numărul nu este prim !”;
void asterisc(int nr){ }
int j; Exerciţiul 1: Folosiţi funcţia este_prim pentru a afişa toate numerele prime mai mici decât un
for(j=1;j<=nr;j++) număr întreg dat.
cout<<”* ”; Exemplul 5. Scrieţi o funcţie care să citească un vector de numere întregi.
}
Funcţia are un singur parametru formal, un întreg nr reprezentând numărul de asteriscuri ce
trebuie afişate. Funcţia poate fi apelata prin asterisc(10); care are ca efect afişarea a 10
asteriscuri.
28
void citeste(int a[30], int n) #include <iostream.h>
{ int cmmdc(int m, int n){
int k; int r;

for(k=0;k<n; k++) do{


cin>>a[k]; r=m%n;
} m=n;
Funcţia are doi parametri: variabila de tip vector care va retine numerele citite şi variabila n=r;
n, care ne spune cate elemente trebuiesc citite. Funcţia main poate să arate astfel: }while(r!=0);
void main (){ return m;
int b[30]; }
int n;
void main(){
cout<<”n=”; int a,b;
cin>>n;
citeste(a,n); cout<<"Primul număr=";
} cin>>a;
Exerciţiul 6: Scrieţi o funcţie pentru afişarea elementelor unui vector şi adăugaţi-o exemplului cout<<"Al doilea număr=";
precedent. cin>>b;
Exemplul 7. Scrieţi o funcţie care calculează suma elementelor dintr-un vector. cout<<cmmdc(a,b);
int suma(int a[40], int n) }
{ Exemplul 12 Să se scrie o funcţie care verifica dacă un întreg x aparţine unui vector v.
int k; int cauta(int v[50], int n){
int s; int k;
s=0; int apartine;
for(k=0;k<n;k++)
s=s+a[k]; apartine=0;
return s; //se presupune ca x nu este element în v
} for(k=0;k<n;k++)
Este necesar să introducem ca parametru şi numărul de elemente din vector n. if(v[k]==x) apartine=1;
Exerciţiul 8: Folosiţi funcţia de mai sus în programul de la exerciţiul precedent. return apartine;
Exemplul 9. Scrieţi o funcţie care calculează ax, unde a real şi x întreg pozitiv. }
float putere(float a, int x) Exemplul 13. Să se scrie o funcţie care realizează suma a doua matrice cu m linii şi n
{ coloane.
int k; void suma_mat(int a[20][20], int b[20][20], int c[20][20], int
int p; //retine puterea m, int n){
p=1; int j, k; //variabile contor în for
for(k=1;k<=x;k++) for(j=0;j<m;j++)
p=p*a; for(k=0;k<n;k++)
return p; c[j][k]=a[j][k]+b[j][k];
} }
Exerciţiul 10. Modificaţi funcţia din exemplul 7 astfel încât să poată ridica pe a şi la puteri Parametrii de care depinde rezolvarea sarcinii sunt:
negative. a - prima matrice
Exemplul 11. Scrieţi o funcţie pentru a calcula cel mai mare divizor comun a 2 numere b - a doua matrice
întregi folosind algoritmul lui Euclid. c - matricea suma (rezultatul sumei)
29
m - numărul de linii Parcurgeţi din nou exemplul 10 şi priviţi cu atenţie antetul funcţiei suma_mat. Parametrul
n - numărul de coloane formal c este o matrice calculata ca suma matricelor a şi b, deci valoarea elementelor lui c este
Exerciţiul 5. Să se scrie funcţia main corespunzătoare funcţiei de mai sus, precum şi funcţii modificata în cadrul funcţiei, dar parametrul formal este corect? Răspunsul este afirmativ
pentru citirea şi afişarea unei matrice. deoarece, după cum ştiţi, tablourile sunt tratate exact ca şi pointerii, deci tablourile care apar
O situaţie interesanta apare atunci când vrem ca variabilele ce apar ca parametri formali să ca parametrii formali se considera parametri referinţa.
poată fi modificate în cadrul funcţiei, modificările fiind disponibile în funcţia apelanta.
Să luam următorul exemplu:
Exemplul 14. Să se scrie o funcţie care interschimbă valorile a doua variabile întregi.
Varianta următoare este greşita:
void schimba(int x, int y){
int temp;
temp=x;
x=y;
y=temp;
}
void main(){
int a, b;
cin>>a;
cin>>b;
schimba(a,b);
cout<<a;
cout<<b;
}
La prima vedere funcţia pare corecta, insa lucrurile stau tocmai pe dos. Dacă introducem
valorile 5 pentru a şi 7 pentru b, programul ar trebui să schimbe intre ele valorile celor doua
variabile (a trebuie să devină 7, iar b să devină 5). Programul de mai sus nu va realiza acest
lucru. Explicaţia este ca, atunci când parametri formali sunt parametri valoare, chiar dacă se
modifica valoarea lor în cadrul funcţiei aceste modificări nu vor avea efect în funcţia apelanta
(în cazul nostru, în funcţia main nu va fi sesizabila schimbarea realizata în funcţia schimba).
Problema se poate rezolva dacă parametrii din funcţia schimba vor fi parametri referinţa
(pointeri).
Varianta corecta este următoarea:
void schimba(int *x, int *y){
int temp;

temp=*x;
*x=*y;
*y=temp;
}
Singura schimbare din funcţia main este apelul funcţiei, care devine
schimba(&a, &b);
Explicaţia corectitudinii acestei variante este aceea ca se lucrează cu adresele variabilelor,
deci orice modificare a conţinutului zonelor de memorie alocate variabilelor x şi y va fi
resimţită şi în funcţia main.

30
Este recomandat ca diversele variabile cu rol temporar sau de indici să aibă nume scurte,
aceasta fiind o indiciu pentru programator că ele nu sunt folosite dincolo de limita a câtorva
Anexe linii de cod.
Numele cel mai des folosite pentru astfel de variabile întregi sunt: i, j, k, m, n,
Recomandări pentru scrierea programelor respectiv c sau d pentru cele de tip caracter.
Numele unui obiect conţine de obicei numele clasei din care face parte, de aceea ar fi bine
să se evite reluarea numelui clasei în numele date metodelor clasei.
Convenţii generale de nume cerc.obtRaza(); // NU: cers.obtRazaCerc();
Inserarea numelui obiectului în numele metodelor pare naturală în cadrul definiţiei clasei,
Numele compuse reprezentând tipuri de date ar fi bine să conţină litere mari la începutul dar se dovedeşte de prisos la utilizarea efectivă, cum se poate vedea şi din exemplul dat.
fiecărui cuvânt component.
Vector, StudentBursier Convenţii specifice de nume
Numele compuse reprezentând variabile ar fi bine să înceapă cu literă mică şi să conţină
Termenii obtine/seteaza (obt/set, get/set) trebuie folosiţi pentru metodele care accesează
litere mari la începutul fiecărui cuvânt component.
contor, nrStud direct o dată membră a clasei.
student.obtineNume();
Astfel, variabilele se vor distinge uşor de tipuri şi se vor evita eventualele conflicte de
matrice.obtElement(2, 4);
nume, ca în declaraţia: Line line.
angajat.seteazăNume(nume);
Numele de constante (inclusiv al celor folosite în enumerări) ar fi bine de scris cu litere
matrice.setElement(2, 4, val);
mari în întregime, utilizându-se liniuţa de subliniere pentru separarea cuvintelor componente.
Practică generalizată în comunitatea programatorilor C++. In Java această convenţie tinde
NR_MAX, SEMAFOR_ROSU, PI
să se standardizeze.
Numele compuse reprezentând metode, ca şi cele ale funcţiilor trebuie să descrie efectul
Ar fi bine ca denumirile listelor de obiecte să conţină sufixul List.
respectivei metode sau funcţii, recomandabil în format Camel Case (la început cu literă mică,
stud (un student),
apoi cu literă mare la începutul fiecărui cuvânt component)
studList (o listă de studenţi)
sumElem(), maxVect(), obtNume(), calcLungTotala()
Lizibilitatea programului creşte de vreme ce numele unui obiect sugerează imediat
Numele compuse reprezentând spaţii de nume ar fi bine să conţină în întregime doar litere
cititorului tipul şi operaţiile ce pot fi efectuate asupra lui.
mici.
Ar fi bine de ataşat prefixul nr variabilelor reprezentând un număr de obiecte.
analizor, managerdialog, fereastraprinc
nrPuncte, nrLinii
Numele pentru tipuri şablon ar fi bine să fie alcătuite dintr-o singură majusculă.
Această notaţie este preluată din matematică.
template<class T>…
Ar fi bine ca variabilele iterative să fie numite i, j, k etc.
template<class C, class D> ...
Exemplu:
Abrevierile şi acronimele nu trebuie scrise cu majuscule atunci când intră în componenţa
for (int i = 0; i < nrLinii); i++) { ... }
unui nume.
Această notaţie este preluată din matematică.
exportHtmlSource();// NU: exportHTMLSource();
Ar fi bine de ataşat prefixul is variabilelor şi funcţiilor booleene şi de evitat negaţiile din
openDvdPlayer(); // NU: openDVDPlayer();
cadrul numelor acestora
Ar fi bine ca variabilele globale să fie totdeauna referite utilizând operatorul "::". isSet, isVisible, isFinished, isFound, isOpen
::ferPrinc.open(), ::contextApl.obtNume() NU: isNotSet, isNotVisible, isNotFound etc.
În general, e bine de evitat folosirea variabilelor globale, acestea putând fi înlocuite cu Practică generalizată în comunitatea programatorilor C++ şi parţial impusă în Java.
obiecte având un singur membru. Utilizarea acestui prefix împiedică alegerea unor denumiri neinspirate de genul status sau flag
Ar fi bine ca toate numele să fie scrise în română (în orice caz, într-o aceeaşi limbă). pentru acţiunile booleene. Deoarece isStatus sau isFlag nu sună bine, programatorul va trebui
numeFisier; // NU: filNavn să găsească denumiri mai sugestive. De asemenea, apar confuzii atunci când un astfel de nume
Engleza este limba general adoptată de comunitatea internaţională, însă este mai firesc ca este folosit împreună cu operatorul de negaţie logică, rezultând o dublă negaţie.
programele destinate utilizatorilor români să conţină nume cât mai sugestive, în limba nativă. Operaţiile opuse trebuie să aibă denumiri antonime
Ar fi bine ca variabilele cu domeniu mare de vizibilitate să aibă nume mai lungi, iar cele
cu domeniu mic de vizibilitate să aibă nume scurte.

31
obt/set, add/remove, creaza/distruge, start/stop, class Student
insert/delete, increment/decrement, old/new, begin/end, {
first/last, up/down, min/max, next/previous, old/new, public:
open/close, show/hide, suspend/resume, etc. float obtMedia () {return media} // NU!
Complexitatea operaţiei de asociere a unui nume cu semantica sa este redusă datorită ...
simetriei. private:
Ar fi bine să fie evitate abrevierile în cadrul numelor. float media;
calculeazaMedia(); // NU: calcMed(); }
Trebuie avute în vedere două tipuri de cuvinte. Întâi, cuvintele obişnuite, care se găsesc în Astfel va fi uşor de regăsit fişierele asociate cu o clasă dată.
dicţionar. Acestea nu trebuiesc niciodată prescurtate. Nu scrieţi niciodată: Conţinutul unui fişier nu trebuie să depăşească 80 de coloane.
cmd în loc de comanda -
cp în loc de copie 80 de coloane este o dimensiune generalizată pentru editoarele de text, emulatoarele de
pt în loc de punct terminal, imprimante şi debuggere, de aceea ar fi bine ca fişierele partajate de mai multe
calc în loc de calculeaza persoane să respecte această restricţie.
init în loc de initializeaza Caracterele speciale de genul "TAB" sau "page break" trebuie evitate.
etc. Aceste caractere pot cauza probleme editoarelor de text, emulatoarelor de terminal,
Apoi, expresiile din diferite domenii popularizate mai mult prin abrevieri/acronime ar fi imprimantelor sau debuggerelor atunci când sunt folosite într-un mediu multi-programare sau
bine de păstrat în aceste forme prescurtate ale lor. Nu scrieţi niciodată: multi-platformă.
HypertextMarkupLanguage în loc de html Trebuie bine evidenţiat faptul că o instrucţiune se întinde pe mai multe linii
CentralProcessingUnit în loc de cpu Atunci când o declaraţie depăşeşte limita de 80 de coloane, ea este divizată pe mai multe
PriceEarningRatio în loc de pe linii. Este dificil de stabilit reguli rigide de divizare a liniilor, dar exemplele de mai sus dau o
etc. oarecare sugestie. În general:
Constantele enumerative pot fi prefixate cu numele tipului lor comun. • Se poate trece pe o linie nouă după o virgulă
Exemplu: • Se poate trece pe o linie nouă după un operator
enum Color { COLOR_RED, COLOR_GREEN, COLOR_BLUE }; • Se aliniază noua linie cu începutul expresiei din linia precedentă
Astfel sunt furnizate informaţii suplimentare despre locul unde poate fi găsită declaraţia,
setul de constante înrudite şi conceptele reprezentate de constante.
Includerea de fişiere şi includerea declaraţiilor
Fişiere sursă Fişierele antet trebuie să conţină o construcţie care să prevină incluziunile multiple.
Convenţia este ca numele acestor construcţii să fie formate doar din litere mari şi să fie
Ar fi bine ca fişierele antet C++ să aibă extensia .h. , iar fişierele sursă extensia .cpp. compuse din numele modulului de program, numele fişierului şi sufixul h.
1_1.cpp, 1_1.h Exemple:
Acestea toate sunt standarde C++ adoptate deja pentru extensiile de fişiere. #ifndef _LISTA_H
Ar fi bine ca o declaraţia unei clase să se găsească într-un fişier antet, iar definiţia ei - într- #define _LISTA_H
un fişier sursă, ambele cu un nume apropiat de cel al clasei. …
student.cpp, student.h #endif
Astfel va fi uşor de regăsit fişierele asociate cu o clasă dată. Scopul este evitarea erorilor de compilare. Această convenţie de nume este deja
Ar fi bine ca toate definiţiile să se găsească în fişiere sursă. generalizată. Ar fi bine ca această construcţie să fie plasată chiar la începutul fişierului
(înaintea tuturor declaraţiilor). Astfel, se va renunţa la parsarea fişierelor iar timpul de
compilare va fi redus.
Ar fi bine ca instrucţiunile de includere să fie sortate (crescător, după poziţia lor ierarhică
în sistem) şi grupate pe categorii (fiind lăsată o linie liberă între diversele grupe).
Exemple:

32
#include <fstream> Conceptele C++ de ascundere a informaţiilor şi de încapsulare sunt violate prin folosirea
#include <iomanip> variabilelor public. În locul lor ar putea fi folosite variabile private şi metode de accesare a
acestora. Există o singură excepţie de la această regulă: în clasele reprezentând structuri de
#include <Xm/Xm.h> date neomogene (echivalentul unor struct din C) este mai indicată declararea variabilelor drept
#include <Xm/DateImp.h> public.
Reţineţi faptul că tipul struct este menţinut în C++ doar din motive de compatibilitate cu C,
#include "ui/ProprietatiDialog.h" iar evitarea lui va spori lizibilitatea programului. În loc de acesta ar putea fi folosi class.
#include "ui/FereastraPrincipala.h" Variabilele înrudite de acelaşi tip pot fi declarate împreună[3].
Este sugerat astfel şi ce module de program sunt implicate. Ar fi bine ca pentru variabilele neînrudite să nu se folosească o aceeaşi declaraţie.
Instrucţiunile de includere trebuie să fie plasate doar la începutul fişierului. Exemplu:
Practică generalizată. Sunt evitate efectele secundare ale compilării unor fişiere incluse float x, y, z;
datorită unor clauze #include ascunse printre liniile programului sursă. int bursaIanuarie, bursaFebruarie, bursaMartie;
Cerinţa generală de a scrie declaraţiile pe linii separate nu se aplică situaţiilor de genul
Tipuri de date celor de mai sus. Grupându-se variabilele astfel, creşte lizibilitatea.
Tipurile de date locale unui singur fişier pot fi declarate în interiorul acelui fişier. Ar fi bine ca simbolul ce indică o referinţă sau un pointer C++ să fie scris lângă numele
Implică ascunderea informaţiilor. variabilei şi nu lângă numele tipului de dată.
Secţiunile unei clase trebuie să fie, în ordine, public, protected şi private, fiecare Exemplu:
trebuind evidenţiată explicit. Celelalte eventuale secţiuni ar fi bine de lăsat deoparte. float *x; // NU: float* x;
Criteriul de ordonare este "cel mai public întâi", astfel încât cei care doresc doar să int &y; // NU: int& y;
utilizeze clasa ştiu că e suficient să citească definiţiile până la întânirea secţiunilor protected şi Este discutabil dacă un pointer este o variabilă de un tip pointer (float* x) sau un
private. pointer la un tip dat (float *x). Recomandarea de mai sus se bazează pe faptul că este
Conversiile de tip trebuie făcute totdeauna explicit. Nu vă încredeţi niciodată în conversiile imposibil să indici mai mult decât un pointer într-o declaraţie de primul fel. De exemplu,
implicite de tip. float* x, y, z; este echivalent cu float *x; float y; float z;. Acelaşi
Exemple: lucru este valabil pentru referinţe.
medie = static_cast<float> nota // AŞA DA! Ar fi bine ca testele implicite de egalitate cu 0 să nu fie folosite decât pentru variabilele
valReala = valIntreaga; // AŞA NU! booleene şi pointeri.
Prin aceasta programatorul indică folosirea conştientă a diferitelor tipuri şi a amestecului Exemplu:
lor. if (nrLinii != 0) // NU: if (nrLinii)
if (valoare != 0.0) // NU: if (valoare)
Variabile Valorile 0 (nule) pentru variabilele întregi şi reale nu sunt în mod necesar implementate de
compilator prin valoarea binară 0. De asemenea, un test explicit sugerează imediat tipul testat.
Ar fi bine ca variabilele să fie iniţializate acolo unde sunt declarate.
Pentru pointeri s-a generalizat practica testelor implicite de egalitate cu 0 (de ex. "if
Aceasta dă siguranţa că variabilele sunt valide în orice moment. Uneori este imposibil ca
(line == 0)" în loc de "if (line)"), totuşi pot fi folosite şi testele explicite.
variabilele să fie iniţializate cu o valori valide chiar în momentul declarării lor:
int x, y, z; Ar fi bine ca variabilele să fie declarate cu cel mai mic domeniu de vizibilitate posibil.
obtCentru (&x, &y, &z); Astfel sunt mai uşor de controlat acţiunile şi efectele secundare ale variabilelor.
În astfel de cazuri este preferabilă varianta neiniţializării decât iniţializarea cu valori
nepotrivite. Bucle repetitive
Variabilele nu trebuie să aibă niciodată un înţeles dual. În construcţia for() trebuiesc incluse doar instrucţiuni de control a buclei repetitive.
Asigurându-se o reprezentare unică pentru fiecare concept, creşte lizibilitatea programului Exemplu:
şi se reduce riscul erorilor datorate efectelor secundare
Ar fi bine ca utilizarea variabilelor globale să fie minimizată.
În C++ nu există nici un motiv special pentru utilizarea acestor variabile. Acelaşi lucru este
valabil pentru funcţiile globale şi pentru variabilele statice.
Ar fi bine ca variabilele membre ale unei clase să nu fie declarate niciodată public.
33
sum = 0; Exemplu:
// NU: for (i = 0, sum = 0; i < 100; i++) isError = readFile (fileName);
for (i = 0; i < 100; i++) if (!isError) {
sum += value[i]; …
Programul devine mai uşor de întreţinut şi de citit, fiind astfel clar care variabile }
controlează bucla şi care instrucţiuni o alcătuiesc. else {
Ar fi bine ca variabilele iterative să fie iniţializate imediat înainte de bucla repetitivă. …
Exemplu: }
terminat = false; Asiguraţi-vă că aţi luat în calcul toate excepţiile care ar putea împiedica execuţia normală a
// NU: bool terminat = false; programului. Este important atât pentru claritate cât şi pentru performanţă.
while (!terminat) { // Ar fi bine ca expresia condiţională să se găsească pe o linie separată.
... Exemplu:
} if (isDone) // NU: if (isDone) doCleanup();
Aceste construcţii pot fi comparate cu instrucţiunile goto şi de aceea este bine să fie doCleanup();
utilizate doar atunci când oferă o mai mare claritate decât corespondentele din programarea Explicaţia este legată de claritate şi de raţiuni de debug: este mai greu de evaluat o expresie
structurată. care se află pe aceeaşi linie cu alte instrucţiuni.
Pentru buclele infinite ar fi bine de folosit forma while(true). Trebuie evitate instrucţiunile executabile în interiorul expresiilor condiţionale.
Exemplu: Exemplu:
while (true) { // Rău!
} if (!(fileHandle = open (fileName, "w"))) {
for (;;) { // NU! …
} }
while (1) { // NU!
} // Mult mai bine!
while (1) nu este prea sugestivă şi cu atât mai puţin for (;;), care pare a se referi la o buclă fileHandle = open (fileName, "w");
infinită. if (!fileHandle) {

Expresii şi instrucţiuni condiţionale }
Mai ales pentru programatorii C++ începători astfel de expresii condiţionale ar fi foarte
Expresiile condiţionale complexe trebuie evitate. În locul lor se pot folosi variabile greoaie.
booleene temporare.
Exemplu:
if ((nrElem < 0) || (nrElem > maxElem)|| nrElem == ultElem) { Altele
… Ar fi bine să fie evitate în program numerele "magice" (cu alte valori decât 0 sau 1), fiind
} indicat să se folosească în locul lor constante declarate la începutul programului.
ar putea fi înlocuite prin: Dacă un număr nu are prin el însuşi o semnificaţie evidentă, e indicat să fie înlocuit printr-
terminare = (nrElem < 0) || (nrElem > maxElem); un nume de constantă sau printr-o funcţie care să-i acceseze valoarea.
repetare = (nrElem == ultElem); Trebuie totdeauna precizat explicit tipul returnat de o funcţie.
if (terminare || repetare) { Exemplu:
… int getValue(){ // NU: getValue()
} …
Asignând variabile booleene (cu nume sugestive) expresiilor, programul devine mai }
explicit. Dacă nu este precizat explicit, C consideră drept int tipul returnat de o funcţie. Acest lucru
Ar fi bine ca situaţia nominală (firească) să fie tratată pe ramura then iar excepţia pe poate să nu fie cunoscut însă de cei care vor citi programul.
ramura else a unei instrucţiuni if [1]. Ar fi bine să nu fie utilizată instrucţiunea goto.

34
Instrucţiunile goto contravin ideii de cod structurat. Doar în foarte puţine cazuri pot fi if (condiţie){ if (condiţie){
avute în vedere (de exemplu pentru ieşirea forţată dintr-un set foarte adânc de stucturi instrucţiuni; instrucţiuni;
imbricate) şi doar dacă nu pot fi rescrise într-un cod structurat mai clar. } }
Trebuie utilizat "0" în loc de "NULL". else if (condiţie){
NULL face parte din biblioteca C standard, însă în C++ este deja demodat. if (condiţie){ instrucţiuni;
instrucţiuni; }
Macheta unei instrucţiuni } else{
else{ instrucţiuni;
Ar fi bine ca dimensiunea unei indentări să fie de 2 spaţii. instrucţiuni; }
Exemplu: }
for (i = 0; i < nrElem; i++)
Scrierea fiecărei părţi a instrucţiunii if-else pe linii separate permite o mai uşoară citire şi
a[i] = 0;
manipulare a ei (de ex., renunţarea la clauza else).
Indentarea cu 1 caracter este prea mică pentru a evidenţia macheta logică a codului. O
Ar fi bine ca o instrucţiune for să fie scrisă sub următoarea formă:
indentare cu mai mult de 4 caractere ar îngreuia citirea structurilor imbricate şi ar crea şansa ca
Exemplu:
o instrucţiune să se întindă pe mai multe linii.
for (iniţializare; condiţie; actualizare){
Ar fi bine ca macheta unei instrucţiuni să arate ca în exemplul 2 de mai jos (recomandat)
instrucţiuni;
sau ca în exemplul 1, însă în nici un caz nu trebuie să arate ca în exemplul 3.
}
Exemple:
La fel, decurge parţial din regula generală pentru structura unui bloc.
while (!done) {
Ar fi bine ca o instrucţiune for cu bucla vidă să fie scrisă sub următoarea formă:
doSomething();
Exemplu:
done = moreToDo();
for (iniţializare; condiţie; actualizare)
}
{ }
Astfel este evidenţiat faptul că instrucţiunea for este construită în mod intenţionat cu bucla
while (!done)
vidă. Totuşi, ar fi bine ca buclele vide să fie evitate.
{
done = moreToDodoSomething(); Ar fi bine ca o instrucţiune while să fie scrisă sub următoarea formă:
done = moreToDo(); Exemplu:
} while (condiţie){
instrucţiuni;
while (!done) }
{ La fel, decurge parţial din regula generală pentru structura unui bloc.
doSomething(); Ar fi bine ca o instrucţiune do-while să fie scrisă sub următoarea formă:
done = moreToDo(); Exemplu:
} do{
Exemplul 3 introduce un nivel suplimentar de indentare care nu evidenţiază la fel de clar instrucţiuni;
ca primele două exemple structura logică a codului. } while (condiţie);
Emacs preferă varianta 3, VisualC varianta 2, iar începătorii o preferă pe prima (mai ales La fel, decurge parţial din regula generală pentru structura unui bloc.
cei care au lucrat în Pascal). Ar fi bine ca o instrucţiune switch să fie scrisă sub următoarea formă:
Ar fi bine ca o instrucţiune if-else să fie scrisă sub următoarea formă: Exemplu:
Exemple:

35
switch (condiţie) { Spaţiile albe
case ABC :
Ar fi bine ca:
instrucţiuni;
1. operatorii convenţionali să fie încadraţi de câte un caracter spaţiu;
// Se execută şi următoarele instrucţiuni până la primul
2. după fiecare cuvânt rezervat să urmeze un spaţiu;
break
case DEF : 3. virgulele să fie urmate de un spaţiu;
instrucţiuni; 4. operatorul : să fie încadrat de câte un caracter spaţiu;
break; 5. după fiecare operator ; să urmeze un spaţiu.
Exemplu:
case XYZ : a = (b + c) * d; // NU: a=(b+c)*d
instrucţiuni; while (true) {// NU: while(true) ...
break; doSomething (a, b, c, d);
// NU: doSomething (a,b,c,d);
default : case 100 : // NU: case 100:
instrucţiuni; for (i = 0; i < 10; i++) {
break; // NU: for (i=0;i<10;i++){
} Astfel, fiecare componentă individuală a unei instrucţiuni este pusă în evidenţă, iar
Observaţi faptul că fiecare cuvânt rezervat case este indentat relativ la cuvântul rezervat lizibilitatea programului în ansamblu creşte.
switch, ceea ce conduce la evidenţierea instrucţiunii switch ca întreg. Observaţi, de asemenea, Ar fi bine ca în funcţiile care au parametri să fie plasat un caracter spaţiu după "(" şi înainte
spaţiul dublu care precede caracterul ":". Dacă instrucţiunea break lipseşte de pe o ramură de ")".
case, ar fi bine să apară în locul ei un comentariu pentru a se şti că ignorarea ei a fost Exemplu:
intenţionată. doSomething( params )
// NU: doSomething(params);
Ar fi bine ca o instrucţiune try-catch să fie scrisă sub următoarea formă:
Exemplu: Astfel, fiecare nume în parte este evidenţiat, crescând lizibilitatea programului. Dacă o
try { funcţie nu are parametri, spaţiul poate fi omis (doSomething()) de vreme ce nu este
instrucţiuni; posibilă nici o confuzie asupra numelui în acest caz.
} Ar fi bine ca unităţile logice din cadrul unui bloc să fie separate printr-o linie goală.
catch (Exception excepţie) { Creşte astfel lizibilitatea programului.
instrucţiuni; Ar fi bine ca, în cadrul declaraţiilor, variabilele să fie aliniate la stânga.
} Exemplu:
La fel, decurge parţial din regula generală pentru structura unui bloc. AsciiFile *file;
Ramurile instrucţiunilor if-else şi buclele intrucţiunilor for sau while formate dintr-o int nrPuncte;
singură instrucţiune pot fi scrise fără paranteze acolade. float x, y;
Exemplu: Creşte astfel lizibilitatea programului. Numele variabilelor sunt astfel mai uşor de distins
if (condiţie) de numele tipurilor lor.
instrucţiuni; Există şi opinia contrară că aceste constructii sunt "fragile" atunci când codul evoluează şi
poate transforma programatorul într-o maşină de formatat.
while (condiţie) Recurgeţi la aliniere oriunde aceasta sporeşte lizibilitatea programului.
instrucţiuni; Exemplu:

for (iniţializare; condiţie; actualizare)


instrucţiuni;
Există ş recomadarea generală (de ex., din partea firmei Sun) ca parantezele acolade să fie
utilizate în toate cazurile. Totuşi, scopul parantezelor e acela de a grupa mai multe instrucţiuni
şi nu una singură.
36
If (a == lowValue) compueSomething(); while (true){
else if (a == mediumValue) computeSomethingElse(); // Efectueaza ceva
else if (a == highValue) computeSomethingElseYet(); prelucrare();
}

value = (potential * oilDensity) / constant1 + // NU:


(depth * waterDensity) / constant2 + while (true) {
(zCoordinateValue * gasDensity) / constant3; // Efectueaza ceva
prelucrare();
}
minPosition = computeDistance (min, x, y, z); Se evită astfel deteriorarea structurii logice a programului din cauza comentariilor.
averagePosition = computeDistance (average, x, y, z);

switch (value) {
Bibliografie:
case PHASE_OIL : strcpy (string, "Oil"); break; [1] Code Complete, Steve McConnel - Microsoft Press
case PHASE_WATER : strcpy (string, "Water"); break; [2] Programming in C++, Rules and Recommendations, M Henricson, e. Nyquist,
case PHASE_GAS : strcpy (string, "Gas"); break; Ellemtel (Swedish telecom)
} [3] Wildfire C++ Programming Style, Keith Gabryelski, Wildfire Communications Inc.
Există mai multe locuri într-un program unde pot fi plasate spaţii (în general în scopul [4] C++ Coding Standard, Todd Hoff
alinierii) pentru a se spori lizibilitatea, chiar dacă astfel se contravine regulilor generale de
scriere. Este dificil de formulat reguli privind alinierea codului, însă exemplele de mai sus http://www.doc.ic.ac.uk/lab/cplus/c++.rules/
ajută la formarea unei idei. http://www.wildfire.com/~ag/Engineering/Development/C++Style/
http://www.possibility.com/Cpp/CppCodingStandard.html
Comentariile
Ar fi bine nu să comentaţi codul care conţine capcane de programare, ci să-l rescrieţi! Anexe
În general, utilizarea comentariilor va fi minimizată la maxim dacă se scrie codul într-un
mod foarte clar, utilizându-se nume sugestive şi o structură logică explicită. Elemente de algebră booleană
Ar fi bine ca toate comentariile să fie scrise în limba engleză.
Engleza este limba preferată în orice mediu internaţional.
Folosiţi "//" pentru toate comentariile, inclusiv pentru cele care se întind pe mai multe linii. Generalităţi
Exemplu: Transferul, prelucrarea şi păstrarea datelor numerice sau nenumerice în interiorul unui
// Comentariu ce se întinde calculator se realizează prin intermediul circuitelor de comutare. Aceste circuite se
// pe mai multe linii. caracterizează prin faptul că prezintă două stări stabile care se deosebesc calitativ între ele.
De vreme ce în limbajul C nu sunt permise comentariile având mai multe nivele, utilizarea Stările sunt puse în corespondenţă cu valorile binare “0” şi “1” sau cu valorile logice
simbolului // face posibilă ataşarea de comentarii tuturor secţiunilor programului. Simbolurile “adevărat” şi “fals” (din acest motiv se mai numesc şi circuite logice). Pornind de la aceste
/* */ vor fi folosite în scopul depanării (eng. debug) (pentru a se verifica funcţionarea unei considerente, un domeniul al logicii matematice, (ştiinţa care utilizează metode matematice în
secţiuni a programului, celelalte secţiuni pot fi marcate temporar drept comentarii) etc. Ar fi soluţionarea problemelor de logică) numit “algebra logicii” şi-a găsit o largă aplicare în
bine să existe un spaţiu între "//" şi comentariul propriu-zis, care ar fi bine să înceapă cu literă analiza şi sinteza circuitelor logice. Algebra logicii operează cu propoziţii care pot fi adevărate
mare şi să se termine cu punct. sau false. Unei propoziţii adevărate i se atribuie valoarea “1”, iar unei propoziţii false i se
Ar fi bine să aliniaţi comentariile relativ la poziţia codului la care ele se referă. atribuie valoarea “0”. O propoziţie nu poate fi simultan adevărată sau falsă, iar două propoziţii
Exemplu: sunt echivalente din punct de vedere al algebrei logice, dacă simultan ele sunt adevărate sau
false. Propoziţiile pot fi simple sau compuse, cele compuse obţinându-se din cele simple prin
legături logice de tipul conjuncţiei ∧, disjuncţiei ∨ sau negaţiei ¬.
37
Bazele algebrei logice au fost puse de matematicianul englez George Boole (1815- 5. Dacă mulţimea M nu conţine decât două elemente, acestea trebuie să fie obligatoriu
1864) şi ca urmare ea se mai numeşte şi algebră booleană. Ea a fost concepută ca o metodă elementul nul 0 şi elementul unitate 1; atunci pentru ∀ x ∈ M există un element unic notat cu
simbolică pentru tratarea funcţiilor logicii formale, dar a fost apoi dezvoltată şi aplicată şi în x cu proprietăţile:
alte domenii ale matematicii. În 1938 Claude Shannon a folosit-o pentru prima dată în analiza x ⋅ x = 0 principiul contradicţiei
circuitelor de comutaţie.
x + x = 1 principiul terţului exclus
x este inversul elementului x.
Definirea axiomatică a algebrei booleene În definirea axiomatică a algebrei s-au folosit diferite notaţii. În tabelul următor se dau
Algebra booleană este o algebră formată din: denumirile şi notaţiile specifice folosite pentru diverse domenii:
• elementele {0,1}
};
Obs. Acestea se mai pot numi Adevărat (engl. True) respectiv Fals (engl. False), Pornit (engl. On) Matematică Logică Tehnică
respectiv Oprit (engl. Off) Prima lege de Disjuncţie SAU
• două operaţii binare numite SAU (OR engl.) notată simbolic + sau ∨ respectiv ŞI (AND compoziţie x1 ∨ x2 x1 + x2
engl.) notate simbolic prin ⋅ sau ∧; x1 + x2
• operaţie unară numită NU negaţie, notată simbolic printr-o bară deasupra a ceea ce se A doua lege de Conjuncţie SI
neagă sau cu simbolul ¬. compoziţie x1 ∧ x2 x1 ⋅ x2
Operaţiile se definesc astfel: x1 ⋅ x2
Şi Sau Nu Sau exclusiv ⊕ Elementul Negare NU
invers ¬x x
0⋅0=0 0+0=0 ¬0 = 1 0 ⊕ 0 = 0
x
0⋅1=0 0+1=0 ¬1 = 0 0 ⊕ 1 = 1
1⋅0=0 1+0=0 1⊕ 0 =1 Proprietăţile algebrei booleene
1⋅1=1 1+1=1 1⊕1 = 0
Plecând de la axiome se deduc o serie de proprietăţi care vor forma reguli de calcul în
cadrul algebrei booleene. Aceste proprietăţi sunt:
Axiomele algebrei booleene sunt următoarele:
6. Principiul dublei negaţii
Fie o mulţime M compusă din elementele x1, x2,…xn, împreună cu operaţiile ⋅ şi +.
Această mulţime formează o algebră dacă: x = x dubla negaţie duce la o afirmaţie
1. Mulţimea M conţine cel puţin 2 elemente distincte x1 ≠ x2 (x1,x2∈ M); 7. Idempotenţa
2. Pentru ∀ x1 ∈ M, x2 ∈ M avem: x⋅x=x
x+x=x
x1 + x2 ∈ M şi x1 ⋅ x2 ∈ M
8. Absorbţia
3. Operaţiile ⋅ şi + au următoarele proprietăţi:
a. sunt comutative x1 ⋅ (x1 + x2) = x1
x1 + (x1⋅ x2) = x1
x1 ⋅ x2 = x2 ⋅ x1
9. Proprietăţile elementelor neutre
x1 + x2 = x2 + x1
b. sunt asociative x⋅0=0 x⋅1=x
x+0=x x+1=1
x1 ⋅ (x2 ⋅ x3) = (x1 ⋅ x2) ⋅ x3
10. Formulele lui De Morgan
x1 + (x2 + x3) = (x1 + x2) + x3
c. sunt distributive una faţă de cealaltă x1 ⋅ x 2 = x1 + x 2
x1 ⋅ (x2 + x3) = x1 ⋅ x2 + x1 ⋅ x3
x1 + (x2 ⋅ x3) = (x1 + x2) ⋅ (x1 + x3)
x1 + x 2 = x1 ⋅ x 2
4. Ambele operaţii admit câte un element neutru cu proprietatea: Aceste formule sunt foarte utile datorită posibilităţii de a transforma produsul logic în
x1 + 0 = 0 + x1 = x1 sumă logică şi invers.
x1 ⋅ 1 = 1 ⋅ x1 = x1 Formulele pot fi generalizate la un număr arbitrar de termeni:
unde 0 este elementul nul al mulţimii, iar 1 este elementul unitate al mulţimii.
38
1 1 0 0 1 0 0 0 1 0 1 1
x1 ⋅ x 2 ⋅ ... ⋅ x n = x1 + x 2 + ... + x n 1 1 1 0 0 0 0 0 1 1 0 1

x1 + x 2 + ... + x n = x1 ⋅ x 2 ⋅ ... ⋅ x n
11. Principiul dualităţii – dacă în axiomele şi proprietăţile algebrei booleene se interschimbă 0
cu 1 şi + cu ⋅, sistemul de axiome rămâne acelaşi, în afara unor permutări. Baze de numeraţie
Verificarea proprietăţilor se poate face cu ajutorul tabelelor de adevăr şi cu observaţia că Omul, din cele mai vechi timpuri încerca să realizeze măsurători sau comparaţii. Deoarece
două funcţii sunt egale dacă iau aceleaşi valori în toate punctele domeniului de definiţie. Prin înţelesurile "mai înalt ca" sau" mai mare ca" nu erau suficiente a trebuit să introducă numere
tabelul de adevăr se stabileşte o corespondenţă între valorile de adevăr ale variabilelor şi pentru a putea exprima aceste lucruri. Era uşor de spus că un obiect era de două ori mai mic ca
valoarea de adevăr a funcţiei. altul sau de trei ori mai valoros. Aceste comparaţii sau măsurători se făceau uneori între
Obs. Comutativitatea şi asociativitatea pot fi extinse la un număr arbitrar, dar finit, de obiecte destul de diferite între ele şi erau specifice trocului. (ex. îţi dau 8 bucăţi mari de sare
termeni, indiferent de ordinea lor. pentru un miel etc.).
În vechime oamenii socoteau pe degetele de la mâini, astfel că având zece degete erau
Tabele de adevăr capabili să realizeze operaţii cu valori până la zece. Evident că, pentru a nu ţine minte prea
multe lucruri trebuiau să-şi noteze calculate realizate. Există mai multe soluţii care rezolvau
Unei funcţii booleene cu n variabile îi putem asocia un tabel care are 2n + 1linii care problema. Cea mai simplă spunea că trebuie scris câte un semn pentru fiecare unitate (de ex.
corespund celor 2n combinaţii posibile ale variabilelor, precum a n+1 coloane care reprezintă pentru 3 obiecte erau desenate fie | | |, fie ooo sau orice alt semn). Pentru a putea reprezenta
cele n variabile plus una care reprezintă valorile corespunzătoare ale funcţiei. valori mai mari, trebuiau pur si simplu scrise prea multe astfel de simboluri. Cu cat valoarea
De exemplu pentru funcţia F(x,y)=x+y avem 2 variabile deci vom vrea un tabel cu 5 linii si de reprezentat era mai mare rea nevoie de o repetare a mai multor simboluri de acelasi fel (vă
3 coloane imaginati cât de fericiti aţi fi sa desenaţi o suta de linii pentru a repezenta valoarea 100).
x y F(x,y)=x+y Pentru a simplifica reprezentarea trebuiau născocite alte simboluri care să reprezinte valorile
0 0 0 mai mari. Astfel, romanii foloseau diferite simboluri pentru a indica diferite "ponderi" ale
0 1 1 valorilor (ex. V pentru 5, X pentru 10, L pentru 50...). Această metodă s-a dovedit a fi greoaie
1 0 1 deoarece operaţiile simple erau destul de greu de realizat (de exemplu adunaţi MCLIV cu
1 1 1 CMIX).
O altă idee era de a folosi câte un simbol diferit pentru fiecare valoare de reprezentat (este
In cazul care funcţia booleană este exprimată sub forma de expresie, pentru a ajunge la ca si cum ai identifica grafic fiecare deget de la mâna), scrierea arabă (care de fapt este la
tabelul de adevăr trebuie realizate mai multe calcule prin care să ne dăm seama care este origine chinezească şi care este cea folosită în zilele noastre) este un astfel de exemplu. Astfel
tabelul de adevăr corespunzător funcţiei date. De exemplu avem simbolurile 0, 1, 2, 3,…, 9 (deci în total 10) care fiecare are o valoare diferită (de la 0
care nu are valoare până la 9 practic fiecare deget de la mână avea un simbol primul deget 1 al
funcţia: f ( x, y , z ) = x ⊕ y + x y + x ⊕ z pentru a ajunge la tabelul de adevăr trebuie să
doilea 2 etc. iar ultimul al zelelea 0). Scrierea pe acre o folosim noi (arabă) este una
realizăm mai multe calcule într-un mod asemănător unor calcule algebrice obişnuite numai că pozitională adică de exemlu numerele mai mari ca 10 erau scrise pe poziţia a doua sau mai
folosind regulile si principiile algebrei booleene. Pentru că în formularea funcţiei apare mare în număr (astfel că de fapt 23 nu însemna 2 obiecte şi încă 3 ci de două ori 10 obiecte şi
negatul pentru z si pentru z în primul rând vom calcula acele valori apoi succesiv vom construi încă 3). Acest stil de a scrie valori este folosit şi în zilele noastre şi este cunoscut de către toată
tabelul de adevăr pentru funcţia dată. Pentru aceasta lumea.
Un număr de mai multe cifre scris în baza 10 de forma:
x n x( n +1) ...x0 (1)
poate fi văzul ca o sumă de produse de forma
x y z x⊕y F
x n * 10 n + x n +1 * 10 n −1 + ... + x0 * 10 0
y z xy x⊕ y + xy x ⊕ y + xy x⊕z x⊕z
a b c d e f = a ⊕b g = a ⋅ d h= f +g i=h j = a ⊕e k = j l =i+k
(2)
0 0 0 1 1 0 0 0 1 1 0 1 Se observă că, în expresia de mai sus valoarea 10 este constantă şi de fapt reprezintă baza
0 0 1 1 0 0 0 0 1 0 1 1 de numeraţie folosită.
0 1 0 0 1 1 0 1 0 1 0 0
0 1 1 0 0 1 0 1 0 0 1 1
Baza de numeraţie este o valoare care indică numărul de simboluri folosite pentru a
1 0 0 1 1 1 1 1 0 0 1 1 reprezenta un număr. Un număr care este scris în baza de numeraţie b
1 0 1 1 0 1 1 1 0 1 0 0
39
y n y ( n +1) ... y 0 (b ) (3) Transformarea numerelor întregi din baza 10 în altă
are forma de mai jos. bază de numeraţie
y n * b n + y n+1 * b n −1 + ... + y 0 * b 0 (4) Pentru această acţiune, ţinem cont de faptul că un număr scris în baza 10 de fapt reprezintă
o cantitate egală cu valoarea scrisă. El trebuie regrupat pentru a putea fi reprezentat în altă
bază de numeraţie. Operaţia se realizează prin împărţiri succesive ale câturilor rezultate la
O bază de numeraţie <10 va folosi mai puţine simboluri (de exemplu baza de numeraţie 7 noua bază de numeraţie. Procedând astfel vom obţine rezultatul scontat, citind invers toate
va folosi doar 7 simboluri 0, 1, 2, 3, 4, 5, şi 6), iar >10 va avea mai multe (de exemplu baza resturile obţinute
15 are nevoie de 15 simboluri). Pentru că nu există decât 10 simboluri pentru a reprezenta
cifre şi nu putem folosi decât un singur simbol pentru reprezentare (deoarece în caz contrar s- Exemplu1: 292(10)=?(6) Rezultatul final este 1204(6)
ar crea confuzie) pentru fiecare cifră în parte, deşi putem folosi orice fel de simbol pentru a 292 6
reprezenta cifre a căror valoare este mai mare ca 10, totuşi vom utiliza litere (majuscule sau
24= 48 6
minuscule de fapt nu contează) pentru a reprezenta simbolurile lipsă. Astfel pentru baza 15
=52 48 8 6
vom avea 15 simboluri şi anume 0, 1, 2, 3, 4, 5, 6,7, 7, 8, 9, A, B, C, D, E (A va înlocui un
=48 =0 6 1 6
simbol care va avea valoarea 10 şi va fi al unsprezecelea simbol de reprezentare, B-11, C-12,
etc.). ==4 2 0 0
Exemple de numere corecte sunt 123(5), 7A3(11) etc. 1
Exemple de numere scrise greşit sunt 264(5), 73X2(16), deoarece simbolurile 6 respectiv X
nu există în bazele de numeraţie 5 respectiv 16. Exemplul2: 2575(10)=?(16)
2575 16
16== 160 16
Transformarea numerelor întregi din altă bază de =97=
=96=
16
==0
10
=0
16
0
numeraţie în baza 10 ==15 10(A)
===0
Pentru această acţiune, plecăm de la prezentarea unui număr în baza de numeraţie b ==15(F)
conform (4). Pentru a transforma un număr întreg din orice bază de numeraţie în baza zece
trebuie să desfacem grupele prin care a fost scris numărul respectiv. Astfel nu avem nimic de Observând că 10 corespunde simbolului A şi 15 simbolului F rezultatul final este A0F(16)
făcut altceva decât să calculăm în baza 10 valoarea finală folosind pentru aceasta formula (4) Pentru aceste trasformări este important sa va reamintiti faptul cifrele din număr sunt
Exemplu: 745(8)=7*82+4*81+5*80 adică poziţionale şi deci resturile împărţirii trebuie transformate individual în noua bază de
=7*64+4*8+5=448+32+5=485(10) numeraţie de exemplu este gresit să realizăm transformarea de mai sus 2575(10)=?(16) astfel:
Un caz mai complicat este dacă baza de numeraţie este mai mare ca zece şi cuprinde 2575(10)=10015(16)
numere a căror valoare este mai mare ca zece
Exemplu:
3CB(15)=3*152+C*151+B*150=3*225+12*15+ 11*1=675+180+11=866(10) Cazuri speciale de transformări
60B(16)=6*162+0*161+B*160=1536+0+11 =1547(10) Se ştie că, toate calculatoarele funcţionează în baza de numeraţie 2, adică simbolurile
Pentru aceste trasformări este important sa va reamintiti faptul cifrele din număr sunt folosite de calculator sunt doar „0” şi „1”. Acest lucru deranjează destul de mult, deoarece
poziţionale şi nu trebuie transformate individual în baza 10 de exemplu este gresit să realizăm oamenii sunt obişnuiţi cu baza de numeraţie 10 şi le este foarte greu să folosească noua bază
transformarea astfel: de numeraţie. Pentru ca programarea să fie mai uşoară trebuia găsită o cale de compromis.
60B(16)=6011(16)=6*163+0*162+1*161+1*160=… Această cale ar fi utilizarea bazelor de numeraţie 8 sau 16 care sunt relativ apropiate de baza
10 şi pe de altă parte permit o schimbare uşoară de bază.
Observăm că 8=23 sau că 16=24. Acest lucru este foarte important pentru că puterile lui
doi au o anumită semnificaţie (arătată mai jos).

40
Se ştie ca folosind o cifră, în baza b putem obţine b valori diferite (adică două pt. baza 2,
cincisprezece pentru baza 15 etc.). Folosind două cifre vom obţine b2 valori deoarece vom
Tabela de Coduri ASCII
obţine pentru fiecare valoare posibila pentru a doua cifră b valori prin modificarea primei cifre Caracterele SCII sunt împărţite în:
adică b*b sau b2. De exemplu pentru baza 3 vom obţine 9 valori, pentru baza 2 patru valori • caractere grafice (adică acele caractere care pot fi reprezentate printr-un simbol
etc. Generalizând, pentru o valoare de n cifre scrisă în baza b vom obţine bn valori. grafic) intervalul [33,126]
Comparând baza 8 cu baza 2 vom observa ca un număr de 3 cifre din baza doi are tocmai opt • precum şi caractere negrafice care cuprind valorile {[0,32], 127}
valori posibile (nici mai multe nici mai puţine). La fel baza 16 se echivalează cu un număr de Coduri ASCII în zecimal
patru cifre în baza 2. Ne existând alte valori, trecerea din baza 2 în baza 8 sau 16 se face doar 000 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015
prin grupări de cifre. Pentru uşurinţă în calcul putem folosi două tabele, cu ajutorul cărora NUL SOH STX ETX EOT ENQ ACK BEL BS HT NL VT NP CR SO SI
putem realiza direct echivalarea. 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031
Baza 2 Baza 8 Baza 2 Baza 16 DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US
000 0 0000 0 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047
001 1 0001 1 SP ! " # $ % & ' ( ) * + , - . /
010 2 0010 2 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063
011 3 0011 3 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
100 4 0100 4 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079
101 5 0101 5 @ A B C D E F G H I J K L M N O
110 6 0110 6 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095
111 7 0111 7 P Q R S T U V W X Y Z [ \ ] ^ _
1000 8 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111
1001 9 ` a b c d e f g h i j k l m n o
1010 A 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
1011 B p q r s t u v w x y z { | } ~ DEL
1100 C Coduri ASCII în hexazecimal
1101 D 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
1110 E NUL SOH STX ETX EOT ENQ ACK BEL BS HT NL VT NP CR SO SI
1111 F
10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
Exemple:
DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US
1100111000111011011101110010101(2)=?(8)
20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
pentru a realiza transformarea din baza 2 în baza 8 vom grupa tot cate trei cifre binare
SP ! " # $ % & ' ( ) * + , - . /
începând de la dreapta spre stânga, iar dacă pentru ultima grupă nu sunt destule cifre atunci
30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
vom completa grupul cu zerouri.
0 1 2 3 4 5 6 7 8 9 : ; < = > ?
001 100 111 000 111 011 011 101 110 010 101
1 4 7 0 7 3 3 5 6 2 5 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
=14707335625(8) @ A B C D E F G H I J K L M N O
110.0111.0001.1101.1011.1010.0011.1001.0101(2)=?(16) 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
pentru a realiza transformarea din baza 2 în baza 16 vom grupa tot cate patru cifre binare P Q R S T U V W X Y Z [ \ ] ^ _
începând de la dreapta spre stânga, completând de asemenea ultimul grup cu zerouri. 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
` a b c d e f g h i j k l m n o
0110 0111 0001 1101 1011 1010 0011 1001 0101 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
6 7 1 D B A 3 9 5 p q r s t u v w x y z { | } ~ DEL
=671DBA395(16) Coduri ASCII în octal
Observaţie: Folosind combinat metoda descrisă mai sus este foarte uşor de convertit un număr 000 001 002 003 004 005 006 007 010 011 012 013 014 015 016 017
din baza 8 în baza 16 sau invers folosind baza 2 ca intermediar. NUL SOH STX ETX EOT ENQ ACK BEL BS HT NL VT NP CR SO SI
020 021 022 023 024 025 026 027 030 031 032 033 034 035 036 037
41
DLE DC1 DC2DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US SYN 22 16 26 Synchronous Idle
040 041 042 043 044 045 046 047 050 051 052 053 054 055 056 057 End Of Transmission Block – Sfârşit
SP ! " # $ % & ' ( ) * + , - . / ETB 23 17 27 Transmisie Bloc
060 061 062 063 064 065 066 067 070 071 072 073 074 075 076 077 CAN 24 18 30 Cancel – Anulare
0 1 2 3 4 5 6 7 8 9 : ; < = > ? EM 25 19 31 End Of Medium – Sfârşit De Mediu
100 101 102 103 104 105 106 107 110 111 112 113 114 115 116 117
SUB 26 1a 32 Substitute - Înlocuire
@ A B C D E F G H I J K L M N O
120 121 122 123 124 125 126 127 130 131 132 133 134 135 136 137 ESC 27 1b 33 Escape
P Q R S T U V W X Y Z [ \ ] ^ _ FS 28 1c 34 File Separator – Separator de Fişier
140 141 142 143 144 145 146 147 150 151 152 153 154 155 156 157 GS 29 1d 35 Group Separator – Separator de Grup
` a b c d e f g h i j k l m n o RS 30 1e 36 Record Separator – Separator de Înregistrare
160 161 162 163 164 165 166 167 170 171 172 173 174 175 176 177 US 31 1f 37 Unit Separator – Separator de Unitate
p q r s t u v w x y z { | } ~ DEL SP 32 20 40 Space - Spaţiu

Numele simbolului ASCII


Baza de numeraţie
Cod Explicaţie
10 16 8
NUL 0 0 0 Null – Terminare Şir C
SOH 1 1 1 Start Of Heading – Început De Antet
STX 2 2 2 Start Of Text– Început De Text
ETX 3 3 3 End Of Text – Sfârşit De Text
EOT 4 4 4 End Of Transmission – Sfârşit De Transmisie
ENQ 5 5 5 Enquiry – Interogare
ACK 6 6 6 Acknowledge – Acceptare
BEL 7 7 7 Bell – Sunet
BS 8 8 10 Backspace – Spaţiu Înapoi
HT 9 9 11 Horiyontal Tab – Tabulator Orizontal
NL 10 a 12 New Line (Or LF, Line Feed) – Linie Nouă
VT 11 b 13 Vertical Tab – Tabulaor Vertical
NP 12 c 14 New Page (Or FF, Form Feed) – Pagină Nouă
CR 13 d 15 Carriage Return – Retur De Car
SO 14 e 16 Shift Out
SI 15 f 17 Shift In
DLE 16 10 20 Data Link Escape
DC1 17 11 21 Device Control 1 – Control Dispozitiv 1
DC2 18 12 22 Device Control 2 – Control Dispozitiv 2
DC3 19 13 23 Device Control 3 – Control Dispozitiv 3
DC4 20 14 24 Device Control 4 – Control Dispozitiv 4
NAK 21 15 25 Negative Acknowledge – Acceptare Negativă

42

You might also like