Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

21
6. Operatori şi expresii Expresiile sunt categorii sintactice fundamentale pentru limbajul C. Practic cele mai multe şi mai des folosite instrucţiuni sunt construite pe baza expresiilor. Expresiile reprezintă un mijloc extrem de puternic de manipulare a valorilor, pentru că instrucţiunile tuturor limbajelor procedurale acţionează asupra datelor prin intermediul acestora. 6.1 Evaluarea expresiilor Singura operaţie ce se poate efectua asupra expresiilor este cea de evaluare. În urma evaluării unei expresii rezultă întotdeauna o valoare, care este utilizată în cadrul instrucţiunilor limbajului într-un mod sau altul, în funcţie de tipul instrucţiunii. Din punct de vedere sintactic, o expresie este formată din operatori, operanzi şi eventual perechi de paranteze rotunde. Operanzii reprezintă elemente asupra cărorra se poate acţiona, iar operatorii reprezintă diferitele operaţii ce se pot efectua asupra operanzilor. Perechile de paranteze rotunde specifică diferitele subexpresii ce sunt puse în evidenţă şi care sunt tratate de către compilator drept operanzi. Operanzii pot fi constante, nume de variabile, nume de funcţii sau subexpresii. Ei generează valori fie direct (în cazul constantelor sau a variabilelor simple), fie după realizarea unei opraţii de prelucrare. Exemple. 2.5 /* operand simplu */ a /* operand simplu */ v[3] /* 3 este operand simplu */ /* v este operand asupra caruia se efectueaza operatia de indexare */ f(n) /* n este operand simplu */ /* f este operand asupra caruia se efectueaza operatia de apel de functie */ a*(b+2) /* doi operanzi: - a este operand simplu, - (b+2) este subexpresie */ x = 3 /* doi operanzi simpli (x si 3); Atentie: atribuirea este considerata operator in limbajul C */ Limbajul C dispune de o mulţime de operatori, fapt ce permite o mare flexibilitate în descrierea prelucrărilor din cadrul programelor. Din punct de vedere al tipului operatorilor şi al semnificaţiei lor, aceştia se pot împărţi în următaorele clase: operatori aritmetici operatori relaţionali

Transcript of Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

Page 1: Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

6. Operatori şi expresii

Expresiile sunt categorii sintactice fundamentale pentru limbajul C. Practic cele mai multe şi

mai des folosite instrucţiuni sunt construite pe baza expresiilor. Expresiile reprezintă un

mijloc extrem de puternic de manipulare a valorilor, pentru că instrucţiunile tuturor limbajelor

procedurale acţionează asupra datelor prin intermediul acestora.

6.1 Evaluarea expresiilor

Singura operaţie ce se poate efectua asupra expresiilor este cea de evaluare. În urma evaluării

unei expresii rezultă întotdeauna o valoare, care este utilizată în cadrul instrucţiunilor

limbajului într-un mod sau altul, în funcţie de tipul instrucţiunii.

Din punct de vedere sintactic, o expresie este formată din operatori, operanzi şi

eventual perechi de paranteze rotunde. Operanzii reprezintă elemente asupra cărorra se poate

acţiona, iar operatorii reprezintă diferitele operaţii ce se pot efectua asupra operanzilor.

Perechile de paranteze rotunde specifică diferitele subexpresii ce sunt puse în evidenţă şi care

sunt tratate de către compilator drept operanzi.

Operanzii pot fi constante, nume de variabile, nume de funcţii sau subexpresii. Ei

generează valori fie direct (în cazul constantelor sau a variabilelor simple), fie după realizarea

unei opraţii de prelucrare.

Exemple. 2.5 /* operand simplu */

a /* operand simplu */

v[3] /* 3 este operand simplu */

/* v este operand asupra caruia se efectueaza

operatia de indexare */

f(n) /* n este operand simplu */

/* f este operand asupra caruia se efectueaza

operatia de apel de functie */

a*(b+2) /* doi operanzi:

- a este operand simplu,

- (b+2) este subexpresie

*/

x = 3 /* doi operanzi simpli (x si 3);

Atentie: atribuirea este considerata

operator in limbajul C */

Limbajul C dispune de o mulţime de operatori, fapt ce permite o mare flexibilitate în

descrierea prelucrărilor din cadrul programelor. Din punct de vedere al tipului operatorilor şi

al semnificaţiei lor, aceştia se pot împărţi în următaorele clase:

operatori aritmetici

operatori relaţionali

Page 2: Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

operatori logici

operatori de atribuire

operatori de adrsare

operatori la nivel de bit

operatori specifici limbajului

În funcţie de numărul de operanzi asupra cărora se aplică, operatorii pot fi unari, binari,

ternari, sau în cazul general n-ari (se aplică asupra a n operanzi).

Exemple. x-y /* operator binar */

i-- /* operator unar */

-a-b /* primul operator este unar */

al doilea este binar */

n?a:b /* ?: este operator ternar */

Din punct de vedere al poziţiei operatorilor faţă de operanzi, aceştia pot fi în poziţie prefixă

(preced operanzii), postfixă (urmează după operanzi) sau infixă (operatorul se află între

operanzi). Primele două poziţii sunt specifice operatorilor unari, pe când ultima este specifică

celor binari.

Exemple. n++ /* operatorul ++ este in pozitie postfixa */

--i /* operatorul -- este in pozitie prefixa */

a+b /* operatorul + este in pozitie infixa */

Pentru evaluarea unei expresii se iau în considerare alte două proprietăţi ale operatorilor:

precedenţa şi asociativitatea acestora. Precedenţa determină prioritatea operatorilor, iar

asociativitatea determină ordinea de aplicare a operatorilor consecutivi.

Pentru a determina ordinea de aplicare a operatorilor asupra operanzilor într-o expresie

fără paranteze, se au în vedere următoarele elemente:

întâi se grupează operatorii în clase de precedenţă; într-o clasă de precedenţă toţi

operatorii au aceeaşi prioritate;

la evaluare, operatorii se aplică în ordinea descrescătoare a precedenţei;

în cadrul fiecărei clase, ordinea depinde de asociativitatea acestora (de la stânga la

dreapta sau invers).

Exemplu. Pentru expresia: a + 2 * 3 + b + 4 + d * e * 5

clasele de precedenţă în ordinea descrescătoare sunt:

1) 2 * 3, d * e * 5

asociativitate de la stânga la dreapta

2) a + (2 * 3) + b + 4 + (d * e * 5)

