Sunteți pe pagina 1din 25

5.

Tipuri de date i variabile

Datele formeaz elementul de baz al unui program, pentru c ele reprezint suportul de
informaie al programului. Instruciunile unui program acioneaz n mod esenial asupra datelor.
Noiunea de tip de date este specific limbajelor de nivel nalt de tip procedural i se bazeaz pe
urmtoarea restricie important: n timpul execuiei unui program, o variabil nu poate primi
valori dect aparinnd unui singur tip.
Observaie. Nu toate limbajele de nivel nalt utilizeaz noiunea de tip de date. De exemplu
limbajele funcionale (Lisp) sau cele logice (Prolog) nu o folosesc, gestiunea tipului datelor
asociate la o variabil este efectuat automat de ctre calculator.
Un tip de date reprezint o mulime finit de elemente care au aceeai reprezentare intern ntrun calculator i asupra crora se pot eventual efectua anumite operaii.

5.1 Ierarhia tipurilor de date


Limbajul C este un limbaj puternic tipizat, n sensul c permite utilizarea unui numr mare de
tipuri de date.
A) Tipuri de date predefinite i tipuri derivate
n C, precum i n majoritatea limbajelor tipizate, tipurile de date se mpart n dou categorii:
tipuri de date predefinite (sau fundamentale) i tipuri definite de programator (tipuri
utilizator).
In cazul tipurilor predefinite, mulimea valorilor acestora i operatorii care se pot utiliza
sunt incluse in sintaxa limbajului de programare. Tipurile predefinite au asociate un nume
reprezentat printr-un cavnt cheie ce poate fi folosit la declararea variabilelor. De exemplu, dac
T reprezint numele unui tip de date, declaraia:
T v;

este similar cu urmtoarea declaraie din matematic:


vT

In limbajul C tipurile predefinite sunt cele aritmetice, iar operatorii predefinii corespund
principalelor operaii aritmetice.
Spre deosebire de tipurile predefinite, tipurile de date definite de programator se
construiesc pe baza celor fundamentale cu ajutorul unor construcii sintactice predefinite. n

acest caz, ntr-o declaratie ca cea anterioar, T nu este numele unei mulimi, ci descrierea unei
mulimi prin intermediul unei proprieti:
v {x | x are proprietatea T}

Exemple:
int i, j;
/* declar 2 variabile apartinand
tipului predefinit int
*/
struct dreptunghi { double h, e} d;
/* declar variabila d ca fiind de tipul structura
ce conine dou componente de tip double
cu numele h i e
*/

n primul caz, T este int, iar n cazul al doilea T este:


struct dreptunghi {double h, e}

Limbajul C permite construirea unor tipuri de date utilizator cu ajutorul unor operatori de
derivare. Operatorii de drivare se pot aplica oricrui tip de date definit ntr-un program
(fundamental sau derivat) pentru a genera noi tipuri de date. n acest caz, tipul de date care s-a
obinut se numete tip de date derivat, iar cel pe baza cruia s-a construit tipul derivat se numete
tip de baz.
Principalii operatori de derivare sunt:
operatorul *: dac un tip T este un tip de date, atunci T* reprezint tipul de date pointer
asociat elementelor de tipul T;
operatorul []: dac un tip T este un tip de date, atunci T[] reprezint tipul tablou ce
conine elemente ale tipului T;
operatorul (): dac un tip T este un tip de date, atunci T() desemneaz mulimea
funciilo ce au ca rezultat o vaoare de tipul T;
Un pointer asociat la un element de tip T permite memorarea adresei zonei de memorie n care
elementul respectiv i pstreaz valoarea curent.
Exemple:
char *ps;
/* ps este o variabil de tip pointer la elemente
de tip char (permite memorarea adresei unui
element de tip char)
*/
double v[10];
/* v este un tablou cu 10 componente de tip double */

n cazul n care se utilizeaz tipuri derivate, se pot folosi operatori specifici pentru selectarea
elementelor tipului de baz. Principalii operatori de selecie sunt:

operatorul de adresare indirect (sau operator de derefeniere) specificat de caracterul *


(ca i operaia de adunare); dac p este un pointer declarat T *p; atunci *p indic
valoarea elementului de tip T spre care p indic la momentul curent;
operatorul de indexare este notat tot cu [], ca i cel de derivare i permite selecia unui
element dintr-un tablou; dac T v[10]; este declaraia tabloului v, atunci v[i]
reprezint elementul (de tip T) din tabloul v cu indicele i;
operatorul de apel de funcie este notat cu () i el permite apelul unei funcii; dac
declaraia unei funcii f este T f(<parametri formali>); atunci
f(<parametri actuai>) reprezint apelul lui f cu parametrii actuali respectivi.
Se observ c n afar de tipurile pointer i tabou, limbajul C trateaz funciile ca un tip de date
derivat al rezultatului acestora. Aceasta confer o mare flexibilitate n modul de tratare a
funciilor n cadrul programelor. De exemplu, se pot defini pointeri la funcii, sau chiar tablouri
ale cror elemente sunt pointeri la funcii:
float a(float);
/* a este o funcie cu un parametru float care
returneaz un rezultat de tip float
*/
int (*f)(float);
/* f este un pointer la o funcie care are un
parametru de tip float i care returneaz
un ntreg
*/
int (*g[])(float);
/* g este un tablou cu elemente de tip pointer la
funcii cu parametru de tip float i care
returneaz un ntreg
*/

n afar de tipurile specificate anterior, n limbajul C mai exist dou categorii de tipuri de date
derivate, pentru care nu exist ns operatori de derivare: tipurile union i struct. Acestea
permit construirea unui tip de date pe baza mai multor tipuri de baz. Tipul struct corespunde
tipului record din limbajul Pascal, iar union prii variante a acestuia.
B) Tipuri de date compuse (structurate)
Acestea corespund unui alt principiu de clasificare a tipurilor de date ale limbajului C. Din acest
punct de vedere, tipurile de date pot fi simple (ale cror valori sunt indivizibile), tipuri compuse
sau structurate (ale cror valori sunt compuse din elemente ce aparin altor tipuri de date) i
tipuri de date referin sau pointer (ale cror elemete specific adresele de memorie ale altor
tipuri de date).
n continuare se prezint o ierarhie a tipurilor de date ale limbajului C conform acestiu
criteriu de clasificare:

tipuri simple

tipul void
tipuri ntregi
tipuri reale
tipul enumerat
tipuri structurate
tipul tablou
tipul struct
tipul union
tipuri referin

Tipurile ntregi i reale sunt tipuri predefinite ale limbajului. Tipul void este de asemenea un tip
predefinit a crui semnificaie poate fi nimic sau orice, n funcie de context. Principalele
tipuri ntregi sunt char i int, iar principalele tipuri reale sunt float i double. Se observ
faptul c tipul caracter (char) este asimilat unui tip ntreg, asupra elementelor sale putndu-se
deci efectua operaii aritmetice specifice numerelor ntregi.
Un tip enumerat este un tip utilizator simplu care corespunde tipului enumerat din
limbajul Pascal. Elementele unui tip enmerat au valor ntregi i pozitive, care se asociaz unor
nume (constante simbolice). n mod uzual pentru elementele unui tip enumerat se folosesc nume
simbolice n locul unor valori ntregi.
Exemplu. Declaraia:
enum {luni,marti,miercuri,joi,vineri,sambata,duminica} zi;

