Documente Academic
Documente Profesional
Documente Cultură
Manual Limbajul C
Manual Limbajul C
____________________________________________
C este un limbaj restrns i se nva relativ uor, iar subtilitile se rein pe msur
ce crete experiena n programare.
Prin tradiie primul program C este un mic exemplu din lucrarea devenit
clasic The C programming language, de Brian W Kernigham i Dennis M
Ritchie.
#include <stdio.h>
int main() {
printf("Hello, world\n");
return 0;
}
scanf("%d",&n);
for (i=0; i<n; i++) scanf("%lf",&a[i]);
printf("%.3lf\n",produs());
return 0;
}
Variabila k, care ar trebui s memoreze valoarea 57600, are tipul ntreg scurt
(short), pentru care domeniul de valori este restrns la 32768 32767. Astfel
____________________________________________
____________________________________________
do
double
else
enum
extern
float
for
goto
if
int
long
register
return
short
signed
sizeof
static
struct
switch
typedef
union
unsigned
void
volatile
while
2.2. Constante
n limbajul C exist urmtoarele tipuri de constante: ntreg (zecimal, octal,
hexazecimal), ntreg lung explicit, flotant, caracter, simbolic.
____________________________________________
10
Constante ntregi
O constant ntreag const dintr-o succesiune de cifre.
O constant octal este o constant ntreag care ncepe cu 0 (cifra zero), i
este format cu cifre de la 0 la 7.
O constant hexazecimal este o constant ntreag precedat de 0x sau 0X
(cifra 0 i litera x). Cifrele hexazecimale includ literele de la A la F i de la a la f
cu valori de la 10 la 15.
n orice alt caz, constanta ntreag este o constant zecimal.
Exemplu: constanta zecimal 31 poate fi scris ca 037 n octal i 0x1f sau
0X1F n hexazecimal.
O constant ntreag este generat pe un cuvnt (doi sau patru octei, dac
sistemul de calcul este pe 16 sau 32 de bii).
O constant zecimal a crei valoare depete pe cel mai mare ntreg cu semn
reprezentabil pe un cuvnt scurt (16 bii) se consider de tip long i este generat
pe 4 octei.
O constant octal sau hexazecimal care depete pe cel mai mare ntreg
fr semn reprezentabil pe un cuvnt scurt se consider de asemenea de tip long.
O constant ntreag devine negativ dac i se aplic operatorul unar de
negativare -.
Constante flotante
O constant flotant 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 snt constituite din cte o succesiune de cifre.
ntr-o constant flotant, 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.456e7 sau 0.12e3
Orice constant flotant se consider a fi n precizie extins.
____________________________________________
11
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 negrafice i caractere grafice ' (apostrof) i \ (backslash)
pot fi reprezentate ca i constante caracter cu ajutorul unor secvene de evitare.
Acestea ofer de altfel i un mecanism general pentru reprezentarea caracterelor
mai dificil de introdus n calculator i a oricror configuraii de bii. Aceste
secvene de evitare snt:
\n new-line
\r carriage return
\\ backslash
\t tab orizontal
\f form feed
\' apostrof
\b backspace
\a semnal sonor
\" ghilimele
\ooo configuraie de bii precizat n baza 8
\xhh configuraie de bii precizat n baza 16
Fiecare din aceste secvene, dei e format din mai multe caractere, reprezint
n realitate un singur caracter.
Exemplu: secvena '\040' va genera caracterul spaiu.
Constante simbolice
O constant simbolic este un identificator cu valoare de constant. Valoarea
constantei poate fi orice ir de caractere introdus prin construcia #define
(capitolul apte).
Exemplu: #define MAX 1000
Dup ntlnirea acestei construcii compilatorul va nlocui toate apariiile
constantei simbolice MAX cu valoarea 1000.
Numele constantelor simbolice se scriu de obicei cu litere mari (fr a fi
obligatoriu).
____________________________________________
12
2.3. iruri
Un ir este o succesiune de caractere scrise ntre ghilimele, de exemplu
"ABCD".
Ghilimelele nu fac parte din ir; ele servesc numai pentru delimitarea irului.
Caracterul " (ghilimele) poate aprea ntr-un ir dac se utilizeaz secvena de
evitare \". n interiorul unui ir pot fi folosite i alte secvene de evitare pentru
constante caracter, de asemenea poate fi folosit caracterul \ (backslash) la sfritul
unui rnd pentru a da posibilitatea continurii unui ir pe mai multe linii, situaie n
care caracterul \ nsui va fi ignorat.
Pentru irul de caractere se mai folosete denumirea constant ir sau
constant de tip ir.
Cnd un ir apare ntr-un program C, compilatorul creeaz un masiv de
caractere care conine caracterele irului i plaseaz automat caracterul null (0) la
sfritul irului, astfel ca programele care opereaz asupra irurilor s poat detecta
sfritul acestora. Aceast reprezentare nseamn c, teoretic, nu exist o limit a
lungimii unui ir, iar programele trebuie s parcurg irul, analizndu-l pentru a-i
determina lungimea. Se admit i iruri de lungime zero.
Tehnic, un ir este un masiv ale crui elemente snt caractere. El are tipul
masiv de caractere i clasa de memorie static (capitolul trei). Un ir este
iniializat cu caracterele date.
La alocare, memoria fizic cerut este cu un octet mai mare dect numrul de
caractere scrise ntre ghilimele, datorit adugrii automate a caracterului null la
sfritul fiecrui ir.
Exemplu. Secvena urmtoare determin lungimea irului de caractere s,
excluznd caracterul terminal null.
for (n=0; s[i]; n++) ;
2.4. Operatori
Limbajul C prezint un numr mare de operatori care pot fi clasificai dup
diverse criterii. Exist operatori unari, binari i ternari, operatori aritmetici, logici,
operatori pe bii etc. Capitolul patru este rezervat n exclusivitate descrierii
operatorilor definii n limbajul C.
____________________________________________
13
2.5. Separatori
Un separator este un caracter sau un ir de caractere care separ unitile
lexicale ntr-un program scris n C.
Separatorul cel mai frecvent este aa numitul spaiu alb (blanc) care conine
unul sau mai multe spaii, tab-uri, new-line-uri sau comentarii.
Aceste construcii snt eliminate n faza de analiza lexical a compilrii.
Dm mai jos lista separatorilor admii n limbajul C.
( )
{ }
[ ]
" "
' '
;
/*
*/
____________________________________________
14
3. Variabile
Ca i constantele, variabilele snt elemente de baz cu care opereaz un
program scris n C. O variabil este un obiect de programare cruia i se atribuie un
nume i i se asociaz o zon de memorie.
Variabilele se deosebesc dup nume i pot primi diferite valori. Numele
variabilelor snt identificatori. Numele de variabile se scriu de obicei cu litere mici
(fr a fi obligatoriu).
n limbajul C, variabilele snt caracterizate prin dou atribute: clas de
memorie i tip. Acestea i snt atribuite unei variabile prin intermediul unei
declaraii. Declaraiile enumer variabilele care urmeaz a fi folosite, stabilesc
clasa de memorie, tipul variabilelor i eventual valorile iniiale. Sintaxa unei
declaraii este:
clas tip list-variabile;
Lista de variabile poate avea un element sau mai multe, n al doilea caz ele
fiind separate prin virgul.
Clasa de memorie precizeaz care funcii pot vedea variabilele declarate n
cadrul unui modul:
doar funcia / blocul unde acestea snt definite: variabile automatice i variabile
statice interne;
toate funciile din cadrul modulului care urmeaz declaraiei: variabile globale
statice;
toate funciile din toate modulele care cunosc declaraia: variabile globale
externe.
Clasa de memorie precizeaz n plus i durata de via a variabilelor declarate.
Variabilele automatice exist doar pe durata execuiei funciei sau blocului unde
au fost definite. Variabilele statice i externe exist pe toat durata execuiei
programului.
Tipul unei variabile precizeaz domeniul de valori pe care le poate lua i
operaiile care se pot efectua cu aceste valori.
Declaraiile se folosesc pentru a specifica interpretarea pe care compilatorul
trebuie s o dea fiecrui identificator, i pot aprea n afara oricrei funcii sau la
nceputul unei funcii naintea oricrei instruciuni. Nu orice declaraie rezerv i
memorie pentru un anumit identificator, de aceea deosebim:
declaraia de definiie a unei variabile, care creeaz variabila i i se aloc
memorie;
declaraia de utilizare a unei variabile, care doar anun proprietile
variabilei care urmeaz a fi folosit.
____________________________________________
15
Variabile automatice
Variabilele automatice snt variabile locale fiecrui bloc sau funcii. Ele se
declar prin specificatorul de clas de memorie auto sau implicit prin context. O
variabil care apare n corpul unei funcii sau al unui bloc pentru care nu s-a fcut
nici o declaraie de clas de memorie se consider implicit de clas auto.
O variabil auto este actualizat la fiecare intrare n bloc i se distruge n
momentul cnd controlul a prsit blocul. Ele nu i rein valorile de la un apel la
altul al funciei sau blocului i trebuie iniializate la fiecare intrare. Dac nu snt
iniializate, conin valori reziduale. Nici o funcie nu are acces la variabilele auto
din alt funcie. n funcii diferite pot exista variabile locale cu aceleai nume, fr
ca variabilele s aib vreo legtur ntre ele.
Exemple. n fiecare program din primul capitol, variabilele locale snt
automatice.
Variabile registru
O variabil registru se declar prin specificatorul de clas de memorie
register. Ca i variabilele auto ele snt 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 fi 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 fi numai variabilele automatice sau parametrii
formali ai unei funcii. Practic exist cteva restricii asupra variabilelor
register care reflect realitatea hardware-ului de baz. Astfel:
numai cteva variabile din fiecare funcie pot fi pstrate n regitri (de obicei
dou sau trei); declaraia register este ignorat pentru celelalte variabile;
numai tipurile de date ntregi i pointer snt admise;
nu este posibil referirea la adresa unei variabile register.
Variabile statice
Variabilele statice se declar prin specificatorul de clas de memorie static.
Aceste variabile snt la rndul lor de dou feluri: interne i externe.
Variabilele statice interne snt locale unei funcii i se definesc n interiorul
unei funcii; spre deosebire de variabilele auto, ele i pstreaz valorile tot
____________________________________________
16
Variabile externe
Variabilele externe snt variabile cu caracter global. Ele se definesc n afara
oricrei funcii i pot fi apelate prin nume din oricare modul (fiier surs) care
intr n alctuirea programului.
n declaraia de definiie aceste variabile nu necesit specificarea nici unei
clase de memorie. La ntlnirea unei definiii de variabil extern compilatorul
aloc i memorie pentru aceast variabil.
ntr-un fiier surs domeniul de definiie i aciune al unei variabile externe
este de la locul de declaraie pn la sfritul fiierului. Aceste variabile exist i i
pstreaz valorile de-a lungul execuiei ntregului program.
Pentru ca o funcie s poat utiliza o variabil extern, numele variabilei
trebuie fcut cunoscut funciei printr-o declaraie.
Detalii despre utilizarea variabilelor externe vor fi date n capitolul apte.
17
Tipul caracter
O variabil de tip caracter se declar prin specificatorul de tip char. Zona de
memorie alocat 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.
Dac un caracter din setul de caractere este memorat ntr-o variabil de tip
char, atunci valoarea sa este egal cu codul ntreg al caracterului respectiv. i
alte cantiti pot fi memorate n variabile de tip char, dar implementarea este
dependent de sistemul de calcul.
Domeniul valorilor variabilelor caracter este ntre -128 i 127. Caracterele
setului ASCII snt toate pozitive, dar o constant caracter specificat printr-o
secven de evitare poate fi i negativ, de exemplu '\377' are valoarea -1.
Acest lucru se ntmpl atunci cnd aceast constant apare ntr-o expresie,
moment n care se convertete la tipul int prin extensia bitului cel mai din stnga
din octet (datorit modului de funcionare a instruciunilor calculatorului).
Domeniul valorilor variabilelor caracter fr semn (unsigned char) este
ntre 0 i 255.
Descriptori de format:
%c pentru o variabil sau o valoare de tip char;
%s pentru o variabil sau o expresie de tip ir de caractere.
Tipul ntreg
Variabilele ntregi pozitive sau negative pot fi declarate prin specificatorul de
tip int. Zona de memorie alocat unei variabile ntregi poate fi de cel mult trei
dimensiuni.
Relaii despre dimensiune snt furnizate de calificatorii short, long i
unsigned, care pot fi aplicai tipului int.
Calificatorul short se refer totdeauna la numrul minim de octei pe care se
reprezint un ntreg, de obicei 2.
Calificatorul long se refer la numrul maxim de octei pe care poate fi
reprezentat un ntreg, de obicei 4.
Tipul int are dimensiunea natural sugerat de sistemul de calcul. Domeniul
numerelor ntregi reprezentabile n main depinde de sistemul de calcul: un
ntreg poate lua valori ntre -32768 i 32767 (sisteme de calcul pe 16 bii) sau
ntre -2147483648 i 2147483647 (sisteme de calcul pe 32 de bii).
Calificatorul unsigned alturi de declaraia de tip int determin ca valorile
variabilelor astfel declarate s fie considerate ntregi fr semn. Un ntreg fr
semn poate lua valori ntre 0 i 65535 (sisteme de calcul pe 16 bii) sau ntre 0 i
4294967295 (sisteme de calcul pe 32 de bii).
____________________________________________
18
Valorile de tip unsigned respect legile aritmeticii modulo 2w, unde w este
numrul de bii din reprezentarea unei variabile de tip int. Numerele de tipul
unsigned snt totdeauna pozitive.
Declaraiile pentru calificatori snt de forma:
short int x;
long int y;
unsigned int z;
unsigned long int u;
Cuvntul int poate fi omis n aceste situaii.
Descriptori de format:
%d pentru o variabil sau o valoare de tip int;
%u pentru o variabil sau o valoare de tip unsigned;
%ld pentru o variabil sau o valoare de tip long;
%lu pentru o variabil sau o valoare de tip unsigned long;
%hd pentru o variabil sau o valoare de tip short;
%hu pentru o variabil sau o valoare de tip unsigned short.
Tipuri derivate
n afar de tipurile aritmetice fundamentale, exist, n principiu, o clas
infinit de tipuri derivate, construite din tipurile fundamentale n urmtoarele
moduri:
masive de T pentru masive de obiecte de un tip dat T, unde T este unul dintre
tipurile admise;
funcii care returneaz T pentru funcii care returneaz obiecte de un tip dat T;
pointer la T pentru pointeri la obiecte de un tip dat T;
structuri pentru un ir de obiecte de tipuri diferite;
reuniuni care pot conine obiecte de tipuri diferite, tratate ntr-o singur zon de
memorie.
____________________________________________
19
Caractere i ntregi
Un caracter poate aprea oriunde unde un ntreg este admis. n toate cazurile
valoarea caracterului este convertit automat ntr-un ntreg. Deci ntr-o expresie
aritmetic tipul char i int pot aprea mpreun. Aceasta permite o flexibilitate
considerabil n anumite tipuri de transformri de caractere. Un astfel de exemplu
este funcia atoi descris n capitolul ase care convertete un ir de cifre n
echivalentul lor numeric.
____________________________________________
20
s[i] - '0'
Atragem atenia c atunci cnd o variabil de tip char este convertit la tipul
int, se poate produce un ntreg negativ, dac bitul cel mai din stnga al octetului
conine 1. Caracterele din setul de caractere ASCII nu devin niciodat negative,
dar anumite configuraii de bii memorate n variabile de tip caracter pot aprea ca
negative prin extensia la tipul int.
Conversia tipului int n char se face cu pierderea biilor de ordin superior.
ntregii de tip short snt convertii automat la int. Conversia ntregilor se
face cu extensie de semn; ntregii snt totdeauna cantiti cu semn.
Un ntreg long este convertit la un ntreg short sau char prin trunchiere
la stnga; surplusul de bii de ordin superior se pierde.
Conversii flotante
Toate operaiile aritmetice n virgul mobil se execut n precizie extins.
Conversia de la virgul mobil la ntreg se face prin trunchierea prii fracionare.
Conversia de la ntreg la virgul mobil este acceptat.
ntregi fr semn
ntr-o expresie n care apar doi operanzi, dintre care unul unsigned iar
cellalt un ntreg de orice alt tip, ntregul cu semn este convertit n ntreg fr
semn i rezultatul este un ntreg fr semn.
Cnd un int trece n unsigned, valoarea sa este cel mai mic ntreg fr
semn congruent cu ntregul cu semn (modulo 2 16 sau 232). ntr-o reprezentare la
complementul fa de 2, conversia este conceptual, nu exist nici o schimbare
real a configuraiei de bii.
Cnd un ntreg fr semn este convertit la long, valoarea rezultatului este
numeric aceeai ca i a ntregului fr semn, astfel conversia nu face altceva dect
s adauge zerouri la stnga.
Conversii aritmetice
Dac un operator aritmetic binar are doi operanzi de tipuri diferite, atunci tipul
de nivel mai sczut este convertit la tipul de nivel mai nalt nainte de operaie.
Rezultatul este de tipul de nivel mai nalt. Ierarhia tipurilor este urmtoarea:
char short int long;
float double long double;
tip ntreg cu semn tip ntreg fr semn;
tip ntreg tip virgul mobil.
____________________________________________
21
Conversii logice
Expresiile relaionale de forma i<j i expresiile logice legate prin operatorii
&& i || snt definite ca avnd valoarea 1 dac snt adevrate i 0 dac snt false.
Astfel atribuirea:
d = (c>='0') && (c<='9');
l face pe d egal cu 1 dac c este cifr i egal cu 0 n caz contrar.
Conversii explicite
Dac conversiile de pn aici le-am putea considera implicite, exist i
conversii explicite de tipuri pentru orice expresie. Aceste conversii se fac prin
construcia special numit cast de forma:
(nume-tip) expresie
n aceast construcie expresie este convertit la tipul specificat dup regulile
precizate mai sus. Mai precis aceasta este echivalent cu atribuirea expresiei
respective unei variabile de un tip specificat, i aceast nou variabil este apoi
folosit n locul ntregii expresii. De exemplu, n expresia:
sqrt((double)n)
se convertete n la double nainte de a se transmite funciei sqrt. Variabila n
nu-i modific valoarea.
Expresia constant
O expresie constant este o expresie care conine numai constante. Aceste
expresii snt evaluate n momentul compilrii i nu n timpul execuiei; ele pot fi
astfel utilizate n orice loc unde sintaxa cere o constant, ca de exemplu:
#define NMAX 1000
char lin[NMAX+1];
3.5. Masive
n limbajul C se pot defini masive unidimensionale, bidimensionale,
tridimensionale etc. Un masiv se compune din mai multe elemente de acelai tip;
un element se identific prin indice (poziia relativ n masiv), sau prin indici
(dac masivul este multidimensional).
Exemple:
char s[100];
int a[10][15];
____________________________________________
22
Prima linie declar un ir de caractere: s[0], s[1], ..., s[99]. A doua linie
declar o matrice de ntregi: a[0][0], ..., a[0][14], a[1][0], ..., a[1]
[14], ..., a[9][0], ..., a[9][14].
Acest subiect va fi detaliat n capitolul opt.
3.6. Iniializri
ntr-o declaraie se poate specifica o valoare iniial pentru identificatorul care
se declar. Iniializatorul este precedat de semnul = i const dintr-o expresie
(variabile simple) sau o list de valori incluse n acolade (masive sau structuri).
Toate expresiile dintr-un iniializator pentru variabile statice sau externe
trebuie s fie expresii constante sau expresii care se reduc la adresa unei variabile
declarate anterior. Variabilele de clas auto sau register pot fi 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 snt iniializate
implicit cu valoarea 0. Variabilele auto i register au valori iniiale
nedefinite (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 fiecare
intrare n funcie sau bloc.
Problema iniializrii masivelor i masivelor de pointeri este detaliat n
capitolul opt. Problema iniializrii structurilor este detaliat n capitolul nou.
#include <stdio.h>
int e = 1;
int f() {
int a = 2;
a++; e++;
return a + e;
}
int g() {
static int s = 2;
s++; e++;
return s + e;
}
int main() {
int v1,v2,v3,v4;
v1 = f(); v2 = g();
v3 = f(); v4 = g();
printf("%d %d %d %d %d\n",v1,v2,v3,v4,e);
return 0;
____________________________________________
23
____________________________________________
24
4. Operatori i expresii
Limbajul C prezint un numr mare de operatori, caracterizai prin diferite
nivele de prioritate sau preceden.
n acest capitol descriem operatorii n ordinea descresctoare a precedenei
lor. Vom preciza de fiecare dat dac asociativitatea este la stnga sau la dreapta.
Expresiile combin variabile i constante pentru a produce valori noi i le vom
introduce pe msur ce vom prezena operatorii.
identificator
Un identificator este o expresie-primar, cu condiia c el s fi fost declarat
corespunztor. Tipul su este specificat n declaraia sa.
Dac tipul unui identificator este masiv de T, atunci valoarea expresieiidentificator este un pointer la primul obiect al masivului, iar tipul expresiei este
pointer la T. Mai mult, un identificator de masiv nu este o expresie valoare-stnga
(detalii n capitolul opt).
La fel, un identificator declarat de tip funcie care returneaz T, care nu apare
pe poziie de apel de funcie este convertit la pointer la funcie care returneaz T
(detalii n capitolul opt).
ir
Un ir este o expresie-primar. Tipul su original este masiv de caractere, dar
urmnd aceleai reguli descrise mai sus pentru identificatori, acesta este modificat
n pointer la caracter i rezultatul este un pointer la primul caracter al irului.
(expresie)
O expresie ntre paranteze rotunde este o expresie-primar, al crei tip i
valoare snt identice cu cele ale expresiei din interiorul parantezelor (expresia din
paranteze poate fi i o valoare-stnga).
expresie-primar[expresie-indice]
O expresie-primar urmat de o expresie ntre paranteze ptrate este o
expresie-primar. Sensul intuitiv este de indexare. De obicei expresia-primar are
tipul pointer la T, expresia-indice are tipul int, iar rezultatul are tipul T. O
____________________________________________
25
expresie-primar(list-expresii)
Un apel de funcie este o expresie-primar. Ea const dintr-o expresieprimar urmat de o pereche de paranteze rotunde, care conin o list-expresii
separate prin virgule. Lista-expresii constituie argumentele reale ale funciei;
aceast list poate fi i vid. Expresia-primar trebuie s fie de tipul funcie care
returneaz T, iar rezultatul apelului de funcie va fi de tipul T (detalii n capitolul
ase).
naintea apelului, oricare argument de tip float este convertit la tipul
double, oricare argument de tip char sau short este convertit la tipul int.
Numele de masive snt convertite n pointeri la nceputul masivului. Nici o alt
conversie nu se efectueaz automat.
Dac este necesar ca tipul unui argument actual s coincid cu cel al
argumentului formal, se va folosi un cast.
Snt permise apeluri recursive la orice funcie.
Despre definirea i apelul funciilor, detalii n capitolul ase.
valoare-stnga . identificator
O valoare-stnga urmat de un punct i un identificator este o expresieprimar. Valoarea-stnga denumete o structur sau o reuniune (capitolul nou)
iar identificatorul denumete un membru din structur sau reuniune. Rezultatul
este o valoare-stnga care se refer la membrul denumit din structur sau
reuniune.
expresie-primar - identificator
List-expresii
O list de expresii este considerat de asemenea expresie, dac acestea snt
separate prin virgul.
____________________________________________
26
* expresie
Operatorul unar * este operatorul de indirectare. Expresia care-l urmeaz
trebuie s fie un pointer, iar rezultatul este o valoare-stnga care se refer la
obiectul ctre care indic expresia. Dac tipul expresiei este pointer la T atunci
tipul rezultatului este T. Acest operator trateaz operandul su ca o adres, face
acces la ea i i obine coninutul (detalii n capitolul opt).
& valoare-stnga
Operatorul unar & este operatorul de obinere a adresei unui obiect sau de
obinere a unui pointer la obiectul respectiv. Operandul este o valoare-stnga iar
rezultatul este un pointer la obiectul referit de valoarea-stnga. Dac tipul valoriistnga este T atunci tipul rezultatului este pointer la T (detalii n capitolul opt).
expresie
Operatorul unar - este operatorul de negativare. Operandul su este o
expresie, iar rezultatul este negativarea operandului. n acest caz snt aplicate
conversiile aritmetice obinuite. Negativarea unui ntreg de tip unsigned se face
scznd valoarea sa din 2w, unde w este numrul de bii rezervai tipului int.
! expresie
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.
~ expresie
Operatorul unar ~ (tilda) este operatorul de complementare la unu. El
convertete fiecare bit 1 la 0 i invers. El este un operator logic pe bii.
Operandul su trebuie s fie de tip ntreg. Se aplic conversiile aritmetice
obinuite.
++ valoare-stnga
valoare-stnga ++
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 fi folosit ca un operator
prefix (naintea variabilei: ++n) sau ca un operator postfix (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
____________________________________________
27
-- valoare-stnga
valoare-stnga -Operatorul unar -- este operatorul de decrementare. Acest operator este
analog cu operatorul ++ doar c produce decrementarea cu 1 a operandului.
(nume-tip) expresie
Operatorul (nume-tip) este operatorul de conversie de tip. Prin nume-tip
nelegem unul dintre tipurile fundamentale admise n C inclusiv tipul pointer.
Operandul acestui operator este o expresie. Operatorul produce conversia valorii
expresiei la tipul denumit. Aceast construcie se numete cast.
sizeof(operand)
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 constant ntreag care
se poate folosi n orice loc n care se cere o constant. Cea mai frecvent utilizare
este n comunicarea cu rutinele de alocare a memoriei sau cele de intrare / ieire.
Operatorul sizeof poate fi aplicat i unui nume-tip. n acest caz el
furnizeaz dimensiunea n octei a unui obiect de tipul indicat.
28
Expresie-aditiv:
expresie + expresie
expresie - expresie
Operatorii aditivi + i - snt operatori aritmetici binari i se grupeaz de la
stnga la dreapta. Se execut conversiile aritmetice obinuite.
Operatorul binar + produce suma operanzilor si. El este asociativ i
expresiile care conin mai muli operatori pot fi rearanjate la fel ca n cazul
operatorului de nmulire.
Operatorul binar - produce diferena operanzilor si.
Expresie-egalitate:
expresie == expresie
expresie != expresie
____________________________________________
29
Expresie-I:
expresie & expresie
Operatorul & este operatorul I logic pe bii. El este asociativ i expresiile care
conin operatorul & pot fi rearanjate. Rezultatul este funcia logic I pe bii
aplicat operanzilor si. Operatorul se aplic numai la operanzi de tipuri ntregi.
Legea dup care funcioneaz este:
&
0
1
0
0
0
1
0
1
Operatorul & este deseori folosit pentru a masca o anumit mulime de bii: de
exemplu:
____________________________________________
30
c = n & 0177;
pune pe zero toi biii afar de ultimii 7 bii de ordin inferior ai lui n, fr a afecta
coninutul lui n.
Expresie-SAU-exclusiv:
expresie ^ expresie
Operatorul ^ este operatorul SAU-exclusiv logic pe bii. El este asociativ i
expresiile care-l conin pot fi rearanjate. Rezultatul este funcia logic SAUexclusiv pe bii aplicat operanzilor si. Operatorul se aplic numai la operanzi de
tipuri ntregi. Legea dup care funcioneaz este:
^
0
1
0
0
1
1
1
0
Expresie-SAU-inclusiv:
expresie | expresie
Operatorul | este operatorul SAU-inclusiv logic pe bii. El este asociativ i
expresiile care-l conin pot fi rearanjate. Rezultatul este funcia logic SAUinclusiv pe bii aplicat operanzilor si. Operatorul se aplic numai la operanzi de
tipuri ntregi. Legea dup care funcioneaz este:
|
0
1
0
0
1
1
1
1
31
Operanzii nu trebuie s aib n mod obligatoriu acelai tip, dar fiecare trebuie
s aib unul dintre tipurile fundamentale sau pointer. Rezultatul este totdeauna de
tip int.
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-inclusiv 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 fiecare trebuie
s aib unul dintre tipurile fundamentale sau pointer. Rezultatul este totdeauna de
tip int.
32
Expresie-atribuire:
valoare-stnga = expresie
valoare-stnga op= expresie
unde op poate fi unul din operatorii +, -, *, /, %, <<, >>, &, ^, |.
ntr-o atribuire simpl cu =, valoarea expresiei nlocuiete pe cea a obiectului
referit de valoare-stnga. Dac ambii operanzi au tip aritmetic, atunci operandul
drept este convertit la tipul operandului stng nainte de atribuire.
Expresiile de forma E1op=E2 se interpreteaz ca fiind echivalente cu
expresiile de forma E1=E1opE2; totui E1 este evaluat o singur dat.
Exemplu: expresia x *= y+1 este echivalent cu
x = x * (y+1)
i nu cu
x=x*y+1
Pentru operatorii += i -=, operandul stng poate fi i un pointer, n care caz
operandul din dreapta este convertit la ntreg (capitolul opt). Toi operanzii din
dreapta i toi operanzii din stnga care nu snt pointeri trebuie s fie de tip
aritmetic.
Atribuirea prescurtat este avantajoas n cazul cnd n membrul stng avem
expresii complicate, deoarece ele se evalueaz o singur dat.
33
are trei argumente, dintre care al doilea are valoarea 5. Expresia acestui argument
este o expresie virgul. n calculul valorii lui se evalueaz nti expresia din stnga
i se obine valoarea 3 pentru t, apoi cu aceast valoare se evalueaz a doua
expresie i se obine t5. Prima valoare a lui t se pierde.
34
Asociativitate
stnga la dreapta
dreapta la stnga
stnga la dreapta
stnga la dreapta
stnga la dreapta
stnga la dreapta
stnga la dreapta
stnga la dreapta
stnga la dreapta
stnga la dreapta
stnga la dreapta
stnga la dreapta
dreapta la stnga
dreapta la stnga
stnga la dreapta
____________________________________________
35
5. Instruciuni
ntr-un program scris n limbajul C instruciunile se execut secvenial, n
afar de cazul n care se indic altfel.
Instruciunile pot fi scrise cte una pe o linie pentru o lizibilitate mai bun, dar
nu este obligatoriu.
36
5.3. Instruciunea if
Sintaxa instruciunii condiionale if admite dou formate:
if (expresie)
if (expresie) instruciune-1
instruciune-1
else instruciune-2
Instruciunea if se folosete pentru a lua decizii. n ambele cazuri se
evalueaz expresia i dac ea este adevrat (deci diferit de zero) se execut
instruciune-1. Dac expresia este fals (are valoarea zero) i instruciunea if are
i parte de else atunci se execut instruciune-2.
n al doilea caz una i numai una dintre cele dou instruciuni se execut.
Deoarece un if testeaz pur i simplu valoarea numeric a unei expresii, se
admite o prescurtare i anume:
if (expresie)
n loc de:
if (expresie != 0)
Deoarece partea else a unei instruciuni if este opional, exist o
ambiguitate cnd un else este omis dintr-o secven de if imbricat. Aceasta se
rezolv asociind else cu ultimul if care nu are else.
if (n>0)
if (a>b)
z = a;
else
z = b;
if (n>0) {
if (a>b)
z = a;
}
else
z = b;
n exemplul de mai sus, n primul caz partea else se asociaz if-ului din
interior. Dac nu dorim acest lucru atunci folosim acoladele pentru a fora
asocierea, ca n al doilea caz.
Instruciunea condiional admite i construcia else-if:
if (expresie-1) instruciune-1
else
if (expresie-2) instruciune-2
else
if (expresie-3) instruciune-3
else instruciune-4
____________________________________________
37
unsigned n, c = 0;
scanf("%u",&n);
do {
c++; n /= 10;
} while (n>0);
printf("%u",c);
____________________________________________
38
Secvena din stnga afieaz numrul de cifre zecimale ale valorii lui n numai
dac n 0, altfel afieaz zero. Secvena din dreapta afieaz numrul de cifre
zecimale ale valorii lui n n orice condiii.
39
40
do {
gets(op);
switch (op[0]) {
case 'i': case 'I':
Initializare(. . .); break;
case 'a': case 'A':
Adaugare(. . .); break;
case 'm': case 'M':
Modificare(. . .); break;
case 's': case 'S':
Stergere(. . .); break;
case 'c': case 'C':
Consultare(. . .); break;
case 'l': case 'L':
Listare(. . .); break;
default:
Eroare(. . .); break;
}
} while (op!='t' && op!='T');
____________________________________________
41
for (...) {
. . .
contin:;
}
do {
. . .
contin:;
} while (...);
42
43
funciei apelante. Dac este nevoie, expresia este convertit, ca ntr-o atribuire, la
tipul funciei n care ea apare.
Detalii despre instruciunea return vor fi prezentate n capitolul urmtor.
n aceast instruciune, care numr caracterele unui ir, corpul lui for este
vid, deoarece toat activitatea se face n partea de test i actualizare dar sintaxa lui
for cere un corp al instruciunii. Instruciunea vid satisface acest lucru.
Am precizat anterior c o instruciune compus nu este urmat niciodat de
caracterul punct i virgul.
if (...) {
. . .
};
else . . .
____________________________________________
44
6. Funcii
Funciile snt elementele de baz ale unui program scris n C: orice program,
de orice dimensiune, const din una sau mai multe funcii, care specific operaiile
care trebuie efectuate.
O funcie ofer un mod convenabil de ncapsulare a anumitor calcule ntr-o
cutie neagr care poate fi utilizat apoi fr a avea grija coninutului ei. Funciile
snt ntr-adevr singurul mod de a face fa complexitii programelor mari, permit
desfacerea programelor mari n module mai 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 definirea de funcii eficiente 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 fi mprit n
mai multe fiiere surs n mod convenabil, iar fiierele surs pot fi compilate
separat.
Un program C const dintr-o secven de definiii externe de funcii i de date.
n fiecare program trebuie s existe o funcie cu numele impus main; orice
program i ncepe execuia cu funcia main. Celelalte funcii snt apelate din
interiorul funciei main. Unele dintre funciile apelate snt definite n acelai
program, altele snt coninute ntr-o bibliotec de funcii.
funcia care nu face nimic. Aceast funcie poate fi util n programe, innd locul
unei alte funcii n dezvoltarea ulterioar a programului.
Numele funciei poate fi precedat de un tip, dac funcia returneaz o valoare
de alt tip dect int, sau dac tipul acesteia este void. O funcie de tip void nu
returneaz o valoare n mod explicit, execut doar o secven de instruciuni.
____________________________________________
45
expresiei
Cnk
Funcia fact este apelat n programul principal de trei ori, fiecare apel
transmite funciei un argument.
O secven mai eficient din punctul de vedere al volumului de calcul i al
corectitudinii
acestora
se
bazeaz
pe
urmtoarea
formul:
Cnk n n 1 ... n k 1
1 2
k
Funcia fact produce rezultate eronate pentru valori mari ale lui n (n8,
sisteme de calcul pe 16 bii; n12, sisteme de calcul pe 32 de bii). Funcia
comb, bazat pe relaia de mai sus, permite operarea cu valori mai mari ale
parametrilor n i k.
____________________________________________
46
Cnk :
n, n 1
Fn
Fn1 Fn2 , n 1
int rfibo(int n) {
if (n<=1) return 1;
else return fibo(n-1) + fibo(n-2);
}
47
fibo(int n) {
a,b,c,i;
0; b = 1; c = n;
(i=2; i<=n; i++) {
c = a + b;
a = b; b = c;
}
return p;
}
48
49
avea acces i poate modifica orice element din masiv. Dac a fost precizat
calificatorul const, modificarea nu este permis.
Pentru funciile cu numr variabil de parametri standardul ANSI definete o
construcie special ... (trei puncte) numit elips. Acesta este de exemplu cazul
funciilor de citire i scriere cu format (familiile ...scanf i ...printf capitolul
zece). n acest caz, parametrii fici snt verificai la compilare, iar cei variabili snt
transmii fr nici o verificare.
50
}
int main() {
/* afieaz toate liniile care conin cuvntul "the" */
char lin[80];
while (gets(lin)>0)
if (index(lin,"the")>=0)
puts(lin);
}
51
int lower(int c) {
if (c>='A' && c<='Z')
return c + 'a' - 'A';
else
return c;
}
Funcia returneaz poziia lui x (un numr ntre 0 i n1), dac x apare n v
sau 1 altfel.
____________________________________________
52
Deseori, o linie sau mai multe linii, de una sau ambele forme apar la nceputul
fiecrui fiier surs pentru a include definiii comune (prin declaraii #define i
declaraii externe pentru variabilele globale).
Facilitatea de includere a unor fiiere ntr-un text surs este deosebit de util
pentru gruparea declaraiilor unui program mare. Ea va asigura faptul c toate
fiierele surs vor primi aceleai definiii i declaraii de variabile, n felul acesta
eliminndu-se un tip particular de erori. Dac se modific un fiier inclus printr-o
linie #include, toate fiierele care depind de el trebuie recompilate.
____________________________________________
53
va fi nlocuit cu:
x = ((p+q)>(r+s) ? (p+q) : (r+s));
54
tip de date, nefiind nevoie de diferite tipuri de funcii maximum pentru diferite
tipuri de date, aa cum este necesar n cazul funciilor propriu-zise.
Dac se examineaz atent expandarea lui Max se pot observa anumite
probleme ce pot genera erori, i anume: expresiile fiind evaluate de dou ori, n
cazul n care ele conin operaii ce genereaz efecte colaterale (apelurile de funcii,
operatorii de incrementare) se pot obine rezultate total eronate.
De asemenea, trebuie avut mare grij la folosirea parantezelor pentru a face
sigur ordinea evalurii dorite. De exemplu macro-operaia Square(x) definit
prin:
#define Square(x) x*x
va produce un rezultat, altul dect cel scontat, datorit prioritii mai mari a
operatorului * fa de cea a operatorului +.
Toate cele trei forme de linii de control precedente pot fi urmate de un numr
arbitrar de linii care, eventual, pot s conin o linie de control forma:
#else
Dac condiia supus verificrii este adevrat, atunci orice linie ntre #else
i #endif este ignorat. Dac condiia este fals atunci toate liniile ntre testul de
verificare i un #else sau n lipsa unui #else pn la #endif snt ignorate.
Toate aceste construcii pot fi imbricate.
7.4. Exemple
1) Se citete de la tastatur o pereche de numere naturale p i q. S se
determine dac fiecare din cele dou numere este prim sau nu, i s se calculeze
cel mai mare divizor comun.
____________________________________________
55
Fiierul surs numere.c este proiectat pentru a putea fi folosit n mai multe
aplicaii care au nevoie de astfel de funcii. Prin includerea fiierului numere.h
se garanteaz c definiia funciilor este conform cu ateptrile modulului
principal, n care este inclus acelai fiier header.
#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;
____________________________________________
56
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 fiiere se poate utiliza o
singur comand de compilare:
Cc princ.c numere.c opiuni-de-compilare
unde Cc este numele compilatorului folosit (exemplu: bcc, gcc). Opiunile de
compilare (atunci cnd snt necesare) snt specifice mediului de programare
folosit.
2) Al doilea proiect gestioneaz o list de valori numerice asupra creia se
efectueaz urmtoarele operaii:
iniializare, operaie realizat automat la lansarea n execuie a programului;
adugarea unei valori n list, dac aceasta nu exist deja;
interogare: o anumit valoare se afl n list?
tergerea unei valori din list;
meninerea n permanen a unei relaii de ordine cresctoare.
Masivul Lis[] memoreaz lista de valori, care are un numr de ne
elemente, iniial zero.
Prezentm mai nti un fiier header (lista.h) care conine declaraiile celor
trei funcii, precum i a variabilelor externe Lis i ne.
#ifndef _Lista_H
#define _Lista_H
extern double Lis[];
extern int ne;
int Adaugare(double v);
int Stergere(double v);
int Interogare(double v);
#endif
57
#include <stdio.h>
#include "lista.h"
int main() {
double atof(char s[]);
double v;
int i;
char o[80];
do {
gets(o); v = atof(op+2);
switch (o[0]) {
case 'a':
i = Adaugare(v);
break;
case 's':
if (Stergere(v))
puts("S-a sters");
else puts("Nu exista");
break;
case 'i':
i = Interogare(v);
if (i>=0)
printf("Pozitia: %d\n",i);
else puts("Nu exista");
break;
default:
puts("Optiune eronata");
break;
}
puts("Lista:");
for (i=0; i<ne; i++)
printf(" %.3lf",Lis[i]);
puts("");
} while (o!='t');
return 0;
}
58
59
tate 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 snt incluse n proiecte nu
se mai pierde timp cu compilarea modulelor surs. n schimb modulele care le
apeleaz au nevoie de modul cum snt definite aceste funcii, i acesta se pstreaz
ca i declaraii n fiiere header.
Fiierele header pstreaz i alte informaii comune mai multor module, cum
snt de exemplu tipurile definite de programator, cel mai adesea tipuri structurate
(detalii n capitolul nou).
____________________________________________
60
8. Pointeri i masive
Un pointer este o variabil care conine adresa unei alte variabile. Pointerii
snt foarte mult utilizai n programe scrise n C, pe de o parte pentru c uneori snt
unicul mijloc de a exprima un calcul, iar pe de alt parte pentru c ofer
posibilitatea scrierii unui program mai compact i mai eficient dect ar putea fi
obinut prin alte ci.
61
*px = 0;
/* greit */
____________________________________________
62
x = y;
y = tmp;
}
63
64
f(&a[2])
f(a+2)
Aceast construcie i altele similare snt cele mai simple i comune formule
ale aritmeticii de adrese, care constituie o caracteristic puternic a limbajului C.
Pentru exemplificare relum inversarea caracterelor unui ir:
void strrev(char s[]) {
int i,j;
char c;
for (i=0,j=strlen(s)-1; i<j; i++,j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
65
66
67
return 0;
return *t-*s;
}
Masivul Zile trebuie s fie declarat global pentru a putea fi folosit de ambele
funcii.
n limbajul C, prin definiie, un masiv cu dou dimensiuni este n realitate un
masiv cu o dimensiune ale crui elemente snt masive. De aceea indicii se scriu
sub forma [i][j] n loc de [i,j], cum se procedeaz n multe alte limbaje.
ntr-un masiv bidimensional elementele snt memorate pe linie, adic indicele cel
mai din dreapta variaz cel mai rapid.
Un masiv se iniializeaz cu ajutorul unei liste de iniializatori nchii ntre
acolade; fiecare linie a unui masiv bidimensional se iniializeaz cu ajutorul unei
subliste de iniializatori. n cazul exemplului nostru, masivul Zile ncepe cu o
coloan zero, pentru ca numerele lunilor s fie ntre 1 i 12 i nu ntre 0 i 11,
aceasta pentru a nu face modificri n calculul indicilor.
i atunci funciile care realizeaz conversiile cerute de exemplul nostru snt:
int NrZile (int an, int luna, int zi) {
____________________________________________
68
int i,bis;
bis = !(an%4) && (an%100) || !(an%400);
for (i=1; i<luna; i++)
zi += Zile[bis][i];
return zi;
}
Deoarece variabila bis poate lua ca valori numai zero sau unu, dup cum
expresia (scris de data aceasta explicit):
(an%4==0) && (an%100!=0) || (an%400==0)
este fals sau adevrat, ea poate fi folosit ca indice de linie n tabelul Zile care
are doar dou linii n exemplul nostru.
void LunaZi(int an, int zian, int *plun, int *pzi) {
int i,bis;
bis = !(an%4) && (an%100) || !(an%400);
for (i=1; zian>Zile[bis][i]; i++)
zian -= Zile[bis][i];
*plun = i; *pzi = zian;
}
____________________________________________
69
____________________________________________
70
Rutina care afieaz liniile n noua lor ordine este WriteLines i are
urmtorul cod:
void WriteLines(char *linptr[], int nrl) {
int i;
for (i=0; i<nrl; i++)
puts(linptr[i]);
}
care indic faptul c linptr este un masiv de NLIN elemente, fiecare element al
masivului fiind un pointer la un caracter. Astfel linptr[i] este un pointer la un
caracter, iar *linptr[i] permite accesul la caracterul respectiv.
Deoarece linptr este el nsui un masiv, care se transmite ca argument
funciei WriteLines, el va fi tratat ca un pointer i atunci funcia
WriteLines mai poate fi scris i astfel:
void WriteLines(char *linptr[], int nrl) {
while (--nrl>=0)
puts(*linptr++);
}
____________________________________________
71
72
rangul j*...*k, ale crui elemente snt masive. Dac operatorul * se aplic acestui
pointer, rezultatul este masivul (d1)-dimensional, care se va converti imediat
ntr-un pointer la un masiv (d2)-dimensional .a.m.d. Raionamentul se poate
aplica n mod inductiv pn cnd, n final, ca urmare a aplicrii operatorului * se
obine ca rezultat un ntreg, de exemplu, dac masivul a fost declarat de tipul int.
S considerm, de exemplu, masivul:
int X[3][5];
X este un masiv de ntregi, de rangul 35. Cnd X apare ntr-o expresie, el este
convertit ntr-un pointer la (primul din cele trei) masive de 5 ntregi.
____________________________________________
|______________|______________|______________|
|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|
X[0]
X[1]
X[2]
73
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 snt 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.
3) Acelai efect se poate obine din declaraia:
int y[4][3] = {1,3,5,2,4,6,3,5,7};
74
n acest caz 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, fiecare
trebuind s fie ncrcat cu adresa unui masiv de ntregi.
Presupunnd c fiecare 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 fi similar n sensul c
a[5][5] i b[5][5], de exemplu, se refer ambele la unul i acelai ntreg
(dac fiecare 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
____________________________________________
75
Iniial se aloc memorie unde se vor depune adresele celor n linii, de aceea
primul apel malloc cere o zon de memorie pentru n pointeri. n continuare
trebuie alocat memorie i pentru matricea propriu-zis. Pentru simplificare am
preferat s alocm o zon continu de nm ntregi (al doilea apel malloc).
n acest moment putem determina adresa fiecrei linii a matricei. Prima linie
are determinat adresa din momentul alocrii. Pentru o linie oarecare i (i 0)
adresa acesteia se obine din adresa liniei precedente la care se adaug m (numrul
de elemente ale liniei); a se vedea i figura de mai jos.
___
________________________________
|__||__|__|__|__|__|__|__|__|__|
____________________________________________
76
|__||
|
|__||
Este foarte important s se respecte aceti pai n alocarea memoriei pentru
matrice. n caz contrar variabilele pointer conin valori necunoscute i nu exist
garanii c indic spre zone de memorie sigure: este foarte probabil c programul
nu are acces la zonele respective.
Funcia principal va fi scris astfel:
int main() {
int **Mat,n,m;
/* alte definiii de variabile */
/* Citete valorile n i m */
Mat = IntMatr(n,m);
/* Completeaz matricea cu valori Mat[i][j] ... */
/* Prelucreaz matricea */
free(Mat[0]); free(Mat);
/* Elibereaz memoria */
}
Spre deosebire de exemplul precedent, unde toat memoria a fost alocat ntro singur operaie (al doilea apel malloc), aici am alocat separat memorie pentru
fiecare linie.
Apelul acestei funcii necesit anumite pregtiri:
____________________________________________
77
double **Dm;
/* pentru o matrice cu elemente de tip double
*/
int n,*M;
/* alte definiii de variabile */
/* Citete valoarea n */
M = (int *)malloc(n*sizeof(int));
/* precizeaz pentru fiecare linie numrul de elemente */
Dm = (double **)Genmatr(n,M,sizeof(double));
/* Operaii cu elementele matricei */
____________________________________________
78
79
unde linia de comand este de exemplu: find limbaj n care find este numele
programului, iar limbaj este ablonul cutat. Rezultatul va fi afiarea tuturor
liniilor textului de intrare care conin cuvntul limbaj.
S elaborm acum modelul de baz, legat de linia de comand i argumentele
ei.
S presupunem c dorim s introducem n linia de comand dou argumente
opionale: unul care s afieze toate liniile cu excepia acelora care conin
ablonul, i al doilea care s precead fiecare linie afiat cu numrul ei de linie.
O convenie pentru programele scrise n limbajul C este ca argumentele dintro linie de comand care ncep cu un caracter - s introduc un parametru opional.
Dac alegem, de exemplu, -x pentru a indica cu excepia i -n pentru a cere
numrarea liniilor, atunci comanda:
find -x -n la
avnd intrarea:
la miezul stinselor lumini
s-ajung victorios,
la temelii, la rdcini,
la mduv, la os.
va produce afiarea liniei a doua, precedat de numrul ei, deoarece aceast linie
nu conine ablonul la.
Argumentele opionale snt permise n orice ordine n linia de comand.
Analizarea i prelucrarea argumentelor unei linii de comand trebuie efectuat n
____________________________________________
80
81
spune c funcpt este un pointer la o funcie care returneaz un ntreg. Primul set
de paranteze este necesar, deoarece fr el
int *funcpt();
82
83
n funcia main, n locul variabilei num de tip ntreg putem folosi un pointer
de tip P_func astfel:
P_func Fcomp = strcmp;
if (ac>1 && av[1][0]=='-' && av[1][1]=='n')
Fcomp = numcmp;
nrl = ReadLines(linptr,NLIN);
if (nrl>=0) {
Sort(linptr,nrl,Fcomp);
WriteLines(linptr,nrl);
}
Dac programul este compus din mai multe module, se utilizeaz un fiier
header care conine declaraiile tuturor funciilor utilizate. Acest fiier trebuie
inclus n fiecare modul.
____________________________________________
84
9. Structuri i reuniuni
O structur este o colecie de una sau mai multe variabile, de acelai tip sau de
tipuri diferite, grupate mpreun sub un singur nume pentru a putea fi tratate
mpreun.
Structurile ajut la organizarea datelor complexe, n special n programele
mari, deoarece permit unui grup de variabile legate s fie tratate ca o singur
entitate. n acest capitol vom ilustra modul de utilizare a structurilor.
85
86
return zi;
}
87
9.2. typedef
Stilul de utilizare a tipurilor de date structurate prezentat mai sus este foarte
frecvent, i se ntlnete mai ales n programe care apeleaz funcii ale sistemelor
de operare Linux.
Considerm totui c a scrie declaraii de funcii care au ca i parametri date
structurate, sau a defini variabile de tip structur, este destul de neplcut datorit
cerinei de a preciza numele tipului precedat de cuvntul rezervat struct. De
aceea, pe parcursul lucrrii vom folosi o facilitate (typedef) de a defini
sinonime pentru tipuri de date existente, care pot fi fundamentale (predefinite) sau
definite de programator.
ntr-o declaraie typedef fiecare identificator care apare ca parte a unui
declarator devine sintactic echivalent cu cuvntul cheie rezervat pentru tipul
asociat cu identificatorul. De exemplu, declaraia urmtoare l face pe LENGTH
sinonim cu int:
typedef int LENGTH;
____________________________________________
88
____________________________________________
89
char *keyw;
int keyc;
} T_key;
Folosim acest tip structur pentru a defini un masiv keym, unde NKEYS este o
constant definit cu ajutorul directivei #define:
T_key keym[NKEYS];
dar parantezele interioare nu mai snt necesare dac iniializatorii snt variabile
simple sau iruri de caractere i dac toi iniializatorii snt prezeni.
Dac masivul keym este global, eventualii membri pentru care nu se
precizeaz o valoare iniial vor primi valoarea zero, dar n acest caz parantezele
interioare snt necesare:
T_key keym[] = { {"break"},{"case"}, . . . }
90
91
92
Dac p este un pointer la un masiv de structuri, orice operaie asupra lui p ine
cont de dimensiunea unei structuri, astfel nct p++ incrementeaz pointerul p la
urmtoarea structur din masiv, adunnd la p dimensiunea corespunztoare a
structurii. Nu ntotdeauna dimensiunea structurii este egal cu suma dimensiunilor
membrilor ei, deoarece din cerine de aliniere a unor membri pot aprea goluri
n interiorul acesteia.
De aceea, dac dorim s economisim ct mai mult memorie n cazul
masivelor de structuri, recomandm gruparea membrilor astfel nct s eliminm
pe ct posibil apariia unor astfel de goluri. n principiu, fiecare tip de date are
anumite cerine de aliniere:
short la multiplu de 2;
long, float, double, long double la multiplu de 4.
Dimensiunea unei structuri este rotunjit la un multiplu ntreg corespunztor
acestor cerine.
____________________________________________
93
94
Dac dorim s eliminm un nod din list, avem nevoie s tim unde este
memorat adresa acestuia. Dac nodul nedorit este primul din list, adresa
acestuia este memorat ntr-un element din masivul hast, altfel aceast adres
este memorat n membrul nxt al nodului precedent din list. Variabila pointer
pp va reine unde se afl memorat adresa care ne intereseaz. n parcurgerea
listei, valoarea variabilei pp este tot timpul cu un pas n urma lui np, care indic
nodul curent.
P_list *pp;
____________________________________________
95
Fiecare nod din list are tipul T_list i conine, printre altele, i adresa
urmtorului nod. Dar adresa primului nod e memorat ntr-un element care are alt
tip dect T_list. De aceea avem nevoie s memorm adresa zonei unde este
memorat adresa care ne intereseaz, de unde necesitatea definiiei globale
P_list *pp;
96
np->def = strdup(def);
if (np->def==NULL) return NULL;
return np;
}
void Remove() {
T_list *np;
if (!pp) return;
free(np=(*pp)->nxt);
*pp = np; pp = NULL;
}
Cum eliberm toate zonele ocupate de o list? Trebuie s fim foarte ateni
deoarece, nainte de a elibera memoria ocupat de nodul curent, trebuie eliberat
memoria ocupat de nodul care urmeaz celui curent. Prezentm mai nti varianta
recursiv:
void FreeList(T_list *np) {
if (np) {
FreeList(np->nxt);
free(np);
}
}
97
98
| car |
/
| bac |
| lac |
| cer |
99
/* nodul de baz */
/* pointer la cuvnt */
/* numrtor de apariii */
/* descendent stng (left) */
/* descendent drept (right) */
100
TreeInsert(&(*p)->l,w);
else
/* noul cuvnt mai mare, mergem spre dreapta */
TreeInsert(&(*p)->r,w);
}
else {
*p = (P_node)calloc(1,sizeof(T_node));
(*p)->w = strdup(w);
(*p)->c = 1;
}
101
9.7. Cmpuri
Un cmp se definete ca fiind o mulime de bii consecutivi dintr-un cuvnt sau
ntreg. Concret, 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 flaguri, fiecare pe un bit, pentru tabela de simboluri a
unui compilator.
Fiecare simbol dintr-un program are anumite informaii asociate lui, cum snt
de exemplu clasa de memorie, tipul, dac este sau nu cuvnt cheie .a.m.d. Cel mai
compact mod de a codifica aceste informaii este folosirea unui set de flaguri, de
cte un bit, ntr-un singur ntreg sau caracter.
Modul cel mai uzual pentru a face acest lucru este de a defini un set de mti,
fiecare masc fiind corespunztoare poziiei bitului n interiorul caracterului sau
cuvntului. De exemplu:
#define KEYWORD 01
#define EXTERNAL 02
#define STATIC 04
102
Expresia urmtoare este adevrat cnd cel puin unul din biii 1 sau 2 din
flags este unu:
if (flags & (EXTERNAL | STATIC)) ...
Expresia urmtoare este adevrat cnd biii 1 i 2 din flags snt ambii zero:
if (!(flags & (EXTERNAL | STATIC))) ...
103
9.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 fie tratate
ntr-o singur zon de memorie.
S relum exemplul tabelei de simboluri a unui compilator, presupunnd c se
gestioneaz constante de tip int, float sau iruri de caractere.
Valoarea unei constante particulare ar putea fi memorat ntr-o variabil de tip
corespunztor, dar este mai convenabil, pentru gestiunea tabelei de simboluri, ca
valoarea s fie memorat n aceeai zon de memorie, indiferent de tipul ei.
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 cmpurilor,
sintaxa definiiei i accesului la o reuniune se bazeaz pe structuri. Fie definiia:
union u_tag {
int ival;
float fval;
char *pval;
} uval;
104
printf("%s\n",uval.pval); break;
default:
printf("tip incorect %d in utype\n",utype);
break;
}
symtab[i].uval.ival
105
} T_struc;
____________________________________________
106
107
Descriere
Funcia fopen deschide fiierul al crui nume este un ir indicat de num i i
asociaz un flux.
Argumentul mod indic un ir care ncepe cu una din secvenele urmtoare:
r deschide un fiier pentru citire;
r+ deschide pentru citire i scriere;
w trunchiaz fiierul la lungime zero sau creeaz un fiier pentru scriere;
w+ deschide pentru adugare la sfrit, n citire i scriere; fiierul este creat dac
nu exist, altfel este trunchiat;
a deschide pentru adugare la sfrit, n scriere; fiierul este creat dac nu exist;
a+ deschide pentru adugare la sfrit, n citire i scriere; fiierul este creat dac
nu exist;
____________________________________________
108
Nume
fclose - nchide un flux
Declaraie
int fclose( FILE *flux);
Descriere
Funcia fclose nchide fiierul asociat fluxului flux. Dac flux a fost
deschis pentru ieire, orice date aflate n zone tampon snt scrise n fiier n
prealabil cu un apel fflush.
Valori returnate
n caz de succes se returneaz 0. n caz de eroare se returneaz EOF i
variabila global errno indic codul erorii.
Nume
tmpfile - creeaz un fiier temporar
Declaraie
FILE *tmpfile();
Descriere
Funcia tmpfile genereaz un nume unic de fiier temporar. Acesta este
deschis n mod binar pentru scriere / citire ("wb+"). Fiierul va fi ters automat la
nchidere sau la terminarea programului.
Valoare returnat
____________________________________________
109
Nume
fflush - foreaz scrierea n flux
Declaraie
int fflush(FILE *flux);
Descriere
Funcia fflush foreaz o scriere a tuturor datelor aflate n zone tampon ale
fluxului flux. Fluxul rmne deschis.
Valori returnate
n caz de succes se returneaz 0. n caz de eroare se returneaz EOF i
variabila global errno indic codul erorii.
Nume
fseek, ftell, rewind - repoziioneaz un flux
Declaraie
int fseek(FILE *flux, long ofs, int reper);
long ftell(FILE *flux);
void rewind(FILE *flux);
Descriere
Funcia fseek seteaz indicatorul de poziie pentru fiierul asociat fluxului
flux. Noua poziie, dat n octei, se obine adunnd ofs octei (offset) la poziia
specificat de reper. Dac reper este SEEK_SET, SEEK_CUR, sau
SEEK_END, ofs este relativ la nceputul fiierului, poziia curent a
indicatorului, respectiv sfritul fiierului. Funcia fseek terge indicatorul de
sfrit de fiier.
Funcia ftell obine valoarea curent a indicatorului de poziie pentru
fiierul asociat fluxului flux.
Funcia rewind poziioneaz indicatorul de poziie pentru fiierul asociat
fluxului flux la nceputul fiierului. Este echivalent cu:
(void)fseek(flux, 0L, SEEK_SET)
____________________________________________
110
Nume
fileno returneaz descriptorul asociat fluxului
Declaraie
int fileno(FILE *flux);
Descriere
Funcia fileno examineaz argumentul flux i returneaz descriptorul
asociat de sistemul de operare acestui flux.
Descriere
Funcia fgets citete cel mult size-1 caractere din flux i le memoreaz
n zona indicat de s. Citirea se oprete la detectarea sfritului de fiier sau newline. Dac se citete caracterul new-line acesta este memorat n s. Dup ultimul
caracter se memoreaz null.
Apeluri ale acestei funcii pot fi combinate cu orice apeluri ale altor funcii de
intrare din bibliotec (fscanf, de exemplu) pentru un acelai flux de intrare.
Valori returnate
Funcia returneaz adresa s n caz de succes, sau NULL n caz de eroare sau la
ntlnirea sfritului de fiier dac nu s-a citit nici un caracter.
Nume
fputs - scrie un ir de caractere ntr-un flux text
Declaraie
int fputs(const char *s, FILE *flux);
Descriere
Funcia fputs scrie irul s n flux fr caracterul terminator null.
Apeluri ale acestei funcii pot fi combinate cu orice apeluri ale altor funcii de
ieire din bibliotec (fprintf, de exemplu) pentru un acelai flux de ieire.
____________________________________________
111
Valori returnate
Funcia returneaz o valoare non-negativ n caz de succes, sau EOF n caz de
eroare.
Nume
fread, fwrite - intrri / ieiri pentru fluxuri binare
Declaraie
unsigned fread(void *ptr, unsigned size,
unsigned nel, FILE *flux);
unsigned fwrite(const void *ptr, unsigned
size, unsigned nel, FILE *flux);
Descriere
Funcia fread citete nel elemente, fiecare avnd mrimea size octei, din
fluxul indicat de flux, i le memoreaz n zona indicat de ptr.
Funcia fwrite scrie nel elemente, fiecare avnd mrimea size octei, din
fluxul indicat de flux, pe care le ia din zona indicat de ptr.
Valori returnate
Funciile returneaz numrul de elemente citite sau scrise cu succes (i nu
numrul de caractere). Dac apare o eroare sau se ntlnete sfritul de fiier,
valoarea returnat este mai mic dect nel (posibil zero).
Descriere
Funciile din familia ...scanf scaneaz intrarea n concordan cu irul de
caractere fmt dup cum se descrie mai jos. Acest format poate conine
specificatori de conversie; rezultatele unor astfel de conversii (dac se efectueaz)
se memoreaz prin intermediul argumentelor pointer. Funcia scanf citete irul
de intrare din fluxul standard stdin, fscanf din flux, i sscanf din irul
indicat de str.
Fiecare argument pointer trebuie s corespund n ordine ca tip cu fiecare
specificator de conversie (dar a se vedea suprimarea mai jos). Dac argumentele
____________________________________________
112
113
e,g Echivalent cu f.
s
114
apariia unui caracter care nu se afl (sau, dac se precizeaz ^, care se afl) n
set sau dac se atinge mrimea maxim specificat.
n
Valori returnate
Funciile returneaz numrul de valori atribuite, care poate fi mai mic dect
numrul de argumente pointer, sau chiar zero, n cazul n care apar nepotriviri
ntre format i irul de intrare. Zero indic faptul c, chiar dac avem un ir de
intrare disponibil, nu s-a efectuat nici o conversie (i atribuire); aceast situaie
apare atunci cnd un caracter din irul de intrare este invalid, cum ar fi un caracter
alfabetic pentru o conversie %d. Valoarea EOF este returnat dac apare o eroare
nainte de prima conversie, cum ar fi detectarea sfritului de fiier. Dac o eroare
sau un sfrit de fiier apare dup ce o conversie a nceput, se returneaz numrul
de conversii efectuate cu succes, i se poziioneaz bitul corespunztor din
structura FILE, care poate fi testat.
Descriere
Funciile din familia ...printf genereaz o ieire n concordan cu format dup
cum se descrie mai jos. Funcia printf afieaz ieirea la fluxul standard
stdout; fprintf scrie ieirea la flux; sprintf scrie ieirea n irul de
caractere str.
Aceste funcii genereaz ieirea sub controlul irului format care specific
cum se convertesc argumentele pentru ieire.
irul de formatare
irul fmt este un ir de caractere, printre care se pot afla zero sau mai multe
directive: caractere obinuite (diferite de %) care snt copiate aa cum snt n fluxul
de ieire, i specificaii de conversie, fiecare dintre ele rezultnd din ncrcarea a
zero sau mai multe argumente. Fiecare specificaie de conversie este introdus de
caracterul % i se termin cu un specificator de conversie. ntre acestea pot fi (n
____________________________________________
115
aceast ordine) zero sau mai muli indicatori, o mrime minim a cmpului
opional, o precizie opional i un modificator opional de lungime.
Argumentele trebuie s corespund n ordine ca tip cu specificatorii de
conversie. Acestea snt folosite n ordinea dat, unde fiecare caracter * i fiecare
specificator de conversie solicit urmtorul argument. Dac argumentele nu snt
suficiente comportamentul programului este imprevizibil.
Caractere indicatori
Caracterul % este urmat de zero, unul sau mai muli indicatori:
0
Sp (spaiu) n cazul unui rezultat al unei conversii cu semn, naintea unui numr
pozitiv sau ir vid se pune un blanc.
+
Limea cmpului
Un ir de cifre zecimale (cu prima cifr nenul) specific o lime minim
pentru cmp. Dac valoarea convertit are mai puine caractere dect limea
specificat, va fi completat cu spaii la stnga (sau dreapta, dac s-a specificat
aliniere la stnga). n locul unui numr zecimal se poate folosi * pentru a specifica
faptul c limea cmpului este dat de argumentul corespondent, care trebuie s
fie de tip int. O valoare negativ pentru lime este considerat un indicator urmat de o valoare pozitiv pentru lime. n nici un caz nu se va trunchia cmpul;
dac rezultatul conversiei este mai mare dect limea cmpului, cmpul este
expandat pentru a conine rezultatul conversiei.
Precizia
Precizia (opional) este dat de caracterul . urmat de un ir de cifre zecimale.
n locul irului de cifre zecimale se poate scrie * pentru a specifica faptul c
precizia este dat de argumentul corespondent, care trebuie s fie de tip int.
____________________________________________
116
Dac precizia este dat doar de caracterul . sau dac precizia este negativ, atunci
aceasta se consider zero. Precizia d numrul minim de cifre care apar pentru
conversii de tip d, i, o, u, x, X, numrul de cifre care apar dup punctul zecimal
pentru conversii de tip e, E, f, F, numrul maxim de cifre semnificative pentru
conversii de tip g i G, sau numrul maxim de caractere generate pentru conversii
de tip s.
Dac se folosete * pentru lime sau precizie (sau ambele), argumentele se
iau n ordine: lime, precizie, valoare de scris.
Modificator de lungime
n acest caz prin conversie ntreag nelegem conversie de tip d, i, o, u, x, X.
h
Specificator de conversie
Un caracter care specific tipul conversiei care se va face. Specificatorii de
conversie i semnificaia lor snt:
d,i
Argumentul de tip int este convertit la notaia zecimal cu semn. Precizia,
dac este dat, d numrul minim de cifre care trebuie s apar; dac valoarea
convertit necesit mai puine cifre, aceasta este completat la stnga cu
zerouri. Precizia implicit este 1. Dac valoarea 0 este afiat cu precizie
explicit 0, ieirea este vid.
o,u,x,X
Argumentul de tip unsigned este convertit la notaie octal fr semn (o),
zecimal fr semn (u), sau hexazecimal fr semn (x i X). Literele
abcdef se folosesc pentru conversii de tip x, literele ABCDEF pentru
conversii de tip X. Precizia, dac este dat, d numrul minim de cifre care
trebuie s apar; dac valoarea convertit necesit mai puine cifre, aceasta
este completat la stnga cu zerouri. Precizia implicit este 1. Dac valoarea 0
este afiat cu precizie explicit 0, ieirea este vid.
____________________________________________
117
e,E
Argumentul de tip flotant este rotunjit i convertit n stil
[ -]d.dddedd
unde avem o cifr nainte de punctul zecimal i numrul de cifre dup acesta
este egal cu precizia; dac aceasta lipsete se consider 6; dac precizia este
zero, punctul zecimal nu apare. O conversie de tip E folosete litera E (n loc
de e) pentru a introduce exponentul. Exponentul are ntotdeauna cel puin
dou cifre; dac valoarea este zero, exponentul este 00.
f,F
Argumentul de tip flotant este rotunjit i convertit n notaie zecimal n stil
[-]ddd.ddd, unde numrul de cifre dup punctul zecimal este egal cu precizia
specificat. Dac precizia lipsete se consider 6; dac precizia este explicit
zero, punctul zecimal nu apare. Dac punctul zecimal apare, cel puin o cifr
apare naintea acestuia.
g,G
Argumentul de tip flotant este convertit n stil f sau e (sau E pentru conversii
de tip G). Precizia specific numrul de cifre semnificative. Dac precizia
lipsete se consider 6; dac precizia este zero se consider 1. Stilul e este
folosit dac exponentul rezultat n urma conversiei este mai mic dect 4 ori
mai mare sau egal cu precizia. Zerourile finale snt eliminate din partea
fracionar a rezultatului; punctul zecimal apare numai dac este urmat de cel
puin o cifr.
c
Valoare returnat
____________________________________________
118
Descriere
Rutina perror afieaz un mesaj la ieirea standard de eroare, care descrie
ultima eroare ntlnit la ultimul apel sistem sau funcie de bibliotec. Mai nti se
afieaz argumentul s, apoi virgula i blanc, i n final mesajul de eroare i newline. 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 errno.
Lista global de erori sys_errlist[] indexat cu errno poate fi folosit
pentru a obine mesajul de eroare fr new-line. Ultimul indice de mesaj din list
este sys_nerr-1. 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 errno indic codul erorii. Aceste
valori pot fi gsite n <errno.h>. Funcia perror servete la afiarea acestui
cod de eroare ntr-o form lizibil. Dac un apel terminat cu eroare nu este imediat
urmat de un apel perror, valoarea variabilei errno se poate pierde dac nu e
salvat.
Nume
clearerr, feof, ferror - verific i reseteaz starea
fluxului
Declaraie
void clearerr(FILE *flux);
int feof(FILE *flux);
int ferror(FILE *flux);
Descriere
Funcia clearerr terge indicatorii de sfrit de fiier i eroare ai fluxului.
____________________________________________
119
120
Nume
opendir - deschide un director
Declaraie
DIR *opendir(const char *nume);
Descriere
Funcia opendir deschide un flux pentru directorul cu numele nume, i
returneaz un pointer la fluxul deschis. Fluxul este poziionat pe prima intrare din
director.
Valoare returnat
Funcia returneaz un pointer la flux n caz de succes, sau NULL n caz de
eroare i variabila global errno indic codul erorii.
Cteva erori posibile
EACCES Acces interzis
ENOTDIR nume nu este un director
Nume
readdir - citete dintr-un director
Declaraie
struct dirent *readdir(DIR *dir);
Descriere
Funcia readdir returneaz un pointer la o structur de tip dirent care
reprezint urmtoarea intrare din directorul indicat de fluxul dir. Returneaz
NULL dac s-a depistat sfritul de director sau dac a aprut o eroare.
Structura de tip dirent conine un cmp char d_name[]. Utilizarea altor
cmpuri din structur reduce portabilitatea programelor.
Valoare returnat
Funcia returneaz un pointer la o structur de tip dirent, sau NULL dac sa depistat sfritul de director sau dac a aprut o eroare.
Nume
closedir - nchide un director
Declaraie
int closedir(DIR *dir);
Descriere
____________________________________________
121
Nume
rename - redenumete un fiier
remove - terge un fiier
Declaraie
int rename(const char *old, const char *new);
int remove(const char *name);
Descriere
Funcia rename schimb numele unui fiier din old n new. Dac a fost
precizat un periferic n new, acesta trebuie s coincid cu cel din old.
Directoarele din old i new pot s fie diferite, astfel c rename poate fi folosit
pentru a muta un fiier dintr-un director n altul. Nu se permit specificatori
generici (wildcards).
Funcia remove terge fiierul specificat prin name.
Valoare returnat
n caz de succes se returneaz 0. n caz de eroare se returneaz EOF i
variabila global errno indic codul erorii.
122
fseek(f,0,SEEK_END);
fprintf(stderr,"File %s, size %ld\n",ftell(f));
fclose(f);
return 0;
}
123
while (k=fread(zon,1,LZON,fi))
fwrite(zon,1,k,fo);
fclose(fi); fclose(fo);
return 0;
}
124
if (!dir) {
perror("Eroare open dir");
return 1;
}
while (ent=readdir(dir))
printf("%s\n",ent->d_name);
return 0;
}
____________________________________________
125
Descriere
Funcia calloc aloc memorie pentru un masiv de nel elemente, fiecare 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 fi
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 modific 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 fi fost returnat de un apel precedent
malloc, calloc sau realloc.
Valori returnate
Pentru calloc i malloc valoarea returnat este un pointer la memoria
alocat, aliniat n mod corespunztor pentru orice tip de variabile, sau NULL dac
nu exist suficient memorie continu.
____________________________________________
126
Descriere
Funcia qsort sorteaz un masiv de nel elemente, fiecare de mrime size.
Argumentul base indic spre nceputul masivului.
Elementele masivului snt sortate n ordine cresctoare n concordan cu
funcia de comparare referit de comp, apelat cu dou argumente care indic
spre obiectele ce se compar. Funcia de comparare trebuie s returneze un ntreg
mai mic dect, egal cu, sau mai mare dect zero dac primul argument este
considerat a fi mai mic dect, egal cu, respectiv mai mare dect al doilea. Dac cele
dou elemente comparate snt egale, ordinea n masivul sortat este nedefinit.
Funcia bsearch caut ntr-un masiv de nel elemente, fiecare de mrime
size, un membru care coincide cu obiectul indicat de key. Argumentul base
indic spre nceputul masivului.
Coninutul masivului trebuie s fie sortat cresctor n concordan cu funcia
de comparare referit de comp, apelat cu dou argumente care indic spre
obiectele ce se compar. Funcia de comparare se definete ca n cazul qsort.
Primul argument este adresa cheii, al doilea este adresa unui element din masiv.
Valoare returnat
Funcia bsearch returneaz un pointer la un membru al masivului care
coincide cu obiectul indicat de key, sau NULL dac nu se gsete nici un
____________________________________________
127
membru. Dac exist mai multe elemente care coincid cu key, poate fi returnat
oricare element cu aceast proprietate.
Descriere
Primele 12 funcii verific dac c, care trebuie s fie o valoare de tip
unsigned char sau EOF, se afl n una din clasele de caractere enumerate mai
sus.
isalnum
Verific dac c este alfanumeric (liter sau cifr).
isalpha
Verific dac c este alfabetic (liter mare sau mic).
isascii
Verific dac c este o valoare pe 7 bii din setul de caractere ASCII.
iscntrl
____________________________________________
128
Nume
____________________________________________
129
Descriere
Funcia memcpy copiaz n octei din zona de memorie src n zona de
memorie dest. Zonele de memorie nu trebuie s se suprapun. Dac exist acest
risc se utilizeaz memmove.
Valoare returnat
Funciile returneaz un pointer la dest.
Nume
memcmp - compar dou zone de memorie
Declaraie
int memcmp(const void *s1, const void *s2,
unsigned n);
Descriere
Funcia memcmp compar primii n octei ai zonelor de memorie s1 i s2.
Valoare returnat
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
memset - umple o zon de memorie cu o constant pe un octet
Declaraie
void *memset(void *s, int c, unsigned n);
Descriere
Funcia memset umple primii n octei ai zonei de memorie indicat de s cu
constanta c pe un octet.
Valoare returnat
Funcia returneaz un pointer la zona de memorie s.
Nume
memchr - caut n memorie un caracter
____________________________________________
130
Declaraie
void *memchr(const void *s, int c, unsigned n);
Descriere
Funcia memchr caut caracterul c n primii n octei de memorie indicai de
s. Cutarea se oprete la primul octet care are valoarea c (interpretat ca
unsigned char).
Valoare returnat
Funcia returneaz un pointer la octetul gsit sau NULL dac valoarea nu
exist n zona de memorie.
Nume
strlen - calculeaz lungimea unui ir
Declaraie
unsigned strlen(const char *s);
Descriere
Funcia strlen calculeaz lungimea irului s, fr a include caracterul
terminator null.
Valoare returnat
Funcia returneaz numrul de caractere din s.
Nume
strcpy, strncpy - copiaz un ir de caractere
Declaraie
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src,
unsigned n);
Descriere
Funcia strcpy copiaz irul indicat de src (inclusiv caracterul terminator
null) n zona indicat de dest. irurile nu trebuie s se suprapun, i n plus zona
dest trebuie s fie suficient de mare pentru a primi copia.
____________________________________________
131
Nume
strdup - duplic un ir
Declaraie
char *strdup(const char *s);
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 fi eliberat cu
free.
Valoare returnat
Funcia returneaz un pointer la irul duplicat, sau NULL dac nu exist
memorie suficient disponibil.
Nume
strcat, strncat - concateneaz dou iruri
Declaraie
char *strcat(char *dest, const char *src);
char *strncat(char *dest, const char *src,
unsigned n);
Descriere
Funcia strcat adaug irul src la irul dest suprascriind caracterul 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 suficient spaiu
pentru a pstra rezultatul.
Funcia strncat 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.
____________________________________________
132
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.
____________________________________________
133
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 determin lungimea segmentului iniial din s format n
ntregime numai cu caractere din acc.
Funcia strcspn determin 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 afl n
acc.
Funcia strcspn returneaz poziia primului caracter din s care se afl n
rej.
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 fi returnate de rand. Aceste
secvene se repet dac srand se apeleaz cu aceeai valoare seed.
Se obinuiete ca generatorul s fie iniializat cu o valoare dat de ceasul
sistemului de calcul, ca n exemplul de mai jos:
#include <time.h>
srand(time(NULL));
Valoare returnat
Funcia rand returneaz o valoare ntre 0 i RAND_MAX.
____________________________________________
134
Observaie
n lucrarea Numerical Recipes in C: The Art of Scientific Computing - William
H Press, Brian P Flannery, Saul A Teukolsky, William T Vetterling / New York:
Cambridge University Press, 1990 (1st ed, p 207), se face urmtorul comentariu:
Dac dorii s generai o valoare aleatoare ntreag ntre 1 i 10, se
recomand s folosii secvena
j=1+(int)(10.0*rand()/(RAND_MAX+1.0));
i nu o secven de tipul
j=1+(int)(1000000.0*rand())%10;
care folosete biii de rang inferior.
Tot n fiierul <stdlib.h> snt descrise i urmtoarele funcii:
valoare absolut
valoare absolut
conversie din ASCII n ntreg
conversie din ASCII n ntreg lung
conversie din ASCII n dubl precizie
135
arctg(y/x) n [,]
exp(double x); ex
log(double x); ln(x)
pow(double x, double y);
xy
sinh(double x); sinh(x)
cosh(double x); cosh(x)
tanh(double x); tgh(x)
ldexp(double x, int e);
x 2e
fmod(double x, double y); x modulo y
Funcia time
Data i ora calendaristic se reprezint n format compact printr-o valoare de
tip time_t. Majoritatea mediilor de programare definesc acest tip ca un sinonim
pentru unsigned long. Aceast valoare se obine prin apelul funciei time.
time_t time(time_t *tims);
____________________________________________
136
struct tm {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
/* secunde, ntre 0 i 59 */
/* minute, ntre 0 i 59 */
/* ore, ntre 0 i 23 */
/* ziua din lun, ntre 1 i 31 */
/* luna, ntre 0 i 11 */
/* anul curent minus 1900 */
/* ziua din sptmn, duminica: 0 */
/* ziua din an, ntre 0 i 365 */
/* opiunea daylight saving time */
137
Funcia clock
clock_t clock(void);
Funcia clock returneaz o aproximare a timpului pe care procesorul l-a
folosit pentru program pn la momentul apelului. Tipul clock_t este definit de
majoritatea mediilor de programare ca un sinonim pentru unsigned long.
Numrul de secunde de la lansarea programului se obine astfel:
(double)clock()/CLOCKS_PER_SECOND
Constanta CLOCKS_PER_SECOND este specific mediului de programare folosit.
De exemplu, biblioteca GNU C Compiler pentru sistemul de operare Linux
definete valoarea 1000000. O consecin a acestui fapt este c pe un sistem de
calcul pe 32 de bii funcia clock va returna aceeai valoare la aproximativ
fiecare 72 de minute.
Observaie. Standardul C nu impune ca aceast cronometrare s nceap de la
zero la lansarea programului. De aceea, pentru a garanta un maxim de
portabilitate, cronometrarea se face astfel:
main() {
double stm;
stm = clock();
...
printf("Time:%.3lf\n",(clock()-stm)/
CLOCKS_PER_SECOND);
}
138
Nume
system execut o comand a interpretorului de comenzi
Declaraie
system(char *com);
Descriere
Funcia system execut comanda com prin lansarea interpretorului de
comenzi cu acest parametru.
Se recomand folosirea cu atenie a acestei funcii sub unele sisteme de
operare (de exemplu Linux), dac interpretorul de comenzi permite precizarea mai
multor comenzi ntr-o singur linie.
139
X=(int *)malloc(n*sizeof(int));
if (!X) return 1;
srand(time(NULL));
for (i=0; i<n; i++)
X[i]=rand()%M;
qsort(X,n,sizeof(int),cmp);
for (i=0; i<k; i++) {
v=rand()%M;
p=(int *)bsearch(&v,X,n,sizeof(int),cmp);
if (p)
printf("Val: %d
Pos: %d\n",v,p-X);
}
free(X);
return 0;
}
140
141
printf("%-12s %c%6.2lf\n",El[i].nm,
El[i].ar,El[i].md);
free(El);
return 0;
}
142
qsort(C,n,l+1,comp);
for (i=0; i<n; i++)
printf("%s\n",C+(l+1)*i);
free(C);
return 0;
}
____________________________________________
143
____________________________________________
144
Cuprins
1. Generaliti asupra limbajului C . . . . . . . . . . . . . . . . . . . .
1.1. Introducere. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2. Reprezentarea valorilor numerice . . . . . . . . . . . . . . . . . . . . . .
1.3. Primele programe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
5
6
14
14
15
17
18
18
3. Variabile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
21
23
26
27
30
30
32
4. Operatori i expresii . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
33
33
35
37
38
39
41
42
43
44
44
5. Instruciuni. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
46
46
46
47
49
49
51
53
55
55
____________________________________________
145
6. Funcii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
57
57
59
61
62
63
67
67
68
70
70
8. Pointeri i masive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
76
76
78
79
81
83
84
87
91
94
98
102
106
109
111
115
117
123
127
129
133
135
138
140
143
148
150
152
146
156
157
158
160
162
166
168
171
172
Bibliografie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
____________________________________________
147