asociativitate de la stânga la dreapta

Tabelul următor conţine toţi operatorii limbajului C grupaţi în ordinea descrescătoare a

precedenţei. Pentru fiecare clasă se specifică şi regula de asociere.

Page 3: Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

Operator Utilizare Semnificaţie Asociere ()

[]

.

->

--

++

f(e)

v[i]

r.c

p->c

a--

a++

apel funcţie

indexare

selecţie

selecţie indirectă

postdecrementare

postincrementare

---->

-

+

--

++

!

~

*

&

sizeof

()

-n

+n

--a

++a

!i

~i

*p

&x

sizeof(x)

(d) e

schimbare de semn

plus unar

predecrementare

preincrementare

negaţie logică

negare la nivel de bit

adresare indirectă

preluare adresă

determinare dimensiune memorie

conversie de tip (cast)

<----

*

/

%

v1 * v2

v1 / v2

i1 % i2

Înmulţire

împărţire

determinare rest (modulo)

---->

+

-

v1 + v2

v1 – v2

Adunare

Scădere

---->

<<

>>

i1 << i2

i1 >> i2

deplasare stânga

deplasare dreapta

---->

<

<=

>

>=

v1 < v2

v1 <= v2

v1 > v2

v1 >= v2

mai mic

mai mic sau egal

mai mare

mai mare sau egal

---->

==

!=

v1 == v2

v1 != v2

Egal

Diferit

---->

& i1 & i2 “şi” la nivel de bit ---->

^ i1 ^ i2 “sau exclusiv” la nivel de bit ---->

| i1 | i2 “sau” la nivel de bit ---->

&& i1 && i2 şi logic ---->

|| i1 || i2 sau logic ---->

?: i1 ? v1 :

v2

operator condiţional ---->

=

*=

/=

-=

+=

&=

^=

|=

<<=

>>=

a = v

a *= v

a /= v

a -= v

a += v

a &= v

a ^= v

a |= v

a <<= v

a >>= v

operatori de atribuire <----

, e1, e2 Secvenţiere ---->

Page 4: Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

În cazul în care o expresie conţine subexpresii, se modifică ordinea de aplicare a operatorilor.

Regula este simplă, are un caracter recursiv şi descrie ordinea de aplicare a operaţiilor

algebrice: dacă într-o expresie există subexpresii, acestea sunt evaluate înaintea celorlalţi

operanzi.

Exemplu. Fie expresia: e =

2