declar variabila zi ca fiind de tip enumerat, care poate avea o valoare din mulimea de constante
simbolice:
{luni,marti,miercuri,joi,vineri,sambata,duminica}.

Un element de tip structur este format dint-un numr de componente care pot avea tipuri de
date diferite. Fiecare component se specific prin numele su i tipul de date asociat.
Exemplu. n declaraia:
struct student {
char *nume;
enum {m, f} sex;
struct {
int an;
int luna;
int zi;
} data_nasterii;
int grupa;
int note[12];
} st1, sr2;

se declar variabilele st1 i st2 ca fiind de tip structur cu urmtoarele componente: nume
(pointer la caractere), sex (enumerat), data_nasterii (structur), grupa (ntreg) i note (tablou).

Dei sintaxa tipului union este asemntoare cu cea a tipului struct, el permite ca o
variabil de acest tip s poat avea o singur valoare dintre mai multe tipuri specificate. n acest
caz, cmpurile unei uniuni partajeaz aceeai zon de memorie.
Exemplu.
union {
float medie;
int restante;
} situatie;

Variabila situatie poate avea o singur valoare n timpul execuiei unui program, care poate fi de
tip float (reprezentnd media unui student, dac acesta este promovat) sau de tip int
(reprezentnd numarul de restane dac este nepromovat).

5.2 Variabile i clase de memorare


O variabil este o entitate prin intermediul creia se pot stoca valori n memoria intern
accesibil unui program, sau se pot accesa aceste valori. Spre deosebire de limbajele algoritmice,
n limbajele de programare este esenial modul i locul n care se pstreaz valoarea curent a
unei variabile. Citirea i scrierea valorii curente a unei variabile se realizeaz prin intermediul
operaiilor de scriere n memorie i citire din memorie.
O variabil poate fi reprezentat printr-o pereche (<nume>, <adres>), unde <nume> este
numele dat de programator variabilei, iar <adres> este adresa zonei de memorie alocat de ctre
calculator pentru pstrarea valorii curente.
Al treilea element care intervine n cazul variabilelor este tipul de date al valorii curente.
Pentru gestiunea corect a valorilor unei variabile, nu este sufiecient determinarea adresei de
memorie a zonei unde se pstreaz valoarea curent, ci i dimensiunea zonei respective, precum
i modul de codifiare a informaiei. Aceste dou elemente sunt specifice tipului de date asociat
variabilei.
A) Declararea i definirea variabilelor
n limbajul C exist o deosebire important ntre definirea unei entiti dintr-un program
(variabi, funcie, etc.) i declararea acesteia. Declararea unei variabile are drept scop asocierea
unui nume de variabil la un tip de date, fr intenia de a rezerva o zon de memorie pentru
variabil. Definirea unei variabile cere calculatorului rezervarea unei zone de memorie
(corespunztoare tipului de date asociat variabilei) pentru un nume de variabil. n mod implicit,
orice definiie de variabil este i o declaraie. n mod suplimentar, la definiia unei variabile se
poate specifica i o valoare iniial pentru aceasta.
Observaie. O variabil nu poate exista ntr-un program dac nu a fost definit.
n mod uzual variabilele se definesc. Declararea unei variabile se poate face, de exemplu, n
cazul n care programul conine mai multe fiiere surs, iar n fiierul curent se dorete utilizarea
unei variabile care a fost definit n alt fiier.

Exemple.
float x, z;
int n = 10;
extern char s[20];

/* definire */
/* definire cu iniializare */
/* declarare */

Observaie. O variabil nu poate fi definit de dou ori ntr-un program, pentru c cererea de
alocare a unei zone de memorie se poate face o singur dat.
n limbajul C exist mai multe moduri de alocare a memoriei pentru variabile, aa nct o
definiie complet trebuie s specifice i acest lucru, indicnd clasa de memorare a variabilei.
n afar de clasa de memorare i de tipul de date, n definirea sau declararea unei
variabile pot s apar i calificatori. Acetia sunt utilizai pentru a specifica dac programul
poate sau nu modifica valoarea unei variabile, sau dac valoarea variabilei poate fi modificat de
ali ageni externi programului (alte programe de exemplu).
Cel mai utilizat calificator este cuvntul cheie const, care specific faptul c valoarea
variabilei respective nu poate fi modificat n timpul execuiei programului:
const int nota_trecere = 5;
n acest caz, variabila respectiv trebuie iniializat i se comport n timpul execuiei
programului ca i o constant simbolic.
Calificatorul volatile specific faptul c valoarea variabilei poate fi modificat n
timpul execuiei programului de ageni externi, care pot afecta zona de memorie ataat
variabilei.
Sintaxa pentru definirea unei variabile este urmtoarea:

definire

calificator
tip

variabil

clas de
memorare

declarator

;
iniializare

unde:
-

tip reprezint tipul de date asociat valorilor variabilei;


declarator reprezint numele unei variabile, dac aceasta este de tipul respectiv, sau o
construcie sintactic desemnnd o variabil derivat din tipul respectiv
iniializare reprezint valoarea iniial a variabilei; ea trebuie s fie o expresie
constant care poate fi evaluat n etapa de compilare a programului;

clasa de memorare este un cuvnt cheie ce poate fi auto, static, extern, sau
register; n cazul n care lipsete, clasa de memorare se determin din context (n
general ea poate fi auto sau extern n funcie de locul definirii variabilei).

n general, compilatorul ncearc s optimizeze codul rezultat n urma compilrii, indiferent de


calculatorul pe care se compileaz un program. n cazul utilizrii calificatorului volatile,
compilatorul va fi informat s nu optimizeze secvena respectiv de cod.
O variabil va fi declarat volatile, ori de cte ori valoarea acesteia va fi modificat
n afara execuiei programului curent. Exemple cazuri n care este necesar utilizarea
calificatorului volatile:
variabil care este mapat pe un port de intrare/ieire;
o variabil care este comun mai multor procese concurente;
o variabil care este este modificat de o rutin de ntreruperi;
o variabil de tip auto, declarat ntr-o funcie care apeleaz funcia sistem setjmp
i a crei valoare este modificat ntre apelul lui setjmp i apelul corespunztor al
celeilalte funcii sistem, longjmp.
Exemple de declaraii volatile:
- declararea unui obiect volatil prin intermediul unui pointer:
volatile T *vptr;

declararea unui pointer volatil (a crui adres memorat de pointer se modific):

Pointer volatil pointer la o variabil volatil:

T* volatile ptrv;
int volatile * volatile ptr;

B) Clase de memorare ale variabilelor


Corespunztor celor patru cuvinte cheie, exit patru clase de memorare ale valorilor variabilelor.
Acestea determin domeniul de vizibilitate, precum i durata de via a variabilelor.
Domeniul de vizibilitate sau domeniul de definiie al unei variabile repreznt acea zon
dintr-un program n care variabila respectiv este vizibil i poate fi referit prin numele su. n
mod uzual domeniul de vizibilitate al unei variabile depinde de locul de definire al acesteia.
n limbajul C exist dou moduri uzuale de definire a variabilelor:
n cadrul blocurilor, nainte de prima instruciune,
n afara oricrei funcii, la nivelul unui fiier surs.
Variabiele definite n afara oricrei funcii se numesc variabile externe sau globale, iar cele
definite n interiorul blocurilor se numesc variabile locale.
O variabil extern este vizibil n toate funciile definite n caelai fiier cu variabila, dar
aflate dupa definirea variabilei, domeniul de vizibilitate fiind reprezentat de corpurile funciilor
din fiier aflate dup definiia variabilei. O variabil extern poate fi referit n cadrul funciilor
respective, acesta fiind un mod prin care se poate face transferul de informaie ntre diferite
funcii ale unui program.

