EXPRESII, OPERANZI, OPERATORI
3.1. EXPRESII
O expresie în limbajul C este formata fie dintr-un operand fie din mai multi operanzi legati între ei prin operatori. O expresie are o valoare si un tip care se determina aplicând operatorii conform prioritatilor si asociativitatii acestora.
În limbajul C operatorii se asociaza de la stânga la dreapta, exceptând operatorii unari si de atribuire, care se asociaza de la dreapta la stânga.. Totodata pot fi folosite parantezele rotunde pentru a impune o anumita ordine în executarea operatiilor.
3.2. OPERANZI
Un operand în limbajul C poate fi una din urmatoarele elemente:
o constanta;
o constanta sim 414c22e bolica;
numele unei variabile simple;
numele unui tablou;
numele unei structuri;
numele unei functii;
referirea la elementul unui tablou (variabila cu indici);
referirea la elementul unei structuri;
apelul unei functii;
o expresie inclusa în paranteze rotunde.
Unele dintre elementele de mai sus nu au fost înca definite, ele se vor prezenta în lectiile viitoare.
Exemple: 9876 - constanta întreaga;
x - variabila simpla;
t[i][3] - variabila cu indici;
0xabcd - constanta hexazecimala;
t - nume de tablou;
(expresie) - expresie inclusa în paranteze rotunde.
f1 - numele unei functii
3.3. OPERATORI
Operatorii limbajului C pot fi grupati în mai multe clase, dar oricum ei pot fi folositi împreuna într-o aceeasi expresie. Operatorii au aritati diferite: unari, binari, ternari si totodata o anumita prioritate implicita care e redata în tabelul de mai jos. Operatorii de aceeasi prioritate se afla trecuti în aceeasi linie. Liniile tabelulul contin operatorii limbajului C în ordinea descrescatoare a prioritatilor. Astfel în prima linie se afla operatorii de prioritate maxima, iar în ultima linie operatorul virgula cu prioritatea cea mai mica. Cu exceptia operatorilor ".", "->","&","*", a parantezelor rotunde (folosite la definitia si apelul functiilor) si a parantezelor drepte (folosite la variabilele cu indici) ceilalti operatori vor fi explicati în aceasta lectie.
( ) [ ] . -> |
- (unar) +(unar) *(unar) &(unar) ! ~ ++ -- (tip) sizeof |
<< >> |
< <= >= > |
& |
&& |
? : (ternar) |
= op= op poate fi: *(binar) / % +(binar) -(binar) << >> & ^ | |
3.3.1. Operatori aritmetici
Lista operatorilor aritmetici este redata mai jos:
- (minus unar);
+ (plus unar);
* / % operatori binari multiplicativi; (înmultire, împartire, restul împartirii întregi);
+ - operatori binari aditivi (adunare si scadere).
Operatorii de pe aceeasi linie au aceeasi prioritate. Cei unari au prioritate mai mare decât cei binari. Operatorii multiplicativi au prioritate mai mare decât cei aditivi.
Exemple:
int i,j,k;
float x,y;
double t[10];
// se dau cateva exemple de expresii folosind operatorii aritmetici
i*x+t[5];
-y+k;
i%j; // daca i=9 si j=4 atunci i%j are valoarea 1
i/j; // daca i=9 si j=4 atunci i/j are valoarea 2
x*-y; // - este operatorul unar deci avem x*(-y)
3.3.2. Operatori relationali
Lista operatorilor relationali este redata astfel:
< (mai mic)
<= (mai mic sau egal; cele doua caractere ce compun operatorul sunt concatenate)
> (mai mare)
>= (mai mare sau egal; cele doua caractere ce compun operatorul sunt concatenate)
Toti operatorii relationali au aceeasi prioritate. Ea este mai mica decât prioritatea operatorilor aditivi. Rezultatul aplicarii unui operator relational este 1 sau 0, dupa cum operanzii se afla în relatia definita de operatorul respectiv sau nu.
Exemple:
a= 4 si b= -5
atunci a>0 are valoarea 1;
a<=0 are valoarea 0;
a+b>0 are valoarea 0;
a>=b are valoarea 1;
a<0 are valoarea 1;
a+b>=b-a are valoarea 1;
a+b<=(b-a)*(b-a) are valoarea 0;
3.3.3. Operatori de egalitate
Lista operatorilor de egalitate este redata mai jos:
= = (egal; doua semne "=" concatenate)
!= (diferit; semnele sunt concatenate).
Operatorii de egalitate au ambii aceeasi prioritate si este imediat mai mica decât a operatorilor relationali. Operatorul "= =" testeaza egalitatea a doi operanzi. Daca operanzii sunt egali atunci rezultatul operatiei "= =" este 1, în caz contrar este 0. Operatorul "!=" furnizeaza rezultatul 1 când cei doi operanzi sunt diferiti si 0 când sunt egali.
Exemple:
a= 2 si b=-1
atunci
a= =b are valoarea 0;
a!=b are valoarea 1;
a*b!=a+b are valoarea 1;
3.3.4. Operatori logici
Lista operatorilor logici este redata mai jos:
(negatia logica - operator unar);
&& (sI logic);
(SAU logic).
Operatorul "!" are aceeasi prioritate cu operatorii unari "+" si "-". Operatorul "&&" este mai prioritar decât operatorul "||", dar are o prioritate mai mica decât operatorii de egalitate.
În limbajul C nu exista valori logice speciale. Valoarea fals se reprezinta prin zero. Orice valoare diferita de zero reprezinta valoarea adevarat.
Daca operatorul "!" se aplica la un operand a carui valoare este zero, atunci rezultatul este 1. Daca acelasi operator se aplica la un operand a carui valoare este diferita de zero, atunci rezultatul este 0.
Dam în continuare tabelele operatorilor logici binari aplicate valorilor 0 si 1.
&& 0 1 || 0 1 sau exclusiv 0 1
0 0 0 0 0 1 0 0 1
1 0 1 1 1 1 1 1 0
Chiar daca pentru "sau exclusiv" nu exista operator el se poate realiza prin expresia urmatoare aplicata operanzilor a si b: !a&&b||!b&&a sau folosind parantezele rotunde ((!a) &&b)||((!b)&&a).
Operatorii logici se evalueaza de la stânga la dreapta. Daca la evaluarea unei expresii se ajunge într-un punct în care se cunoaste valoarea întregii expresii, atunci restul expresiei nu se mai evalueaza.
Daca a=0 si b=1 atunci expresia ! a||b are valoarea 1 pentru ca !a are deja valoarea 1.
3.3.5. Operatori logici pe biti
Lista operatorilor logici pe biti este redata mai jos în ordinea descrecatoare a prioritatilor:
(operator unar; complement fata de 1)
>> << (deplasari la dreapta, respectiv la stânga)
& (sI pe biti)
(SAU-EXCLUSIV pe biti)
(SAU pe biti)
Operatorul "~", fiind unar, are aceeasi prioritate ca si ceilalti operatori unari ai limbajului C. El schimba fiecare bit 1 al operandului în 0 si invers.
Operatorul ">>" realizeaza deplasarea la dreapta care este echivalenta cu o împartire întreaga cu puteri a lui 2; a >> 3 este echivalenta cu [a/23].
Operatorul "<<" realizeaza deplasarea la stânga care este echivalenta cu o înmultire cu puteri a lui 2; a << 3 este echivalenta cu a*8.
Pentru operatorii &, |, ^ dam în continuare tabelele operatiilor:
& 0 1 | 0 1 ^ 0 1
0 0 0 0 0 1 0 0 1
1 0 1 1 1 1 1 1 0
Observatii:
1o. Operanzii care nu ocupa un cuvânt (16 biti) se extind la un cuvânt. De exemplu expresia ~0 are ca rezultat un cuvânt cu toti biti egali cu 1.
2o. Operatorii logici pe biti se executa bit cu bit spre deosebire de operatorii logici care se evalueaza global. De exemplu daca x=2 i y=1 sunt variabile de tip int atunci:
x&&y are valoarea 1 pentru ca ambii operanzi sunt diferiti de 0.
x&y are valoarea 0 conform schemei de mai jos
0000 0000 0000 0010
0000 0000 0000 0001
& 0000 0000 0000 0000
3o. Operatorul & se foloseste frecvent pentru a anula biti din configuratia unui cuvânt, iar operatorul | pentru a seta (pune) biti într-un anumit mod;
4o. Operanzii trebuie sa fie întregi (de tipul int sau long).
5o. Atentie la deplasari nu se modifica valoarea operandului; deci trebuie sa facem o atribuire; de exemplu a = a << 3 va modifica valoarea lui a pe când a << 3 nu modifica valoarea lui a.
Exemple:
Fie declaratia:
int i;
atunci expresia i >> 8 & 255 are ca rezultat valoarea celui mai semnificativ octet a lui i; i >> 8 deplaseaza octetul mai semnificativ al lui i în pozitia mai putin semnificativa; se face apoi un sI logic pe biti cu masca 255 care pastreaza octetul mai putin semnificativ.
2) Fie expresia: (x >> 6) & ~(~ 0 << 3)
Sa presupunem ca x are valoarea în biti 1010 1011 1000 1101.
Atunci x>>6 are valoarea 1111 1110 1010 1110
Al doilea operand pregateste o masca astfel:
~0 1111 1111 1111 1111
~0<<3 1111 1111 1111 1000
~(~0<<3) 0000 0000 0000 0110
Rezultatul final este dat de:
0000 0000 0000 0111
1111 1110 1010 1110
Practic s-a obtinut valoarea bitilor 8,7,6 a lui x (numerotati de la dreapta la stânga începând cu 0).
3.3.6. Operatori de atribuire
În forma cea mai simpla operatorul de atribuire se noteaza cu "=" si se utilizeaza în constructii de forma:
v=expresie;
(v este fie o variabila simpla, fie variabila cu indici sau un element de structura).
Aceasta constructie se mai numeste expresie de atribuire. Ea este considerata ca fiind un caz particular de expresie. Tipul ei coincide cu tipul lui v, iar valoarea întregii expresii este chiar valoarea atribuita lui v.
O expresie de forma:
v1=(v=expresie);
este si ea legala si se efectueaza în felul urmator :
se evalueaza expresia expresie si valoarea ei se atribuie lui v;
valoarea lui v se atribuie apoi si lui v1.
Deoarece operatorii de atribuire se asociaza de la dreapta la stânga, expresia de mai sus se poate scrie si fara paranteze:
v1=v=expresie;
În general, putem realiza atribuiri multiple printr-o expresie de forma:
vn =. . . =v1=v=expresie
Daca expresia din dreapta semnului egal are un tip diferit de cel al variabilei v, atunci întâi valoarea ei se converteste spre tipul variabilei v si pe urma se realizeaza atribuirea,
Pentru operatia de atribuire, în afara semnului egal se mai poate folosi si succesiunea :
op=
unde prin op se întelege unul din operatorii binari aritmetici sau logici pe biti, adica unul din urmatorii:
% / * - + & ^ | << >>
Acest mod de constructie se foloseste pentru a compacta un anumit tip de atribuire. Astfel expresia:
v op = expresie;
este identica cu expresia de atribuire:
v = op expresie;
Exemple:
int i, j;
double x, y;
int v[10];
i=5;
j=10;
x=y=10.01;
i +=1; // echivalenta cu i=i+1 si cu i++
x*=3; // echivalenta cu x=x*3
j<<=10; // echivalenta cu j=j<<10
v[i]*=i // echivalenta cu v[i]=v[i]*i
x /= x-y // echivalenta cu x = x/(x-y)
3.3.7. Operatori de incrementare si decrementare
Acesti operatori sunt unari si au aceeasi prioritate cu ceilalti operatori unari ai limbajului C. Operatorul de incrementare se noteaza prin "++" si mareste valoarea operandului cu unu, iar operatorul de decrementare se noteaza prin "- -" si micsoreaza valoarea operandului cu unu. Operatorii sunt folositi prefixat si postfixat. Astfel operatorii prefixati au notatia:
++operand;
- - operand;
Ei se aplica mai întâi si apoi se foloseste valoarea lor.
Astfel operatorii postfixati au notatia:
operand++;
operand - -;
Se foloseste valoarea operanzilor si apoi se aplica incrementarea sau decrementarea.
Mentionam ca acesti operatori se pot aplica numai la urmatorii operanzi:
variabila simpla;
variabila cu indici;
referire la elementul unei structuri.
Exemple:
int i,j;
double x,y;
int vector [5];
j=i++; // este echivalent cu j=i si i=i+1;
y=--x; // este echivalent cu x=x-1 si y=x;
i=++vector[j] // este echivalent cu vector[j]=vector[j]+1 si i=vector[j]
3.3.8. Operatorul de conversie explicita (expresie cast)
Pentru fortarea tipului unui operand se foloseste o constructie de forma:
(tip) operand
Prin aceasta valoarea operandului se converteste spre tipul indicat în paranteze.
Exemplu:
int i,j;
double y;
i=8; j=5;
y=i/j; // y are valoarea 1, pentru ca se face impartirea intreaga i/j
Daca vom converti operanzii i si j spre tipul double se va obtine rezultatul corect adica 1.6.
Deci:
int i,j;
double y;
i=8; j=5;
y=(double) i / (double) j; // y are valoarea 1.6,
Constructia (tip) este un operator unar prin care se expliciteaza conversia dorita. Are aceeasi prioritate ca restul operatorilor unari.
3.3.9. Operatorul dimensiune (sizeof)
Pentru a determina lungimea în octeti a unei date se poate folosi constructia:
sizeof (data)
unde data poate fi:
numele unei variabile simple;
numele unui tablou;
numele unei structuri;
numele unui tip;
referirea la elementul unui tablou sau structura.
Exemple:
int i;
long l;
float f;
double d;
char c;
int itablou[5];
double dtablou[5];
sizeof (i) // are valoarea 2;
sizeof (l) // are valoarea 4;
sizeof (f) // are valoarea 4;
sizeof (d) // are valoarea 8;
sizeof (c) // are valoarea 1;
sizeof (itablou[1]) // are valoarea 2;
sizeof (dtablou[1]) // are valoarea 8;
sizeof (itablou) // are valoarea 10;
sizeof (dtablou) // are valoarea 40;
Regula conversiilor implicite
În general o expresie C contine operanzi de tipuri diferite. Pentru operatorii binari exista situatii când operanzii nu sunt de acelasi tip si trebuie executate conversii astfel încât operatorii sa se aplice pentru operanzi de acelasi tip. Aceste conversii le face automat compilatorul. Exista o regula a conversiilor implicite care are urmatorii pasi:
fiecare operand de tip char se converteste spre tipul int si fiecare operand de tipul float se converteste spre double;
daca unul dintre operanzi este de tip double atunci si celalalt se converteste spre tipul double si rezultatul va avea tipul double;
daca unul dintre operanzi este de tip long, atunci si celalalt se converteste spre tipul long si rezultatul va avea tipul long;
daca unul dintre operanzi este de tip unsigned, atunci si celalalt se converteste spre tipul unsigned si rezultatul va fi de tipul unsigned;
la acest pas se ajunge numai daca ambii operanzi sunt de tip int si deci operatia se executa cu operanzii respectivi, iar rezultatul va fi de tip int.
Aplicând regula de mai sus pas cu pas (la fiecare operator în momentul efectuarii lui), se ajunge în final la evaluarea întregii expresii si prin acesta se determina tipul expresiei. Regula conversiilor implicite nu se aplica pentru operatorul de atribuire (valoarea expresiei din partea dreapta a semnului de atribuire se converteste spre tipul variabilei din stânga semnului egal).
Exemple:
int i, j, k;
float a, b;
double x, y;
unsigned p;
long r;
char c;
expresii conversii tipul expresiei
i-j/k nu int
a/b a spre double
b spre double double
x+y nu double
i+a a spre double
i spre double double
i-3.14 i spre double double
i+3 nu int
i+x i spre double double
i-c c spre int int
x+10 10 spre double double
p-10 10 spre unsigned unsigned
r*5 5 spre long long
(double)(i/j) se realizeaza împartirea întreaga între
i si j si rezultatul se converteste spre double double
Daca rezultatul unei operatii depaseste domeniul de valori ce corespunde tipului rezultatului, valoarea respectiva se trunchiaza si rezultatul este eronat.
3.3.11. Operatori conditionali
Operatorii conditionali sunt ? si : si se folosesc împreuna în constructii de forma:
exp1 ? exp2 : exp3
Evaluarea se face astfel:
se evalueaza expresia exp1;
daca exp1 este diferita de zero, atunci valoarea si tipul expresiei conditionale sunt egale cu valoarea si tipul expresiei exp2; altfel cu expresia exp3.
Exemplu: procesul de determinare a maximului a doua numere a si b este:
daca a>b atunci max=a
altfel max=b
sfdaca
În limbajul C se poate realiza acest proces cu ajutorul operatorilor conditionali astfel:
max= a>b ? a : b
Daca a>b atunci expresia conditionala are valoarea si tipul lui a altfel expresia conditionala are valoarea si tipul lui b.
Operatorul virgula
Operatorul "," este folosit pentru gruparea mai multor expresii într-una singura.
Cu ajutorul acestui operator (care are prioritatea cea mai mica) se construiesc expresii de forma:
exp1, exp2,. . ., expn
Aceasta expresie are valoarea si tipul ultimei expresii (deci a lui expn).
Exemplu:
k= (i=10, j=j+5; i+j)
Se executa pe rând cele doua atribuiri de la stânga la dreapta din parantezele rotunde apoi se face suma i+j si în final se atribuie aceasta suma lui k,
LECŢIA 4.
INTRĂRI / IEsIRI STANDARD
Limbajul C nu poseda instructiuni de intrare / iesire. Aceste operatii se realizeaza prin apeluri de functii din bibliotecile standard ale mediului de programare. De obicei astfel de functii asigura interfata programului cu terminalul de la care s-a lansat, cu imprimanta, etc. Se numesc intrari standard si iesiri standard intrarile respectiv iesirile de la terminalul de la care s-a lansat programul. Totodata se presupune ca datele de intrare / iesire sunt organizate în fisiere.
Unui program C i se ataseaza în mod implicit urmatoarele fisiere:
- stdin intrare standard;
- stdout iesire standard;
- stderr iesire standard pentru erori;
- stdprn iesire pe imprimanta;
- stdaux intrare / iesire seriala.
|