1

))(**(**

e

e

hgfedcba

- în expresia: a*b+c*e2, se evaluează întâi expresia e2;

- în expresia: d+e*f*e1, se evaluează întâi expresia e1;

- expresiile: a*b+c+e2, d+e*f*e1 se evaluează conform regulilor de precedenţă;

Observaţie. Se va nota în continuare cu Eval operaţia de evaluare. De exemplu, pentru

expresia precedentă, evaluarea ei se poate descrie astfel: Eval(e) = Eval (a*b+c*(d+e*f*(g+h))) =

= Eval (a*b+c*Eval(d+e*f*Eval(g+h)))

Spre deosebire de alte limbaje de programare, în limbajul C evaluarea unei expresii poate

avea şi efecte laterale datorate modificării valorilor unor variabile în timpul evaluării. Acest

lucru se poate întâmpla datorită operatorului de atribuire.

Exemplu. if ( x + ( y = v[k]) < a)

z = 1;

else

z = 2;

În expresia condiţională anterioară, se evaluează întâi subexpresia y=v[k], care are drept

efect modificarea valorii variabilei y.

Această facilitate permite descrierea mai compactă a unor secvenţe de prelucrări care

în mod normal necesită mai multe instrucţiuni de atribuire. În cazul utilizării excesive a

acestui stil de programare, există însă riscul srierii unor programe criptice, greu de înţeles şi

nu întotdeauna corecte.

Un alt aspect ce intervine în operaţia de evaluare a unei expresii se referă la

conversiile automate ale tipurilor de date ale diferitelor valori ce intervin într-o expresie.

Există mai multe motive ce impun conversii de tip, principala cuză fiind determinată de

tipurile de date diferite ale operanzilor asupra cărora se aplică un operator.

Marea majoritate a operatorilor, în special cei aritmetici, necesită operanzi de acelaşi

tip, iar din acest motiv, în cazul în care operanzii sunt de tipuri diferite, este necesară (dacă

este posibil) o operaţie de conversie a valorii unui operand sau a ambilor operanzi. Acestă

operaţie se numeşte în mod uzual reechilibrare, regula de bază fiind următoarea:

dacă operanzii sunt de tip unsigned int şi long atunci

dacă valorile unsigned int pot fi reprezentate ca long atunci

tipul echilibrat este long

altfel

tipul echilibrat este unsigned int

altfel

tipul echilibrat este tipul unuia dintre cei doi operanzi,

care apare ultimul în lista:

int

Page 5: Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

unsigned int

long

unsigned long

float

double

long double

Tipul de date al valorii rezultate în urma evaluării unei expresii simple este stabilit în urma

operaţiei de echilibrare.

Aşa cum se observă, regula presupune existanţa a doi operanzi. În cazul operatorilor

unari, este evident faptul că nu este necesară operaţia deechilibrare. În cazul operatorului

condiţional, care este singurul operator ternar al limbajului C, ultimii doi operanzi sunt cei

care contează la determinarea tipului valorii rezultate.

6.2 Operatori aritmetici

Operatorii aritmetici se împart în mod uzual în două categorii: operatori aditivi, specifici

operaţiilor de adunare şi scădere, precum şi operatori multiplicativi, specifici operaţiilor de

înmulţire şi împărţire. În plus, există operatori de incrementare şi decrementare, care

reprezintă un caz particular al operatorilor aditivi.

Operatorii aditivi sunt reprezentaţi de caracterele + şi – şi în mod uzual sunt operatori

binari. Aceleaşi caractere pot însă fi utilizate şi pentru specificarea unor operatori unari:

operatorul de schimbare de semn (de exemplu: -4, -(a+b)),

operatorul unar plus, care nu are însă nici un efect (de exemplu +4)

Aceşti operatori unari au o poziţie prefixă.

Operatorii multiplicativi sunt întotdeauna binari:

operatorul * reprezintă operaţia de înmulţire, fiind utilizat atât pentru numerele

întregi, cât şi pentru cele reale;

operatorul / reprezintă operaţia de împărţire, dar are o semnificţie distinctă pentru

numerele întregi:

în cazul în care cel puţin un operand este real, operatorul reprezintă operaţia de

împărţire reală;

în cazul în care ambii operanzi sunt întregi, operatorul reprezintă operaţia de

determinare a câtului împărţirii celor doi operanzi; De exemplu: - Eval(2.0/4.0) = 0.5

- Eval(2/4.0) = 0.5

- Eval(2/4) = 0

operatorul % este utilizat doar pentru operatori întregi şi reprezintă operaţia de

determinare a restului împărţirii celor două valori; de exemplu: Eval(2%4) = 2.

Operatorii de incrementare (++) şi decrementare (--) sunt operatori unari care pot fi folosiţi

în cazul în care se doreşte ca valoarea unei variabile să crească cu 1 (incrementare) sau să

scadă cu 1 (decrementare). De exemplu, următoarele instrucţiuni sunt echivalente: k = k + 1; k++;

k = k - 1; k--;

Page 6: Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

Din punct de vedere al priorităţii operatorilor aritmetici, aceştia se împart în grupe de

prioritate, a căror ordine descrescătoare este:

operatori de incrementare şi decrementare

operatori aditivi unari

operatori multiplicativi

operatori aditivi binari

Utilizarea operatorilor de incrementare şi decrementare necesită anumite precauţii, deoarece

poziţia lor poate fi atât infixă, cât şi postfixă. Privit doar ca un efect lateral, nu este nici o

deosebire între utilizarea postfixă şi cea prefixă, deoarece în ambele cazuri modificarea valorii

operandului este aceeaşi. Probleme pot apare doar în cazul în care expresia ce conţine astfel

de operatori este utilizată ca operand în cadrul altei expresii.

De exemplu, instrucţiunea: n = k++;

este echivalentă cu secvenţa: n = k;

k = k + 1;

pe când instrucţiunea: n = ++k;

este echivalentă cu secvenţa: k = k + 1;

n = k;

Se observă faptul că în cele două cazuri, valoarea variabilei n este diferită după evaluarea

expresiei respective.

În general, la evaluarea unei expresii ce conţine un operand care este o subexpresie care

conţine la rândul ei un operator de incrementare/decrementare se utilizează următoarea regulă:

în cazul unui operator prefix de incrementare/decrementare, întâi se modifică valoarea

operandului aferent operatorului şi apoi se evaluează expresia;

în cazul unui operator postfix, se evaluaează întâi expresia cu valoarea veche a

operandului aferent operatorului de incrementare/decrementare şi apoi se modifică

valoarea operandului.

Un caz uzual de utilizare al operatorilor de incrementare/decrementare se referă la operaţiile

cu tablouri, când se doreşte modificarea indicilor. De exemplu, instrucţiunea următoare

iniţializează un tablou cu valorile: xk = k, k = 0, 1, …, n-1: for (k=0; k<n; x[k++]=k);

6.3 Operatori de relaţie

Operatorii de relaţie corespund operaţiilor de comparare din matematică şi presupun

compararea valorilor a două expresii:

< mai mic <= mai mic sau egal > mai mare

Page 7: Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

>= mai mare sau egal == egal != diferit

Aceşti operatori sunt binari şi presupun operaţia de echilibrare a valorilor operanzilor. Din

punct de vedere al priorităţii, ei se împart în două clase de precedenţă:

<, <=, >, >=

==, !=

Din punct de vedere matematic, rezultatul unei operaţii de comparare este o valoare logică.

Conform regulilor de interpretare a valorilor logice în limbajul C, rezultă că rezultatul

evaluării unei expresii de relaţie poatr fi:

- constanta zero, în cazul în care valorile operanzilor nu respectă relaţia aferentă

operatorului;

- o constantă întregă diferită de zero (în mod uzual canstanta 1 pentru multe

compilatoare) în caz contrar.

Observaţie. Nu trebuie confundat operatorul de comparare (==) cu cel de atribuire (=). În

cazul utilizării din greşeală a operatorului de atribuire în locul celui de comparare, efectul

lateral al operaţiei de atribuire este greu de detectat în anumite situaţii.

Exemplul 6.1. Secvenţa următoare testează dacă o valoare dintr-un şir de numere este egală

cu o anumită valoare dată. int k, n, y = 7, v[4];

/* ... */

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

if (v[k] == y)

printf(“Valoare gasita in sir pe pozitia %d\n”, k);

Dacă în interiorul instrucţiunii if s-ar fi scris: if (v[k] = y)

printf(“Valoare gasita in sir pe pozitia %d\n”, k);

expresia condiţională ar fi fost tot timpul adevărată, deoarece prin atribuirea v[k]=y,

valoarea lui v[k] ar fi fost alterată la valoarea 7.

O altă problemă în utilizarea expresiilor condiţionale o poate constitui apariţia operatorilor de

incrementare/decrementare, datorită posibiltăţii poziţiei prefixe sau postfixe a acestora. În

acest caz rezultatul evaluării unei expresii condiţionale depinde de poziţia operatorilor.

Exemplul 6.2. Următoarea secvenţă calculează suma: S = 1 + 1/2 + … 1/(n-1) int n = 4;

float s = 0;

while (--n > 0)

s = s +1.0/n;

La începutul fiecărei iteraţii se decrementează valoarea lui n şi apoi se evaluează expresia

condiţională, astfel încât la a 4-a iteraţie n va avea valoarea 1. După decrementare n va avea

valoarea zero şi execuţia instrucţiunii while se termină.

Dacă se inversează poziţia operatorului de decrementare: while (n-- > 0)

s = s +1.0/n;

Page 8: Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

execuţia programului în acest caz va genera o eroare (împărţire la zero). În acest caz, la

începutul fiecărei iteraţii se evaluează întâi expresia condiţională şi apoi se decremantează

valoarea lui n. Astfel, la iteraţia a 4-a n va avea valoarea 1 şi deci expresia condiţională este

adevărată, dar înainte de execuţia instrucţiunii de atribuire interne instrucţiunii while,

valoarea lui n se va decrementa, instrucţiunea fiind de fapt: s = s +1.0/0;

6.4 Operatori logici

Rolul operatorilor logici este acela de a putea reprezenta expresii condiţionale

corespunzătoare propoziţiilor compuse din logica matematică. Din acest motiv, operatorii

logici corespund principalelor operaţii logice:

! negaţie logică && conjuncţie logică (şi logic) || disjuncţie logică (sau logic)

De exemplu, pentru a specifica faptul că un număr real se află într-un interval:

x [a, b]

se poate scrie propoziţia logică:

(x a) (x b)

Transcrierea acesteia în limbajul C este: (x >= a) && (x <= b)

Observaţie. Prezenţa parantezelor rotunde nu este necesară, deoarece după cum se poate

observa din tabelul tuturor operatorilor, operatorii de relaţie au o precedenţă mai mare decât

operatorii logici şi subexpresiile x >= a , x >= a se evaluează primele.

Rezultatul evaluării unei expresii logice se determină în conformitate cu tabelel de adevăr ale

celor trei operaţii. În figura 6.1, a şi b reprezintă doi operanzi întregi, iar x o valoare întreagă

diferită de zero:

Observaţie. Datorită regulii de interpretare a constantelor logice şi a semanticii opeatorilor

logici şi relaţionali, anumite expresii condiţionale pot avea forme diferite de reprezentare. De

exemplu, următoarele două perechi de expresii sunt echivalente: Eval(x == 0) = Eval(!x)

Eval(x != 0) = Eval(x)

Ordinea de evaluare a expresiilor logice este de la stânga la dreapta. Datorită acestui fapt şi în

concordanţă cu semantica operatorilor logici, în anumite situaţii o expresie logică nu este

evaluată până la sfârşit.

a b

0

0

x

x

0 0

0 x

a && b

a b

0

0

x

x

0 x

x x

a || b

0

x

x

0

a !a

!a

Figura 6.1. Operatori logici

Page 9: Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

Pentru reducerea timpului de execuţie al programelor, compilatoarele limbajului C

întrerup evaluarea unei expresii logice atunci când rezultatul devine sigur. Următoarele două

cazuri sunt uzuale:

a) Într-o expresie de forma t1 || t2 || … || tn, se întrerupe evaluarea

expresiei la apariţia primului operand tk diferit de zero;

b) Într-o expresie de forma t1 && t2 && … && tn, se întrerupe evaluarea