Exemplul 5.1. n programul urmtor se folosete o variabil extern de tip tablou n cadrul mai
multor funcii.
#include <stdio.h>
float v[10];
void Citeste(int n) {
int i;
for (i=0; i<n; i++)
scanf(%f, &v[i]);
}
void Scrie(int n) {
int i;
for (i=0; I<n; i++)
printf(v[%d]=%f, i, v[i]);
}
int main() {
int dim;
printf(\nDati dimensiunea vectorului: );
scanf(%d, &dim);
printf(\nDati elementele vectorului: );
Citeste(n);
printf(\nAfisare vector: );
Scrie(n);
return 0;
}

n cazul n care variabila v ar fi fost definit ntre funciile Citeste i Scrie, ar fi fost o eroare
deoarece v nu ar fi fost vizibil n funcia Scrie.
n cazul variabilelor definite n interiorul unor blocuri, domeniul de vizibilitate se reduce
la blocul de definire i la toate blocurile interne acestuia. Acest mod de determinare a domeniului
de vizibilitate impune cteva precizri:
a) Variabile cu acelai nume definite n blocuri diferite reprezint variabile diferite.
b) n cazul n care n blocul n care a fost definit o variabil exist unul sau mai mute
blocuri interne n care variabila este redefinit (are acelai nume), din domeniul de
vizibilatate al acesteia se scad toate blocurile interne n care variabila a fost redefinit.
Exemplul 5.2. Funcia urmtoare are ca mrime de intrare un vector ce conine notele unui
student; ea afieaz notele stdentului i media sa n cazul n care studentul este promovat:
void AfisareNote(int note, int nr_note)
{
/* bloc AfisareNote */
int k, rest = 0;
for (k=0; k<nr_note; k++)
if (note[k]<5)
rest++;

if (!rest)
{
/* bloc NotRest */
int k;
float s=0;
printf(\nNotele sunt: );
for (k=0; k<nr_note; k++)
{
/* bloc For */
printf( %d, note[k]);
s += note[k];
}
/* sfarsit bloc For */
printf(\nMedia este %f, s/nr_note);
}
/* sfarsit bloc NotRest */
}
/* sfarsit bloc AfisareNote */

Figura 5.1 prezint domeniile de definiie ale variabilelor din exemplul precedent:
AfisareNote
NotRest

k, rest
k, s

for

Figura 5.1. Domeniul de definiie al variabilelor


Notnd pentru fiecare variabil numele su i blocul n care este definit, domeniile de definiie
ale variabilelor (considerate ca mulimi) se poate descrie astfel:
D(k/AfisareNote) = AfisareNote NotRest
D(rest/AfisareNote) = AfisareNote
D(k/NotRest) = D(s/NotRest) = NotRest
Durata de via a unei variabile est specific execuiei unui program i indic intervalul sau
intervalele de timp n care variabila exist (adic are asociat o zon de memorie); cu alte cuvinte
ea specific timpul n care calculatorul aloc memorie pentru variabil.
Exist dou moduri distincte prin care se aloc memorie pentru variabile: modul de alocare
temporar i modul de alocare static.
A) Modul de alocare temporar, este specific variabilelor locale, prin care unei variabile i se
aloc memorie la intrarea n blocul de definire al variabilei (moment n care variabila este
creat, devine viabil), iar la ieirea din bloc variabilei respective i se dezafacteaz zona de
meorie asociat (moment n care variabila se distruge, devine neviabil). Memoria alocat
ntr-un mod temporar este rezervat ntr-o zon de memorie distinct, numit zona stiv, n
care sunt pstrate toate informaiile temporare ale unui program.

B) Modul de alocare static sau persistent poate fi aplicat att variabilelor locale, ct i celor
externe. n acest caz unei variabile nu i se aloc memorie n zona stiv, ci n zona de date
statice. Datorit modului de alocare, variabilele alocate static se creaz nainte de nceputul
execuiei programului (nainte de execuia funcieie main) i se distrug dup sfritul
execuiei acestuia (dup execuia funcieie main), durata de via fiind dat de intervalul de
timp al execuiei programului.
Pentru variabilele externe aceasta reprezint o metod normal de alocare, deoarece ele pot fi
apelate n mai multe funcii ale unui program. O atenie special o au variabilele locale cu
alocare static. Deosebirea important ntre o variabil local alocat static i una alocat
temporar const n faptul c cea alocat static i pstreaz valoarea i dup ieirea din blocul de
definire, valoarea sa putnd fi regsit la urmtoarea intrare n blocul respectiv.
Exemplul 5.3. S se calculeze valoarea expresiei:
e = 1! + 2! + + n!
Descrierea algoritmului.
Notnd cu pi produsul 1*2* *i, expresia e se poate scrie:
e = p 1 + p2 + + pn
unde pn este definit astfel:
p1=1, pk = pk-1*k, k=2,3, , n
iar e = sn poate fi definit astfel:
s1=1, si = si-1+pi, i=2,3, , n
Secvena din limbajul algoritmic ce corespunde calcului lui s este:
pentru i 1 la n executa

s s + pi

Descrierea programului. Utiliznd o variabil static s, funcia SumaFactoriale permite att


calculul produselor pk ct i memorarea sumelor pariale si. La fiecare apel al funciei se
calculeaz un produs parial pi i se adaug la valoarea curent a variabilei s (care i pstreaz
valoarea ntre apeluri).
#include stdio.h
int SumaFactoriale (int i) {
int k, p = 1;
static int s = 0;
for (k=1; k<=i; k++)
p = p*k;
s = s+p;
return s;
}
int main () {
int i, n, e=0;
printf(\nDati n: );
scanf(%d, &n);

for (i=1; i<=n; i++)


e = SumaFactoriale(i);
printf(\nS=%d, s);
return 0;
}

Diagrama care specific duratele de via ale variabilelor din programul anterior este prezentat
n figura 5.2.

s/SumaFactoriale
tmax
k,p/SumaFactoriale
t1i

t1f

t2i

t2f

t3i

t3f

t4i

t4f

i,n,e/main

ti

tf
Figura 5.2. Durata de via a variabilelor

S-a presupus c n=4, execuia funciei main este cuprins ntre ti i tf, cele patru execuii ale
funciei SumaFactoriale sunt cuprinse ntre tki i tkf, k=1, 2, 3, 4, iar execuia programului este
cuprins ntre 0 i tmax.
Se observ cteva elemente referitoare la variabila static s, care sunt valabile pentru
toate variabilele cu alocare static:
iniializarea variabilei se realizeaz o singur dat, la prima intrare n blocul de definire al
variabilei; daca nu este specificat nici o valoare de iniializare, aceasta este implicit
zero;
valoarea curent a variabilei se conserv ntre dou intrri consecutive in blocul de
definire.
Prin contrast, pentru variabilele alocate temporar i i p din funcia SumaFactoriale:
iniializarea se realizeaz la fiecare intrare n blocul de definire; n cazul n care valoarea
de iniializare lipsete, variabilele nu au o valoare iniial, iar referirea lor nainte ca ele
s primeasc valori constituie o surs de erori n programe;
valorile curente ntre dou intrri consecutive n blocul de definire se pierd, pentru c
variabilele se recreeaz la fiecare intrare n bloc:

Observaie. Datorit momentului de timp cnd se realizeaz iniializarea variabilelor cu alocare


static, expresiile de iniializare trebuie s poat fi evaluate nainte de nceperea execuiei
programului. Urmtorea secven de program genereaz o eroare de compilare:
void f() {
int n = 5;
static int *p = &n;
}

Motivul const n faptul c variabila n are un mod de alocare temporar (pe stiv), pe cnd
pointerul p are un mod de alocare static (n zona de date). Compilatorul nu poate determina
valoarea sa de iniializare, deoarece operaia de iniializare se efectueaz nainte de execuia
programului, cnd variabila n nu exist nc.
Acum se pot caracteriza clasele de memorare ale variabilelor:
1) Clasa auto este reprezentat da variabilele declarate local n interiorul blocurilor, avnd
o metod de alocare temporar a memoriei asociate. Aceasta este clasa implicit de
memorare pentru variabilele locale.
2) Clasa register este repezentat de variabilele definite local cu alocare temporar.
Deosebirea ntre clasa register i auto const n locul de stocare al valorilor
variabilelor: pentru variabilele din clasa register compilatorul ncearc s memoreze
valorile curente n registrele generale ale calculatorului, accesul fiind mult mai rapid n
acest caz; pentru variabilele din clasa auto stocarea se face n memoria intern. Nu ste
ns sigur ns alocarea valorilor variabilelor auto n registrele generale, datorit
numrului limitat al acestora. n cazul n care alocarea nu se poate face n registrele
generale, o variabil register se comport asemntor variabilelor de tip auto.
3) Clasa extern corespunde variabilelor externe care sunt definite n afara oricrei funcii
i au o alocare static a memoriei, aceasta fiind i clasa implicit pentru variabilele
globale. Asupra acestei clase trebuie fcut ns urmtoarea precizare: cuvintele cheie
auto, register i static se asociaz unor definiii de variabile avnd drept rezultat
alocarea de memorie pentru variabilele respective, pe cnd cuvntul cheie extern se
asociaz doar unor declaraii de variabile. Se declar astfel c o anumit variabil a fost
definit n alt modul de program, dar se dorete extinderea domeniului de vizibilitate i n
modulul curent. n acest mod poate s apar un element oarecum bizar: definirea unei
variabile externe nu trebuie s conin cuvtul cheie extern.
Exemplul 5.4. S se afieze toate numerele palindrome mai mici dect un numr ntreg
dat (un numr este palindrom dac cifrele egal deprtate de extremiti sunt identice).
Descrierea programului. Pentru testarea faptului c un numr este palondrom, se vor
extrage cifrele numrului respectiv i se vor introduce ntr-un vector. Se vor utiliza dou
funcii, DeterminaCifre pentru determinarea cifrelor unui numr (n baza 10) i
Palindrom pentru efectuarea testului de numr palindrom. Ambele funcii utilizeaz dou
variabile globale: vectrul v ce conine cifrele numrului, precum i k ce specific numrul

de cifre al numrului curent. Cele dou funcii, precum i funcia main se grupeaz n
dou fiiere separate.
/* fisierul main.c */
#include <stdio.h>
int k, v[10];
extern int Palindrom();
void DeterminaCifre (int n) {
k = -1;
while (n) {
v[++k] = n%10;
n = n/10;
}
}
int main () {
int i, n;
printf (\nDati n: );
scanf (%d, &n);
for (i=1; i<n; i++) {
DeterminaCifre (i);
if (Palindrom())
printf(\n%d, i);
}
return 0;
}
/* fisierul Palind.c */
extern int k, v[10];
int Palindrom () {
int i;
for (i=0; i<=k/2; i++)
if (v[i] != v[k-i])
return 0;
return 1;
}

Variabilele k i v sunt de tip extern, memoria pentru ele fiind alocat n fiierul main.c.
Prin declararea lor ca externe n fiierul Palind.c, domeniul de vizibilitate se extinde i
asupra funciei Palindrom. Pentru ca fiierul main.c s poat fi compilat corect, a fost
necesar declararea funciei Palindrom, care este definit n Palind.c i utilizat n
main.c.
4) Clasa de memorare static se poate aplica att variabilelor locale ct i celor globale
(externe), indicnd tipul static pentru alocarea memoriei. Cazul variabilelor locale a fost

discutat anterior. n cazul n care se aplic variabilelor globale, are au tot tipul static de
alocare, trebuie fcut urmtoarea precizare: o variabil extern declarat static nu
mai poate fi vizibil n alte fiiere surs ale unui program, chiar dac se redefinete cu
acelai nume. Aceasta este o important restricie asupra domeniului de vizibilitate.
O variabil extern se declar static atunci cnd se dorete ca ea s rmn local
fiierului unde a fost definit, fr s poat fi importat n alte fiiere. De exemplu, dac o
problem se descompune n mai multe subprobleme disjuncte, iar fiecare subproblem
este rezolvat ntr-un fiier distinct, funciile aceluiai fiier pot comunica prin
intermediul variabilelor globale declarate static, fr teama de a se suprapune cu alte
variabile externe cu acelai nume din alte fiiere.

5.3 Tipuri de date predefinite


Tipurile de date standard sau predefinite ale limbajului C pot fi referite prin intermediul unor
cuvinte cheie, pentru ele existnd moduri predefinite de reprezentare intern a datelor, precum i
anumite operaii ce se pot efectua cu aceste date.
A) Tipuri ntregi
Valorile unui asemenea tip de date reprezint o submulime a numerelor ntregi, care se pot
reprezenta intern ntr-un anumit calculator.
Reprezentarea intern este dependent de calculator, dar n mod uzual ea se face pe doi
sau patru octei. Indiferent de numrul de octei utilizai, un bit este folosit pentru reprezentarea
semnului, ceilali bii fiind folosii pentru reprezentarea numrului pozitiv n baza doi.
n afar de tipul int, mai exist tipuri ntregi derivate, care se specific astfel:
short, sau short int;
long, sau long int.
long long, sau long long int.
ntre tipurile ntregi exist urmtoarea relaie (sizeof este un operator specific limbajului C ce
permite determinarea lungimii zonei de memorie alocat de compilator pentru un tip de date sau
pentru reprezentarea valorii unei expresii):
sizeof(short int) sizeof(int) sizeof(long int) sizeof(long long

int)

De asemenea, limbajul C permite utilizarea numerelor ntregi fr semn. Declararea acestora se


realizeaz prin specificarea cuvntului cheie unsigned n faa tipului de date (unsigned
int, unsigned short, unsigned long), dar nu modific mrimea zonei de memorie
alocat elementelor. n cazul numerelor fr semn, toi biii sunt folosii pentru reprezentare.
Dac se noteaz cu maxint valoarea cea mai mare ntreg pozitiv ce se poate reprezenta,
domeniul valorilor unui tip ntreg cu semn este:
-maxint maxint,
pe cnd domeniul unui tip ntreg fr semn este:

0 2*maxint.
Observaie. Valorile maxime i minime ale constantelor ntregi sunt dependente de
implementare. Exist ns nume predefinite (specificate cu ajutorul directivei preprocesor
define) asociate acestor valori, aflate n fiierul header limits.h. Coninutul acestui fiier
poate diferi la diversele vesriuni de compilatoere C. In continuare se prezint un fragment dintrun asemenea fiier. Numele predefinite pentru aceste constante sunt SHRT_MIN, SHRT_MAX,
USHRT_MAX, INT_MIN, INT_MAX, UINT_MAX, LONG_MIN, LONG_MAX,
ULONG_MAX.
#define
#define
#define
#define
#define
#define
#define
#define
#define

SHRT_MIN
SHRT_MAX
USHRT_MAX
INT_MIN
INT_MAX
UINT_MAX
LONG_MIN
LONG_MAX
ULONG_MAX

(-32768)
32767
0xffff
(-2147483647 - 1)
2147483647
0xffffffff
(-2147483647L - 1)
2147483647L
0xffffffffUL

/*
/*
/*
/*
/*
/*
/*
/*
/*

minimum
maximum
maximum
minimum
maximum
maximum
minimum
maximum
maximum

(signed)
(signed)
unsigned
(signed)
(signed)
unsigned
(signed)
(signed)
unsigned

short value */
short value */
short value */
int value */
int value */
int value */
long value */
long value */
long value */

Constantele ntregi care se utilizeaz n cadrul programelor folosesc n mod uzual cifrele bazei de
numeraie 10. Se pot folosi i constante ntregi n bazele de numeraie 8 sau 16, caz n care se
utilizeaz un prefix: caracterul 0 pentru numerele din baza 8 i grupul de caractere 0x pentru
numerele scrise n baza 16. Exemple:
011 reprezint numrul 118 = 910
11 reprezint numrul 1110 (care este diferit de constanta 011)
0x11 reprezint numrul 1116 = 1710 (care este diferit de ambele constante precedente).
Limbajul C permite specificarea n cadrul programelor a constantelor ntregi de tip long sau
unsigned. Se utilizeaz pentru aceasta sufixele L i U. Exemple:
1L reprezint constanta ntreg 1 de tip long ;
1LL reprezint constanta ntreg 1 de tip long long ;
2U reprezint constanta ntreg 2 de tip unsigned ;
3LU reprezint constanta ntrag 3 de tip unsigned long .
Asupra datelor ntregi se pot aplica operatorii aritmetici, care produc un rezultat ntreg.
Principalii operatori sunt:
* : nmulire;
/ : ctul mpririi a dou numere ntregi;
% : restul mpririi a dou numere ntregi;
+ : adunare;
- : scdere.
Exemple:
5 / 2 = 2

5 % 2 = 1
Specificatorii de format utilizai n cadrul funciilor de intrare/ieire cei mai folosii sunt:
%d i %i pentru numerele ntregi,
%u pentru ntregii fr semn,
%o pentru numere n baza 8,
%x pentru numere n baza 16,
%hd , %hi, %hu, %ho, %hx pentru ntregii de tip short,
%ld , %li, %lu, %lo, %lx pentru ntregii de tip long,
%lld , %lli, %llu, %llo, %llx pentru ntregii de tip long long.
n mod uzual, numrul de caractere pe care se afieaz un numr ntreg este cel rezultat n urma
conversiei. Dac se dorete ca afiarea s se realizeze pe un numr specificat de caractere,
sintaxa pentru specificatorii de format se poate extinde opional astfel:
%[<aliniere>][<numr>]<format>
Primul caracter poate fi 0, caz n care cifrele numrului se vor alinia la dreapta i se vor completa
la stnga cu zerouri (dac este cazul), sau caracterul -, caz n care cifrele se vor alinia la stnga.
<numr> specific numrul de caractere pe care se va afia numrul. De exemplu,
specificatorul %06d utilizat ntr-o funcie printf pentru afiarea numrului 32 va genera irul
de caractere 000032, pa cnd specificatorul %06d va genera caracterele 32 urmate de 4 spaii.
B) Tipuri reale
Valorile unui tip real de date reprezint o submultime finit a numerelor reale, care se pot
reprezenta intern pe un anumit calculator. Reprezentarea intern se face n general pe 4, 8 sau 10
octei, considernd numerele sub forma normalizat:
x*10n,
unde x reprezint un numr supraunitar cu o singur cifr la partea ntreaga, diferit de zero,
numit mantis, iar n reprezint exponentul numrului. ntruct reprezentarea intern se face
folosind baza de numeraie 2, forma normalizat a acestora este:
x*2n,
x reprezentnd un numr subunitar scris n baza 2 (cu cifra prii ntregi = 1).
n afar de tipul float mai exist dou tipuri reale, care se pot specifica astfel:
double
long double
Utiliznd acelai operator sizeof, relaiile ntre mrimea spaiului de memorie alocat de un
compilator pentru tipurile reale este:
sizeof(float) sizeof(double) sizeof(long double)

Dup cum s-a precizat n paragraful 1.4.2, n reprezentarea intern a valorilor reale, se reprezint
separat mantisa i exponentul. Influena celor dou elemente la reprezentarea unui numr real
este diferit: de numrul de bii alocai mantisei depinde precizia de reprezentare, pe cnd
numrul de bii alocai exponentului determin domeniul de reprezentare a numerelor.
Reprezentarea numerelor reale cu virgul flotant a fost standardizat la nceputul anilor
80, prin standardul IEEE-754 (i revizuit n anul 2008). Standardul descrie trei tipuri de
reprezentare:
- reprezentare n simpl precizie (tipul float in limbajul C), unde numerele sunt
reprezentate pe 4 octei,
- reprezentare n dubl precizie (tipul double in limbajul C), unde numerele sunt
reprezentate pe 8 octei,
- reprezentare n precizie extins, unde numerele sunt reprezentate pe 10 sau 16 octei.
Reprezentarea n simpl precizie utilizeaz 32 de bii:
- 1 bit pentru semnul numrului
- 8 bii pentru exponent
- 23 bii pentru mantis (al 24-lea bit se omite, fiind 1, partea ntreag a mantisei
normalizate)
Pentru exponent nu se mai utilizeaz un bit pentru semn, deoarece se folosete un deplasament
D = 127 = 28-1,
astfel nct:
Exponentul stocat n memorie = Exponentul real D,
domeniul de reprezentare fiind astfel:
- Emin = -126
- Emax = 127
Exponentul se reprezint n complement fa de 2.
Ordinea de stocare a biilor semnului (pentru toate cele trei tipuri de reprezentare, nu doar
n cazul reprezentrii n simpl precizie), a exponentului i a mantisei este n ordine
descresctoare a biilor din cuvntul de memorie: de la bitul 31 la bitul 0. n plus, ordinea de
stocare a octeilor n cadrul unui cuvnt de memorie poate fi de dou tipuri:
- litle endian: cel mai puin semnificativ octet se memoreaz la adresa cea mai mic
(folosit in sistemele bazate pe procesoare Intel),
- big endian: cel mai puin semnificativ octet se memoreaz la adresa cea mai mare (folosit
in calculatoarele IBM).
Reprezentarea n dubl precizie (double in limbajul C) utilizeaz 64 de bii:
- 1 bit pentru semnul numrului
- 11 bii pentru exponent
- 52 bii pentru mantis (al 53-lea bit se omite, fiind 1)
Deplasamentul (pentru exponent) este n acest caz, D = 1023 = 210-1, iar domeniul de
reprezentare este:
- Emin = -1022
- Emax = 1023
Reprezentarea n precizie extins este definit n standardul IEEE 754, altfel dect n
precedentele formate:
- Specific doar un numr minim de cerine pentru un format extins
- Nu impune modul de implementare intern, pentru diferite arhitecturi de calculatoare
Exist dou categorii de formate:

Reprezentarea n precizie dubl extins (n general pe 80 de bii), utilizat de procesoare,


precum Intel i Motorola.
- Reprezentarea n precizie quadrupl (pe 128 de bii), utilizat de ctre sistemele
IBM/370.
Reprezentarea n precizie dubl extins (long double in limbajul C) utilizeaz 80 de bii.
Procesoarele Intel utilizeaz acest format, pe cnd procesoarele Motorola utilizeaz 96 bii (16
nefiind utilizai efectiv).
Structura de memoria a acestui format cuprinde:
- 1 bit pentru semnul numrului
- 15 bii pentru exponent
- 64 bii pentru mantis:
o Bitul 63 reprezint partea ntreag a mantisei, care nu mai este implicit n
acest caz,
o Biii 62-0 reprezint partea fracionar a mantisei.
Deplasamentul (pentru exponent) este:
D = 16383 = 214-1
Domeniul de reprezentare al numerelor, n acest caz, este: -16382 ... 16383
- Emin = -16382
- Emax = 16383
n acest caz, standardul mai permite i reprezentri ale unor valori speciale, care nu pot fi
reprezentate n celelalte cazuri: infinit i NaN (valoare care nu este numr). Cele dou valori se
reprezint astfel:
-

Constantele reale folosite n cadrul programelor pot avea dou forme: constante cu punct
zecimal i constante cu format exponenial. Constantele cu punct zecimal folosesc punctul pentru
separarea prii ntregi de partea fracionar. Constantele cu format exponenial sunt folosite
pentru numerele de forma x*10n, unde x reprezint o constant cu punct zecimal. Baza de
numeraie 10 este nlocuit de caracterul e sau E, iar exponentul se scrie la acelai nivel ca i
baza. De exemplu, numrul 2.73*10-15 se poate scrie ca 2.73e-15 sau 2.73E-15.
Asupra datelor de tip real se pot aplica operatorii aritmetici (*, /, +, -), care produc un
rezultat de asemenea real. n cazul n care operanzii au tipuri diferite, se aplic o regul de
conversie: operanzii care au un tip mai puin prioritar se convertesc la tipul cel mai prioritar.
Ordinea descresctoare a prioritii tipurilor numerice este: long double, double, float,
long long int, long int, int, short int.
Astfel, n cazul expresiei: 5.0/2, se va converti constanta ntreg 2 la constanta real
2.0 i se va efectua mprirea real (rezultatul fiind 2.5). n cazul expresiei: 5/2, ambii operanzi
sunt de tip ntreg i mprirea este ntreag (rezultatul fiind 2).
Specificatorii de format cei mai utilizai n cadrul funciilor de citire sunt:
%f pentru tipul float,
%lf pentru tipul double,
%Lf pentru tipul long double.

n cazul operaiilor de scriere, alegerea specificatorilor se face n funcie de tipul de date al


valorii ce se dorete afisat (care dup operaia de conversie a tipurilor poate fi doar double sau
long double) i de forma de afiare (cu punct zecimal sau cu format exponenial). Pentru
afiarea valorilor de tip double se pot utiliza urmtorii specificatori de format:
%f, pentru reprezentarea cu punct zecimal n format implicit, cu 6 cifre la partea
subunitar;
%e sau %E, pentru reprezentarea exponenial n format implicit, cu o cifr la partea
ntrag, 6 cifre la partea subunitar i separarea mantisei de exponent cu ajutorul literei e
sau E;
%g sau %G, caz n care se alege reprezentarea cu cel mai mic numr de caractere ntre %f
i %e sau %E.
n cazul valorilor long double, se pot utiliza specificatorii urmtori, care au aceeai
semnificaie ca i cei anteriori: %lf, %le, %lE, %lg, %lG.
Ca i n cazul valorilor ntregi, afiarea valorilor reale se poate face specificnd explicit
numrul de caractere de afiare, numrul de caractere al prii subunitare i eventual modul de
aliniere. ntre caracterul % i cel care specific tipul de conversie, se pot utiliza urmtoarele
cmpuri opionale:
<afiare><numr1>.<numr2>
unde, <afiare> are aceeai semnificaie ca i n cazul valorilor ntregi, <numr1>
reprezint numrul total al cifrelor ce se vor afia, iar<numr2> reprezint numrul cifrelor
prii subunitare.
De exemplu, pentru valoarea real 43.5678, specificatorul %f va afia 43.5678,
specificatorul %9.2f va afia 43.56, iar specificatorul %12.5e va afia 4.35678e+01.
C) Tipul caracter
Tipul caracter reprezint o mulime finit de elemente utilizat de un calculator pentru operaiile
de intrare/ieire. n mod uzual, aceast mulime are 256 de elemente i conine caractere
alfabetice (literele mari si mici), caractere numerice (cifrele bazei zece de numeraie), caractere
speciale (de exemplu: punctul, virgula, paranteze, etc.), precum i caractere neafiabile care au
un rol de control asupra operaiilor de intrare/ieire.
Codificarea intern se face n mod uzual pe un octet, reprezentnd numrul (n baza doi)
pe care l ocup fiecare caracter ntr-o tabel predefinit, numit tabela de caractere. Poziiile
caracterelor n aceast tabel ncep cu numrul 0 i se termin cu 255.
Din punct de vedere al tipurilor de date, exist trei categorii de tipuri caracter: char,
unsigned char i signed char, toate reprezentnd valori pe un octet. Dei standardul
limbajului C nu specific, cele mai multe compilatoare asimileaz tipul char cu tipul
unsigned char. Tipul signed char este asimilat n mod uzual tipurilor ntregi i conine
valori ntre -127 i 127.
Constantele de tip caracter folosite n cadrul programelor pot fi de mai multe tipuri:
1. Caractere afibile, care se reprezint ntre dou apostrofuri (cu excepia apostrofului
i a caracterului \). De exemplu:

a A 3 * (
2. Secvene escape simple, formate din dou caractere, care ncep cu caracterul \:
a. \, \, \?, \\ (reprezint al doilea caracter)
b. \a, \b, \f, \n, \r, \t, \v (reprezint caractere de control neafiabile: alert,
backspace, form feed, new line, carriage return, horizontal tab, vertical tab)
3. Secvene escape octale, care ncep cu caracterul \ i sunt urmate de o secven de
maxim trei caractere octale, reprezentnd poziia caracterului respectiv n tabela de
caractere (de exemplu \23). Caracterul \0 reprezint caracterul nul (cu codul 0).
4. Secvene escape hexazecimale, care ncep cu caracterele \x i sunt urmate de o
secven de maxim trei caractere hexazecimale, reprezentnd poziia caracterului
respectiv n tabela de caractere (de exemplu \xa1).
Pentru datele de tip caracter, specificatorul de format este %c.
Observaie. Elementele de tip caracter sunt asociate n limbajul C tipurilor ntregi de date, astfel
nct specificatorii de format i operatorii specifici numerelor ntregi se pot aplica i asupra
caracterelor. n acest caz se folosete grupul de caracere hh:
%hhd , %hhi, %hhu, %hho, %hhx
D) Tipul void
Tipul void nu a fcut iniial parte din mulimea tipurior fundamentale n vaianta Kernighan i
Ritchie. El a fost adugat ulterior pentru a uniformiza tratarea tipurilor de date derivate, inclusiv
a funciilor.
Din punct de vedere al tipurilor de date, el reprezint o mulime vid de constante.
Spre deosebire de celelalte tipuri fundamentale, utilizaea tipului void este supus
urmtoarelor restricii:
variabilele simple nu pot fi de tipul void; de exemplu, declaraia urmtoare este greit:
void x, z;

tipul void poate fi derivat doar cu ajutorul operatorilor * i (), cu alte cuvinte, se pot
folosi doar pointeri la void, precum i funcii care nu returneaz un rezultat; urmtoarele
declaraii sunt corecte:
void *p;
void f(int n);

de asemenea, tipul void poate fi utilizat n antetul unei funcii sau la declararea acesteia,
pentru a specifica lipsa parametrilor formali; de exemplu:
float Citeste(void);

Dac utilizarea tipului void n cadrul funciilor are o interpretare simpl, nu acelai lucru se
ntmpl i n cazul pointerilor la void. Principalul raionament care a condus la utilizarea
pointerilor la void const n faptul c el permite construcia tipurilor de date generice. Un tip
de date generic este o generalizare a noiunii de tip de date n sensul c el permite specificarea
doar a operaiior ce se pot efectua asupra elementelor unui tip de date, nu i a valorilor propriuzise ale elementelor.

Un exemplu elocvent de utilizare a tipului void* este acela al gestionrii obiectelor


dinamice cu ajutorul pointerilor. Pentru a crea un obiect dinamic trebuie alocat zona de
memorie necesar acestuia, iar funcia cea mai des utilizat este malloc care are urmtoarea
declaraie (n fiierul alloc.h):
void* malloc (size_t dim);

Aceast funcie rezarv o zon de memorie de dim octei i reurneaz adresa de nceput a ei.
Adresele de memorie ntr-un program C pot fi gestionate cu ajutorul pointerilor. ntruct aceeai
funcie este folosit pentru orice tip de pointer, tipul returnat de malloc este void*, urmnd ca
n program s se realizeze o conversie a acestui tip la tipul folosit (cu ajutorul unui operator de
converise). De exemplu:
float* p;
p = (float*)malloc(sizeof(float));

5.4 Tipul enumerat. Construcia typedef.


Tipul enumerat este un tip de date utilizator, dar are o poziie singular printre tipurile de date
ale limbajului C, pentru c nu este un tip compus, i nici derivat din alte tipuri de date. Din punct
de vedere al reprezentrii interne ale valorilor de tip enumerat, precum i al operatorilor ce se pot
aplica asupra acestor elemente, tipurile enumerate sunt considerate tipuri de date ntregi.
Constantele de tip enumerat se specific n cadrul programelor prin nume simbolice,
acesta fiind i principalul avantaj al utilizrii tipurilor enumerate: posibilitatea specificrii unor
valori ntregi prin nume simbolice. Definirea unui tip enumerat se face prin specificarea
constantelor simbolice care formeaz mulime elementelor sale, conform urmtoarei sintaxe:
,
tip
enum

ident

enumerat

ident

}
=

constant

ident
unde:
identificatorul specificat dup cuvntul cheie enum reprezint numele tipului de date
enumerat ce se definete sau se declar, pe cnd identificatorii dintre acolade reprezint
numele simbolice ale elementelor tipului respectiv;
<constant> reprezint o expresie ntreag constant i este o expresie de iniializare
opional pentru elementele unui tip enumerat.
Exemplu. n secvena urmtoare se definesc tipurile de date enumerat logic, zi i note_limita:
enum logic {false, true};
enum zi {luni, marti, miercuri, joi, vineri, \

sambata, duminica};
enum note_limita {nota_trecere=5, nota_bursa=8};

Observaii. Definiia sintactic anterioar necesit cteva informaii suplimentare:


1) n cazul n care elementele mulimii nu sunt specificate, aceasta reprezint o declaraie i nu
o definiie. Limbajul C permite o asemenea declaraie (care poate fi utilizat eventual n
cadrul altor declaraii sau definiii de tipuri de date utilizator), cu observaia c n program
trebuie s existe o definiie a tipului enumerat nainte de prima definiie a unei variabile
aparinnd tipului respectiv. De exemplu, linia urmtoare reprezint declararea unui tip
enumerat:
enum valori;

2) Deoarece tipurile enumerate sunt asociate unor tipuri ntregi, valorile constantelor simbolice
sunt numere ntregi ce pot fi specificate explicit de ctre programator prin valorile de
iniializare, sau pot fi ataate n mod automat de ctre compilator. n acest din urm caz,
valorea atribuit pentru fiacare constant simbolic este mai mare cu 1 dect valoarea
constantei precedente, valoarea primei constante fiind implicit zero. n exemplul urmtor se
precizeaz valorile constantelor simbolice din definirea unor tipuri enumerate:
enum A {x, y, z};
/* x=0, y=1, z=2 */
enum B {a=2, b, c=7, d, e}; /* a=2, b=3, c=7, d=8, e=9 */

3) n cazul unei definiii, numele tipului enumerat este opional. n cazul n care acesta lipsete,
tipul respectiv reprezint un tip anonim. Un tip anonim nu poate fi dect definit, nu i
declarat, deoarece el nu poate fi ulterior identificat n cadrul programului. Din acest motiv,
tipul anonim poate fi utilizat n dou situaii uzuale: (a) fie mpreun cu definirea unor
variabile ale tipului respectiv, care nu mai pot fi definite ulterior, fie (b) doar pentru definirea
unor constante simbolice ce pot fi referite direct prin numele lor n acea zona de program ce
corespunde domeniului de definiie a tipului enumerat respectiv.
Exemplul 5.5. Programul urmtor, care afieaz studenii restanieri i cei bursieri dintr-o
grup, utilizeaz a doua situaie uzual.
#include <stdio.h>
enum {nota_trecere=5, nota_bursa=8};
/* domeniul de definitie al constantelor nota_trecere
si nota_bursa este global in fisierul curent */
int main () {
int i, n;
printf (\nDati numarul de studenti: );
scanf (%d, &n);
for (i=0; i<n; i++) {
int nota;
printf (\nDati nota studentului %d: , i+1);
scanf (%d, &nota);
if (nota < nota_trecere)

printf (\n%d est restantier, i+1);


else (nota >= nota_bursa)
printf (\n%d est bursier, i+1);
}
return 0;
}

