O variabila este un obiect de programare caruia i se atribuie un nume. x3c6cg
Variabilele ca si constantele sint elemente de baza cu care opereaza un
program scris in C.
Variabilele se deosebesc dupa denumire si pot primi diferite valori. Numele
variabilelor sint identificatori. Numele de variabile se scriu de obicei
cu litere mici (fara a fi obligatoriu).
Variabilele in limbajul C sint caracterizate prin doua atribute:
clasa de memorie si tip.
Aceste doua atribute ii sint atribuite unei variabile prin intermediul
unei declaratii. Declaratiile listeaza variabilele care urmeaza a fi folosite,
stabilesc clasa de memorie, tipul variabilelor si eventual valorile initiale,
dar despre declaratii vom discuta in capitolul 5.
3.1. Clase de memorie
Limbajul C prezinta patru clase de memorie: automatica, externa, statica,
registru.
Variabile automatice
Variabilele automatice sint variabile locale fiecarui bloc (sectiunea
6.2) sau functii (capitolul 7). Ele se declara prin specificatorul de clasa
de memorie auto sau implicit prin context. O variabila care apare in corpul
unei functii sau al unui bloc pentru care nu s-a facut nici o declaratie de
clasa de memorie se considera implicit de clasa auto.
O variabila auto este actualizata la fiecare intrare in bloc si se distruge
in momentul cind controlul a parasit blocul. Ele nu isi retin
valorile de la un apel la altul al functiei sau blocului si trebuie initializate
la fiecare intrare. Daca nu sint initializate, contin valori reziduale.
Nici o functie nu are acces la variabilele auto din alta functie. In functii
diferite pot exista variabile locale cu aceleasi nume, fara ca variabilele sa
aiba vreo legatura intre ele.
Variabile externe
Variabilele externe sint variabile cu caracter global. Ele se definesc
in afara oricarei functii si pot fi apelate prin nume din oricare functie
care intra in alcatuirea programului.
In declaratia de definitie aceste variabile nu necesita specificarea nici
unei clase de memorie.
La intilnirea unei definitii de variabila externa compilatorul aloca
si memorie pentru aceasta variabila.
Intr-un fisier sursa domeniul de definitie si actiune al unei variabile
externe este de la locul de declaratie pina la sfirsitul fisierului.
Aceste variabile exista si isi pastreaza valorile de-a lungul executiei
intregului program.
Pentru ca o functie sa poata utiliza o variabila externa, numele variabilei
trebuie facut cunoscut functiei printr-o declaratie. Declaratia poate fi facuta
fie explicit prin utilizarea specificatorului extern, fie implicit prin context.
Daca definitia unei variabile externe apare in fisierul sursa inaintea
folosirii ei intr-o functie particulara, atunci nici o declaratie ulterioara
nu este necesara, dar poate fi facuta.
Daca o variabila externa este referita intr-o functie inainte ca
ea sa fie definita, sau daca este definita intr-un fisier sursa diferit
de fisierul in care este folosita, atunci este obligatorie o declaratie
extern pentru a lega aparitiile variabilelor respective.
Daca o variabila externa este definita intr-un fisier sursa diferit de
cel in care ea este referita, atunci o singura declaratie extern data
in afara oricarei functii este suficienta pentru toate functiile care
urmeaza declaratiei.
Functiile sint considerate in general variabile externe afara de
cazul cind se specifica altfel.
Variabilele externe se folosesc adeseori in locul listelor de argumente
pentru a comunica date intre functii, chiar daca functiile sint
compilate separat.
Variabile statice
Variabilele statice se declara prin specificatorul de clasa de memorie static.
Aceste variabile sint la rindul lor de doua feluri: interne si externe.
Variabilele statice interne sint locale unei functii si se definesc in
interiorul unei functii, dar spre deosebire de variabilele auto, ele isi
pastreaza valorile tot timpul executiei programului. Variabilele statice interne
nu sint create si distruse de fiecare data cind functia este activata
sau parasita; ele ofera in cadrul unei functii o memorie particulara permanenta
pentru functia respectiva.
Alte functii nu au acces la variabilele statice interne proprii unei functii.
Ele pot fi declarate si implicit prin context; de exemplu sirurile de caractere
care apar in interiorul unei functii cum ar fi argumentele functiei printf
(vezi capitolul 11) sint variabile statice interne.
Variabilele statice externe se definesc in afara oricarei functii si orice
functie are acces la ele. Aceste variabile sint insa globale numai
pentru fisierul sursa in care ele au fost definite. Nu sint recunoscute
in alte fisiere.
In concluzie, variabila statica este externa daca este definita in
afara oricarei functii si este static interna daca este definita in interiorul
unei functii.
In general, functiile sint considerate obiecte externe. Exista insa
si posibilitatea sa declaram o functie de clasa static. Aceasta face ca numele
functiei sa nu fie recunoscut in afara fisierului in care a fost
declarata.
Variabile registru
O variabila registru se declara prin specificatorul de clasa de memorie register.
Ca si variabilele auto ele sint locale unui bloc sau functii si valorile
lor se pierd la iesirea din blocul sau functia respectiva. Variabilele declarate
register indica compilatorului ca variabilele respective vor fi folosite foarte
des. Daca este posibil, variabilele register vor li plasate de catre compilator
in registrii rapizi ai calculatorului, ceea ce conduce la programe mai
compacte si mai rapide.
Variabile register pot fi numai variabilele automatice sau parametrii formali
ai unei functii. Practic exista citeva restrictii asupra variabilelor
register care reflecta realitatea hardware-ului de baza. Astfel:
? numai citeva variabile din fiecare functie pot fi pastrate in
registri (de obicei 2 sau 3); declaratia register este ignorata pentru celelalte
variabile;
? numai tipurile de date int, char si pointer sint admise;
? nu este posibila referirea la adresa unei variabile register.
3.2. Tipuri de variabile
Limbajul C admite numai citeva tipuri fundamentale de variabile: caracter,
intreg, flotant.
Tipul caracter
O variabila de tip caracter se declara prin specificatorul de tip char. Zona
de memorie alocata unei variabile de tip char este de un octet. Ea este suficient
de mare pentru a putea memora orice caracter al setului de caractere implementate
pe calculator.
Daca un caracter din setul de caractere este memorat intr-o variabila
de tip char, atunci valoarea sa este egala cu codul intreg al caracterului
respectiv. Si alte cantitati pot fi memorate in variabile de tip char,
dar implementarea este dependenta de sistemul de calcul.
Ordinul de marime al variabilelor caracter este intre -128 si 127. Caracterele
setului ASCII sint toate pozitive, dar o constanta caracter specificata
printr-o secventa de evitare poate fi si negativa, de exemplu '\377' are valoarea
-1. Acest lucru se intimpla atunci cind aceasta constanta
apare intr-o expresie, moment in care se converteste la tipul int
prin extensia bitului cel mai din stinga din octet (datorita modului de
functionare a instructiunilor calculatorului).
Tipul intreg
Variabilele intregi pozitive sau negative pot fi declarate prin specificatorul
de tip int. Zona de memorie alocata unei variabile intregi poate fi de
cel mult trei dimensiuni.
Relatii despre dimensiune sint furnizate de calificatorii short, long
si unsigned, care pot fi aplicati tipului int.
Calificatorul short se refera totdeauna la numarul minim de octeti pe care poate
fi reprezentat un intreg, in cazul nostru 2.
Calificatorul long se refera la numarul maxim de octeti pe care poate fi reprezentat
un intreg, in cazul nostru 4.
Tipul int are dimensiunea naturala sugerata de sistemul de calcul. Scara numerelor
intregi reprezentabile in masina depinde de asemenea de sistemul
de calcul: un intreg poate lua valori intre -32768 si 32767 (sisteme
de calcul pe 16 biti) sau intre -2147483648 si 2147483647 (sisteme de
calcul pe 32 de biti).
Calificatorul unsigned alaturi de declaratia de tip int determina ca valorile
variabilelor astfel declarate sa fie considerate intregi fara semn.
Numerele de tipul unsigned respecta legile aritmeticii modulo 2n, unde n este
numarul de biti din reprezentarea unei variabile de tip int. Numerele de tipul
unsigned sint totdeauna pozitive.
Declaratiile pentru calificatori sint de forma: short int x; long int y; unsigned int z;
Cuvintul int poate fi omis in aceste situatii.
Tipul flotant (virgula mobila)
Variabilele flotante pot fi in simpla precizie si atunci se declara
prin specificatorul de tip float sau in dubla precizie si atunci se declara
prin specificatorul double. Majoritatea sistemelor de calcul admit si reprezentarea
in precizie extinsa; o variabila in precizie extinsa se declara
prin specificatorul long double.
Tipul void (tip neprecizat)
Un pointer poate fi declarat de tip void. In aceasta situatie pointerul
nu poate fi folosit pentru indirectare (dereferentiere) fara un cast explicit,
si aceasta deoarece compilatorul nu poate determina marimea obiectului pe care
pointerul il indica.
int x; float r; void *p = &x; /* p indica pe x */ int main() A
*(int *) p = 2; p = &r; /* p indica pe r */
*(float *)p = 1.1;
S
Daca o functie este declarata de tip void, aceasta nu va returna o valoare:
void hello(char *name) A printf("Hello, %s.",name);
S
Tipuri derivate
In afara de tipurile aritmetice fundamentale, exista, in principiu,
o clasa infinita de tipuri derivate, construite din tipurile fundamentale in
urmatoarele moduri:
-; „masive de T” pentru masive de obiecte de un tip dat T,
unde T este unul dintre tipurile admise;
-; „functii care returneaza T” pentru functii care returneaza
obiecte de un tip dat T;
-; „pointer la T” pentru pointeri la obiecte de un tip dat
T;
-; „structuri” pentru un sir de obiecte de tipuri diferite;
-; „reuniuni” care pot contine obiecte de tipuri diferite,
tratate intr-o singura zona de memorie.
In general aceste metode de construire de noi tipuri de obiecte pot fi
aplicate recursiv. Amanunte despre tipurile derivate sint date in
sectiunea 5.3.
3.3. Obiecte si valori-stinga
Alte doua notiuni folosite in descrierea limbajului C sint obiectul
si valoarea-stinga.
Un obiect este continutul unei zone de memorie.
O valoare-stinga este o expresie care se refera la un obiect. Un exemplu
evident de valoare-stinga este un identificator. Exista operatori care
produc valori-stinga: de exemplu, daca E este o expresie de tip pointer,
atunci *E este o expresie valoare-stinga care se refera la obiectul pe
care-l indica E. Numele valoare-stinga (in limba engleza left value)
a fost sugerat din faptul ca in expresia de atribuire E1 = E2 operandul
sting E1 trebuie sa fie o expresie valoare-stinga. In paragraful
de descriere a operatorilor se va indica daca operanzii sint valori-stinga
sau daca rezultatul operatiei este o valoare-stinga.
3.4. Conversii de tip
Un numar mare de operatori pot cauza conversia valorilor unui operand de la
un tip la altul. Daca intr-o expresie apar operanzi de diferite tipuri,
ei sint convertiti la un tip comun dupa un mic numar de reguli. In
general se fac automat numai conversiile care an sens, de exemplu: din intreg
in flotant, intr-o expresie de forma f+i. Expresii care nu au sens,
ca de exemplu un numar flotant ca indice, nu sint admise.
Caractere si intregi
Un caracter poate aparea oriunde unde un intreg este admis. In
toate cazurile valoarea caracterului este convertita automat intr-un intreg.
Deci intr-o expresie aritmetica tipul char si int pot aparea impreuna.
Aceasta permite o flexibilitate considerabila in anumite tipuri de transformari
de caractere. Un astfel de exemplu este functia atoi descrisa in sectiunea
7.5 care converteste un sir de cifre in echivalentul lor numeric.
Expresia: saii - '0' produce valoarea numerica a caracterului (cifra) memorat in ASCII.
Atragem atentia ca atunci cind o variabila de tip char este convertita
la tipul int, se poate produce un intreg negativ, daca bitul cel mai din
stinga al octetului contine 1. Caracterele din setul de caractere ASCII
nu devin niciodata negative, dar anumite configuratii de biti memorate in
variabile de tip caracter pot aparea ca negative prin extensia la tipul int.
Conversia tipului int in char se face cu pierderea bitilor de ordin superior.
Intregii de tip short sint convertiti automat la int. Conversia
intregilor se face cu extensie de semn; intregii sint totdeauna
cantitati cu semn.
Un intreg long este convertit la un intreg short sau char prin trunchiere
la stinga; surplusul de biti de ordin superior se pierde.
Conversii flotante
Toate operatiile aritmetice in virgula mobila se executa in precizie
extinsa. Conversia de la float la int se face prin trunchierea partii fractionare.
Conversia de la int la float este acceptata.
Intregi fara semn
Intr-o expresie in care apar doi operanzi, dintre care unul unsigned
iar celalalt un intreg de orice alt tip, intregul cu semn este convertit
in intreg fara semn si rezultatul este un intreg fara semn.
Cind un int trece in unsigned, valoarea sa este cel mai mic intreg
fara semn congruent cu intregul cu semn (modulo 216 sau 232). Intr-o
reprezentare la complementul fata de 2 (deci pentru numere negative), conversia
este conceptuala, nu exista nici o schimbare reala a configuratiei de biti.
Cind un intreg fara semn este convertit la long, valoarea rezultatului
este numeric aceeasi ca si a intregului fara semn, astfel conversia nu
face altceva decit sa adauge zerouri la stinga.
Conversii aritmetice
Daca un operator aritmetic binar are doi operanzi de tipuri diferite, atunci
tipul de nivel mai scazut este convertit la tipul de nivel mai inalt inainte
de operatie. Rezultatul este de tipul de nivel mai inalt. Ierarhia tipurilor
este urmatoarea:
-; char ? short ? int ? long;
-; float ? double ? long double;
-; tip intreg cu semn ? tip intreg fara semn;
-; tip intreg ? virgula mobila.
Conversii prin atribuire
Conversiile de tip se pot face prin atribuire; valoarea membrului drept este
convertita la tipul membrului sting, care este tipul rezultatului.
Conversii logice
Expresiile relationale de forma i<j si expresiile logice legate prin operatorii
&& si || sint definite ca avind valoarea 1 daca sint
adevarate si 0 daca sint false.
Astfel atribuirea: d = (c>='0') && (c<='9');
il face pe d egal cu 1 daca c este cifra si egal cu 0 in caz contrar.
Conversii explicite
Daca conversiile de pina aici le-am putea considera implicite, exista
si conversii explicite de tipuri pentru orice expresie. Aceste conversii se
fac prin constructia speciala numita cast de forma:
(nume-tip) expresie
In aceasta constructie expresie este convertita la tipul specificat dupa
regulile precizate mai sus. Mai precis aceasta este echivalenta cu atribuirea
expresiei respective unei variabile de un tip specificat, si aceasta noua variabila
este apoi folosita in locul intregii expresii. De exemplu, in
expresia: sqrt((double)n) se converteste n la double inainte de a se transmite functiei sqrt. Notam
insa ca, continutul real al lui n nu este alterat. Operatorul cast are
aceeasi precedenta ca si oricare operator unar.
Expresia constanta
O expresie constanta este o expresie care contine numai constante. Aceste
expresii sint evaluate in momentul compilarii si nu in timpul
executiei; ele pot fi astfel utilizate in orice loc unde sintaxa cere
o constanta, ca de exemplu:
#define MAXLINE 1000 char lineaMAXLINE+1i;