expresiei la apariţia primului operand tk care are o valoare egală cu zero;

Observaţie. Regula de întrerupere a evaluării expresiilor logice în condiţiile prezentate

anterior poate conduce la neevaluarea anumitor operanzi. Acest fapt poate avea consecinţe

nedorite în program, dacă operanzii au asociate efecte laterale (în cazul neevaluării lor,

efectele laterale nu mai apar).

Exemplul 6.3. Se consideră un şir de numere reale x1, x2, …, xn. Să se determine suma

pătratelor numerelor pozitive, dar şi a celor negative al căror pătrat nu depăşeşte o valoare

dată y. #include <stdio.h>

int main() {

int k, n;

double y, d, x[10], s = 0;

scanf(“%d%lf”, &n, &y);

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

scanf(“%lf”, &x[k]);

if ((d=x[k]*x[k])<y || x[k] > 0)

s = s + d;

}

printf(“\ns = %lf”, s);

return 0;

}

Dacă în programul precedent s-ar inversa poziţia operanzilor din expresia condiţională: if (x[k] > 0 || (d=x[k]*x[k])<y)

programul ar conţine o eroare: în cazul în care x[k]>0, a doua subexpresie nu mai este

evaluată şi valoarea variabilei d nu este calculată corect.

Din acest motiv, este indicat ca expresiile cu efecte laterale să fie plasate în faţă, sau

atribuirile ce constituie efecte laterale să fie scoase în afara (dar înaintea) expresiilor

condiţionale.

6.5 Operatori de atribuire

Operaţia de atribuire are o semnificaţie asemănătoare atribuirii din celelalte limbaje de

rpogramare. Operatorul de atribuire (=) este binar, iar sintaxa atribuirii este:

variabilă = expresie

Din punct de vedere pragmatic, atribuirea presupune două acţiuni distincte, o operaţie de

evaluare şi una de scriere în memorie şi constă în scrierea valorii rezultate în urma evaluării

expresiei din dreapta operatorului de atribuire în zona de mamorie asociată variabilei din

partea stângă. Din acest motiv, în sintaxa anterioară, variabilă nu înseamnă neapărat

numele unei variabile simple, ci o construcţie sintactică ce are asociată o zonă de memorie.

Page 10: Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

Există două noţiuni importante legate de lucrul cu variabile şi valori: noţiunea de L-

valoare şi cea de R-valoare. Valoarea curentă a unei variabile (conţinutul zonei de memorie

ataşată) reprezintă R-valoarea variabilei (right value, valoarea din partea dreaptă a

operatorului de atribuire), iar adresa zonei de memorie ataşată variabilei este o L-valoare (left

value, valoarea din partea stângă a operatorului de atribuire).

Deoarece în dreapta operatorului de atribuire poate fi o expresie, care evaluată produce

o valoare, prin extensie se numeşte R-valoare orice valoare specifică unui tip de date

fundamental sau derivat, cu excepţia funcţiilor şi tablourilor. În mod asemănător, deoarece în

partea stângă a operatorului de atribuire poate fi o construcţie sintactică ce generează o adresă

de memorie, se numeşte L-valoare adresa de memorie a unei valori de orice tip. În plus, există

noţiunea de F-valoare, care este o referinţă către o funcţie.

Exemple. int n = 10, v[7];

float x, *px;

struct { int k; float r; } a;

int f(int);

int (*pf)(float) = f1;

/* pf este un pointer la o functie cu un parametru

de tip float care returneaza un intreg

*/

void f2(float);

v[3] = n;

/* n este R-valoare, v[3] este L-valoare */

x = 1;

/* 1 este R-valoare, x este L-valoare */

px = &x;

/* &x este R-valoare, px este L-valoare */

a.k = v[3];

/* v[3] este R-valoare, valoarea componantei a 4-a

a tabloului v, a.k este L-valoare, adresa

de memorie a componentei k din variabila a

*/

n = (*pf)(v[3]);

/* v[3] este R-valoare, n este L-valoare,

*pf este F-valoare, o referinta spre functia f1,

iar (*pf)(v[3]) este R-valoare

*/

f2(*px);

/* *px este o R-valoare, continutul zonei de

memorie indicata de px, iar f2 este F-valoare

*/

Rezulă că în cazul general, o atribuire se poate reprezenta astfel:

L-valoare = R-valoare

O problemă poate apare în cadrul operaţiei de atribuire dacă operandul din stânga şi din

dreapta atibuirii nu au acelaşi tip de date. În cazul în care tipurile sunt incompatibile se

generează un mesaj de eroare, iar în cazul în care ele sunt compatibile, dar diferite, are loc o

