Documente Academic
Documente Profesional
Documente Cultură
Programare C
Theory without practice is useless; practice without theory is blind
Roger Bacon
Constante otante
O constant otant const dintr-o parte ntreag, un punct zecimal, o
parte fracionar, litera e sau E i opional, un exponent care este un ntreg
cu semn. Partea ntreag i partea fracionar sunt constituite din cte o
succesiune de cifre. ntr-o constant otant, att partea ntreag ct i
partea fracionar pot lipsi dar nu ambele; de asemenea poate lipsi punctul
zecimal sau litera e i exponentul, dar nu deodat (i punctul i litera e i
exponentul).
Exemplu: 123.456e-7 sau 0.12e-3
Orice constant otant se consider a n precizie extins.
Constante caracter
O constant caracter const dintr-un singur caracter scris ntre
apostrofuri, de exemplu x. Valoarea unei constante caracter este valoarea
numeric a caracterului, n setul de caractere al calculatorului. De exemplu n
setul de caractere ASCII caracterul zero sau 0 are valoarea 48 n zecimal,
total diferit de valoarea numeric zero.
Constantele caracter particip la operaiile aritmetice ca i oricare alte
numere. De exemplu, dac variabila c conine valoarea ASCII a unei cifre,
atunci prin instruciunea:
C = c 0;
Aceast valoare se transform n valoarea efectiv a cifrei.
Anumite caractere negrace i caractere grace (apostrof) i
(backslash) pot reprezentate ca i constante caracter cu ajutorul aa
numitor secvene de evitare. Secvenele de evitare ofer de altfel i un
mecanism general pentru reprezentarea caracterelor mai greu de introdus n
calculator i a oricror conguraii de bii. Aceste secvene de evitare sunt:
New-linecarriage return\~backslash
Tab orizontalform feed'apostrof
Backspacesemnal sonor" ghilimele
Conguraie de bii (ddd)
Aceste secvene, dei sunt formate din mai multe caractere, ele
reprezint n realitate un singur caracter. Secvena unde ddd este un ir de
1 pn la 3 cifre octale, genereaz pe un octet valoarea caracterului dorit sau
a conguraiei de bii dorite, date de irul ddd.
Exemplu: secvena 40 va genera caracterul spaiu.
Un caz special al acestei construcii este secvena care indic
caracterul NULL, care este caracterul cu valoarea zero. este scris deseori n
locul lui 0 pentru a sublinia natura de caracter a unei anumite expresii.
Cnd caracterul care urmeaz dup un backslash nu este unul dintre
cele specicate, backslash-ul este ignorat. Atragem atenia c toate
caracterele setului ASCII sunt pozitive, dar o constant caracter specicat
printr-o secven de evitare poate i negativ, de exemplu 77 are valoarea
-l.
Constante simbolice
Variabile statice
Variabilele statice se declar prin specicatorul de clas de memorie
static. Aceste variabile sunt la rndul lor de dou feluri: interne i externe.
Variabilele statice interne sunt locale unei funcii i se denesc n
interiorul unei funcii, dar spre deosebire de variabilele auto, ele i pstreaz
valorile tot timpul execuiei programului. Variabilele statice interne nu sunt
create i distruse de ecare dat cnd funcia este activat sau prsit; ele
ofer n cadrul unei funcii o memorie particular permanent pentru funcia
respectiv.
Alte funcii nu au acces la variabilele statice interne proprii unei funcii.
Ele pot declarate i implicit prin context; de exemplu irurile de
caractere care apar n interiorul unei funcii cum ar argumentele funciei
printf (vezi capitolul 11) sunt variabile statice interne.
Variabilele statice externe se denesc n afara oricrei funcii i orice
funcie are acces la ele. Aceste variabile sunt ns globale numai pentru
ierul surs n care ele au fost denite. Nu sunt recunoscute n alte iere.
n concluzie, variabila static este extern dac este denit n afara
oricrei funcii i este static intern dac este denit n interiorul unei
funcii.
n general, funciile sunt considerate obiecte externe. Exist ns i
posibilitatea s declarm o funcie de clas static. Aceasta face ca numele
funciei s nu e recunoscut n afara ierului n care a fost declarat.
Variabile registru
O variabil registru se declar prin specicatorul de clas de memorie
register. Ca i variabilele auto ele sunt locale unui bloc sau funcii i valorile
lor se pierd la ieirea din blocul sau funcia respectiv. Variabilele declarate
register indic compilatorului c variabilele respective vor folosite foarte
des. Dac este posibil, variabilele register vor li plasate de ctre compilator n
regitrii rapizi ai calculatorului, ceea ce conduce la programe mai compacte i
mai rapide.
Variabile register pot numai variabilele automatice sau parametrii
formali ai unei funcii. Practic exist cteva restricii asupra variabilelor
register care reect realitatea hardware-ului de baz. Astfel:
Numai cteva variabile din ecare funcie pot pstrate n regitri
(de obicei 2 sau 3); declaraia register este ignorat pentru celelalte
variabile;
Numai tipurile de date int, char i pointer sunt admise;
Nu este posibil referirea la adresa unei variabile register.
3.2. Tipuri de variabile
Limbajul C admite numai cteva tipuri fundamentale de variabile:
caracter, ntreg, otant.
Tipul caracter
O variabil de tip caracter se declar prin specicatorul de tip char.
Zona de memorie alocat unei variabile de tip char este de un octet. Ea este
Constant
ir (expresie)
Expresie-primar [expresie]
Expresie-primar (list-expresii<opt>)
Valoare-stnga. Identicator
Expresie-primar -> identicator
List-expresii:
Expresie
List-expresii, expresie
Un identicator este o expresie-primar, cu condiia c el s fost
declarat corespunztor. Tipul su este specicat n declaraia sa.
Dac tipul unui identicator este masiv de., atunci valoarea expresieildenticator este un pointer la primul obiect al masivului, iar tipul expresiei
este pointer la.. Mai mult, un identicator de masiv nu este o expresie
valoare-stnga.
La fel, un identicator declarat de tip funcie care returneaz., care
nu apare pe poziie de apel de funcie este convertit la pointer la funcie
care returneaz..
O constant este o expresie-primar. Tipul su poate int, long sau
double. Constantele caracter sunt de tip int, constantele otante sunt de tip
long double.
Un ir este o expresie-primar. Tipul su original este masiv de
caractere, dar urmnd aceleai reguli descrise mai sus pentru identicatori,
acesta este modicat n pointer la caracter i rezultatul este un pointer la
primul caracter al irului. Exist cteva excepii n anumite iniializri (vezi
paragraful 5.4).
O expresie ntre paranteze rotunde este o expresie-primar, al crei tip
i valoare sunt identice cu cele ale expresiei din interiorul parantezelor
(expresia din paranteze poate i o valoare-stnga).
O expresie-primar urmat de o expresie ntre paranteze ptrate este
o expresie-primar. Sensul intuitiv este de indexare. De obicei expresiaprimar are tipul pointer la., expresia-lndice are tipul int, iar rezultatul are
tipul .. O expresie de forma El[E2] este identic (prin deniie) cu *(El)
+(E2), unde * este operatorul de indirectare.
Un apel de funcie este o expresie-primar. Ea const dintr-o expresieprimar urmat de o pereche de paranteze rotunde, care conin o listexpresii separate prin virgule. Lista-expresii constituie argumentele reale ale
funciei; aceast list poate i vid. Expresia-primar trebuie s e de tipul
funcie care returneaz., iar rezultatul apelului de funcie va de tipul ..
naintea apelului, oricare argument de tip oat este convertit la tipul
double, oricare argument de tip char sau short este convertit la tipul int.
Numele de masive sunt convertite n pointeri la nceputul masivului. Nici o
alt conversie nu se efectueaz automat.
Dac este necesar pentru ca tipul unui argument actual s coincid cu
cel al argumentului formal, se va folosi un cast (vezi seciunea 3.4).
Sunt permise apeluri recursive la orice funcie.
O valoare-stnga urmat de un punct i un identicator este o expresieprimar. Valoarea-stnga denumete o structur sau o reuniune (vezi
capitolul 10) iar identicatorul denumete un membru din structur sau
reuniune. Rezultatul este o valoare-stnga care se refer la membrul denumit
din structur sau reuniune.
O expresie-primar urmat de o sgeat (constituit dintr-o liniu i
semnul > urmat de un identicator este o expresie-primar. Prima expresie
trebuie s e un pointer la o structur sau reuniune, iar identicatorul trebuie
s e numele unui membru din structura sau reuniunea respectiv. Rezultatul
este o valoare-stnga care se refer la membrul denumit din structura sau
reuniunea ctre care indic expresia pointer.
Expresia El->E2 este identic din punctul de vedere al rezultatului cu
(*El). E2
Descriem n continuare operatorii limbajului C mpreun cu expresiile
care se pot constitui cu aceti operatori.
4.2. Operatori unari
Toi operatorii unari au aceeai preceden, iar expresiile unare se
grupeaz de la dreapta la stnga.
Expresie-unar:
* expresie
& valoare-stnga
Expresie
! Expresie
~ expresie
+ valoare-stnga
Valoare-stnga
Valoare-stnga +
Valoare-stnga (nume-tip) expresie
Sizeof (nume-tip)
Operatorul unar * este operatorul de indirectare. Expresia care-l
urmeaz trebuie s e un pointer, iar rezultatul este o valoare-stnga care se
refer la obiectul ctre care indic expresia. Dac tipul expresiei este pointer
la. atunci tipul rezultatului este .. Acest operator trateaz operandul su
ca o adres, face acces la ea i i obine coninutul.
Exemplu: instruciuneay = *px;atribuie lui y coninutul adresei ctre
care indic px.
Operatorul unar & este operatorul de obinere a adresei unui obiect sau
de obinere a unui pointer la obiectul respectiv. Operandul este o valoarestnga iar rezultatul este un pointer la obiectul referit de valoarea-stnga.
Dac tipul valorii-stnga este . atunci tipul rezultatului este pointer la..
Exemplu. Fie x o variabil de tip int i px un pointer creat ntr-un anumit
fel (vezi capitolul 9). Atunci prin instruciunea
Px = &x;
Se atribuie variabilei de tip pointer la int px adresa variabilei x;
putem spune acum c px indic spre x. Secvena:
Px = &x;y = *px;
Este echivalent cu
Y = x;
Operatorul & poate aplicat numai la variabile i la elemente de masiv.
Construcii de forma & (x+1) i &3 nu sunt admise. De asemenea nu se
admite ca variabila s e de clas register.
Operatorul unar & ajut la transmiterea argumentelor de tip adres n
funcii.
Operatorul unar este operatorul de negativare. Operandul su este o
expresie, iar rezultatul este negativarea operandului. n acest caz sunt
aplicate conversiile aritmetice obinuite. Negativarea unui ntreg de tip
unsigned se face scznd valoarea sa din 2n, unde n este numrul de bii
rezervai tipului int.
Operatorul unar! Este operatorul de negare logic. Operandul su este
o expresie, iar rezultatul su este 1 sau 0 dup cum valoarea operandului
este 0 sau diferit de zero. Tipul rezultatului este int. Acest operator este
aplicabil la orice expresie de tip aritmetic sau la pointeri.
Operatorul unar ~ (tilda) este operatorul de complementare la unu. El
convertete ecare bit 1 la 0 i invers. El este un operator logic pe bii.
Operandul su trebuie s e de tip ntreg. Se aplic conversiile
aritmetice obinuite.
Operatorul unar + este operatorul de incrementare. Operandul su este
o valoare-stnga. Operatorul produce incrementarea operandului cu 1. Acest
operator prezint un aspect deosebit deoarece el poate folosit ca un
operator prex (naintea variabilei: +n) sau ca un operator postx (dup
variabil: n+). n ambele cazuri efectul este incrementarea lui n. Dar expresia
+n incrementeaz pe n nainte de folosirea valorii sale, n timp ce n+
incrementeaz pe n dup ce valoarea sa a fost utilizat. Aceasta nseamn c
n contextul n care se urmrete numai incrementarea lui n, oricare
construcie poate folosit, dar ntr-un context n care i valoarea lui n este
folosit +n i n+ furnizeaz dou valori distincte.
Exemplu: dac n este 5, atunci
X = n+;atribuie lui x valoarea 5
X = +n;atribuie lui x valoarea 6
n ambele cazuri n devine 6.
Rezultatul operaiei nu este o valoare-stnga, dar tipul su este tipul
valorii-stnga.
Operatorul unar este operatorul de decrementare. Acest operator este
analog cu operatorul + doar c produce decrementarea cu 1 a operandului.
Operatorul (nume-tip) este operatorul de conversie de tip. Prin numetip nelegem unul dintre tipurile fundamentale admise n C. Operandul
acestui operator este o expresie. Operatorul produce conversia valorii
expresiei la tipul denumit. Aceast construcie se numete cast.
Operatorul sizeof furnizeaz dimensiunea n octei a operandului su.
Aplicat unui masiv sau structuri, rezultatul este numrul total de octei din
masiv sau structur. Dimensiunea se determin n momentul compilrii, din
declaraiile obiectelor din expresie. Semantic, aceast expresie este o
Pune pe zero toi biii afar de ultimii 7 bii de ordin inferior ai lui n, fr
a afecta coninutul lui n.
4.9. Operatorul SAU-exclusiv pe bii
Expresie-SAU-exclusiv:
Expresie ^ expresie
Operatorul ^ este operatorul SAU-exclusiv logic pe bii. El este
asociativ i expresiile care-l conin pot rearanjate. Rezultatul este funcia
logic SAU-exclusiv pe bii aplicat operanzilor si. Operatorul se aplic
numai la operanzi de tipuri ntregi. Legea dup care funcioneaz este: 4.10.
Operatorul SAU-lnclusiv pe bii
Expresie-SAU-lnclusiv:
Expresie | expresie
Operatorul | este operatorul SAU-lnclusiv logic pe bii. El este
asociativ i expresiile care-l conin pot rearanjate. Rezultatul este funcia
logic SAU-lnclusiv pe bii aplicat operanzilor si. Operatorul se aplic
numai la operanzi de tipuri ntregi. Legea dup care funcioneaz este:
Operatorul | este folosit pentru a poziiona bii; de exemplu:
X = x | MASK;
Pune pe 1 toi biii din x care corespund la bii poziionai pe 1 din
MASK. Se efectueaz conversiile aritmetice obinuite.
4.11. Operatorul I-logic
Expresie-I-logic:
Expresie & expresie
Operatorul & este operatorul I-logic i el se grupeaz de la stnga la
dreapta. Rezultatul este 1 dac ambii operanzi sunt diferii de zero i 0 n
rest. Spre deosebire de operatorul I pe bii &, operatorul I-logic &
garanteaz o evaluare de la stnga la dreapta; mai mult, al doilea operand nu
este evaluat dac primul operand este 0.
Operanzii nu trebuie s aib n mod obligatoriu acelai tip, dar ecare
trebuie s aib unul dintre tipurile fundamentale sau pointer. Rezultatul este
totdeauna de tip int.
4.12. Operatorul SAU-logic
Expresie-SAU-logic:
Expresie || expresie
Operatorul || este operatorul SAU-logic i el se grupeaz de la stnga
la dreapta. Rezultatul este 1 dac cel puin unul dintre operanzi este diferit
de zero i 0 n rest.
Spre deosebire de operatorul SAU-lnclusiv pe bii |, operatorul SAU-logic
|| garanteaz o evaluare de la stnga la dreapta; mai mult, al doilea operand
nu este evaluat dac valoarea primului operand este diferit de zero.
Operanzii nu trebuie s aib n mod obligatoriu acelai tip, dar ecare
trebuie s aib unul dintre tipurile fundamentale sau pointer. Rezultatul este
totdeauna de tip int.
4.13. Operatorul condiional
Expresie-condiional:
Expresie? Expresie: expresie
=! =
Stnga la dreapta
&
Stnga la dreapta
^
Stnga la dreapta
|
Stnga la dreapta
&
Stnga la dreapta
||
Stnga la dreapta
?:
Dreapta la stnga
=op=
Dreapta la stnga ,
Stnga la dreapta 5. Declaraii
Declaraiile se folosesc pentru a specica interpretarea pe care
compilatorul trebuie s o dea ecrui identicator.
Declaraie:
Specicator-declaraielista-declarator<opt>;
Specicator-declaraie:
Specicator-tipspecicator-declaraie<opt>
Specicator-clas-memorie specicator-declaraie<opt>
Specicator-tip:
Char
Short
Int
Long
Unsigned
Float
Double
Void
Specicator-structur-sau-reuniune
Typedef-nume
Specicator-clas-memorie:
Auto
Static
Extern
Register
Const
Typedef
Lista-declarator:
Declarator-cu-lniializare
Declarator-cu-lniializare, lista-declarator
Declarator-cu-lniializare:
Declaratoriniializator<opt>
Declarator:
Identicator (declarator)
* declarator
Declarator ()
Declarator [expresie-constant<opt>]
Declaraiile listeaz toate variabilele care urmeaz a folosite ntr-un
program. O declaraie specic tipul, clasa de memorie i eventual valorile
iniiale pentru una sau mai multe variabile de acelai tip. Declaraiile se fac
sau n afara oricrei funcii sau la nceputul unei funcii naintea oricrei
instruciuni.
Nu orice declaraie rezerv i memorie pentru un anumit identicator,
de aceea deosebim:
Declaraia de deniie a unei variabile, care se refer la locul unde
este creat variabila i unde i se aloc memorie;
Declaraia de utilizare a unei variabile, care se refer la locul unde
numele variabilei este declarat pentru a anuna proprietile variabilei care
urmeaz a folosit.
5.1. Specicatori de clas de memorie
Specicatorii de clas de memorie sunt:
Autostaticextemregister
Consttypedef
Specicatorul typedef nu rezerv memorie i este denumit specicator
de clas de memorie numai din motive sintactice; el va discutat n
capitolul 10.
Semnicaia diferitelor clase de memorie a fost discutat deja n
paragraful 3.1.
Declaraiile cu specicatorii auto, static i register determin i
rezervarea unei zone de memorie corespunztoare. Declaraia cu
specicatorul extern presupune o deniie extern pentru identicatorii dai,
undeva n afara funciei sau ierului n care ei sunt declarai.
ntr-o declaraie poate s apar cel mult un specicator de clas de
memorie. Dac specicatorul de clas lipsete din declaraie, el se consider
implicit auto n interiorul unei funcii i deniie extern n afara funciei.
Excepie fac funciile care nu sunt niciodat automatice. De exemplu liniile:
Int sp;
Double val [MAXVAL];
Care apar ntr-un program n afara oricrei funcii, denesc variabilele
externe sp de tip int i val de tip masiv de double. Ele determin alocarea
memoriei i servesc de asemenea ca declaraii ale acestor variabile n tot
restul ierului surs. Pe de alt parte liniile:
Extern int sp;
Extern double val [];
Declar pentru restul ierului surs c variabilele sp i val sunt
externe, sp este de tip int i val este un masiv de double i c ele au fost
denite n alt parte, unde li s-a alocat i memorie. Deci aceste declaraii nu
creeaz aceste variabile i nici nu le aloc memorie.
5.2. Specicatori de tip
Specicatorii de tip sunt:
Charshortintlongunsigned
Floatdoublevoid
Specicator-structur-sau-reuniune
Typedef-nume
Cuvintele long, short i unsigned pot considerate i ca adjective;
urmtoarele combinaii sunt acceptate:
Short int
Long int
Unsigned int
Unsigned long int
Long double
ntr-o declaraie se admite cel mult un specicator de tip, cu excepia
combinaiilor amintite mai sus. Dac specicatorul de tip lipsete din
declaraie, el se consider implicit int.
Specicatorii de structuri i reuniuni sunt prezentai n seciunea 10.9,
iar declaraiile cu typedef n seciunea 10.10.
5.3. Declaratori
Lista-declarator care apare ntr-o declaraie este o succesiune de
declaratori separai prin virgule, ecare dintre ei putnd avea un iniializator.
Declaratorii din lista-declarator sunt identicatorii care trebuie
declarai.
Fiecare declarator este considerat ca o armaie care, atunci cnd
apare o construcie de aceeai form cu declaratorul, produce un obiect de
tipul i de clasa de memorie indicat. Fiecare declarator conine un singur
identicator. Gruparea declaratorilor este la fel ca i la expresii.
Dac declaratorul este un identicator simplu, atunci el are tipul indicat
de specicatorul din declaraie.
Un declarator ntre paranteze este tot un declarator, dar legtura
declaratorilor compleci poate alterat de paranteze.
S considerm acum o declaraie de forma:
TD1
Unde T este un specicator de tip (ca de exemplu int) i D1 un
declarator. S presupunem c aceast declaraie face ca identicatorul s
aib tipul . T unde . este vid dac D1 este un identicator simplu (aa
cum tipul lui x n int x este int). Dac D1 are forma:
*D
Atunci tipul identicatorului pe care-l conine acest declarator este
pointer la T.
Dac D1 are forma:
D ()
Atunci identicatorul pe care-l conine are tipul funcie care returneaz
T.
Char d;
Char m [100];
Aceasta ultim form ocup mai mult spaiu dar este mai convenabil
pentru adugarea unui comentariu pentru ecare declaraie sau pentru
modicri ulterioare.
5.4. Modicatorul const
Valoarea unei variabile declarate cu acest modicator nu poate
modicat.
Sintaxa:
Const nume-variabil = valoare;
Nume-funcie (., const tip *nume-variabil,.)
n prima variant, modicatorul atribuie o valoare iniial unei variabile
care nu mai poate ulterior modicat de program. De exemplu,
Const int vrsta = 39;
Orice atribuire pentru variabila vrsta va genera o eroare de compilare.
Atenie! O variabil declarat cu const poate indirect modicat prin
intermediul unui pointer:
Int *p = &vrsta;
*p = 35;
n a doua variant modicatorul const este folosit mpreun cu un
parametru pointer ntr-o list de parametri ai unei funcii. Funcia nu poate
modica variabila pe care o indic pointerul:
Int printf (const char *format,.); 5.5. Iniializare
Un declarator poate specica o valoare iniial pentru identicatorul
care se declar. Iniializatorul este precedat de semnul = i const dintr-o
expresie sau o list de valori incluse n acolade.
Iniializator:
Expresie {list-lniializare}
List-lniializare:
Expresie
List-lniializare, list-lniializare {list-lniializare}
Toate expresiile dintr-un iniializator pentru variabile statice sau externe
trebuie s e expresii constante (vezi seciunea 3.4) sau expresii care se
reduc la adresa unei variabile declarate anterior, posibil oset-ul unei expresii
constante. Variabilele de clas auto sau register pot iniializate cu expresii
oarecare, nu neaprat expresii constante, care implic constante sau
variabile declarate anterior sau chiar funcii.
n absena iniializrii explicite, variabilele statice i externe sunt
iniializate implicit cu valoarea 0. Variabilele auto i register au valori iniiale
nedenite (reziduale).
Pentru variabilele statice i externe, iniializarea se face o singur dat,
n principiu nainte ca programul s nceap s se execute.
Pentru variabilele auto i register, iniializarea este fcut la ecare
intrare n funcie sau bloc.
Dac un iniializator se aplic unui scalar (un pointer sau un obiect de
tip aritmetic) el const dintr-o singur expresie, eventual n acolade. Valoarea
Break;
Default:
Na+;
Break;
}
Printf (cifre: );
For (i=0; i<10; i+)
Printf ( %d, ne [i]);
Printf (albe: %d, altele: %d,
Nb, na);
n acest exemplu se parcurg toate caracterele dintr-un ir, se numr
cifrele, spaiile albe i alte caractere i se aeaz aceste numere nsoite de
comentarii.
Instruciunea while este cea care asigur parcurgerea irului pn la
sfrit. Pentru ecare caracter se execut corpul instruciunii while care
const dintr-o singur instruciune switch.
Se evalueaz expresia ntreag din paranteze (n cazul nostru
caracterul c) i se compar valoarea sa cu toate constantele-case. n
momentul cnd avem egalitate se ncepe execuia de la case-ul respectiv.
Aarea rezultatelor se face prin intermediul instruciunii for i a
funciei printf (vezi capitolul 11).
6.8. Instruciunea break
Format:
Break;
Aceast instruciune determin terminarea celei mai interioare
instruciuni while, do, for sau switch care o conine. Controlul trece la
instruciunea care urmeaz dup instruciunea astfel terminat.
6.9. Instruciunea continue
Format:
Continue;
Aceast instruciune determin trecerea controlului la poriunea de
continuare a ciclului celei mai interioare instruciuni while, do sau for care o
conine, adic la sfritul ciclului i reluarea urmtoarei iteraii a ciclului. n
while i do se continu cu testul, iar n for se continu cu expresie-3.
Mai precis n ecare dintre instruciunile:
While (.) {
Contin:;
}
For (.) {
Contin:;
}
Do {
Contin:;
} while (.);
Dac apare o instruciune continue aceasta este echivalent cu un salt
la eticheta contin. Dup contin: urmeaz o instruciune vid (vezi seciunea
6.11).
Poriunea de program din exemplul urmtor prelucreaz numai
elementele pozitive ale unui masiv.
For (i=0; i<n; i+) {
If (a [i] <0)/* sare peste elementele negative */
Continue;
/* prelucreaz elementele pozitive */
} 6.10. Instruciunea return
O instruciune return permite ieirea dintr-o funcie i transmiterea
controlului apelantului funciei. O funcie poate returna valori apelantului su,
prin intermediul unei instruciuni return.
Formate:
Return;
Return expresie;
n primul caz valoarea returnat nu este denit. n al doilea caz
valoarea expresiei este returnat apelantului funciei. Dac se cere, expresia
este convertit, ca ntr-o atribuire, la tipul funciei n care ea apare.
6.11. Instruciunea vid
Format:
;
Instruciunea vid este util pentru a introduce o etichet naintea unei
acolade drepte, ntr-o instruciune compus, sau pentru a introduce un corp
nul ntr-o instruciune de ciclare care cere corp al instruciunii, ca de exemplu
while sau for.
Exemplu:
For (ne=0; s [ne]! =0; +ne);
Aceast instruciune numr caracterele unui ir. Corpul lui for este vid,
deoarece tot lucrul se face n partea de test i actualizare dar sintaxa lui for
cere un corp al instruciunii. Instruciunea vid satisface acest lucru.
7. Funciile i structura unui program
Funciile sunt elementele de baz ale unui program scris n C; orice
program, de orice dimensiune, const din una sau mai multe funcii, care
specic operaiile care trebuie efectuate.
O funcie ofer un mod convenabil de ncapsulare a anumitor calcule
ntr-o cutie neagr care poate utilizat apoi fr a avea grija coninutului ei.
Funciile sunt ntr-adevr singurul mod de a face fa complexitii
programelor mari. Funciile permit desfacerea programelor mari n unele mici
i dau utilizatorului posibilitatea de a dezvolta programe, folosind ceea ce alii
au fcut deja n loc s o ia de la nceput.
Limbajul C a fost conceput s permit denirea de funcii eciente i
uor de mnuit. n general e bine s concepem programe constituite din mai
multe funcii mici dect din puine funcii de dimensiuni mari. Un program
poate mprit n mai multe iere surs n mod convenabil, iar ierele
surs pot compilate separat.
Mai precis, un program C const dintr-o secven de deniii externe.
Acestea sunt deniii de funcii i de date. Sintaxa deniiilor externe este
aceeai ca i a tuturor declaraiilor.
7.1. Deniia funciilor
Sintaxa deniiei unei funcii este urmtoarea:
Deniia-funciei:
Tip-funcie<opt> nume-funcie (lista-parametri) corp-funcie
Lista-parametri:
Declaraie-parametru
Declaraie-parametru,lista-parametri
Corpul-funciei:
Instruciune-compus
Dintre specicatorii de clas de memorie numai extern i static sunt
admii. Un declarator de funcie este similar cu un declarator pentru funcie
care returneaz. cu excepia c el listeaz parametrii formali ai funciei care
se denete.
Dup cum se observ, diferitele pri pot s lipseasc; o funcie minim
este:
Dummy () {}
Funcia care nu face nimic. Aceast funcie poate util n programe,
innd locul unei alte funcii n dezvoltarea ulterioar a programului.
Numele funciei poate precedat de un tip, dac funcia returneaz
altceva dect o valoare ntreag (vezi seciunea 7.2).
Numele funciei poate de asemenea precedat de clasa de memorie
extern sau static. Dac nici un specicator de clas de memorie nu este
prezent, atunci funcia este automat declarat extern, deoarece n C nu se
admite ca o funcie s e denit n interiorul altei funcii.
Declaraia unei funcii se face implicit la apariia ei. Se interpreteaz ca
funcie orice identicator nedeclarat anterior i urmat de o parantez (.
Pentru a evita surprize neplcute datorit neconcordanei dintre tipurile de
parametri aceast practic nu este recomandat.
Dm mai jos un exemplu de funcie complet denit:
Int max (int a, int b, int c) {
Int m;
M = (a>b)? A: b;
Return (m>c)? M: c;
}
Aceast funcie determin maximul dintre 3 numere date:
Int este un specicator de tip care indic faptul c funcia max
returneaz o valoare ntreag;
Max (int a, int b, int c) este declaraia funciei i a parametrilor
formali;
{.} este corpul funciei.
iar argumentul lim reprezint lungimea maxim a unei linii care poate
citit.
Funcia index caut conguraia de caractere dorit n interiorul liniei i
furnizeaz poziia sau indexul n irul s, unde ncepe irul t, sau -l dac linia
nu conine irul t. Argumentele funciei sunt s care reprezint adresa irului
de studiat i t care reprezint conguraia cutat.
Funcia care realizeaz aarea este printf din bibliotec.
Programul care realizeaz structura de mai sus este:
#dene MAXLINE 1000
#dene EOF -l
Getline (char s [], int lim) {
/*citete o linie n s; returneaz lungimea */
Int c, i;
I = 0;
While (-lim>0 & (c=getchar ()! = EOF &
C! =)
S [i+] =c;
If (c=) s [i+] =c;
S [i] =;
Return i;
}
Index (char s [], char t []) {
/*returneaz poziia din irul s unde ncepe irul t, sau -l */
Int i, j, k;
For (i=0; s [i]! =; i+) {
For (j=i, k=0; t [k]! = &
S [j] =t [k]; j+, k+)
;
If (t [k] =)
Return i;
}
Return -l;
}
Main () {
/* imprim toate liniile care conin cuvntul the */
Char line [MAXLINE];
While (getline (line, MAXLINE) >0)
If (index (line,the) >=0)
Printf (%s, line);
} 2. Funcia atof convertete un ir de cifre din formatul ASCII ntr-un
numr otant n precizie dubl.
Double atof (char s []) {
/* convertete irul s n dubl precizie */
Double val, power;
Int i, sign;
For (i=0; s [i] = || s [i] = ||
}
Funcia returneaz poziia lui x (un numr ntre 0 i n-l), dac x apare n
v sau -l altfel.
Exemplul ilustreaz o decizie tripl, dac x este mai mic, mai mare sau
egal cu elementul din mijlocul irului v [mid].
8. Liniile de control ale compilatorului
Limbajul C ofer o facilitate de extensie a limbajului cu ajutorul unui
preprocesor de macro-operaii simple. Folosirea liniilor de forma:
#dene
#include
Este cea mai uzual metod pentru extensia limbajului, caracterul
# (diez) indicnd faptul c aceste linii vor tratate de ctre preprocesor.
Liniile precedate de caracterul # au o sintax independent de restul
limbajului i pot aprea oriunde n ierul surs, avnd efect de la punctul de
deniie pn la sfritul ierului.
8. L. nlocuirea simbolurilor; substituii macro
O deniie de forma:
#dene identicator ir-simboluri
Determin ca preprocesorul s nlocuiasc toate apariiile ulterioare ale
identicatorului cu ir-simboluri dat (ir-simboluri nu se termin cu ;
deoarece n urma substituiei identicatorului cu acest ir ar aprea prea
multe caractere ;).
ir-simboluri sau textul de nlocuire este arbitrar. n mod normal el este
tot restul liniei ce urmeaz dup identicator. O deniie ns poate
continuat pe mai multe linii, introducnd ca ultim caracter n linia de
continuat caracterul \u8217? (backslash).
Un identicator care este subiectul unei linii #dene poate redenit
ulterior n program printr-o alt linie #dene. n acest caz, prima deniie are
efect numai pn la deniia urmtoare. Substituiile nu se realizeaz n cazul
n care identicatorii sunt ncadrai ntre ghilimele. De exemplu e deniia:
#dene ALFA 1
Oriunde va aprea n programul surs identicatorul ALFA el va
nlocuit cu constanta 1, cu excepia unei situaii de forma:
Printf (ALFA);
n care se va tipri chiar textul ALFA i nu constanta 1, deoarece
identicatorul este ncadrat ntre ghilimele.
Aceast facilitate este deosebit de valoroas pentru denirea
constantelor simbolice ca n:
#dene TABSIZE 100
Int tab [TABSIZE];
Deoarece ntr-o eventual modicare a dimensiunii tabelului tab se va
modica doar o singur linie n ierul surs. O linie de forma:
#dene identif (identif-l identif-n) ir-simboluri
n care nu exist spaiu ntre primul identicator i caracterul ( este o
deniie pentru o macro-operaie cu argumente, n care textul de nlocuire
Unsigned p, q, k;
Citire (&p);
Citire (&q);
K=cmmdc (p, q);
Printf (Cmmdc: %u, k);
Return 0;
}
Fiierul surs numere. C este prezentat n continuare.
#include numere. H
Unsigned eprim (unsigned n) {
Unsigned i, a, r;
If (n=0) return 0;
If (n<4) return 1;
If (n&1) =0) return 0;
For (i=3; i+=2) {
R=n%i;
If (r=0) return 0;
A=n/i;
If (a<=i) return 1;
}
}
Unsigned cmmdc (unsigned p, unsigned q) {
While (p>0) & (q>0)
If (p>q) p%=q;
Else q%=p;
If (p=0) return q;
Else return p;
}
Pentru a obine un program executabil din aceste dou iere se poate
utiliza o singur comand de compilare:
Ce princ. C numere. C opiuni-de-compilare
Unde Ce este numele compilatorului folosit (exemplu: bcc, gcc).
Opiunile de compilare (atunci cnd sunt necesare) sunt specice mediului de
programare folosit.
Proiectele programe de dimensiuni mari sunt compuse de cele mai
multe ori din module care se elaboreaz i se pun la punct separat. Uneori
pot identicate funcii care prezint un interes general mai mare i care pot
utilizate n elaborarea unor tipuri de aplicaii foarte diverse. Acestea sunt
dezvoltate separat i, dup ce au fost puse la punct n totalitate, se depun
ntr-o bibliotec de funcii n format obiect. n momentul n care acestea sunt
incluse n proiecte nu se mai pierde timp cu compilarea modulelor surs. n
schimb modulele care le apeleaz au nevoie de modul cum sunt descrise
aceste funcii i acesta se pstreaz n iere header.
9. Pointeri i masive
Un pointer este o variabil care conine adresa unei alte variabile.
Pointerii sunt foarte mult utilizai n programe scrise n C, pe de o parte
altera o variabil din funcia apelant. Problema care se pune este cum
procedm dac totui dorim s schimbm un argument?
De exemplu, o rutin de sortare poate schimba ntre ele dou elemente
care nu respect ordinea dorit, cu ajutorul unei funcii swap. Fie funcia
swap denit astfel:
Swap (int x, int y) {/* greit */
Int temp;
Temp = x;
X = y;
Y = temp;
}
Funcia swap apelat prin swap (a, b) nu va realiza aciunea dorit
deoarece ea nu poate afecta argumentele a i b din rutina apelant.
Exist ns o posibilitate de a obine efectul dorit, dac funcia apelant
transmite ca argumente pointeri la valorile ce se doresc interschimbate.
Atunci n funcia apelant apelul va :
Swap (&a, &b);
Iar forma corect a lui swap este:
Swap (int *px, int *py) {/* interschimb *px i *py */
Int temp;
Temp = *px;
*px = *py;
*py = temp;
} 9.3. Pointeri i masive
n limbajul C exist o strns legtur ntre pointeri i masive. Orice
operaie care poate realizat prin indicarea masivului poate de asemenea
fcut prin pointeri, care, n plus, conduce i la o accelerare a operaiei.
Declaraia:
Int a [10];
Denete un masiv de dimensiune 10, care reprezint un bloc de 10
obiecte consecutive numite a [0],. a [9]. Notaia a [i] reprezint al i-lea
element al masivului sau elementul din poziia i+1, ncepnd cu primul
element. Dac pa este un pointer la un ntreg declarat sub forma:
Int *pa;
Atunci atribuirea:
Pa = &a [0];
ncarc variabila pa cu adresa primului element al masivului a.
Atribuirea:
X = *pa;
Copiaz coninutul lui a [0] n x.
Dac pa indic un element particular al unui masiv a, atunci prin
deniie pa+i indic un element cu i poziii dup elementul pe care l indic
pa, dup cum pa-l indic un element cu i poziii nainte de cel pe care indic
pa. Astfel, dac variabila pa indic pe a [0] atunci *(pa+i) se refer la
coninutul lui a [i].
Allocp = p;
}
Testulif (allocp+n<=allocbuf+ALLOCSIZE)
Veric dac exist spaiu sucient pentru satisfacerea cererii de
alocare a n caractere. Dac cererea poate satisfcut, alloc revine cu un
pointer la zona de n caractere consecutive. Dac nu, alloc trebuie s
semnaleze lipsa de spaiu pe care o face returnnd valoarea constantei
simbolice NULL. Limbajul C garanteaz c nici un pointer care indic corect o
dat nu va conine zero, prin urmare o revenire cu valoarea zero poate
folosit pentru semnalarea unui eveniment anormal (n cazul nostru, lipsa de
spaiu). Atribuirea valorii zero unui pointer este deci un caz special.
Observm de asemenea c variabilele allocbuf i allocp sunt declarate
static cu scopul ca ele s e locale numai ierului surs care conine
funciile alloc i free.
Exemplul de mai sus demonstreaz cteva din facilitile aritmeticii de
adrese (pointeri). n primul rnd, pointerii pot comparai n anumite situaii.
Dac p i q sunt pointeri la membri unui acelai masiv, atunci relaiile <, <=,
>, >=, =,! = sunt valide. Relaia p<q, de exemplu, este adevrat dac p
indic un element mai apropiat de nceputul masivului dect elementul
indicat de pointerul q. Comparrile ntre pointeri pot duce ns la rezultate
imprevizibile, dac ei se refer la elemente aparinnd la masive diferite.
Se observ c pointerii i ntregii pot adunai sau sczui. Construcia
de forma:
P+n
nseamn adresa celui de-al n-lea element dup cel indicat de p,
indiferent de tipul elementului pe care l indic p. Compilatorul C aliniaz
valoarea lui n conform dimensiunii elementelor pe care le indic p,
dimensiunea ind determinat din declaraia lui p (scara de aliniere este 1
pentru char, 2 pentru int etc).
Dac p i q indic elemente ale aceluiai masiv, p-q este numrul
elementelor dintre cele pe care le indic p i q. S scriem o alt versiune a
funciei strlen folosind aceast ultim observaie:
Strlen (char *s) {/* returneaz lungimea unui ir */
Char *p;
P = s;
While (*p! = )
P+;
Return p-s;
}
n acest exemplu s rmne constant cu adresa de nceput a irului, n
timp ce p avanseaz la urmtorul caracter de ecare dat. Diferena p-s
dintre adresa ultimului element al irului i adresa primului element al irului
indic numrul de elemente.
n afar de operaiile binare menionate (adunarea sau scderea
pointerilor cu ntregi i scderea sau compararea a doi pointeri), celelalte
operaii cu pointeri sunt ilegale. Nu este permis adunarea, nmulirea,
Int x [3][5];
X este un masiv de ntregi, de rangul 3*5. Cnd x apare ntr-o expresie,
el este convertit ntr-un pointer la (primul din cele trei) masive de 5 ntregi.
n expresia x [i], care este echivalent cu expresia *(x+i), x este
convertit ntr-un pointer la un masiv, ale crui elemente sunt la rndul lor
masive de 5 elemente; apoi i se convertete la tipul x, adic indicele i se
nmulete cu lungimea elementului pe care l indic x (adic 5 ntregi) i apoi
rezultatele se adun. Se aplic operatorul * pentru obinerea masivului i (de
5 ntregi) care la rndul lui este convertit ntr-un pointer la primul ntreg din
cei cinci.
Se observ deci c primul indice din declaraia unui masiv nu joac rol
n calculul adresei.
9.8. Iniializarea masivelor i masivelor de
Pointeri
Iniializatorul unei variabile declarate masiv const dintr-o list de
iniializatori separai prin virgul i nchii ntre acolade, corespunztori
tuturor elementelor masivului. Ei sunt scrii n ordinea cresctoare a indicilor
masivului. Dac masivul conine sub-masive atunci regula se aplic recursiv
membrilor masivului. Dac n lista de iniializare exist mai puini iniializatori
dect elementele masivului, restul elementelor neiniializate se iniializeaz
cu zero. Nu se admite iniializarea unui masiv de clas cu automatic.
Acoladele {i} se pot omite n urmtoarele situaii:
Dac iniializatorul ncepe cu o acolad stng ({), atunci lista de
iniializatori, separai prin virgul, va iniializa elementele masivului; nu se
accept s existe mai muli iniializatori dect numrul elementelor
masivului;
Dac ns iniializatorul nu ncepe cu acolad stng ({), atunci se
iau din lista de iniializatori atia iniializatori ci corespund numrului de
elemente ale masivului, restul iniializatorilor vor iniializa urmtorul membru
al masivului, care are ca parte (sub-masiv) masivul deja iniializat.
Un masiv de caractere poate iniializat cu un ir, caz n care
caracterele succesive ale irului iniializeaz elementele masivului.
Exemple: 1)int x [] = {1,3,5};
Aceast declaraie denete i iniializeaz pe x ca un masiv
unidimensional cu trei elemente, n ciuda faptului c nu s-a specicat
dimensiunea masivului. Prezena iniializatorilor nchii ntre acolade
determin dimensiunea masivului.
2) Declaraia
Int y [4][3] = {
};
Este o iniializare complet nchis ntre acolade. Valorile 1,3,5
iniializeaz prima linie a masivului y [0] i anume pe y [0][0], y [0][1], y [0]
[2]. n mod analog urmtoarele dou linii iniializeaz pe y [1] i y [2].
Deoarece iniializatorii sunt mai putini dect numrul elementelor masivului,
linia y [3] se va iniializa cu zero, respectiv elementele y [3][0], y [3][1], y [3]
[2] vor avea valorile zero.
Int a [10][10];
Int *b [10];
n aceast declaraie a este un masiv de ntregi cruia i se aloc spaiu
pentru toate cele 100 de elemente, iar calculul indicilor se face n mod
obinuit pentru a avea acces la oricare element al masivului.
Pentru masivul b, declaraia aloc spaiu numai pentru zece pointeri,
ecare trebuind s e ncrcat cu adresa unui masiv de ntregi.
Presupunnd c ecare pointer indic un masiv de zece elemente
nseamn c ar trebui alocate nc o sut de locaii de memorie pentru
elementele masivelor.
n aceast accepiune, folosirea masivelor a i b poate similar n
sensul c a [5][5] i b [5][5], de exemplu, se refer ambele la unul i acelai
ntreg (dac ecare element b [i] este iniializat cu adresa masivului a [i]).
Astfel, masivul de pointeri utilizeaz mai mult spaiu de memorie dect
masivele bidimensionale i pot cere un pas de iniializare explicit. Dar
masivele de pointeri prezint dou avantaje i anume: accesul la un element
se face cu adresare indirect, prin intermediul unui pointer, n loc de
procedura obinuit folosind nmulirea i apoi adunarea, iar al doilea avantaj
const n aceea c dimensiunea masivelor pointate poate variabil. Acest
lucru nseamn c un element al masivului de pointeri b poate indica un
masiv de zece elemente, altul un masiv de dou elemente i altul de exemplu
poate s nu indice nici un masiv.
Cu toate c problema prezentat n acest paragraf am descris-o n
termenii ntregilor, ea este cel mai frecvent utilizat n memorarea irurilor de
caractere de lungimi diferite (ca n funcia month_name prezentat mai sus).
9.10. Argumentele unei linii de comand
n sistemul de calcul care admite limbajul C trebuie s existe
posibilitatea ca n momentul execuiei unui program scris n acest limbaj s i
se transmit acestuia argumente sau parametri prin linia de comand. Cnd
un program este lansat n execuie i funcia main este apelat, apelul va
conine dou argumente. Primul argument (numit convenional argc)
reprezint numrul de argumente din linia de comand care a lansat
programul. Al doilea argument (argv) este un pointer la un masiv de pointeri
la iruri de caractere care conin argumentele, cte unul pe ir.
S ilustrm acest mod dinamic de comunicare ntre utilizator i
programul su printr-un exemplu.
Fie programul numit pri care dorim s imprime la terminal argumentele
lui luate din linia de comand, imprimarea fcndu-se pe o linie, iar
argumentele imprimate s e separate prin spaii.
Comanda:
Pri succes colegi
Va avea ca rezultat imprimarea la terminal a textului
Succes colegi
Prin convenie, argv [0] este un pointer la numele pri al programului
apelat, astfel c argc, care specic numrul de argumente din linia de
comand este cel puin 1.
n exemplul nostru, argc este 3, iar argv [0], argv [1] i argv [2] sunt
pointeri la pri, succes i respectiv colegi. Primul argument real este
argv [1] iar ultimul esteargv [argc-l]. Dac argc este 1, nseamn c linia de
comand nu are nici un argument dup numele programului.
Atunci programul pri are urmtorul cod:
Main (int argc, char *argv []) {
/* tiprete argumentele */
Int i;
For (i=1; i<argc; i+)
Printf (%s%c, argv [i], (i<argc-l)?
:);
}
Deoarece argv este un pointer la un masiv de pointeri, exist mai multe
posibiliti de a scrie acest program. S mai scriem dou versiuni ale acestui
program.
Main (int argc, char *argv []) {
/*versiunea a doua */
While (-argc>0)
Printf (%s%c, *+argv, (argv>1)?
:);
}
Deoarece argv este un pointer la un masiv de pointeri, incrementndul, (+argv), el va pointa la argv [1] n loc de argv [0]. Fiecare incrementare
succesiv poziioneaz pe argv la urmtorul argument, iar *argv este
pointerul la argumentul irului respectiv. n acelai timp argc este
decrementat pn devine zero, moment n care nu mai sunt argumente de
imprimat.
Alternativ:
Main (int argc, char *argv []) {
/*versiunea a treia */
While (-argc>0)
Printf (argc>1)? %s :%s, *+argv);
}
Aceast versiune arat c argumentul funciei printf poate o expresie
ca oricare alta, cu toate c acest mod de utilizare nu este foarte frecvent.
Ca un al doilea exemplu, s reconsiderm programul din seciunea 7.5,
care imprim ecare linie a unui text care conine un ir specicat de
caractere (schem).
Dorim acum ca aceast schem s poat modicat dinamic, de la
execuie la execuie. Pentru aceasta o specicm printr-un argument n linia
de comand.
i atunci programul care caut schema dat de primul argument al
liniei de comand este:
#dene MAXLINE 1000
Main (int argc, char *argv []) {
/* gsete schema din primul argument */
/* caut schema */
Char line [MAXLINE], *s;
Long line0;
Int except, number;
Line0 = 0;
Number = 0;
While (-argc>0 & (*+argv)[0] =-)
For (s=argv [0]+1; *s! =; s+)
Switch (*s) {
Case x: except = 1; break;
Case n: number = 1; break;
Default:
Printf (nd: optiune ilegala %c,
*s);
Argc = 0;
Break;
}
If (argc! =1)
Printf (Nu exista argumente sau schema);
Else
While (getline (line, MAXLINE) >0) {
Line0+;
If (index (line, *argv) >=0)! =except) {
If (number)
Printf (%d:, line0);
Printf (%s, line);
}
}
}
Dac nu exist erori n linia de comand, atunci la sfritul primului
ciclu while argc trebuie s e 1, iar *argv conine adresa schemei. *+argv
este un pointer la un ir argument, iar (*+argv)[0] este primul caracter al
irului. n aceast ultim expresie parantezele sunt necesare deoarece fr
ele expresia nseamn *+(argv [0]) ceea ce este cu totul altceva (i greit): al
doilea caracter din numele programului. O alternativ corect pentru (*+argv
[0]) este *+argv.
9.11. Pointeri la funcii
n limbajul C o funcie nu este o variabil, dar putem deni un pointer la
o funcie, care apoi poate prelucrat, transmis unor alte funcii, introdus ntrun masiv i aa mai departe. Relativ la o funcie se pot face doar dou
operaii: apelul ei i considerarea adresei ei. Dac numele unei funcii apare
ntr-o expresie, fr a urmat imediat de o parantez stng, deci nu pe
poziia unui apel la ea, atunci se genereaz un pointer la aceast funcie.
Pentru a transmite o funcie unei alte funcii, ca argument, se poate proceda
n felul urmtor:
Int f ();
G (f);
Unde funcia f este un argument pentru funcia g. Deniia funciei g va
:
G (int (*funcpt) () { (*funcpt)();
}
Funcia f trebuie declarat explicit n rutina apelant(int f ();), deoarece
apariia ei n g (f) nu a fost urmat de parantez stng (. n expresia g (f) f
nu apare pe poziia de apel de funcie. n acest caz, pentru argumentul
funciei g se genereaz un pointer la funcia f. Deci g apeleaz funcia f printrun pointer la ea.
Declaraiile din funcia g trebuie studiate cu grij.
Int (*funcpt)();
Spune c funcpt este un pointer la o funcie care returneaz un ntreg.
Primul set de paranteze este necesar, deoarece fr el
Int *funcpt ();
nseamn c funcpt este o funcie care returneaz un pointer la un
ntreg, ceea ce este cu totul diferit fa de sensul primei expresii. Folosirea lui
funcpt n expresia: (*funcpt)();
Indic faptul c funcpt este un pointer la o funcie, *funcpt este funcia,
iar (*funcpt)() este apelul funciei.
O form echivalent simplicat de apel este urmtoarea:
Funcpt ();
Ca un exemplu, s considerm procedura de sortare a liniilor de la
intrare, descris n seciunea 9.7, dar modicat n sensul ca dac
argumentul opional -n apare n linia de comand, atunci liniile se vor sorta
nu lexicograc ci numeric, liniile coninnd grupe de numere.
O sortare const adesea din trei pri: o comparare care determin
ordinea oricrei perechi de elemente, un schimb care inverseaz ordinea
elementelor implicate i un algoritm de sortare care face comparrile i
inversrile pn cnd elementele sunt aduse n ordinea cerut. Algoritmul de
sortare este independent de operaiile de comparare i inversare, astfel nct
transmind diferite funcii de comparare i inversare funciei de sortare,
elementele de intrare se pot aranja dup diferite criterii.
Compararea lexicograc a dou linii se realizeaz prin funciile strcmp
i swap. Mai avem nevoie de o rutin numcmp care s compare dou linii pe
baza valorilor numerice i care s returneze aceiai indicatori ca i rutina
strcmp.
Declarm aceste trei funcii n funcia principal main, iar pointerii la
aceste funcii i transmitem ca argumente funciei sort, care la rndul ei va
apela aceste funcii prin intermediul pointerilor respectivi.
Funcia principal main va avea atunci urmtorul cod:
#dene LINES 100/* nr maxim de linii de sortat */
Main (int argc, char *argv []) {
Char *lineptr [LINES]; /* pointeri la linii text */
Int nlines; /* numr de linii citite */
Int strcmp (), numcmp (); /* funcii de comparare */
High = n 1;
While (low<=high) {
Mid = (low + high) /2;
If ( (cond=strcmp (word, tab [mid]. Keyword)
High = mid 1;
Else
If (cond>0) low = mid + 1;
Else
Return mid;
}
Return -l;
}
Main () {/* numr cuvintele cheie */
Int n, t;
Char word [MAXWORD];
While (t=getword (word, MAXWORD)! =EOF)
If (t=LETTER)
If ( (n=binary (word, keytab, NKEYS)
Keytab [n]. Keycount+;
For (n=0; n<NKEYS; n+)
If (keytab [n]. Keycount>0)
Printf (%4d %s,
Keytab [n]. Keycount,
Keytab [n]. Keyword);
}
nainte de a scrie funcia getword este sucient s spunem c ea
returneaz constanta simbolic LETTER de ecare dat cnd gsete un
cuvnt n textul de intrare i copiaz cuvntul n primul ei argument.
Cantitatea NKEYS este numrul cuvintelor cheie din keytab
(dimensiunea masivului de structuri). Dei putem calcula acest numr
manual, este mai simplu i mai sigur s-o facem cu calculatorul, mai ales dac
lista cuvintelor cheie este supus modicrilor. O posibilitate de a calcula
NKEYS cu calculatorul este de a termina lista iniializatorilor cu un pointer
NULL i apoi prin ciclare pe keytab s detectm sfritul lui. Acest lucru este
mai mult dect necesar deoarece dimensiunea masivului de structuri este
perfect determinat n momentul compilrii. Numrul de intrri se determin
mprind dimensiunea masivului la dimensiunea structurii key.
Operatorul sizeof descris n seciunea 4.2 furnizeaz dimensiunea n
octei a argumentului su.
n cazul nostru, numrul cuvintelor cheie este dimensiunea masivului
keytab mprit la dimensiunea unui element de masiv. Acest calcul este
fcut ntr-o linie #dene pentru a da o valoare identicatorului NKEYS:
#dene NKEYS (sizeof (keytab) /
Sizeof (struct key)
cuvintele mai mari dect cuvntul curent. Rutina treeprint este una din cele
mai tipice rutine recursive.
Treeprint (struct tnode *p) {
/*tiprete arborele p recursiv */
If (p! =NULL) {
Treeprint (p->left);
Printf (%5d %s, p->count, p->word);
Treeprint (p->right);
}
}
Este important de reinut faptul c n algoritmul de cutare n arbore,
pentru a ajunge la un anumit nod, se parcurg toate nodurile precedente, pe
ramura respectiv (stng sau dreapt), ncepnd ntotdeauna cu nodul
rdcin. Dup ecare ieire din rutina tree, din cauza recursivitii, se
parcurge acelai drum, de data aceasta de la nodul gsit spre rdcina
arborelui, refcndu-se toi pointerii drumului parcurs.
Dac considerai ca nu ai neles sucient de bine recursivitatea,
desenai-v un arbore i imprimai-l cu ajutorul rutinei treeprint, avnd grij
s memorai ecare ieire din tree i treeprint.
O observaie legat de acest exemplu: dac arborele este nebalansat
, adic cuvintele nu sosesc n ordine aleatoare din punct de vedere
lexicograc, atunci timpul de execuie al programului poate deveni foarte
mare. Cazul limit n acest sens este acela n care cuvintele de la intrare sunt
deja n ordine, (cresctoare sau descresctoare), caz n care programul
nostru simuleaz o cutare liniar ntr-un mod destul de costisitor.
S ne oprim puin asupra alocrii de memorie. Cu toate c se aloc
diferite tipuri de obiecte, este de preferat s existe un singur alocator de
memorie ntr-un program. Relativ la acest alocator de memorie se pun doua
probleme: n primul rnd cum poate satisface el condiiile de aliniere ale
obiectelor de un anumit tip (de exemplu ntregii trebuie alocai la adrese
pare); n al doilea rnd cum se poate declara c alocatorul returneaz
pointeri la tipuri diferite de obiecte.
Cerinele de aliniere pot n general rezolvate cu uurin pe seama
unui spaiu care se pierde, dar care este nesemnicativ ca dimensiune. De
exemplu, alocatorul alloc returneaz totdeauna un pointer la o adres par.
n cazul n care cererea de alocare poate satisfcut i de o adres impar
(pentru iruri de caractere, de exemplu) se pierde un caracter.
n ceea ce privete declararea tipului alocatorului alloc (adic a tipului
de obiect pe care l indic pointerul returnat de alloc), un foarte bun procedeu
n limbajul C este de a declara c funcia alloc returneaz un pointer la char i
apoi s convertim explicit acest pointer la tipul dorit printr-un cast. Astfel
dac p este declarat n forma:
Char *p;
Atunci: (struct tnode *) p;
Return NULL;
Return np;
}
Deoarece apelurile la funciile alloc i free pot aprea n orice ordine i
deoarece alinierea conteaz, versiunea simpl a funciei alloc, prezentat n
capitolul 9 nu este adecvat aici. n biblioteca standard exist funcii de
alocare fr restricii, care se apeleaz implicit sau explicit de ctre utilizator
dintr-un program scris n C pentru a obine spaiul de memorie necesar.
Deoarece i alte aciuni dintr-un program pot cere spaiu de memorie ntr-o
manier asincron, spaiul de memorie gestionat de funcia alloc poate s e
necontiguu. Astfel, spaiul liber de memorie este pstrat sub forma unui lan
de blocuri libere, ecare bloc coninnd o dimensiune, un pointer la urmtorul
bloc i spaiul liber propriu-zis. Blocurile sunt pstrate n ordinea cresctoare
a adreselor iar, ultimul bloc, de adresa cea mai mare, indic primul bloc, prin
pointerul lui la blocul urmtor din lan, astfel nct lanul este circular.
Cnd se lanseaz o cerere, se examineaz lista spaiului liber, pn se
gsete un bloc sucient de mare pentru cererea respectiv. Dac blocul are
exact dimensiunea cerut, el se elibereaz din lanul blocurilor libere i este
returnat utilizatorului. Dac blocul este mai mare se descompune, astfel nct
partea cerut se transmite utilizatorului, iar partea rmas se introduce
napoi n lista de spaiu liber. Dac nu se gsete un bloc sucient de mare
pentru cererea lansat se caut un alt bloc de memorie.
Eliberarea unei zone de memorie prin intermediul rutinei free cauzeaz,
de asemenea, o cutare n lista de spaiu liber, pentru a gsi locul
corespunztor de inserare a blocului de memorie eliberat. Dac blocul de
memorie eliberat este adiacent cu un bloc din lista de spaiu liber la orice
parte a sa, el este alipit la acel bloc, crendu-se un bloc mai mare, astfel ca
memoria s nu devin prea fragmentat. Determinarea adiacenei este
uurat de faptul c lista de spaiu liber se pstreaz n ordinea cresctoare
a adreselor de memorie.
Exemplul de utilizare a acestor funcii iniializeaz elementele
masivului hashtab cu NULL. n continuare se ateapt de la tastatur
introducerea unui nume i a unei deniii pentru acest nume. Dac numele
introdus nu exist n lista hashtab atunci se aeaz un mesaj corespunztor,
altfel se aeaz vechea deniie care este apoi nlocuit de noua deniie
introdus.
Main () {
Char num [30], def [30];
Int i;
Struct nlist *np;
For (i=0; i<HASHSIZE; i+)
Hashtab [i] = NULL;
Do {
Getword (num); getword (def);
If (np=lookup (num) =NULL)
Printf (New name);
Else
Printf (Old denition: %s,
Np->def);
Install (num, def);
} while (1);
} 10.7. Cmpuri
Un cmp se denete ca ind o mulime de bii consecutivi dintr-un
cuvnt sau ntreg. Adic din motive de economie a spaiului de memorie, este
util mpachetarea unor obiecte ntr-un singur cuvnt main. Un caz
frecvent de acest tip este utilizarea unui set de aguri, ecare pe un bit,
pentru tabela de simboluri a unui compilator.
Fiecare simbol dintr-un program are anumite informaii asociate lui,
cum sunt de exemplu, clasa de memorie, tipul, dac este sau nu cuvnt cheie
.a.m.d. Cel mai compact mod de a codica aceste informaii este folosirea
unui set de aguri, de cte un bit, ntr-un singur ntreg sau caracter.
Modul cel mai uzual pentru a face acest lucru este de a deni un set de
mti, ecare masc ind corespunztoare poziiei bitului m interiorul
caracterului sau cuvntului. De exemplu:
#dene KEYWORD 01
#dene EXTERNAL 02
#dene STATIC 04
Denesc mtile KEYWORD, EXTERNAL i STATIC care se refer la biii
0, 1 i respectiv 2 din caracter sau cuvnt. Atunci accesarea acestor bii se
realizeaz cu ajutorul operaiilor de deplasare, mascare i complementare,
descrii ntr-un capitol anterior. Numerele trebuie s e puteri ale lui 2.
Expresii de forma:
Flags | = EXTERNAL | STATIC;
Apar frecvent i ele seteaz biii 1 i 2 din caracterul sau ntregul ags
(n exemplul nostru)
n timp ce expresia:
Flags &= (EXTERNAL | STATIC);
Selecteaz biii 1 i 2 din ags.
Expresia:
If (ags & (EXTERNAL | STATIC).
Este adevrat cnd cel puin unul din biii 1 sau 2 din ags este unu.
Expresia:
If (! (ags & (EXTERNAL | STATIC).
Este adevrat cnd biii 1 i 2 din ags sunt ambii zero.
Limbajul C ofer aceste expresii, ca o alternativ, pentru posibilitatea
de a deni i de a accesa biii dintr-un cuvnt, n mod direct, folosind
operatorii logici pe bii.
Sintaxa deniiei cmpului i a accesului la el se bazeaz pe structuri.
De exemplu construciile #dene din exemplul de mai sus pot nlocuite prin
denirea a trei cmpuri:
Struct {
Unsigned is_keyword: 1;
Unsigned is_external:1;
Unsigned is_static: 1;
} ags;
Aceast construcie denete variabila ags care conine 3 cmpuri,
ecare de cte un bit. Numrul care urmeaz dup : reprezint lungimea
cmpului n bii. Cmpurile sunt declarate unsigned pentru a sublinia c ele
sunt cantiti fr semn. Pentru a ne referi la un cmp individual din variabila
ags folosim o notaie similar cu notaia folosit pentru membrii structurilor.
Flags.is_keyword
Flags.is_static
Cmpurile se comport ca nite ntregi mici fr semn i pot participa
n expresii aritmetice ca orice ali ntregi. Astfel, expresiile anterioare pot
scrise mai natural sub forma urmtoare:
Flags.is_extern = ags.is_static = 1;
Pentru setarea biilor 1 i 2 din variabila ags,
Flags.is_extern = ags.is_static = 0;
Pentru tergerea biilor, iar:
If (ags.is_extern=0 &
Flags.is_static=0)
Pentru testarea lor.
Un cmp nu trebuie s depeasc limitele unui cuvnt. n caz contrar,
cmpul se aliniaz la limita urmtorului cuvnt. Cmpurile nu necesit s e
denumite. Un cmp fr nume, descris numai prin caracterul : i lungimea
lui n bii este folosit pentru a rezerva spaiu n vederea alinierii urmtorului
cmp. Lungimea zero a unui cmp poate folosit pentru forarea alinierii
urmtorului cmp la limita unui nou cuvnt, el ind presupus a conine tot
cmpuri i nu un membru obinuit al structuri, deoarece n acest ultim caz,
alinierea se face n mod automat. Nici un cmp nu poate mai lung dect un
cuvnt. Cmpurile se atribuie de la dreapta la stnga.
Cmpurile nu pot constitui masive, nu au adrese, astfel nct operatorul
& nu se poate aplica asupra lor.
10.8. Reuniuni
O reuniune este o variabil care poate conine, la momente diferite,
obiecte de diferite tipuri i dimensiuni; compilatorul este cel care ine
evidena dimensiunilor i aliniamentului.
Reuniunile ofer posibilitatea ca mai multe tipuri diferite de date s e
tratate ntr-o singur zon de memorie, fr a folosi n program vreo
informaie dependent de main.
S relum exemplul tabelei de simboluri a unui compilator,
presupunnd c constantele pot de tip int, oat sau iruri de caractere.
Valoarea unei constante particulare trebuie memorat ntr-o variabil
de tip corespunztor, cu toate c este mai convenabil, pentru gestiunea
tabelei de simboluri, ca valoarea s e memorat n aceeai zon de
memorie, indiferent de tipul ei i s ocupe aceeai cantitate de memorie.
Acesta este scopul unei reuniuni: de a furniza o singur variabil care s
poat conine oricare dintre valorile unor tipuri de date. Ca i n cazul
}
Trebuie subliniat faptul c declaraia typedef nu creeaz noi tipuri n
nici un caz; ea adaug doar sinonime pentru anumite tipuri de date, deja
existente. Variabilele declarate n acest fel au exact aceleai proprieti ca i
cele declarate explicit. De fapt, typedef se aseamn cu #dene, cu excepia
faptului c n timp ce #dene este tratat de preprocesor, typedef este tratat
de ctre compilator. De exemplu:
Typedef int (*PFI)();
Creeaz numele PFI pentru pointer la o funcie care returneaz un
ntreg, tip care poate folosit ulterior ntr-un context de tipul:
PFI strcmp, numcmp, swap;
n programul de sortare din capitolul 9.
Exist dou motive principale care impun folosirea declaraiilor typedef.
Primul este legat de problemele de portabilitate. Cnd se folosesc declaraii
typedef pentru tipuri de date care sunt dependente de main, atunci pentru
o compilare pe un alt sistem de calcul este necesar modicarea doar a
acestor declaraii nu i a datelor din program.
Al doilea const n faptul c prin crearea de noi nume de tipuri se ofer
posibilitatea folosirii unor nume mai sugestive n program, deci o mai rapid
nelegere a programului.
11. Intrri/ieiri
ntruct limbajul C nu a fost dezvoltat pentru un sistem particular de
operare i datorit faptului c s-a dorit realizarea unei portabiliti ct mai
mari, att a unui compilator C, ct i a programelor scrise n acest limbaj, el
nu posed faciliti de intrare/ieire.
Exist totui un sistem de intrare/ieire (sistemul I/O) constituit dintr-un
numr de subprograme care realizeaz funcii de intrare/ieire pentru
programe scrise n C, dar care nu fac parte din limbajul C. Aceste
subprograme se gsesc n biblioteca C.
Scopul acestui capitol este de a descrie cele mai utilizate subprograme
de intrare/ieire i interfaa lor cu programele scrise n limbajul C.
11.1. Intrri i ieiri standard; iere
Sistemul I/O ofer utilizatorului trei iere standard de lucru. Cuvntul
ier a fost pus ntre ghilimele, deoarece limbajul nu denete acest tip de
dat i pentru c ierele reprezint mai degrab nite uxuri de intrare/
ieire standard puse la dispoziia utilizatorului. Aceste iere sunt:
Fiierul standard de intrare (stdin);
Fiierul standard de ieire (stdout);
Fiierul standard de aare a mesajelor (stderr).
Toate aceste trei iere sunt secveniale i n momentul execuiei unui
program C sunt implicit denite i deschise.
Stdin i stdout sunt asociate n mod normal terminalului de la care a
fost lansat programul n execuie. Sistemul I/O permite redirectarea acestor
iere pe alte periferice sau nchiderea lor dup lansarea programului.
Redirectarea ierului stdin se specic prin construcia: <specicator-ier
n linia de comand prin care a fost lansat programul.
Nume
Fseek, ftell, rewind repoziioneaz un ux
Declaraie
Int fseek (FILE *ux, long oset,
Int reper);
Long ftell (FILE *ux);
Void rewind (FILE *ux);
Descriere
Funcia fseek seteaz indicatorul de poziie pentru ierul asociat
uxului ux. Noua poziie, dat n octei, se obine adunnd oset octei la
poziia specicat de reper. Dac reper este SEEK_SET, SEEK_CUR, sau
SEEK_END, oset este relativ la nceputul ierului, poziia curent a
indicatorului, respectiv sfritul ierului. Funcia fseek terge indicatorul de
sfrit de ier.
Funcia ftell obine valoarea curent a indicatorului de poziie pentru
ierul asociat uxului ux.
Funcia rewind poziioneaz indicatorul de poziie pentru ierul asociat
uxului ux la nceputul ierului. Este echivalent cu: (void) fseek (ux, 0L,
SEEK_SET)
Cu completarea c funcia rewind terge i indicatorul de eroare al
uxului.
Valori returnate
Funcia rewind nu returneaz nici o valoare. n caz de succes, fseek
returneaz 0 i ftell returneaz oset-ul curent. n caz de eroare se
returneaz EOF i variabila global ermo indic codul erorii.
11.3. Citire i scriere fr format
Nume
Fgets citete un ir de caractere dintr-un ux text
Declaraie
Char *fgets (char *s, int size, FILE *ux);
Descriere
Funcia fgets cel mult size-l caractere din ux i le memoreaz n zona
indicat de s. Citirea se oprete la detectarea sfritului de ier sau newline. Dac se citete caracterul new-line acesta este memorat n s. Dup
ultimul caracter se memoreaz null.
Apeluri ale acestei funcii pot combinate cu orice apeluri ale altor
funcii de intrare din bibliotec (fscanf, de exemplu) pentru un acelai ux de
intrare.
Valori returnate
Funcia returneaz adresa s n caz de succes, sau NULL n caz de eroare
sau la ntlnirea sfritului de ier dac nu s-a citit nici un caracter.
Nume
Fputs scrie un ir de caractere ntr-un ux text
Declaraie
Int fputs (const char *s, FILE *ux);
Descriere
*format,.);
Int sprintf (char *str, const char *format,
);
Descriere
Funciile din familia printf genereaz o ieire n concordan cu format
dup cum se descrie mai jos. Funcia printf aeaz ieirea la uxul standard
stdout; fprintf scrie ieirea la ux; sprintf scrie ieirea n irul de caractere str.
Aceste funcii genereaz ieirea sub controlul irului format care
specic cum se convertesc argumentele pentru ieire.
irul de formatare
irul format este un ir de caractere, printre care se pot aa zero sau
mai multe directive: caractere obinuite (diferite de %) care sunt copiate aa
cum sunt n uxul de ieire i specicaii de conversie, ecare dintre ele
rezultnd din ncrcarea a zero sau mai multe argumente. Fiecare specicaie
de conversie este introdus de caracterul % i se termin cu un specicator
de conversie. ntre acestea pot (n aceast ordine) zero sau mai muli
indicatori, o mrime minim a cmpului opional, o precizie opional i un
modicator opional de lungime.
Argumentele trebuie s corespund n ordine cu specicatorii de
conversie. Acestea sunt folosite n ordinea dat, unde ecare caracter * i
ecare specicator de conversie solicit urmtorul argument. Dac
argumentele nu sunt suciente comportamentul programului este
imprevizibil.
Caractere indicatori
Caracterul % este urmat de zero, unul sau mai muli indicatori:
#Valoarea numeric se convertete n format alternativ. Pentru
conversii de tip o, primul caracter al irului de ieire este zero (prin prexare
cu 0 dac valoarea nu este zero). Pentru conversii de tip x i X, o valoare
nenul este prexat cu 0x (sau 0X pentru conversii de tip X). Pentru
conversii de tip e, E, f, F, g i G, rezultatul va conine ntotdeauna punctul
zecimal, chiar dac nu apare partea fracionar (n mod normal punctul
zecimal apare n aceste conversii numai dac exist i partea fracionar).
Pentru conversii de tip g i G zerourile nale nu sunt eliminate aa cum se
procedeaz n mod normal. Pentru alte conversii rezultatul este nedenit.
0Valoarea numeric este convertit cu zerouri la stnga. Pentru
conversii de tip d, i, o, u, x, X, e, E, f, F, g i G, valoarea convertit este
completat cu zerouri la stnga n loc de blanc. Dac apar indicatorii 0 i
mpreun, indicatorul 0 este ignorat. Dac pentru o conversie numeric (d, i,
o, u, x, X) este dat o precizie, indicatorul 0 este ignorat. Pentru alte conversii
rezultatul este nedenit.
Valoarea convertit este aliniat la stnga (implicit alinierea se face
la dreapta). Cu excepia conversiilor de tip n, valoarea convertit este
completat la dreapta cu blanc, n loc s e completat la stnga cu blanc
sau zero. Dac apar indicatorii 0 i mpreun, indicatorul 0 este ignorat.
Sp(spaiu) n cazul unui rezultat al unei conversii cu semn, naintea unui
numr pozitiv sau ir vid se pune un blanc.
Nume
Perror aeaz un mesaj de eroare sistem
Declaraie
Void perror (const char *s);
#include <ermo. H>
Const char *sys_errlist [];
Int sys_nerr;
Descriere
Rutina perror aeaz un mesaj la ieirea standard de eroare, care
descrie ultima eroare ntlnit la ultimul apel sistem sau funcie de bibliotec.
Mai nti se aeaz argumentul s, apoi virgula i blanc i n nal mesajul de
eroare i new-line. Se recomand (mai ales pentru depanare) ca argumentul
s s includ numele funciei n care a aprut eroarea. Codul erorii se ia din
variabila extern ermo.
Lista global de erori sys_errlist [] indexat cu ermo poate folosit
pentru a obine mesajul de eroare fr new-line. Ultimul indice de mesaj din
list este sys_nerr-l. Se recomand o atenie deosebit n cazul accesului
direct la list deoarece unele coduri noi de eroare pot lipsi din sys_errlist [].
Dac un apel sistem eueaz variabila ermo indic codul erorii. Aceste
valori pot gsite n <ermo. H>. Funcia perror servete la aarea acestui
cod de eroare ntr-o form lizibil. Dac un apel terminat cu eroare nu este
imediat urmat de un apel perror, valoarea variabilei ermo se poate pierde
dac nu e salvat.
Nume
Clearerr, feof, ferror veric i reseteaz starea
Fluxului
Declaraie
Void clearerr (FILE *ux);
Int feof (FILE *ux);
Int ferror (FILE *ux);
Int leno (FILE *ux);
Descriere
Funcia clearerr terge indicatorii de sfrit de ier i eroare ai uxului.
Funcia feof testeaz indicatorul de sfrit de ier al uxului i
returneaz non-zero dac este setat. Acesta este setat dac o operaie de
citire a detectat sfritul de ier.
Funcia ferror testeaz indicatorul de eroare al uxului i returneaz
non-zero dac este setat. Acesta este setat dac o operaie de citire sau
scriere a detectat o eroare (datorat de exemplu hardware-ului).
Funciile de citire (cu sau fr format) nu fac distincie ntre sfrit de
ier i eroare, astfel c trebuie apelate funciile feof i ferror pentru a
determina cauza.
Funcia leno examineaz argumentul ux i returneaz descriptorul
asociat de sistemul de operare acestui ux.
If (ac! =2) {
Fputs (Un argument!, stderr);
Return 1;
}
F = fopen (av [1],rb);
If (! F) {
Perror (Eroare la deschidere);
Return 1;
}
Fseek (f, 0, SEEK_END);
Fprintf (stderr,File %s, size %ld,
Ftell (f);
Fclose (f);
Return 0;
} 2) Copierea unui ier
Funciile fgets i fputs se folosesc pentru uxuri deschise n mod text.
Cum se utilizeaz pentru copierea unui ier text?
#include <stdio. H>
#dene LSIR 80
Char lin [LSIR];
FILE *, *fo;
Int main (int ac, char *av) {
If (ac! =3) {
Fputs (Doua argumente!, stderr);
}
Fi=fopen (av [1],rt); fo=fopen (av [2],wt);
If (! Fi ||! Fo) {
Perror (Eroare la deschidere);
Return 1;
}
While (fgets (lin, LSIR, )
Fputs (lin, fo);
Fclose (); fclose (fo);
Return 0;
}
Funciile fread i fwrite se folosesc pentru uxuri deschise n mod binar.
Cum se utilizeaz pentru copierea unui ier binar?
#include <stdio. H>
#dene LZON 80
Char zon [LZON];
FILE *, *fo;
Int k;
Int main (int ac, char *av) {
If (ac! =3) {
Fputs (Doua argumente!, stderr);
Return 1;
}
Fi=fopen (av [1],rb); fo=fopen (av [2],wb);
If (! Fi ||! Fo) {
Perror (Eroare la deschidere);
Return 1;
}
While (k=fread (zon, 1, LZON, )
Fwrite (zon, 1, k, fo);
Fclose (); fclose (fo);
Return 0;
} 3) Prelucrarea unui ier text
Programul prezentat n continuare citete un ier text care conine pe
ecare linie un ir de caractere (fr spaii) i trei valori ntregi i aeaz pe
terminal numele pe 12 poziii aliniat la stnga i media aritmetic a celor trei
valori ntregi.
#include <stdio. H>
FILE *;
Char num [10];
Int a, b, c;
Double m;
Int main (int ac, char *av) {
If (ac! =2) {
Fputs (Un argument!, stderr);
Return 1;
}
Fi=fopen (av [1],rt);
If (! Fi) {
Perror (Eroare la deschidere);
Return 1;
}
While (fscanf (,%s %d %d %d,
Num, &a, &b, &c)! =EOF) {
M= (a+b+c)/3.0;
Printf (%-l2s%6.2lf, num, m);
}
Fclose ();
Return 0;
} 4) Aarea coninutului unui director
#include <dirent. H>
#include <stdio. H>
DIR *dir;
Struct dirent *ent;
Int main (int ac, char *av) {
If (ac! =2) {
Printf (Un parametru);
Return 1;
}
Dir = opendir (av [1]);
If (! Dir) {
Perror (Eroare open dir);
Return 1;
}
While (ent=readdir (dir)
Printf (%s, ent->d_name);
Return 0;
} 12. Alte rutine din biblioteca standard
n acest capitol sunt descrise funcii care rezolv probleme legate de
alocarea dinamic a memoriei, sortare i cutare, clasicare, operaii cu
blocuri de memorie i iruri de caractere, funcii matematice.
12.1. Alocarea dinamic a memoriei
Nume
Calloc,malloc, realloc aloc memoria n mod dinamic
Free elibereaz memoria alocat n mod dinamic
Declaraie
#include <stdlib. H>
Void *calloc (unsigned nel, unsigned size);
Void *malloc (unsigned size);
Void *realloc (void *ptr, unsigned size);
Void free (void *ptr);
Descriere
Funcia calloc aloc memorie pentru un tablou de nel elemente, ecare
de mrime size octei i returneaz un pointer la memoria alocat. Coninutul
memoriei este pus la zero.
Funcia malloc aloc size octei i returneaz un pointer la memoria
alocat. Coninutul memoriei nu este ters.
Funcia free elibereaz spaiul de memorie indicat de ptr, care trebuie
s fost returnat de un apel anterior malloc, calloc sau realloc. n caz
contrar, sau dac a existat deja un apel anterior free (ptr), comportamentul
programului este imprevizibil.
Funcia realloc schimb mrimea blocului de memorie indicat de ptr la
size octei. Coninutul rmne neschimbat la mrimea minim dintre
mrimea veche i cea nou; noul spaiu de memorie care este eventual
alocat este neiniializat. Dac ptr este NULL apelul este echivalent cu malloc
(size); dac size este egal cu zero apelul este echivalent cu free (ptr). Cu
excepia cazului cnd ptr este NULL, acesta trebuie s fost returnat de un
apel precedent malloc, calloc sau realloc.
Valori returnate
Pentru calloc i malloc valoarea returnat este un pointer la memoria
alocat, care este aliniat n mod corespunztor pentru orice tip de variabile,
sau NULL dac nu exist sucient memorie continu.
Funcia free nu returneaz nimic.
Descriere
Funcia strdup returneaz un pointer la un nou ir care este un duplicat
al irului s. Memoria pentru noul ir se obine cu malloc i poate eliberat
cu free.
Valoare returnat
Funcia returneaz un pointer la irul duplicat, sau NULL dac nu exist
memorie sucient disponibil.
Nume
Strcat, stmcat concateneaz dou iruri
Declaraie
Char *strcat (char *dest, const char *src);
Char *stmcat (char *dest, const char *src,
Unsigned n);
Descriere
Funcia strcat adaug irul src la irul dest suprascriindcaracterul null
de la sfritul lui dest i la sfrit adaug un caracter terminator null. irurile
nu trebuie s se suprapun i n plus irul dest trebuie s aib sucient spaiu
pentru a pstra rezultatul.
Funcia stmcat este similar, cu excepia faptului c numai primele n
caractere din src se adaug la dest.
Valoare returnat
Funciile returneaz un pointer la irul rezultat dest.
Nume
Strcmp compar dou iruri de caractere
Declaraie
Int strcmp (const char *s1, const char
*s2);
Descriere
Funcia strcmp compar cele dou iruri s1 i s2.
Valoare returnat
Funcia returneaz un ntreg mai mic dect, egal cu, sau mai mare
dect zero dac s1 este mai mic dect, coincide, respectiv este mai mare
dect s2.
Nume
Strchr, strrchr localizeaz un caracter
Declaraie
Char *strchr (const char *s, int c);
Char *strrchr (const char *s, int c);
Descriere
Funcia strchr returneaz un pointer la prima apariie a caracterului c n
irul s.
Funcia strrchr returneaz un pointer la ultima apariie a caracterului c
n irul s.
Valoare returnat
Funciile returneaz un pointer la caracterul gsit sau NULL dac
valoarea nu a fost gsit.
Nume
Strstr localizeaz un subir
Declaraie
Char *strstr (const char *sir, const char
*subs);
Descriere
Funcia strstr gsete prima apariie a subirului subs n irul sir.
Caracterul terminator null nu este luat n considerare.
Valoare returnat
Funcia returneaz un pointer la nceputul subirului, sau NULL dac
subirul nu este gsit.
Nume
Strspn, strcspn caut un set de caractere ntr-un ir
Declaraie
Unsigned strspn (const char *s, const char
*acc);
Unsigned strcspn (const char *s, const char
*rej);
Descriere
Funcia strspn calculeaz lungimea segmentului iniial din s format n
ntregime numai cu caractere din acc.
Funcia strcspn calculeaz lungimea segmentului iniial din s format n
ntregime numai cu caractere care nu se gsesc n rej.
Valori returnate
Funcia strspn returneaz poziia primului caracter din s care nu se a
n acc.
Funcia strcspn returneaz poziia primului caracter din s care se a n
rej.
12.6. Biblioteca matematic 1) Funciile din prima categorie sunt
descrise n <stdlib. H>.
Nume
Rand, srand generarea numerelor pseudo-aleatoare
Declaraie
Int rand (void);
Void srand (unsigned int seed);
Descriere
Funcia rand returneaz un ntreg pseudo-aleator ntre 0 i RAND_MAX
(pentru majoritatea mediilor de programare C aceast constant este egal
cu valoarea maxim cu semn reprezentabil pe un cuvnt al sistemului de
calcul).
Funcia srand iniializeaz generatorul cu valoarea seed pentru o nou
secven de valori ntregi pseudo-aleatoare care vor returnate de rand.
Aceste secvene se repet dac srand se apeleaz cu aceeai valoare seed.
Se obinuiete ca generatorul s e iniializat cu o valoare dat de
ceasul sistemului de calcul, ca n exemplul de mai jos:
#include <time. H>
Return 0;
} 2) S relum al treilea exemplu din capitolul precedent. Se citete un
ier text care conine pe ecare linie un nume (ir de caractere fr spaiu)
i trei valori reale (note). Pentru ecare linie se calculeaz media aritmetic
a celor trei valori i se determin dac elementul este admis (ecare not
este minimum 5) sau respins (cel puin o not este sub 5). n nal se aeaz
liniile n ordinea urmtoare: mai nti elementele admise n ordinea
descresctoare a mediei i apoi elementele respinse n ordine alfabetic dup
nume. Se aeaz doar numele, situaia (A/R) i media.
n acest exemplu punem n eviden o modalitate comod de selectare
a membrilor unei structuri cu ajutorul macrourilor. Macroul Fld selecteaz din
zona referit de pointerul P membrul f. Deoarece pointerul P (care poate
argumentul A sau B al funciei comp) refer o zon de tip void, este necesar
mai nti un cast pentru a preciza tipul concret al acesteia. Membrul f poate
: nm, ar, md, denii n cadrul structurii de tip StEl.
Deoarece nu tim de la nceput cte linii are ierul de intrare, suntem
nevoii s folosim urmtoarea strategie. La nceput alocm pentru tabloul El
o zon care s memoreze NA elemente. Pe msur ce aceast zon se
completeaz, la un moment dat numrul de linii citite coincide cu NA. n
acest moment se aloc o zon nou care s poat memora un numr mai
mare de elemente. Desigur, de ecare dat se va actualiza mrimea spaiului
alocat.
#include <stdlib. H>
#include <string. H>
#include <stdio. H>
#dene NA 32
Typedef struct {
Char nm [10], ar;
Float na, nb, ne, md;
} StEl;
#dene Fld (P, f) (StEl *) P)->f
Int comp (const void *A, const void *B) {
Float w;
Int d;
If (d=Fld (A, ar)-Fld (B, ar)
Return d;
If (Fld (A, ar) =A) {
W=Fld (B, md)-Fld (A, md);
If (w>0) return 1;
If (w<0) return -l;
}
Return strcmp (Fld (A, nm), Fld (B, nm);
}
Int main (int ac, char *av) {
Int na, ne, i;
StEl *El;
FILE *;
If (ac! =2) {
Fputs (Un argument!, stderr);
Return 1;
}
Fi=fopen (av [1],rt);
If (! Fi) {
Perror (Eroare la deschidere);
Return 1;
}
Na=NA;ne=0;
El= (StEl *) malloc (na*sizeof (StEl);
While (fscanf (,%s %d %d %d,
El [ne]. Nm, &El [ne].na, &El [ne]. Nb,
&El [ne].ne)! =EOF) {
If (El [ne].na>=5) & (El [ne]. Nb>=5) & (El [ne].ne>=5)
El [ne].ar=A;
Else El [ne].ar=R;
El [ne].md= (El [ne].na+El [ne]. Nb+
El [ne].ne)/3.0;
Ne+;
If (ne=na) {
Na+=NA;
El= (StEl *) realloc (El, na*
Sizeof (StEl);
}
}
Fclose ();
Qsort (El, ne, sizeof (StEl), comp);
For (i=0; i<ne; i+)
Printf (%-l2s %c%6.2lf,
El [i]. Nm, El [i].ar, El [i].md);
Free (El);
Return 0;
} 3) Se citete dintr-un ier text o valoare natural n. Urmtoarele linii
conin n cuvinte, ecare cuvnt avnd acelai numr de litere (cel mult 10).
S se aeze cuvintele din ier ordonate alfabetic.
Pentru a memora lista de cuvinte folosim urmtoarea strategie. n loc
s alocm pentru ecare cuvnt (ir de caractere) citit o zon nou de
memorie, alocm de la nceput o zon n care s putem memora toate
cuvintele din list. Aceast zon va avea mrimea de (l+1)*n octei, unde l
este lungimea ecrui cuvnt (numrul de litere). De ce (l+1)?Pentru c
trebuie s memorm i caracterul terminator null.
Avantaje: memoria este utilizat mai ecient dac se aloc de la
nceput o zon contigu de dimensiune mai mare i se reduce foarte mult
fragmentarea memoriei.
SFRIT