Documente Academic
Documente Profesional
Documente Cultură
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.
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
*/
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:
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).
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:
-
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).
T* volatile ptrv;
int volatile * volatile ptr;
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
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
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:
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.
int)
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:
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.
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.
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));
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};
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, ¬a);
if (nota < nota_trecere)
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;
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);
}
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.
5.4.
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.
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.