conversie de tip. Mai exact, valoarea expresiei din dreapta este convertită la tipul variabilei

din stânga. În general, rezultatul unei asemenea conversii este dependent de implementare şi

poate conduce la depăşiri.

Page 11: Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

Exemple. float s;

s = 2;

/* se converteste intregul 2 la valoarea

reala 2.0; corect

*/

int n;

n = 12.73;

/* se converteste valoarea reala 12.73 la valoarea

intreaga 12 prin trunchiere; corect

*/

n = 124E200;

/* depasire, deoarece partea intreaga a numarului

124*10200 nu se poate reprezenta ca o valoare

intreaga; gresit

*/

După cum s-a precizat anterior, o particularitate a limbajului C este aceea că tratează

atribuirea ca un operator uzual ce poate interveni în cadrul expresiilor. Aceasta permite

modificarea valorii unei variabile în timpul evaluării unei expresii, ceea ce reprezintă un efect

lateral al operaţiei de evaluare (al cărui scop principal este să producă o valoare după

evaluare).

Exemplul 6.4. Se va relua problema referitoare la determinarea celui mai mare divizor

comun. În programul anterior, din exemplul 3.5, expresia folosită pentru determinarea restului

era evaluată de două ori: o dată în expresia condiţională a instrucţiunii while, iar a doua oară

în corpul acesteia.

while(m%n != 0) {

r = m%n;

m = n;

n = r;

}

În continuare se va evalua expreia o singură dată.

#include <stdio.h>

int cmmdc(int m, int n) {

int r;

while (r = m % n) {

m = n;

n = r;

}

return n;

}

int main() {

int m, n;

printf(“\nm, n: “);

scanf(“%d%d”, &m, &n);

printf(“\ncmmdc = %d”, cmmdc(m, n));

return 0;

}

Page 12: Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

Datorită asocierii de la dreapta la stânga a operatorului de atribuire (se evaluează întâi

operandul din dreapta şi apoi ce din stânga), limbajul C permite atribuirea multiplă. De

exemplu, în secvenţa următoare: int a, b, c;

c = b = a = 5;

se atribuie întâi variabilei a valoarea 5, apoi lui b şi apoi lui c. Instrucţiunea anterioară este

tratată de către compilator ca având forma următoare: c = (b = (a = 5));

În afara operatorului simplu de atribuire, limbajul C mai conţine o categorie de operatori de

atribuire compuşi. Rolul lor este acela de a descrie mai compact operaţii de atribuire de

forma:

variabilă = variabilă operator expresie

fără scrierea de două ori a L-valorii (în acest caz operator este un operator binar).

Pentru expresiile de forma anterioară, scrierea compactă este următoarea:

variabilă = operator_compus expresie

unde operator_compus se obţine prin alăturarea operatorului binar la cel de atribuire.

Operatorii binari ce se asociază operatorului de atribuire sunt în mod uzual cei aritmetici şi la

nivel de bit. Principalii operatori compuşi de atribuire sunt: +=

-=

*=

/=

%=

&=

^=

|=

<<=

>>=

De exemplu, instrucţiunea: x = x + y;

se poate scrie condensat folosind un operator compus de atribuire astfel: x += y;

Avantajul utilizării operatorilor compuşi de atribiure apare în situaţiile în care L-valoarea din

cadrul atribuirii nu este o variabilă simplă, ci o expresia mai complexă, conţinând la rândul ei

mai mulţi operatori şi operanzi. De exemplu, instrucţiunea: grupa[i].situatie.nr_restante =

grupa[i].situatie.nr_restante + 1;

se poate scrie mai simplu astfel: grupa[i].situatie.nr_restante += 1;

Observaţie. În cazul în care expresia din dreapta operatorului compus de atribuire conţine la

rândul ei operatori, aceasta este tratată de către compilator ca o subexpresie inclusă între

paranteze. De exemplu, instrucţiunea: x *= y + 1;

este echivalentă cu:

Page 13: Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

x = x * (y + 1);

şi nu cu instrucţiunea: x = x * y + 1;

Exemplul 6.5. Secvenţa următoare calculează suma şi produsul elementelor unui şir de

numere: int k, n = 4;

float v[4] = {1, 2, 3, 4}, s = 0, p = 1;

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

s += v[k];

p *= v[k];

}

6.6 Operatori de adresare

Operatorii de adresare sunt folosiţi în câteva cazuri tipice:

pentru a avea acces la o componentă dintr-un element compus (operatorii de indexare

şi de selecţie);

pentru a determina adresa unui element al unei anumite entităţi (operatori de

determinare a adresei);

pentru a avea acces la o anumită entitate accesibilă doar prin adresa sa de memorie

(operatori de adresare indirectă).

Rezultatul evaluării unei operaţii de adresare este interpretat în funcţie de contextul în care

apare, fie ca o L-valoare (dacă apare în stânga unei atribuiri) indicând adresa de memorie a

unui obiect, fie ca o R-valoare, indicând valoarea curentă a elementului respectiv.

Operatorii de adresare sunt următorii:

a) Operatorul de indexare, reprezentat de caracterele “[]”, este un operator binar, utilizat în

expresii de forma:

tablou [ expresie indice ]

Se observă poziţia specială a operatorului faţă de operanzi: operatorul, format din două

caractere (ca şi operatorul de apel de funcţie), încadrează operandul al doilea.

Primul operand reprezintă un tablou, iar al doilea o expresie întreagă specificând

indicele elementului selectat. Expresia ce conţine operatorul de selecţie returnează

valoarea elementului specificat.

b) Operatorul de selecţie directă, este reprezentat de caracterul “.” şi este utilizat pentru a

selecta o componentă dintr-o structură sau uniune. Este un operator cu o poziţie infixă,

separând structura respectivă de numele componentei:

structură . selector

Despre acest operator se va discuta în cadrul capitolului rezervat structurilor şi uniunilor.

c) Operatorul de selecţie indirectă, este reprezentat de caracterele “->” şi este utilizat

pentru a selecta o componentă dintr-o structură sau uniune prin intermediul unui pointer.

Expresia de utilizare este:

pointer -> selector

Page 14: Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

Despre acest operator se va discuta în cadrul capitolului rezervat structurilor şi uniunilor.

d) Operatorul de determinare a adresei este reprezentat de caracterul “&” şi utilizat în

expresii de forma:

& entitate

Operatorul returnează adresa de memorie a entităţii respective.