Unul dintre avantajele utilizrii n acest mod a constantelor simbolice const n modificarea
simpl a programelor la care anumite constante trebuie schimbate. De exemplu, pentru
programul precedent, n cazul n care se modific nota pentru burs, va trebui modificat doar
linia din program n care se definete valoarea constantei, nu i n tot restul programului.
Definirea unor variabile aparinnd unui tip enumerat se poate face fie n cadrul aceleiai
definiii, fie ntr-o definiie separat, ce succede definiiei tipului respectiv. n cazul n care
variabilele se definesc mpreun cu tipul enumerat, acestea se specific dup definiia tipului. De
exemplu, n definiia urmtoare se definete tipul enumerat TipEnumerat, mpreun cu
variabilele t1 i t2:
enum TipEnumerat {x=3, u, v} t1, t2;

n cazul n care variabilele se definesc separat, specificarea tipului enumerat se face prin numele
asociat acestuia precedat de cuvntul cheie enum. Avantajul unui asemenea mod de definire
const n faptul c un tip de date enumerat se definete o singur dat n program, dar poate fi
utilizat de cte ori este nevoie.
Pentru exemplul precedent, urmtoarele dou definiii sunt echivalente cu cea precedent:
enum TipEnumerat {x=3, u, v};
enum TipEnumerat t1, t2;

pe cnd sevena urmtoare este greit:


enum TipEnumerat {x=3, u, v};
TipEnumerat t1, t2;

Limbajul C permite ca unui anumit tip de date s i se poat asocia un nume, care s poat fi
utilizat n definiille i declaraiile variabilelor dintr-un program ca i numele unui tip de date
predefinit. De exemplu, secvena urmtoare este echivalent cu ultimele definiii corecte:
typedef enum {x=3, u, v} TipEnumerat;
TipEnumerat t1, t2;

Aceast operaie se poate realiza cu ajutorul construciei typedef, care definete un tip de date
utilizator, n sensul c asociaz un nume la un tip de date ce poate fi definit cu ajutorul sintaxei
limbajului. n majoritatea cazurilor (de exemplu, o excepie o constituie definirea unei mulimi
de pointeri la un tip de funcii), construcia are o sintax de forma urmtoare:
definire
tip

typedef

definire tip

identificator

unde <definire tip> reprezint tipul de date definit, iar <identificator> reprezint
numele asociat acestuia.

Observaii.
1) Construcia typedef nu creeaz o zon de memorie, ea doar asociaz un nume la un tip de
date.
2) Tipul de date specificat ntr-o construcie typedef poate fi un tip de date predefinit,
definirea unui tip utilizator conform unei sintaxe specifice, sau numele unui alt tip de date
definit anterior ntr-o alt construcie typedef.
Exemplul 5.6. Secvena urmtoare de program definete o funcie ce permite planificarea
activitilor dintr-o sptmn.
typedef enum {luni, marti, miercuri, joi, vineri, \
sambata, duminica} ZiSaptamana;
void Planifica (ZiSaptamana ziua) {
if (ziua >= luni && ziua <= vineri)
printf(Ora 8 Facultate\n);
else if (ziua == sambata)
printf(Ora 18 Discoteca\n);
else if (ziua == duminica)
printf(Ora 18 Filarmonica\n);
else
printf(Zi eronata\n);
}

Observaie. Utilizarea variabilelor de tip enumerat impune cteva precizri:


1) n mod uzual expresia din partea dreapt a unei instruciuni de atribuire care are n partea
stng o variabil de tip enumerat trebuie s fie o variabil de acelai tip, sau o constant
simbolic a tipului respectiv. De exemplu:
enum aa { x=2, y } a;
a = y;

2) Constantele simbolice ale unui tip enumerat pot s apar ntr-o expresie de tip ntreg. De
exemplu, valoarea variabilei k din secvena urmtoare este 6:
enum aa { x=2, y } a;
int k = 1 + x + y;

3) Tipurile enumerate nu posed operatori proprii, astfel nct o expresie ce conine constante de
tip enumerat i operatori aritmetici este convertit de ctre compilator n mod automat la un
tip de date ntreg. Pentru a putea folosi corect o asemenea expresie n partea dreapt a unui
operator de atribuire care are n stnga o variabil de tip enumerat, va trebui utilizat un
operator de conversie de tip. De exemplu, dintre instruciunile imediat urmtoare, prima este
incorect, pe cnd a doua este corect (s-a convertit tipul ntreg la tipul enum aa printr-un
operator de conversie care se va studia ulterior):
enum aa { x=2, y } a, b;
a = x + y;
b = (enum aa)(x + y);

5.5 Probleme
5.1.

Declarai o funcie cu numele f1 care returneaz un pointer la double i are doi parametri
de tip int i double. Declarai apoi un pointer cu numele f2 la o funcie care returneaz
un double i are doi parametri de tip int i double.

5.2.

Utilizai construcia typedef pentru a defini un tip de date cu numele PF, asociat
mulimii pointerilor la funcii care returneaz void i au un parametru de tip int.
Definii apoi doi pointeri de acest tip, cu numele pf1 i pf2.

5.3.

Definii un pointer v1 la un tablou cu 10 componente de tip int. Definii apoi un tablou


v2 de 10 componente care sunt pointeri la int.

5.4.

Definii o structur cu numele student care s conin urmtoarele cmpuri:


- nume student
- grupa
- an de studiu
- dac este promovat sau restanier
- media anual a sa, dac studentul este promovat
- numrul de restane, dac studentul este restanier.

5.5.

S se modifice programul din exemplul 5.4, astfel nct s permit i afiarea tuturor
numerelor mai mici dect k, pentru care suma cifrelor este ptrat perfect (adic exist un
numr natural p, astfel nct suma cifrelor numrului este p2).

5.6.

S se modifice programul din exemplul 5.5, astfel nct s permit o afiare mai detaliat a
studenilor: cu burs de merit, cu burs obinuit, nebursieri dar nerestanieri, restanieri
cu o restan, cu dou restane, cu trei restane, cu mai multe de trei restane.

5.7.

Generarea numerelor pseudo-aleatoare se poate realiza cu ajutorul urmtorului ir: a0 = 0,


an+1=(an + p) % m, unde p i m sunt numere ntregi 1. irul generat de relaia anterioar
este un ir ciclic: dup un numr de ori, care depinde de p i m, valorile se repet. S se
scrie un program care citete valorile lui p i m i determin dac irul ciclic generat an
este uniform, adic va conine mulimea de numere {0, 1, ..., m-1}. De exemplu, pentru
p=3 i m=5, irul generat va fi 0, 3, 1, 4, 2 (este uniform), iar pentru p=5 i m=20, irul
generat va fi 0, 15, 10, 5 (nu este uniform).

5.8.

S se scrie un program pentru decriptarea unei secvene de numere ntregi, folosind dou
chei cu valori complexe. Se consider cheile X i B, reprezentnd doua valori complexe,
specificate prin perechile (XRe, XIm) i (BRe, BIm). S se determine i s se afieze, dac
este posibil, un numr natural n i secvena de numere ntregi a0, a1, ..., an, aa nct:
X = a0 + a1B + a2B2 + ... + anBn
Dac n i secvena de numere ntregi a0, a1, ..., an nu se pot determina, se va afia un mesaj
de eroare.

S-ar putea să vă placă și