Documente Academic
Documente Profesional
Documente Cultură
1
#include <stdio.h>
#include<conio.h>
void main(void)
{ int i, n ,s = 0,p = 1;
clrscr();
printf("\n\t Introduceti n=");
scanf("%d", &n);
for(i = 1; I <= n; i++) s += i*i;
for(i = n; i >= 1; --i) p*= i;
printf("\n \ts=%d p=%d", s, p);
getch(); }
Introduceti n=5
s=15 p=120
Programul 8.6.1.
7 Operatorul de adresare
Determinarea adresei afectate unei entităţi în vederea înscrierii sau modificării de valori
cu un tip adecvat, selectarea unui element de tablou, accesarea unui cîmp dintr-o
structură, referirea unui cîmp dintr-o uniune şi transmiterea de parametri unor funcţii
pentru tratarea lor în diverse contexte de rezolvare sînt situaţiile de bază în care se
folosesc operatorii de adresare.
Adresarea la o entitate poate fi directă, prin nume sau indirectă, prin intermediul unui
pointer. Adresarea indirectă apare în alocarea dinamică a unei variabile sau în selectarea
unei entităţi dintre mai multe de acelaşi tip.
La ambele tipuri de adresare, rezultatul este, fie o Rvalue, fie o Lvalue.
Simbolurile şi sintaxele de accesare ale operatorilor de adresare sînt următoarele:
1. & (determinare adresă): & nume_enitate. Precizează adresa entităţii în care urmează
să se înscrie o valoare de un tip adecvat (în cazul funcţiei de citire scanf(), pentru a o
furniza unei funcţii, cu efect lateral asupra entităţii în cazul transmiterii prin valoare sau
pentru a o atribuii unui pointer.
2. [ ] (indexare): nume_element_tablou[expresie_indice]. Acest tip de adresare a fost
descris în secţiunea Tablouri cu aplicare la referirea elementelor de tablou.
3. (selectare): nume_structura.nume_cîmp sau
nume_uniune.nume_cîmp. Selectează cîmpul cu numele precizat, din structura
sau uniunea respectivă, în vederea prelucrării lui.
4. -> (selectare indirectă): pointer->nume_cîmp sau
(*pointer). nume_cîmp. Adresa cîmpului selectat din structura sau uniunea
precizată se memorează în variabila de tip pointer.
5. *(adresare indirectă): * pointer. Accesează adresa memorată în operandul de tip
pointer.
2
8 Operatorul de secvenţiere
În limbajul C virgula poate fi interpretată, fie ca separator de entităţi de acelaşi tip în
declaraţii de tip, de adrese de variabile în liste de intrare, de variabile în liste de ieşire şi
de parametri în definirea sau apelarea unor funcţii, fie ca operator de secvenţiere într-o
secvenţă de expresii de forma: expresie_1, expresie_2, …, expresie_n,
secvenţa însăşi fiind considerată o expresie.
Evaluarea secvenţei se face de la stînga la dreapta în mod secvenţial, adică expresiile se
calculează una după alta în ordinea în care apar. Valoarea ultimei expresii constituie
valoarea întregii secvenţe. Nu se impune nici o restricţie la ultima expresie, în schimb
primele n-1 componente din secvenţă trebuie să fie atribuiri valide. Parantezele simple
pot fi utilizate în delimitarea secvenţei într-o situaţie în care poate să apară confuzii.
Programul 8.8.1 are ca scop aflarea valorii unei secvenţe de atribuirii cu următoarea
structură: y=(i=5*i, j=i-2, k++, y=(i+j+k)*x);. În tabelul care însoţeşte programul se
evidenţiază şi rezultatele expresiilor componente în ordinea execuţiei lor.
/* Operatorul de secventiere */
#include <stdio.h>
#include <conio.h>
void main(void)
{ float x = 2.5, y;
int i = 10, j, k;
clrscr();
printf("\n Introduceti j si k : ");
scanf("%d%d", &j, &k);
printf("\n y=(i=5*i, j=i-2,k++,y=(i+j+k)*x): %f",
y=(i=5*i, j=i-2, k++, y=(i+j+k)*x)); i = 10;
printf("\n Introduceti j si k : "); scanf("%d%d", &j, &k);
printf("\n Valorile expresiilor din y sint : ");
printf("\n i=5*i : %d", i=5*i); printf("\n j=i-2 : %d", j=i-2);
printf("\n k++ : %d", k++);
printf("\n y=(i+j+k)*x : %f",y=(i+j+k)*x);
getch(); }
Introduceti j si k : 3 15
y=(i=5*i, j=i-2,k++,y=(i+j+k)*x) : 285.000000
Valorile expresiilor din y sint :
1. i=i*5 : 50 3. k++ : 15
2. j=i-2 : 48 4. y=(i+j+k)*x : 285.000000
Programul 8.8.1
9. Operatorul sizeof
Cu operatorul sizeof într-o primă sintaxă, am făcut cunoştinţă deja în secţiunea 2.2. Spre
deosebire de ceilalţi operatori folosiţi în limbajul C++, care se aplică asupra unor valori,
sizeof este singurul care se aplică unui tip de dată (standard sau derivat). La forma
sizeof(tip) adăugăm acum şi sizeof expresie.
3
Efectul aplicării acestui operator asupra unei expresii este precizarea dimensiunii
spaţiului de memorie, în octeţi, necesar tipului valorii expresiei. Fără să se cunoască
valoarea expresiei, sizeof se rezolvă în faza de compilare, după ce se stabileşte tipul
expresiei în funcţie de tipul operanzilor componenţi.
Programul următor precizează numărul de octeţi necesar pentru alocarea tipurilor
variabilelor j, z şi expresiei w = z*j. După care se determină valoarea lui w.
/* Operatorul sizeof */
#include <stdio.h>
#include <conio.h>
void main(void)
{ float z = 2.5;
int j = 235;
double w;
clrscr();
printf("\n Tipul int :%d\n Tipul float :%d\
\n Tipul double :%d \n w= %lf", sizeof(j), sizeof(z),
sizeof(w=z*j), w=z*j);
getch(); }
Tipul int :2
Tipul float : 4
Tipul double : 8
w=587.500000
Programul 8.9.1
4
x>=1 ? (f=x*x+1) : (f=x*x-1));
getch(); }
Introduceti x : 17.57
x>=1 ? (f=x*x+1) : (f=x*x-1) : 309.704889
Introduceti x : -5.2
x>=1 ? (f=x*x+1) : (f=x*x-1) : 26.039998
Programul 8.10.1.
Ultimul printf() poate fi înlocuit printr-o expresie condiţională de forma: x>=1 ? printf(“\
nf=%f”, x*x+1) : printf(“\nf=%f”, x*x-1);.
Al doilea program află maximul a trei numere reale a, b şi c, comparînd numerele două
cîte două (comparări imbricate).
/* Operatorul conditional */
#include <stdio.h>
#include <conio.h>
void main(void)
{ float a, b, c, maxim;
clrscr();
printf("\n Introduceti trei numere reale:");
scanf("%f%f%f", &a, &b, &c);
maxim = a>b? (a>c? a: c):(b>c? b : c);
printf("\n maxim= %5.2f", maxim);
getch(); }
Introduceti trei numere reale: 3.5 75. 22.35
maxim = 75.00
Programul 8.10.2.
Şi aici, linia de program cu ajutorul căreia se determină maximul a trei numere
reale poate fi înlocuită prin una din variantele:
a>b? maxim =(a>c? a : c) : (b>c? b : c);
a>b? (a>c? maxim = a : maxim = c) : (b>c? maxim = b : maxim = c);
a>b? (a>c? printf("\n maxim= %5.2f", a) :
printf("\n maxim= %5.2f", c)) :
(b>c? printf("\n maxim= %5.2f", b):
printf("\n maxim= %5.2f", maxim));
În plus, prin combinarea operatorului condiţional cu instrucţiunea if sau numai prin
utilizarea instrucţiunii if se pot adăuga încă multe alte variante
5
implicite. Am văzut deja în cazul operatorilor de atribuire că acest tip de conversie poate
afecta în mod grosolan precizia rezultatelor.
De aceea, există posibilitatea de a se interveni din exterior ( în mod explicit), prin
operatorul cast, asupra tipului unui operand în vederea obţinerii unui rezultat conform
cerinţelor programatorului.
a) Conversii implicite
Conversiile implicite permit efectuarea expresiilor în care se operează cu valori de tipuri
diferite şi pentru care precizia rezultatelor nu este pe primul plan.
Dacă într-o operaţie intervin doi operanzi de acelaşi tip, atunci se execută operaţia şi
rezultatul va avea un tip egal cu tipul operanzilor. Rezultatul este exact dacă nu se
depăşeşte domeniul de valori al tipului respectiv.
Dacă într-o operaţie intervin doi operanzi cu tipuri diferite, atunci regula de bază este
egalarea tipurilor acestora cu tipul comun. În general, tipul comun este dat de tipul cu
domeniul de valori mai larg. Deci, rezultatul operaţiei este exact dacă nu se depăşeşte
domeniul tipului comun. Altfel, se consideră nedefinit.
Regulile după care se realizează conversiile implicite sînt următoarele:
- conversia tipurilor short int, unsigned short int şi enum la tipul int nu afectează
valorile corespunzătoare;
- conversia tipului char la tipul int se produce prin completarea octetului mai
semnificativ cu 0 sau cu extensie de semn, în funcţie de tipul char implicit: unsigned,
respectiv signed. Una din cele două variante se alege şi în declararea explicită a tipurilor
unsigned char şi signed char pentru conversia la tipul int.
- pentru conversia unei perechi de tipuri din mulţimea int (inclusiv variantele cu
modificatorii unsigned şi long), float, double sau long double se reţine tipul cu domeniul
de valori cel mai vast sau unsigend în cazul cînd unul din operanzi are tipul unsigned.
După execuţia unei astfel de operaţii, nu se afişează eroare în cazul depăşirii domeniului
de valori al tipului comun. Valoarea furnizată este negativă.
Conversiile implicite evidenţiate prin programului 8.11.1.1 se referă la o împărţire
în care intervin operanzi sau atribuiri de diferite tipuri, astfel:
- în prima linie a tabelului, operanzi sînt de tip int, rezultatul de prima împărţire
este de tip int, iar de la cea de a doua este de tip float. La primul rezultat s-a pierdut doar
din precizie, în schimb al doilea este complet eronat.
- în a doua linie, rezultatul este de tip float deoarece cel de al doilea operand este
de tip float. Precizia rezultatului este acceptabilă.
- în linia a treia se pot observa, de asemenea, diferenţe în precizia valorilor finale,
rezultatul împărţirii a două numere întregi se atribuie unei variabile de tip double în prima
situaţie, iar în cea de a doua rezultatul este de tip double deoarece unul din operanzi este
double. Coincidenţa ultimului rezultat cu cel din linia a doua este numai în aparenţă,
fiindcă am văzut în secţiunile anterioare că, intern, reprezentările în virgulă mobilă diferă
de la o situaţie la alta.
/* Conversii implicite */
#include <stdio.h>
#include <conio.h>
void main(void)
{ int a = 17, b =3;
6
float e = 3;
double d, f = 3;
clrscr();
printf("\n a/b= %d, a/b=%f", a/b, a/b);
printf("\n a/e=%f", a/e);
printf("\n a/b= %lf a/f=%lf", d=a/b, a/f);
getch(); }
a/b=5 a/b=0.000000 a/e=5.666667
a/b=5.000000 a/f=5.666667
Programul 8.11.1.1
b) Operatorul cast
Operatorul unar cast realizează conversia explicită a tipului unui operand numeric la cel
precizat de acesta. Sintaxa prin care se descrie utilizarea lui este: (nume_tip) expresie.
Reprezentarea rezultatului expresiei se face conform tipului prezentat între paranteze
simple prin operatorul de conversie. Prin utilizarea acestui operator se pot evita
conversiile degradante din cadrul expresiilor de atribuire.
Programul 8.11.1.2 descrie utilizarea operatorului cast în două situaţii. Valoarea
lui a se converteşte la tipul float în prima împărţire, iar în a doua valoarea lui b se
converteşte la tipul double.
/* Operatorul cast */
#include <stdio.h>
#include <conio.h>
void main(void)
{ int a = 217, b =35;
clrscr();
printf("\n a/b= %f" ,(float)a/b);
printf("\n a/b= %lf", a/(double)b); }
a/b=6.200000
a/b=6.200000
Programul 8.11.1.2
7
Sintaxă Semnificaţie Aso Tip
cier
e
f(lista_p ) apel funcţie
t[indice] indexare
s.c sau u.c selecţie directă
sc sau u selecţie indirectă
!vi negaţie logică unar
~vi negaţie la nivel de bit
+v plus (fără efect)
-v minus
++v preincrementare
--v predecrementare
v++ postincrementare
v-- postdecrementare
&v deteminare adresă
*p adresare indirectă
p adresare indirectă
(tip)v conversie de tip (cast)
sizeof(tip) determină lungimea unei
sizeof e locaţii de memorie
v1 * v2 înmulţire binar
v1 / v2 împărţire
vi1%vi2 restul unei împărţiri întregi (modulo)
adunare
v1 + v2 scădere
v1 – v2
vi1<<vi2 deplasare stînga binar
vi1>>vi2 deplasare dreapta
v1 < v2 mai mic binar
v1 > v2 mai mare
v1<=v2 mai mic sau egal
v1>=v2 mai mare sau egal
v1==v2 egal
v1!=v2 diferit
vi1&vi2 conjuncţie la nivel de bit binar
vi1^vi2 sau exclusiv la nivel de
bit
vi1 | vi2 disjuncţie la nivel de bit
vi1&& vi2 conjuncţie logică binar
vi || vi2 disjuncţie logică
ei? e1 : e2 operatorul condiţional ternar
8
v += e v -= e v &= e
v ^= e v |= e v <<= e, v >>= e
e1, e2, …, en secvenţiere
Tabelul 8.12.1
Legendă:
- asociere stînga - dreapta - asociere dreapta – stînga
f – nume funcţie lista-p – listă de parametri
s – nume structură u – nume uniune
c – nume cîmp vi, vi1, vi2 – nume variabile întregi
v,v1, v2 – nume variabile p – nume pointer
e, e1, e2, …, en - expresii