Un exemplu frecvent de utilizare este în cazul apelului funcţiei scanf, pentru citirea

valorilor unor variabile de intrare. Operatorul este folosit pentru determinarea adresei de

meorie a acestor variabile. De exemplu: int n;

scanf(“%d”, &n);

Despre alte cazuri de utilizare a acestui operator se va discuta în cadrul capitolului

rezervat pointerilor şi tablourilor.

e) Operatorul de adresare indirectă este reprezentat de caracterul “*” şi utilizat în expresii

de forma:

* pointer

unde este o entitate ce memorează adresa unui element din program. Rezultatul evaluării

unei asemenea expresii este valoarea elementului a cărui adresă este memorată de către

pointer.

Exemple: int a = 3, b, *p;

p = &a; /* pointerul p memoreaza adresa variabilei a */

b = *p; /* b primeste valoarea elementului a carui

adresa este memorata de p, adica 3

*/

Şi despre acest operator se va discuta în cadrul capitolului rezervat structurilor şi

uniunilor.

6.7 Operatori la nivel de bit

Operatorii la nivel de bit reprezintă operaţii specifice limbajelor de asamblare. Spre deosebire

de ceilalţi operatori ai limbajului C, această categorie prelucrează fiecare cifră binară din

cadrul operanzilor (care în acest caz sunt numai de tip întreg).

Operatorii la nivel de bit corespund în general operaţiilor principale din logica booleană

(operatorul de negaţie este singurul operator unar, ceilalţi sunt binari):

operatorul ~ reprezintă operaţia de negaţie;

operatorul & reprezintă operaţia booleană “şi”;

operatorul ^ reprezintă operaţia booleană “sau exclusiv”;

operatorul | reprezintă operaţia booleană “sau”.

În plus, există doi operatori binari de deplasare:

operatorul << pentru operaţia de deplasare la stânga;

operatorul >> pentru operaţia de deplasare la dreapta.

Operatorii ce corespund operaţiilor booleene operează asupra cifrelor binare conform

următoarelor tabele de adevăr din figura 6.2 (a şi b reprezintă cifre binare):

Page 15: Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

Pentru exemplificare, în tabelul următor se prezintă câteva cazuri de aplicare a acestor

operatori asupra unor operanzi de tip char:

a 0 0 0 1 0 1 1 0

b 0 1 1 1 1 0 1 1

~a 1 1 1 0 1 0 0 1

a & b 0 0 0 1 0 0 1 0

a | b 0 1 1 1 1 1 1 1

a ^ b 0 1 1 0 1 1 0 1

În cazul operatorilor de deplasare, cei doi operanzi au semnificaţii diferite: primul reprezintă

numărul ai cărui biţi se deplasează, iar al doilea specifică numărul de poziţii cu care se face

deplasarea în direcţia respectivă. De exemplu, expresia n << 2 specifică faptul că cifrele

binare ale numărului n se vor deplasa cu două poziţii spre stânga.

La deplasarea spre stânga cu k cifre, primii k biţi ai numărului se pierd, iar ultimii k se

completează cu zero. La deplasarea spre dreapta cu k cifre, ultimii k biţi ai numărului se

pierd, iar primii k se completează cu cifra binară 0 sau 1, cifră ce depinde de implementare

(valoarea nu se specifică in standardul limbajului).

Dacă valoarea expresiei de deplasare este negativă, sau depășește lungimea de

memorie a operandului din stânga, semnificația operației este nedefinită.

Exemplu pentru un operand de tip char:

a 0 0 1 1 1 1 0 1

a << 2 1 1 1 1 0 1 0 0

a >> 2 0 0 0 0 1 1 1 1

În exemplul precedent s-a considerat că la deplasarea spre dreapta se introduc zerouri. În

mod uzual, valoarea cifrei cu care se completează primii k biţi este aleasă astfel încât

operaţia să fie echivalentă cu o împărţire cu 2k (pentru numere pozitive cifra este 0, iar pentru

numere negative este 1). Această alegere este sugerată de următoarea observaţie: în cazul

deplasării spre stânga cu k cifre, în cazul în care nu se produce o depăşire, rezultatul obţinut

este echivalent cu o înmulţire a numărului cu 2k.

Pentru exemplificare, se poate compara numărul: n = 00000101

cu numărul n1 = n << 2:

n1 = 00010100 (înmulțire cu 22).

În mod similar, n2 = n1 >> 2:

n2 = 00000101 (împărțire cu 22)

a b

0

0

1

1

0 0

0 1

a & b

a b

0

0

1

1

0 1

1 1

a | b

a b

0

0

1

1

0 1

1 0

a ^ b

0

1

1

0

a ~a

~a

Figura 6.2. Operatori la nivel de bit

Page 16: Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

Exemplul 6.6. Un exemplu elocvent de utilizare a operatorilor la nivel de bit îl constituie

cazul programelor care lucrează cu informaţii codificate pe porţiuni. Să presupunem că un

program trebuie să conducă un robot. Pentru simplitate, se consideră doar următoarele

comenzi:

- deplasare înainte,

- deplasare înapoi,

- deplasare la stânga,

- deplasare la dreapta,

- apucare a unui obiect (închidere mână),

- lăsare a unui obiect (deschidere mână).

Pentru primele patru comenzi, trebuie specificat în plus şi distanţa pe care trebuie să se

deplaseze robotul (considerată în milimetri).

Pentru codificarea a celor 6 comenzi diferite sunt necesare 3 cifre binare. În cazul în

care o comandă conţine 8 cifre binare (un operand de tip char), ultimele 5 cifre vor codifica

distanţa. Un exemplu de codificare al tipului comenzilor:

- 000: deplasare înainte,

- 001: deplasare inapoi,

- 010: deplasare spre stânga,

- 011: deplasare spre dreapta,

- 100: apucare obiect,

- 101: lăsare obiect.

Să presupunem de exemplu că există o comandă de deplasare spre stânga cu 6 mm de forma: | 0 1 0 | 0 0 1 1 0 |

Programul trebuie să detecteze tipul comenzii, iar în cazul în care comanda este de deplasare,

să determine distanţa de deplasare.

Funcţia care decodifică o comandă şi apelează funcţiile specifice ce realizează

operaţiile respective trebuie să izoleze cele două câmpuri. Ea returnează un rezultat întreg,

specificând dacă s-a putut sau nu decodifica şi executa respectiva comandă:

int DecodificareComanda(unsigned char comanda) {

unsigned char masca_tip _operatie = 0x7;

/* masca_tip_operatie = 00000111 */

unsigned char masca_distanta = 0x1f;

/* masca_distanta = 00011111 */

unsigned char tip_operatie, distanta;

masca_tip_operatie <<= 5;

/* masca_tip_operatie devine 11100000 */

tip_operatie = (comanda & masca_tip_operatie) >> 5;

distanta = comanda & masca_distanta;

if (tip_operatie == 0)

DeplasareInainte(distanta);

else if (tip_operatie == 1)

DeplasareInapoi(distanta);

else if (tip_operatie == 2)

DeplasareStanga(distanta);

else if (tip_operatie == 3)

DeplasareDreapta(distanta);

else if (tip_operatie == 4)

ApucareObiect();

else if (tip_operatie == 5)

LasareObiect();

Page 17: Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

else

Return 0;

return 1;

}

O mască reprezintă un grup de cifre binare 1 consecutive şi se utilizează pentru a putea reţine

din mai multe cifre binare un grup de cifre dorit. Selecţia grupului de cifre se realizează cu

ajutorul operaţiei “şi” la nivel de bit între numărul dorit şi şablon.

În exemplu, s-au utilizat două măşti: prima reţine primii 3 biţi (masca_tip_operatie),

iar a doua ultimii 5 biţi (masca_distanta). După efectuarea operaţiei “şi” la nivel de bit, se

obţin utmătoarele structuri de cifre binare:

Comanda b7 b6 b5 b4 b3 b2 b1 b0

Masca_tip_operatie 1 1 1 0 0 0 0 0

Masca_distanta 0 0 0 1 1 1 1 1

Tip_operatie b7 b6 b5 0 0 0 0 0

Distanta 0 0 0 b4 b3 b2 b1 b0

Tip_operatie >> 5 0 0 0 0 0 b7 b6 b5

Valoarea corectă pentru masca_tip_operatie se obţine după o deplasare spre stânga cu 5 cifre

binare. După selectarea biţilor b7, b6 şi b5 din cadrul octetului aferent unei comenzi, aceştia

trebuie deplasaţi spre dreapta cu 5 cifre binare. În acest mod, octetul corespunzător variabilei

tip_operatie poate fi utilizat simplu prin valoarea sa în cadrul expresiilor condiţionale din

instrucţiunile if (de exemplu: 00000101 reprezintă valoarea 5, 00000100 reprezintă

valoarea 4, etc.).

6.8 Operatori specifici ai limbajului C

Limbajul C conţine o serie de operatori specifici, care pot mări flexibilitatea şi compactitatea

programelor.

A) Operatorul sizeof

Acesta este un operator special al limbajului, fiind singurul operator care nu evaluează

valoarea operandului asociat. Operatorul sizeof nu se aplică asupra unei valori, ci asupra

unui tip de date, forma sa de utilizare fiind:

sizeof ( tip )

sau

sizeof expresie_unară

În primul caz operatorul se aplică direct asupra tipului de date specificat, iar în al doilea se

aplică asupra tipului de date al expresiei respective.

Operatorul returnează o valoare întreagă, reprezentând numărul de octeţi necesari

pentru memorarea valorilor tipului asociat.

Observaţie. Expresia unară este o expresie care nu conţine operatori binari sau ternari. În

cazul unei expresii complexe, operatorul sizeof se va aplica numai asupra primului

operand. De exemplu, considerându-se secvenţa: int n1, n2, n3, a = 5;

Page 18: Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

double b = 2.2;

n1 = sizeof a + b;

n2 = sizeof (a + b);

n3 = sizeof(double);

se observă faptul că valorile lui n2 şi n3 sunt egale. Presupunând faptul că valorile de tip int

se memorează pe 4 octeţi şi cele de tip double pe 8 octeţi, valorile lui n2 şi n3 sunt ambele

egale cu 8 (în cazul lui n2, nu se evaluaează expresia a + b, ci se determină tipul de date al

acesteia), iar valoarea lui n1 este 7 (conversia valorii 7.2 la valoare întregă). Se remarcă

următoarele echivalenţe: n1 = Eval(sizeof a + b) =

= Eval(sizeof a) + Eval(b)

În cazul în care operandul lui sizeof este numele unui tablou, acesta nu este convertit la un

pointer. Valoarea returnată în acest caz reprezintă numărul total de octeţi alocat tabloului

respectiv. De exemplu, în secvenţa: int n1, n2, a[10], *p;

n1 = sizeof (a);

n2 = sizeof (p);

presupunând faptul că valorile de tip int se reprezintă pe 2 octeţi, valoarea lui n1 este 20, pe

când valoarea lui n2 (p are tipul int*) este în general 4 (adică numărul de octeţi necesari

pentru memorarea adresei unui obiect de tip int).

B) Operatorul de conversie de tip

Acest operator, numit şi operator cast, determină schimbarea forţată a tipului de date a

valorii unei expresii sau subexpresii la un alt tip de date specificat explicit de programator.

Operatorul cast are o poziţie prefixă, forma de utilizare fiind următoarea:

( tip ) expresie_unară

Se evaluează expresia unară, iar rezultatul este convertit la tipul specificat între paranteze.

Observaţie. Ca şi în cazul operatorului sizeof, trebuie avută grijă în cazul în care expresia

în care apare operatorul cast este mai complexă (operatorul se aplică doar asupra

operandului următor). De exemplu, în cazul în care variabilele a şi b sunt de tip întreg: int a = 5, b = 7;

în cadrul expresiei: (double) a / b;

operatorul cast se aplică doar asupra variabilei a schimbându-i valoarea întragă 5 în constanta

de tip double 5.0, astfel încât operatorul / joacă rol de împăţire reală.

O folosire uzuală a operatorului cast este în cazul apelului funcţiilor, fie când se doreşte

conversia tipului de date a valorii returnate de o funcţie, fie când se doreşte conversia tipului

de date al parametrilor de apel.

Exemple.

1) O funcţie des utilizată pentru alocarea memoriei în zona heap a programului este

malloc, care are prototipul: void* malloc(size_t);

Page 19: Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

Dacă se doreşte să se aloce memorie pentru o valoare de tip float, se poate utiliza un

pointer, ca în secvenţa următoare: float *p;

p = (float*)malloc(sizeof(float));

Se converteşte astfel tipul void* la tipul float* pentru a exista compatibilitate cu tipul

variabilei p.

2) O funcţie matematică corespunzătoare operaţiei de ridicare la putere este funcţia pow, care

are prototipul: double pow(double, double);

În cazul în care a şi b sunt două variabile întregi, apelul acestei funcţii se poate scrie: x = pow((double)a, (double)b);

Observaţie. Operatorul nu afecatează valoarea variabilelor din cadrul expresiei, astfel încât a

şi b îşi păstrează valorile iniţiale.

C) Operatorul condiţional (?:)

Acesta este singurul operator ternar al limbajului C şi are următoarea formă de utilizare:

expr.1 ? expr.2 : expr.3

Denumirea sa provine de la faptul că valoarea de evaluare a unei asemenea expresii depinde

de tipul primei expresii:

0)1.exp(),3.exp(

0)1.exp(),2.exp()3.exp:2.exp?1.exp(

rEvaldacarEval

rEvaldacarEvalrrrEval

Avantajul utilizării unui asemenea operator constă în faptul că permite scrierea unui cod

compact şi evitarea utilizării intrucţiunilor if.

Exemplul 6.7. Presupunând faptul că variabila c este de tip caracter şi memorează în timpul

execuţiei programului o cifră a bazei de numeraţie 16:

c {‘0’, ‘1’, ..., ‘9’} {‘a’, ‘b’, ..., ‘f’}

instrucţiunea următoare determină valoarea zecimală echivalentă a acesteia: if (c >= ’0’ && c <= ’9’)

v = c – ‘0’;

else

v = c – ‘a’ + 10;

Scris condensat, această instrucţiune este echivalentă cu: v = (c >= ’0’ && c <= ’9’) ? c – ‘0’ : c – ‘a’ + 10;

Observaţie. S-a utilizat poziţia relativă a caracterelor alfabetice şi numerice din tabela de

caractere.

Operatorii condiţionali pot fi imbricaţi. De exemplu, pentru a determina valoarea maximă a

trei numere, x, z şi z, se poate scrie funcţia următoare: double max3(double x, double y, double z) {

return (x > y) ? (x > z ? x : z) : (y > z ? y : z) ;

}

Page 20: Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

D) Operatorul de secvenţiere (,)

Acesta este un operator de evaluare secvenţială a unor expresii. Forma uzuală de folosire este

următoarea:

expr.1 , expr.2 , ... , expr.k

unde cel puțin o expresie este o expresie de atribuire. Ea se utilizează atunci când sintaxa

limbajului presupune prezenţa unei singure expresii, dar algoritmul problemei de rezolvat

necesită prelucrarea secvenţială a mai multor expresii.

Operatorul de secvențiere nu poate fi utilizat pentru a separa elementele dintr-o listă.

În mod uzual, el se folosește în cadrul unei expresii condiționale, sau într-o expresie ce

conține paranteze.

Evaluarea unei asemenea expresii se face de la stânga la dreapta, valoarea de evaluare fiind de

fapt valoarea ultimei expresii:

Eval(expr.1, expr.2 , ... , expr.k) = Eval(expr.k)

Celelalte expresii sunt folosite de obicei pentru efectele laterale pe care le produc.

De exemplu, presupunând că variabilele x, y, z şi t sunt de tip numeric, atunci instrucţiunea: z = (x > y) ? x : y;

atribuie lui z valoarea maximă, pe când instrucţiunea: z = (x > y) ? (t = x, x = y, y = t) : y;

are acelaşi efect, dar în plus realizează şi ordonarea crescătoare a valorilor x şi y. O utilizare

eronată este următoarea: z = (x > y) ? (t = y, y = x, x = t) : y;

O altă utilizare uzuală a operatorului de secvenţiere este în cadrul instrucțiunii for.

Exemplul 6.8. Funcţia următoare afişează poziţiile succesive ale unui cal pe tabla de şah,

plecând din poziţia (a, 1) şi utilizând tot timpul aceeaşi mişcare:

void PozitieCal(int jos, int dreapta) {

int i, j;

for (i=j=1; i<=8 && j<=8; i+ = jos, j+= dreapta)

printf(“%c %d\n”, ‘a’-i, j);

}

Funcţia converteşte valorile numerice 1, 2, …, 8 la caracterele ‘a’, ‘b’, …, ‘h’. Parametrii jos

şi dreapta pot avea doar valorile (1, 2) sau (2, 1). Exemplu de utilizare:

int main() {

PozitieCal(1, 2);

PozitieCal(2, 1);

return 0;

}

6.9 Probleme

6.1. Să se scrie un program pentru rezolvarea ecuaţiaei bipătrate: a*x4 + b*x

2 + c = 0.

6.2. Să se scrie un program pentru rezolvarea problemei 2.3.

Page 21: Pc_Cap6 Fara 6.7 ; 6.8 - Operatorul de Secventiere

6.3. Să se scrie un program pentru rezolvarea problemei 2.11.

6.4. Se consideră un punct P în plan specificat prin coordonatele sale şi un segment de

dreaptă specificat prin coordonatele extremităţilor. Să se scrie un program care să

determine dacă punctul P se află sau nu pe segment.

6.5. Se consideră două segmente de dreaptă specificate prin coordonatele extremităţilor. Să

se scrie un program care să determine intersecţia segmentelor.

6.6. Să se scrie un program pentru determinarea naturii unui patrulater specificat prin

coordonatele vârfurilor.

6.7. Să se scrie un program pentru calculul ariei determinate de intersecția a două patrulatere

specificate prin coordonatele vârfurilor.

6.8. Se consideră o placă din oțel, de formă poligonală, specificată prin coordonatele

vîrfurilor poligonului în ordine trigonometrică. Să se determine centrul de greutate al

plăcii.

6.9. Să se determine dacă un număr întreg n este prim.

6.10. Se consideră operaţii cu mulţimi de numere întregi din domeniul 0, 1, …, 31. Utilizând

operatorii la nivel de bit, să se scrie funcţii C pentru principalele operaţii: intersecţia,

reuniunea şi diferenţa a două mulţimi, testul de incluziune a unei mulţimi în altă

mulţime, precum şi testul de apartenenţă a unui element la o mulţime.

6.11. Utilizând funcţiile C de la problema 6, să se scrie un program pentru determinarea

tuturor numerelor prime mai mici decât un număr n dat, utilizând un algoritm numit

“Ciurul lui Erathostene”. Se utilizează două mulţimi, a şi b, cu următoarea semnificaţie:

- la început, a conţine toate numerele de la 2 la n, iat b va fi vidă;

- la sfârşitul calculului, a va fi vidă, iar b va conţine numerele dorite.