Sunteți pe pagina 1din 108

BORLAND C Manual de utilizare

BORLAND C Manual de utilizare


LECIA 1.
STRUCTURA GENERAL A UNUI PROGRAM C
1.1 ISTORIC, CONCEPIE, EVOLUIE
Limbajul C a fost finalizat n 1972 de Dennis M. Ritchie si Brian W.
Kernighan de la firma american Bell Laboratories.
Prima versiune a limbajului se numete BCPL apoi urmtoarele poart numele
de A, B i C. Cei doi autori au dezvoltat aceste prime versiuni n jurul
sistemului de operare UNIX.
La vremea respectiv din aproximativ 13000 linii surs ale UNIX-ului doar
200 de linii surs nu erau scrise n limbajul C. De acest fapt se leag
detractorii limbajului care spun c limbajul C nu este un limbaj deosebit ci
doar un fel de limbaj oficial al sistemului de operare UNIX.
n anul 1978 apare manualul The C Programming Language care este de fapt
i prima standardizare a limbajului. Cei doi autori intr astfel n istorie...
Dup anul 1980 odat cu dezvoltarea hardware apar i primele PC-uri iar
acestea implic i produse software adecvate. Principalele firme productoare de
sofware -MICROSOFT i BORLAND - au dezvoltat unelte adecvate pentru programarea
i utilizarea limbajului C. Deocamdat firma BORLAND deine supremaia prin
versiunile mediului BORLAND C. Cele mai folosite sunt versiunile 2.0, 3.1, 4.0.
n ultimii doi ani au aprut aa numitele medii visuale: VISUAL C versiunile
4.5 i 5.0 care sunt de fapt extensii ale mediului BORLAND C adaptate
programrii orientate obiect i interfeei grafice WINDOWS 95. Mediile de
programare BORLANDC pot compila 3 tipuri de programe surs C:
fiiere cu extensia .C (fiiere cu prg. standard C);
fiiere cu extensia .CP (fiiere cu prg. C+,);
fiiere cu extensia .CPP (fiiere cu programe C++).
Menionm c limbajul C++ a fost elaborat de Bjarne Stroustrup de la AT&T.
El este un superset al limbajului C i permite principalele concepte ale
programrii prin abstractizarea datelor i programrii orientate spre obiecte.
Limbajul C este un limbaj hibrid avnd faciliti caracteristice
limbajelor de asamblare ct i faciliti ale limbajelor de nalt nivel.
Cteva dintre principalele caracteristici ale limbajului C sunt:
portabilitate: chiar dac acest concept nu-i definit foarte riguros spunem c
un program este portabil dac el poate fi transferat uor de la un tip de
calculator la altul; limbajul C este un astfel de limbaj;
flexibilitate: compilatorul face un numr mai redus de controale (face multe
conversii implicite);
programare structurat: limbajul are principalele structuri ale programrii
structurate: structura secvenial, structura iterativ i structura de
selecie;
compactizare: unele instruciuni sunt scrise foarte compact; de exemplu
i:=i+1 se poate scrie mai scurt ca i++;
lucrul pe bii i calcule cu adrese.
1.2 CONCEPTUL DE FUNCIE
Un program C se compune din una sau mai multe funcii. Funcia este o
unitate lexical de program compilabil independent.
Una dintre funcii este funcie principal, numele ei este predefinit i
anume main.
Execuia programului ncepe cu prima instruciune din funcia principal.
Funcia principal main este obligatorie pentru orice program celelalte
elemente fiind optionale. Pentru ca o anumit funcie s poat fi apelat e
necesar ca ea s aib declarat prototipul dac implementarea (definiia) ei se
afl dup funcia main (exemplul 1). Dac funcia principal se afl la
sfritul fiierului atunci nu mai e necesar prototipul funciei apelate ci doar
implementarea ei (exemplul 2). Comparnd structura unui program C cu structura
unui program PASCAL se observ nivelul de imbricare diferit. n PASCAL apare o
imbricare a procedurilor i funciilor pe cnd n C nu exist o astfel de
imbricare (rmne la nivelul fiecrei funcii dac e cazul).

- 1 -

BORLAND C Manual de utilizare

1.2.1. Definiia unei funcii


Definiia unei funcii n limbajul C se compune din antet i corp. O
funcie poate fi apelat dac este precedat de definiia sau de prototipul ei.
Aceste lucruri care sunt valabile n limbajul C se regsesc i n limbajul C++.
Antet i prototip
Antetul simplificat al unei funcii n C are formatul:
tip nume_funcie (lista_parametrilor_formali)
unde: tip - reprezint tipul valorii returnate de funcie sau dac funcia
nu returneaz nici o valoare se pune cuvntul cheie void;
nume_funcie reprezint un identificator clasic format dintr-un mixaj
de litere i cifre, primul caracter fiind obligatoriu litera;
printre litere se numr i liniua de subliniere;
lista_parametrilor_formali nume de variabile separate prin virgule.
Exemple:
1) double radical (double x) // calculeaza
returneaza valoarea gasita
2) double radical_n (double x, int n)
//
ordinul n din x

radacina

patrata

calculeaza

din

radacina

si
de

Prototipul unei funcii este asemntor antetului dar la sfrit se pune


caracterul ;
1.2.3. Corpul unei funcii
Corpul unei funcii C se compune din declaraii
instruciuni scrise ntre acolade conform figurii de mai
{ declaraii
instruciuni
}
i pentru c autorii limbajului C consider c un
nva mai repede scriind i executnd programe ct mai
exemplu de funcie.

de variabile locale i
jos.

limbaj de programare se
timpuriu vom da un mic

int modul (int i)


// determina valoarea absoluta a intregului i si
retruneaza aceasta valoare
{ if (i < 0)
return i;
if (i = = 0)
return 0;
else
return i;
}
1.3. CONSTRUCIILE DE BAZ ALE LIMBAJULUI C
1.3.1. Caractere (Alfabetul)
Limbajul C folosete setul de caractere al codului ASCII care se codific
prin numere ntregi din intervalul [0,127], adic 128 de coduri. Un astfel de
ntreg se pstreaz pe un BYTE (OCTET) adic pe 8 bii.
Mulimea caracterelor se mparte n trei grupe:
- caractere negrafice (coduri cuprinse ntre 00=NUL i 31) i 127=DEL;
- spaiu (codul 32);
- caractere grafice (coduri cuprinse ntre 33 i 126).
Caracterele grafice se mpart la rndul lor n:
litere mari (coduri ntre 65 i 90);
litere mici (coduri ntre 97 i 122);
cifre (coduri ntre 48 i 59);
caractere speciale (celelalte coduri).
Caracterele negrafice au diferite funcii. Astfel codul 10 semnific LF
(Line Feed), adic deplaseaz cursorul pe linia urmtoare n coloana 1, iar
codul 13 semnific CR (Carriage Return) adic deplaseaz cursorul n coloana 1
aceeai linie. n limbajul C combinaia celor dou caractere se noteaz prin: \n
i are semnificaia trecerii cursorului la linie nou i coloana 1 (newline).
Tabulatorul orizontal (deplasarea cursorului peste un anumit numr de
poziii) se precizeaz prin notaia: \t
S mai precizm c urmtoarele 3 caractere: spaiu, newline i tabulator
orizontal se mai numesc spaii albe (white spaces).
- 2 -

BORLAND C Manual de utilizare

1.3.2. Nume (Identificatori)


n limbajul C, un nume este o succesiune de litere i eventual cifre, care
ncepe cu o liter. Ca lungime un nume poate fi orict de lung dar numai primele
32 de caractere se iau n considerare. Folosind notaia BNF (vezi anexa) un nume
se poate defini recursiv, ca mai jos:
<nume> ::= <litera> | <nume><litera> | <nume><cifra>
<litera> ::= A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Z|
a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|z|_
<cifra> ::= 0|1|2|3|4|5|6|7|8|9|
Identificatorii se folosesc pentru denumirea variabilelor, tablourilor,
funciilor, etc.
Important Limbajul C/C++ este case sensitive adica un identificator
scris cu litere mari nu este echivalent cu acelasi identificator scris cu litere
mici.
Exemple:
A, _start, a_, matrice, matrice_patratica.
Dm i cteva contraxemple:
&B - conine caracterul &;
x+y - conine caracterul +;
1.3.3. Cuvinte cheie
Un cuvnt cheie este un cuvnt mprumutat din limba englez, care are un
neles predefinit. Aceste cuvinte se scriu cu litere mici. Un cuvnt cheie nu
poate avea alt utilizare ntr-un program C dect cea care i-a fost predefinit.
Fiind o succesiune de litere, un cuvnt cheie este un nume. Lista cuvintelor
cheie se d n anexa de la sfritul crii. Sensul fiecrui cuvnt cheie va
rezulta la definirea construciei n care se utilizeaz.
Exemple:
for, do, if, while, else, break, return, int, long, double, static,
extern.
1.3.4. Tipuri de baz
n limbajul C distingem cteva tipuri predefinte de date care se mai
numesc tipuri de baz. n general un tip de dat are trei atribute bine
conturate:
mulimea valorilor;
reprezentarea (intern i extern)
comportamentul (adic operaiile ce se pot face cu acel tip).
n tabelul de mai jos dm cuvntul cheie, mulimea valorilor,
reprezentarea intern.
Reprezentarea intern
Cuvnt cheie Mulimea valorilor
Lungime (bii)
Formatul intern
int
short
long
unsigned
char
float
double
precizie

ntregii
ntregii
ntregii
ntregii

din
din
din
din

[-215; 215-1]
[-215; 215-1]
[-231; 231 - 1]
[0; 216-1]

[-3.4*10-38; 3.4*1038]
[-1.7*10-308; 1.7*10308]

16
16
32
16
8
32
64

reprezentare binar
reprezentare binar
reprezentare binar
reprezentare binar
cod ASCII
virgul flot. simpl prec.
virgul
flotant
dubl

Facem precizarea c se poate folosi i combinaia unsigned long pentru


ntregii fr semn n dubl precizie.
Cu tipurile de baz se pot defini i tipuri utilizator folosind
instruciunea struct.
1.3.5. Constante
O constant are un tip i o valoare. Att tipul ct i valoarea unei
constante se definesc prin caracterele care compun constanta respectiv.
Constant ntreag zecimal
O constant ntreag este un ir de cifre care eventual este prefixat de
un semn (+ sau -) i postfixat de litera L sau l. O constant ntreag se
- 3 -

BORLAND C Manual de utilizare

reprezint n binar pe 16 sau 32 de bii. Sufixul L sau l foreaz reprezentarea


pe 32 de bii.
Constant ntreag octal
O constant ntreag octal este un ir de cifre octale (cifre cuprinse
ntre 0 i 7) precedat de un zero nesemnificativ.
Constant ntreag hexazecimal
O constant ntreag hexazecimal este un ir de cifre hexazecimale
prefixat cu 0x sau 0X.
Exemple:
Reprezentare Interpretare
12345
ntreg zecimal reprezentat n binar pe 16 bii
-12345
ntreg zecimal reprezentat n binar pe 16 bii
12345L
ntreg zecimal reprezentat n binar pe 32 bii
012345
nt. octal reprez. n binar pe 16 bii (o cifr oct. pe 3 bii)
0xabcd
ntreg hexa reprezentat n binar pe 16 bii (o cifr pe 4 bii)
12345678
ntreg zecimal reprezentat pe 32 de bii
Constant flotant
O constant flotant este un numr raional care se compune din
urmtoarele elemente:
un semn (+ sau -) care poate lipsi pentru numerele pozitive;
o parte ntreag care poate fi i vid;
o parte fracionar care poate fi i vid;
un exponent care poate fi i vid.
Prezena prii fracionare este suficient pentru ca numrul respectiv s
reprezinte o constant flotant. Absena prii fracionare implic prezena
prii ntregi i a exponentului.
Partea ntreag reprezint o succesiune de cifre zecimale. Partea
fracionar se compune din caracterul punct urmat de o succesiune de cifre
zecimale, care poate fi i vid. Exponentul se compune din litera e sau E urmat
de un + sau -, opional, i un ir de cifre zecimale.
Constantele flotante se pstreaz n format flotant dubl precizie.
Exemple:
3.14; 0.314e1; 3.1415926; 2.71828; 2.; 271828E-5.
Constant caracter
O constant caracter reprezint un caracter i are ca valoare codul ASCII
al caracterului respectiv. O constant caracter grafic se poate scrie incluznd
caracterul respectiv ntre caractere apostrof.
Exemple:
Constant caracter valoare cod ASCII
A
B
a
0
9
*

65
66
97
48
58
77

Anumite caractere negrafice au notaii speciale la scrierea crora se


utilizeaz caracterul backslash (\). Dm n continuare un tabel cu cele mai
folosite caractere negrafice:
Caracter Reprezentare ca i constant caracter Valoare cod ASCII
Backspace
\b
8
Retur de car
\r
13
Newline
\n
10
Apostrof
\
39
Backslash
\\
92
Tabulator vertical
\v
11
Salt pagin imprimant
\f
12
Carcterul NUL
\0
0
- 4 -

BORLAND C Manual de utilizare

Constant ir de caractere
O constant ir de caractere este o succesiune de zero sau mai multe
caractere delimitate prin ghilimele. Ghilimelele nu fac parte din irul de
caractere.
Exemple:
123; Limbajul C; sir de caractere; sir\; (irul vid).
Constanta ir de caractere se reprezint n memoria calculatorului printro succesiune de octei n care se pstreaz codurile ASCII ale caracterelor
irului, iar ultimul octet conine caracterul NUL care marcheaz sfritul
irului de caractere.
Dup cum se observ din exemplele date putem s folosim i convenia cu
backslash. De reinut c X i X reprezint construcii diferite.
1.3.6. Variabile simple
Prin variabil nelegem o dat a crei valoare se poate schimba n timpul
execuiei programului care o conine. Unei variabile i se ataeaz un nume prin
intermediul cruia o putem referi sau modifica. Totodat valorile pe care le
poate lua o variabil trebuie s aparin aceluiai tip. Corespondena dintre
numele i tipul unei variabile se realizeaz printr-o construcie special
numit declaraie.
Dup modul de grupare datele sunt:
date izolate denumite i variabile simple;
date grupate:
- mulimi ordonate de date de acelai tip la care ne referim cu indici,
- structuri n care date de tipuri diferite se grupeaz.
Declaraia de variabil simpl are formatul general:
tip list_de_nume;
unde list_de_nume este format fie dintr-un singur nume fie din mai
multe, separate prin virgule.
n limbajul C trebuie declarate toate variabilele nainte de a fi
utilizate.
Exemple:
int a,b,c; // a, b, c sunt variabile de tip int reprezentate in binar pe
2 octei;
float x,y,z;
// x, y, z sunt variabile de tip float in format flotant
simpla precizie pe 32 de bii;
char car; // car este o variabila de tip char pe 1 octeti poate conine
coduri ASCII;
long i,j,k;
// i, j, k sunt variabile de tip long in format binar pe
32 de bii.
Tablouri
Un tablou ca orice variabil simpl trebuie declarat nainte de a fi
utilizat. Dac referirea la elementele tabloului se face cu un singur indice se
spune c tabloul este unidimensional (se mai numete vector); dac referirea se
face cu doi indici tabloul se numete bidimensional(matrice); iar cu n indici
tabloul este n-dimensional.
Declaraia unui tablou n forma cea mai simpl este:
tip nume[l1][l2]...[ln]; unde:
l1, l2, ... ln sunt expresii constante care au valori ntregi ce pot
fi evaluate de compilator la ntlnirea lor.
Evident c se pot declara mai multe tablouri deodat i atunci numele de
tablouri se pot nirui ntr-o list, fiecare separat prin virgul.
Exemple:
int t[5];
//
s-a
declarat
un
tablou
unidimensional
de
5
componente;
float a[5][3];
// s-a declarat un tablou bidimensional de 5*3=15
componente;
La elementele unui tablou ne referim prin variabile cu indici. O variabil
cu indici se compune din numele tabloului urmat de unul sau mai muli indici,
fiecare indice fiind inclus n paranteze drepte. Numrul indicilor definete
dimensiunea tabloului. Indicii sunt expresii care au valori ntregi. Limita
inferioar a indicilor este zero. Astfel dac t este tabloul de tip int n
exemplul de mai sus, elementele lui sunt:
t[0], t[1], t[2], t[3], t[4].
- 5 -

BORLAND C Manual de utilizare

n cazul matricii a declarate mai sus elementele ei vor fi:


prima linie: a[0][0], a[0][1], a[0][2];
a doua linie: a[1][0], a[1][1], a[1][2];
...
a cincea linie: a[4][0], a[4][1], a[4][2];
Deci pentru dimensiunea k indicele variaz ntre 0 i lk-1.
Repartizarea memoriei pentru un tablou se face astfel: pentru fiecare
element al tabloului se repartizeaz o zon de memorie necesar n conformitate
cu tipul tabloului respectiv (pentru tipul int cte 2 octei, pentru tipul float
cte 4 octei, etc). Numele unui tablou este un pointer, el poate fi utilizat n
diferite construcii i el are ca valoare adresa primului su element.
Comentariu
n limbajul C un comentariu se scrie ntre /* i */ pe oricte rnduri.
ntre /* i */ se poate scrie o succesiune arbitrar de caractere, care ns nu
poate s conin secvena de terminare (adic */). Comentariul poate fi inserat
ntr-un program n orice poziie n care este legal s apar un caracter alb. El
constituie o explicaie pentru programator sau pentru utilizator. Compilatorul
nu interpreteaz comentariul n nici un mod. Comentariul se recomand a fi
inserat n punctele n care programatorul poate lmuri prin explicaii, anumite
aspecte ale procesului de calcul sau ale datelor utilizate. n mediile BORLAND C
exist i o alt convenie de a marca un comentariu la nivelul unui rnd cu
ajutorul a dou caractere slash (//), convenie pe care am folosit-o de altfel
n exemplele anterioare.
1.4. PREPROCESARE
Un program surs C poate fi prelucrat nainte de a fi compilat. O astfel
de prelucrare se numete preprocesare sau precompilare. Acest lucru se
realizeaz printr-un program special numit preprocesor. Acesta este apelat
automat nainte de a ncepe compilarea.
Preprocesorul limbajului C realizeaz urmtoarele:
includeri de alte fiiere (de obicei fiiere surs);
definiii i apeluri de macrouri simple;
compilare condiionat.
1.4.1. Includerea unui fiier surs
Fiierele surs pot fi incluse cu ajutorul directivei include.
Dou formate se folosesc pentru a include un fiier surs n locul n care
apare directiva (de obicei se pune la nceputul programului):
#include specificator_de_fisier sau
#include <specificator_de_fisier>
unde: specificator_de_fiier trebuie s fie un nume de fiier valid din
punct de vedere al sistemului de operare DOS i de obicei are extensia .h sau
.c.
Prima variant este folosit de obicei cnd fiierele de inclus sunt
furnizate de utilizator; dac nu este indicat calea atunci fiierele sunt
cutate n directorul curent i apoi n directoarele setate pentru directiva
include.
A doua variant este folosit pentru ncorporarea unui fiier standard
care se caut n directoarele setate pentru directiva include (de obicei astfel
de fiiere standard sunt livrate n biblioteci ataate mediului de programare
C).
Odat localizat fiierul dintr-o directiv include se nlocuiete aceasta
prin textul fiierului surs. Deci compilatorul nu va mai ntlni directiva
include ci textul fiierului inclus de preprocesor.
Includerile de fiiere se fac de obicei la nceput pentru ca textele
fiierelor surs (date i funcii) s poat fi utilizate n tot fiierul surs
de lucru. De aceea, la nceputul fiierelor surs vom ntlni mai multe
includeri de fiiere standard: stdio.h, stdlib.h, etc. Textul unui fiier inclus
poate la rndul su s conin directiva include. Fiierul stdio.h (prescurtarea
de la standard input output header) conine printre altele i funciile standard
de intrare-ieire printf i scanf. Fiierele cu extensia .h se mai numesc i
fiiere header (fiiere care se pun la nceputul fiierului surs). Un alt
- 6 -

BORLAND C Manual de utilizare

exemplu de fiier header este iostream.h folosit n mediul


conine funciile cin (console input) i cout (console output).
1.4.2. Constante simbolice
Cu directiva define se pot defini
Constantele simbolice se definesc astfel:

constante

BORLAND C

simbolice

care

macrouri.

#define nume succesiune_de_caractere


Preprocesorul substituie nume cu succesiune_de_caractere peste tot n
fiierul
surs
care
urmeaz
poziiei
directivei
define.
Dac
succesiune_de_caractere nu ncape pe un rnd atunci se poate continua pe rndul
urmtor scriind caracterul \ la sfritul primului rnd.
Numele nume definit ca mai sus se spune c este o constant
simbolic. Se recomand ca nume s fie scris cu litere majuscule pentru a scoate
n eviden c este o constant simbolic.
Construcia succesiune_de_caractere folosit pentru a defini o
constant simbolic poate la rndul ei s conin alte constante simbolice.
O constant simbolic poate fi redefinit (tot cu define) sau poate
fi anihilat cu undef (#undef nume).
Exemple:
1)#define PROCENT 10// din acest punct al fisierului sursa se substituie
// PROCENT cu 10
. . .
#define PROCENT 15 // de aici PROCENT se substituie cu 15
. . .
#undef PROCENT
// din acest punct constanta simbolica PROCENT
// isi inceteaza existenta
. . .
#define DIM 100
// s-au definit doua constante simbolice DIM
#define DOI_PI (2*3.1415926)
// si DOI_PI
. . .
int vector[DIM];
// DIM va fi inlocuit cu 100
. . .
x=DOI_PI;
. . .

- 7 -

BORLAND C Manual de utilizare

- 8 -

BORLAND C Manual de utilizare

LECIA 2.
V A R I A B I L E
Compilatorul C aloc memorie variabilelor din program de dimensiune
corespunztoare tipului fiecreia.
Memoria se aloc n 2 moduri:
static, repartizat ntr-o zon special asociat programului;
dinamic, repartizat ntr-o zon special numit stiv (se comport ca o
list LIFO).
n funcie de modul cum se aloc memorie, vom distinge mai multe clase de
variabile.
O prim clas de variabile este aceea a variabilelor globale crora li se
aloc memorie pe toat durata execuiei programului i ele pot fi utilizate n
orice funcie a programului. Alt clas de variabile este clasa variabilelor
locale, aceste variabile au o utilizare local la nivelul unei funcii.
2.1. VARIABILE GLOBALE
O variabil global are o definiie i attea declaraii de variabil
extern cte sunt necesare.
Definiia unei variabile globale coincide sintactic cu o declaraie
obinuit, dar care este scris n afara oricrei funcii a programului
(fiierului surs). Implicit, definiia unei variabile globale determin ca
variabila respectiv s fie definit ncepnd din punctul scrierii ei i pn la
sfritul fiierului surs respectiv. De aceea se recomand ca definiiile
variabilelor globale s fie scrise la nceputul fiierului surs, pentru a fi
accesate n orice funcie a fiierului.
Pentru a utiliza variabilele globale i n alte funcii situate n alte
fiiere surs dect n cel n care sunt definite, ele trebuie declarate ca
externe n funciile respective.
O declaraie de variabil extern coincide cu o declaraie obinuit doar
c ncepe cu cuvntul cheie extern.
Exemplu:
fiierul n care sunt declarate ca variabile globale fiierul n care sunt
folosite ca variabile externe
int i;
float f; void functie(. . .)
void main(void) { extern int i;
{ i = 10; extern double f;
. . . . . .
f = 3.14; f = f*i;
. . . . . .
} }
Variabilele i i f sunt declarate n afara funciei main i n afara
oricrei funcii, deci sunt variabile globale. Ele pot fi folosite n toate
funciile din fiierul surs care conine definiiile lor. Pentru a le utiliza
n funcii situate n alte fiiere surs dect n cel n care sunt definite ele
sunt declarate ca externe. Deci variabilele i i f sunt declarate ca externe n
funcia functie din al doilea fiier surs. Cele dou fiiere surs care pot fi
scrise n momente i de persoane diferite se pot asambla ntr-un singur program
cu ajutorul directivei de preprocesare include.
2.2. VARIABILE LOCALE
Variabilele locale nu sunt valabile n tot programul. Ele au o utilizare
local n dou feluri:
ca i variabile automatice (alocate pe stiv) la nivelul unei funcii;
ca i variabile statice (alocate n zona programului) la nivel de fiier
(eventual i la nivelul unei funcii).
Variabilele declarate n interiorul unei funcii i care nu sunt declarate
ca externe sunt variabile locale. Lor li se aloc memorie pe stiv la intrarea
n funcia n care sunt declarate. La ieirea din funcie, stiva se reface la
coninutul dinaintea apelului i variabilele locale pierd alocarea. Deci ori de
cte ori se apeleaz o funcie, variabilele locale acesteia (denumite i
variabile automatice) se aloc (primesc memorie) pe stiv i la ieirea din
funcie variabilele locale sunt terse din stiv.
- 9 -

BORLAND C Manual de utilizare

Variabilele locale pot s nu fie alocate pe stiv, ci ntr-o zon de


memorie destinat acestui scop. O astfel de variabil local se numete
variabil static. O variabil local static se declar printr-o declaraie
obinuit, precedat de cuvntul cheie static. O variabil static poate fi
declarat att n corpul unei funcii ct i n afara oricrei funcii. n cazul
unei variabile statice declarat n interiorul unei funcii alocarea nu se face
pe stiv ci ntr-o zon de memorie destinat acestui scop, aceasta fiind
deosebirea esenial fa de variabilele automatice. n cazul n care o
variabil static este declarat n afara funciilor, ea este definit din
punctul n care a fost declarat i pn la sfritul fiierului surs care
conine declaraia ei. Spre deosebire de variabilele globale, o variabil
static nu poate fi declarat ca extern i deci nu poate fi utilizat n
funciile din alte fiiere surs diferite de cel n care a fost declarat.
Se recomand ca tablourile mari s fie declarate statice, deoarece dac
sunt automatice pot depi capacitatea stivei (care are implicit 4K octei).
Exemple:
Fiierul fisier1.c este un fiier surs care conine 2 variabile globale i
i d , o variabil static x i dou funcii f i main. Funcia main conine
variabila static a iar funcia f conine variabila static b.
int i;
double d;
static int x;
fisierului fisier1.c

// definiia variabilei globale i


// definiia variabilei globale d
//
definiia
variabilei
statice

x,

locala

void main (void)


{ static char a; // definiia variabilei statice a, locala funciei main
float c;
// definiia variabilei automatice c, locala funciei main
/* in acest moment se pot folosi variabilele i,d,x,a si c */
. . .
}
{ int p;
// definiia variabilei automatice p, locala funciei f
static float b; // definiia variabilei statice b, locala funciei f
/* in acest moment se pot folosi variabilele i,d,x, p si b */
. . .
}
Variabilele a i c fiind locale funciei main nu pot fi utilizate n
funcia f. Analog, variabilele p i b sunt locale n funcia f, nu pot fi
utilizate n funcia main.
Fiierul fisier2.c conine funciile f1 i f2 care intr n componena
aceluiai program ca i funciile main i f din fiierul fisier1.c
static unsigned t; // definitia variabilei statice t, locala fisierului
fisier2.c
void f1(...)
{ extern int i;
// declaratie externa pentru i
extern double d;
// declaratie externa pentru d
static int k;
// definitia variabilei statice k, locala functiei f1
/* in acest moment se pot folosi varibilele i,d, k si t */
. . .
}
void f2(...)
{ extern int i;
// declaratie externa pentru i
static double s; // definitia variabilei statice s, locala functiei f2
/* se pot folosi variabilele i, s si t */
. . .
}
Variabila static x definit n fiierul fisier1.c nu poate fi
utilizat n fiierul fisier2.c. De asemenea, variabila static t nu poate fi
utilizat n fiierul fisier1.c. Variabila global d nu poate fi utilizat n
funcia f2, ea nefiind declarat ca i extern.
- 10 -

BORLAND C Manual de utilizare

Observaii:
1o. Variabilele globale constituie un mijloc simplu de interfa ntre
funciile unui program. Se recomand a fi folosite cnd dorim transferuri de
valori ntre dou sau mai multe funcii n aa fel nct modificrile realizate
de o funcie s fie accesibile pentru toate funciile programului. Nu trebuie s
se fac abuz n utilizarea variabilelor globale deoarece constituie i o surs
potenial de erori, pentru c accesul unui mare numr de funcii la anumite
date globale conduce deseori la modificri nedorite i greu evideniabile.
2o. Funciile sunt considerate cu atributul implicit extern. Dac ntr-un
program exist mai multe fiiere surs atunci o funcie poate fi apelat
oriunde, bine neles respectnd convenia definirii ei sau a prototipului ei
nainte de a fi folosit. Putem s limitm definind funciile cu atributul
static precednd antetul funciei prin cuvntul cheie static. Astfel funcia
respectiv devine local i deci apelabil doar n fiierul n care este
definit.
2.4. INIIALIZARE
Variabilelor li se pot atribui valori iniiale. Pentru variabilele globale
valorile iniiale se atribuie prin definiiile lor, iar n cazul celorlalte
variabile se pot atribui valori prin declaraiile lor. Pentru c de multe ori am
folosit cuvintele definiia variabilelor sau declaraiile varibilelor precizm
c ele au neles distinct n anumite contexte. O variabil global se definete
o singur dat i se poate declara ori de cte ori e necesar utilizarea ei n
alte fiiere (evident declarat extern). n cazul celorlalte tipuri de
variabile definiiile i declaraiile coincid. Totodat definiia i declaraia
(prototipul) unei funcii nu coincid.
O variabil simpl se poate iniializa printr-o declaraie de forma:
tip nume=expresie;
Variabilelor globale i statice li se atribuie valori iniiale la lansarea
programului. Expresia utilizat n cazul acestor variabile trebuie s fie o
expresie constant care s poat fi evaluat de compilator la ntlnirea ei.
Aceasta, deoarece variabilele globale i statice se iniializeaz prin valori
definite la compilare.
Variabilele automatice se iniializeaz la execuie, de fiecare dat
cnd se activeaz funcia n care sunt declarate. Din aceast cauz, nu mai este
necesar ca expresia s fie o expresie constant. Totui, la ntlnirea ei,
trebuie s fie definii operanzii expresiei de iniializare.
Exemplu:
void f(int n)
{ int i=10;
int k=i+n;
. . .
}
La ntlnirea expresiei i+n sunt deja definii ambii operanzi:
i a fost n prealabil iniializat cu valoarea 10;
n are o valoare care e transferat la apel.
Variabilele globale i statice neiniializate au implicit valoarea egal
cu zero, iar varibilele automatice neiniializate au o valoare iniial
imprevizibil.
Tablourile se pot iniializa printr-o list de expresii incluse
ntre acolade. Astfel un tablou unidimensional se poate iniializa folosind
urmtorul format:
tip nume[n] = { exp1, exp2, . . . expn }
La iniializarea tablourilor se pot utiliza numai expresii constante.
Numrul expresiilor poate fi mai mic dect numrul elementelor tabloului.
Elementele neiniializate au valoarea zero n cazul tablourilor globale i
statice. Dac se iniializeaz fiecare element al tabloului atunci numrul n al
elementelor acestuia nu mai este obligatoriu n declaraia tabloului respectiv.
Deci se poate scrie astfel:
tip nume[ ] = { exp1, exp2, . . . expn};
- 11 -

BORLAND C Manual de utilizare

Numrul elementelor tabloului se consider c este egal cu


expresiilor care realizeaz iniializarea lor.
Pentru un tablou bidimensional vom folosi urmtoarea structur:

cel

al

tip nume [n][m] = { {exp11, exp12, . . . exp1m}, // pentru linia nti


{exp21, exp22, . . . exp2m}, // pentru linia a doua
. . .
{expn1, expn2, . . . expnm}, // pentru ultima linie
};
Numrul expresiilor poate fi mai mic dect m n oricare din acoladele
corespunztoare celor n linii ale tabloului bidimensional. n acest caz se poate
omite doar numrul n (al liniilor tablourilor), m fiind obligatoriu. Formatul de
iniializare a tablourilor bidimensionale se extinde imediat pentru tablouri cu
mai multe dimensiuni.
Tablourile de tip caracter pot fi iniializate folosind un format mai
simplu dect cel indicat anterior. Astfel. un tablou de tip caracter se poate
iniializa printr-o declaraie de forma:
char sir[n] = ir_de_caractere;
Evident, marginea superioar n poate fi omis i n acest caz. Totodat
compilatorul pune automat caracterul NUL dup ultimul caracter al irului
utilizat n iniializare.
Exemple:
1)int itab[] = {1,2,3,4,5}
itab[0] = 1,. . . itab[4] = 5

//

tabloul

de

tip

intreg

are

elemente

2)int m[3][3] = {{-1,0,1},{-1},{0,1}};// tabloul are 3 linii si 3 coloane.


Elementele primei linii sunt iniializate astfel:
m[0][0] = 1;
m[0][1] = 0;
m[0][2] = 1;
n linia a doua se iniializeaz numai m[1][0] = -1; Dac tabloul ar fi
declarat global sau static atunci m[1][1] i m[1][2] ar avea valoarea zero.
Altfel ele au o valoare imprevizibil.
Elementele ultimei linii se iniializeaz astfel:
m[2][0] = 0;
m[2][1] = 1;
declaraiile de mai jos sunt identice:
char sir [ ] = {L,I,M,B,A,J,U,L, ,C};
char sir [ ] = {LIMBAJUL C};

- 12 -

BORLAND C Manual de utilizare

LECIA 3.
EXPRESII, OPERANZI, OPERATORI
3.1. EXPRESII
O expresie n limbajul C este format fie dintr-un operand fie din mai
muli operanzi legai ntre ei prin operatori. O expresie are o valoare i un
tip
care
se
determin
aplicnd
operatorii
conform
prioritilor
i
asociativitii acestora.
n limbajul C operatorii se asociaz de la stnga la dreapta, exceptnd
operatorii unari i de atribuire, care se asociaz de la dreapta la stnga..
Totodat pot fi folosite parantezele rotunde pentru a impune o anumit ordine n
executarea operaiilor.
3.2. OPERANZI
Un operand n limbajul C poate fi una din urmtoarele elemente:
o constant;
o constant simbolic;
numele unei variabile simple;
numele unui tablou;
numele unei structuri;
numele unei funcii;
referirea la elementul unui tablou (variabil cu indici);
referirea la elementul unei structuri;
apelul unei funcii;
o expresie inclus n paranteze rotunde.
Unele dintre elementele de mai sus nu au fost nc definite, ele se vor
prezenta n leciile viitoare.
Exemple:
9876
- constant ntreag;
x
- variabil simpl;
t[i][3]
- variabil cu indici;
0xabcd
- constant hexazecimal;
t
- nume de tablou;
expresie)
- expresie inclus n paranteze rotunde.
f1
- numele unei funcii
3.3. OPERATORI
Operatorii limbajului C pot fi grupai n mai multe clase, dar oricum ei
pot fi folosii mpreun ntr-o aceeai expresie. Operatorii au ariti
diferite: unari, binari, ternari i totodat o anumit prioritate implicit care
e redat n tabelul de mai jos. Operatorii de aceeai prioritate se afl trecui
n aceeai linie. Liniile tabelulul conin operatorii limbajului C n ordinea
descresctoare a prioritilor. Astfel n prima linie se afl operatorii de
prioritate maxim, iar n ultima linie operatorul virgul cu prioritatea cea mai
mic. Cu excepia operatorilor ., ->,&,*, a parantezelor rotunde
(folosite la definiia i apelul funciilor) i a parantezelor drepte (folosite
la variabilele cu indici) ceilali operatori vor fi explicai n aceast lecie.
( ) [ ] . ->
- (unar) +(unar) *(unar) &(unar) ! ~ ++ -- (tip) sizeof
* / %
+ << >>
< <= >= >
= = !=
&
^
|
&&
| |
? : (ternar)
= op= op poate fi: *(binar) / % +(binar) (binar) << >> & ^ |
,
- 13 -

BORLAND C Manual de utilizare

3.3.1. Operatori aritmetici


Lista operatorilor aritmetici este redat mai jos:
- (minus unar);
+ (plus unar);
* / % operatori binari multiplicativi; (nmulire, mprire, restul
mpririi ntregi);
+ - operatori binari aditivi (adunare i scdere).
Operatorii de pe aceeai linie au aceeai prioritate. Cei unari au
prioritate mai mare dect cei binari. Operatorii multiplicativi au prioritate
mai mare dect cei aditivi.
Exemple:
int i,j,k;
float x,y;
double t[10];
// se dau cateva exemple de expresii folosind operatorii aritmetici
i*x+t[5];
-y+k;
i%j;
// daca i=9 si j=4 atunci i%j are valoarea 1
i/j;
// daca i=9 si j=4 atunci i/j are valoarea 2
x*-y;
// - este operatorul unar deci avem x*(-y)
3.3.2. Operatori relaionali
Lista operatorilor relaionali este redat astfel:
<
(mai mic)
<=
(mai mic sau egal; cele dou caractere ce compun operatorul sunt
concatenate)
>
(mai mare)
>=
(mai mare sau egal; cele dou caractere ce compun operatorul sunt
concatenate)
Toi operatorii relaionali au aceeai prioritate. Ea este mai mic dect
prioritatea operatorilor aditivi. Rezultatul aplicrii unui operator relaional
este 1 sau 0, dup cum operanzii se afl n relaia definit de operatorul
respectiv sau nu.
Exemple:
a= 4 i b= -5
atunci
a>0
are valoarea 1;
a<=0
are valoarea 0;
a+b>0
are valoarea 0;
a>=b
are valoarea 1;
a<0
are valoarea 1;
a+b>=b-a
are valoarea 1;
a+b<=(b-a)*(b-a) are valoarea 0;
3.3.3. Operatori de egalitate
Lista operatorilor de egalitate este redat mai jos:
= = (egal; dou semne = concatenate)
!= (diferit; semnele sunt concatenate).
Operatorii de egalitate au ambii aceeai prioritate i este imediat mai
mic dect a operatorilor relaionali. Operatorul = = testeaz egalitatea a
doi operanzi. Dac operanzii sunt egali atunci rezultatul operaiei = = este
1, n caz contrar este 0. Operatorul != furnizeaz rezultatul 1 cnd cei doi
operanzi sunt diferii i 0 cnd sunt egali.
Exemple:
a= 2 i b=-1
atunci
a==b
are valoarea 0;
a!=b
are valoarea 1;
a*b!=a+b
are valoarea 1;
3.3.4. Operatori logici
Lista operatorilor logici este redat mai jos:
!
(negaia logic - operator unar);
&&
(I logic);
||
(SAU logic).
- 14 -

BORLAND C Manual de utilizare

Operatorul ! are aceeai prioritate cu operatorii unari + i -.


Operatorul && este mai prioritar dect operatorul ||, dar are o prioritate
mai mic dect operatorii de egalitate.
n limbajul C nu exist valori logice speciale. Valoarea fals se
reprezint prin zero. Orice valoare diferit de zero reprezint valoarea
adevrat.
Dac operatorul ! se aplic la un operand a crui valoare este zero,
atunci rezultatul este 1. Dac acelai operator se aplic la un operand a crui
valoare este diferit de zero, atunci rezultatul este 0.
Chiar dac pentru sau exclusiv nu exist operator el se poate realiza
prin expresia urmtoare aplicat operanzilor a i b: !a&&b||!b&&a sau folosind
parantezele rotunde ((!a) &&b)||((!b)&&a).
Operatorii logici se evalueaz de la stnga la dreapta. Dac la evaluarea
unei expresii se ajunge ntr-un punct n care se cunoate valoarea ntregii
expresii, atunci restul expresiei nu se mai evalueaz.
Dac a=0 i b=1 atunci expresia ! a||b are valoarea 1 pentru c !a are
deja valoarea 1.
3.3.5. Operatori logici pe bii
Lista operatorilor logici pe bii este redat mai jos n ordinea
descrectoare a prioritilor:
~
(operator unar; complement fa de 1)
>> <<
(deplasri la dreapta, respectiv la stnga)
&
(I pe bii)
^
(SAU-EXCLUSIV pe bii)
|
(SAU pe bii)
Operatorul ~, fiind unar, are aceeai prioritate ca i ceilali
operatori unari ai limbajului C. El schimb fiecare bit 1 al operandului n 0 i
invers.
Operatorul >> realizeaz deplasarea la dreapta care este echivalent cu
o mprire ntreag cu puteri a lui 2; a >> 3 este echivalent cu [a/23].
Operatorul << realizeaz deplasarea la stnga care este echivalent cu o
nmulire cu puteri a lui 2; a << 3 este echivalent cu a*8.
Observaii:
1o.Operanzii care nu ocup un cuvnt (16 bii) se extind la un cuvnt. De
exemplu expresia ~0 are ca rezultat un cuvnt cu toi bii egali cu 1.
2o.Operatorii logici pe bii se execut bit cu bit spre deosebire de
operatorii logici care se evalueaz global. De exemplu dac x=2 i y=1 sunt
variabile de tip int atunci:
x&&y are valoarea 1 pentru c ambii operanzi sunt diferii de 0.
x&y are valoarea 0 conform schemei de mai jos
0000 0000 0000 0010
0000 0000 0000 0001
&
0000 0000 0000 0000
3o.Operatorul & se folosete frecvent pentru a anula bii din
configuraia unui cuvnt, iar operatorul | pentru a seta (pune) bii ntr-un
anumit mod;
4o. Operanzii trebuie s fie ntregi (de tipul int sau long).
5o. Atenie la deplasri nu se modific valoarea operandului; deci trebuie
s facem o atribuire; de exemplu a = a << 3 va modifica valoarea lui a pe cnd a
<< 3 nu modific valoarea lui a.
Exemple:
Fie declaraia:
int i;
atunci expresia i >> 8 & 255 are ca rezultat valoarea celui mai
semnificativ octet a lui i; i >> 8 deplaseaz octetul mai semnificativ al lui i
n poziia mai puin semnificativ; se face apoi un I logic pe bii cu masca
255 care pstreaz octetul mai puin semnificativ.
2) Fie expresia: (x >> 6) & ~(~ 0 << 3)
S presupunem c x are valoarea n bii 1010 1011 1000 1101.
Atunci x>>6 are valoarea
1111 1110 1010 1110
Al doilea operand pregtete o masc astfel:
- 15 -

BORLAND C Manual de utilizare

~0
~0<<3
~(~0<<3)

1111 1111 1111 1111


1111 1111 1111 1000
0000 0000 0000 0110

Rezultatul final este dat de:


0000 0000 0000 0111
1111 1110 1010 1110
0000 0000 0000 0110
Practic s-a obinut valoarea biilor 8,7,6 a lui x (numerotai de la
dreapta la stnga ncepnd cu 0).
3.3.6. Operatori de atribuire
n forma cea mai simpl operatorul de atribuire se noteaz cu = i se
utilizeaz n construcii de forma:
v=expresie;
(v este fie o variabil simpl, fie variabil cu indici sau un element de
structur).
Aceast construcie se mai numete expresie de atribuire. Ea este
considerat ca fiind un caz particular de expresie. Tipul ei coincide cu tipul
lui v, iar valoarea ntregii expresii este chiar valoarea atribuit lui v.
O expresie de forma:
v1=(v=expresie);
este i ea legal i se efectueaz n felul urmtor :
se evalueaz expresia expresie i valoarea ei se atribuie lui v;
valoarea lui v se atribuie apoi i lui v1.
Deoarece operatorii de atribuire se asociaz de la dreapta la stnga,
expresia de mai sus se poate scrie i fr paranteze:
v1=v=expresie;
n general, putem realiza atribuiri multiple printr-o expresie de forma:
vn =. . . =v1=v=expresie
Dac expresia din dreapta semnului egal are un tip diferit de cel al
variabilei v, atunci nti valoarea ei se convertete spre tipul variabilei v i
pe urm se realizeaz atribuirea,
Pentru operaia de atribuire, n afara semnului egal se mai poate folosi
i succesiunea :
op=
unde prin op se nelege unul din operatorii binari aritmetici sau logici
pe bii, adic unul din urmtorii:
% / * - + & ^ | << >>
Acest mod de construcie se folosete pentru a compacta un anumit tip de
atribuire. Astfel expresia:
v op = expresie;
este identic cu expresia de atribuire:
v = op expresie;
Exemple:
int i, j;
double x, y;
int v[10];
i=5;
j=10;
x=y=10.01;
i +=1;
// echivalenta cu i=i+1 si cu i++
x*=3;
// echivalenta cu x=x*3
j<<=10;
// echivalenta cu j=j<<10
v[i]*=i
// echivalenta cu v[i]=v[i]*i
x /= x-y
// echivalenta cu x = x/(x-y)

- 16 -

BORLAND C Manual de utilizare

3.3.7. Operatori de incrementare i decrementare


Aceti operatori sunt unari i au aceeai prioritate cu ceilali operatori
unari ai limbajului C. Operatorul de incrementare se noteaz prin ++ i
mrete valoarea operandului cu unu, iar operatorul de decrementare se noteaz
prin - - i micoreaz valoarea operandului cu unu. Operatorii sunt folosii
prefixat i postfixat. Astfel operatorii prefixai au notaia:
++operand;
- - operand;
Ei se aplic mai nti i apoi se folosete valoarea lor.
Astfel operatorii postfixai au notaia:
operand++;
operand - -;
Se folosete valoarea operanzilor i apoi se aplic incrementarea sau
decrementarea.
Menionm c aceti operatori se pot aplica numai la urmtorii operanzi:
variabil simpl;
variabil cu indici;
referire la elementul unei structuri.
Exemple:
int i,j;
double x,y;
int vector [5];
j=i++;
// este echivalent cu j=i si i=i+1;
y=--x;
// este echivalent cu x=x-1 si y=x;
i=++vector[j]
// este echivalent cu vector[j]=vector[j]+1 si
i=vector[j]
3.3.8. Operatorul de conversie explicit (expresie cast)
Pentru forarea tipului unui operand se folosete o construcie de forma:
(tip) operand
Prin aceasta valoarea operandului se convertete spre tipul indicat n
paranteze.
Exemplu:
int i,j;
double y;
i=8; j=5;
y=i/j;// y are valoarea 1, pentru ca se face impartirea intreaga i/j
Dac vom converti operanzii i i j spre tipul double se va obine
rezultatul corect adic 1.6.
Deci:
int i,j;
double y;
i=8; j=5;
y=(double) i / (double) j;
// y are valoarea 1.6,
Construcia (tip) este un operator unar prin care se expliciteaz
conversia dorit. Are aceeai prioritate ca restul operatorilor unari.
3.3.9. Operatorul dimensiune (sizeof)
Pentru a determina lungimea n octei
construcia:

unei

sizeof (data)
unde data poate fi:
numele unei variabile simple;
numele unui tablou;
numele unei structuri;
numele unui tip;
referirea la elementul unui tablou sau structur.
- 17 -

date

se

poate

folosi

BORLAND C Manual de utilizare

Exemple:
int i;
long l;
float f;
double d;
char c;
int itablou[5];
double dtablou[5];
sizeof (i)
//
sizeof (l)
//
sizeof (f)
//
sizeof (d)
//
sizeof (c)
//
sizeof (itablou[1])
sizeof (dtablou[1])
sizeof (itablou)
sizeof (dtablou)

are
are
are
are
are

valoarea 2;
valoarea 4;
valoarea 4;
valoarea 8;
valoarea 1;
// are valoarea
// are valoarea
// are valoarea
// are valoarea

2;
8;
10;
40;

Regula conversiilor implicite


n general o expresie C conine operanzi de tipuri diferite. Pentru
operatorii binari exist situaii cnd operanzii nu sunt de acelai tip i
trebuie executate conversii astfel nct operatorii s se aplice pentru operanzi
de acelai tip. Aceste conversii le face automat compilatorul. Exist o regul a
conversiilor implicite care are urmtorii pai:
fiecare operand de tip char se convertete spre tipul int i fiecare
operand de tipul float se convertete spre double;
dac unul dintre operanzi este de tip double atunci i cellalt se
convertete spre tipul double i rezultatul va avea tipul double;
dac unul dintre operanzi este de tip long, atunci i cellalt se
convertete spre tipul long i rezultatul va avea tipul long;
dac unul dintre operanzi este de tip unsigned, atunci i cellalt se
convertete spre tipul unsigned i rezultatul va fi de tipul unsigned;
la acest pas se ajunge numai dac ambii operanzi sunt de tip int i
deci operaia se execut cu operanzii respectivi, iar rezultatul va fi
de tip int.
Aplicnd regula de mai sus pas cu pas (la fiecare operator n momentul
efecturii lui), se ajunge n final la evaluarea ntregii expresii i prin
acesta se determin tipul expresiei. Regula conversiilor implicite nu se aplic
pentru operatorul de atribuire (valoarea expresiei din partea dreapt a semnului
de atribuire se convertete spre tipul variabilei din stnga semnului egal).
Exemple:
int i, j, k;
float a, b;
double x, y;
unsigned p;
long r;
char c;
expresii
conversii
tipul expresiei
i-j/k nu
a/b
x+y
i+a
i-3.14
i+3
i+x
i-c
x+10
p-10
r*5
(double)(i/j)

int
a spre double
b spre double
double
nu
double
a spre double
i spre double
i spre double
double
nu
int
i spre double
double
c spre int
int
10 spre double
double
10 spre unsigned
unsigned
5 spre long
long
se realizeaz mprirea ntreag ntre
i i j i rezultatul se convertete spre double double
- 18 -

BORLAND C Manual de utilizare

Dac rezultatul unei operaii depete domeniul de valori ce corespunde


tipului rezultatului, valoarea respectiv se trunchiaz i rezultatul este
eronat.
3.3.11. Operatori condiionali
Operatorii condiionali sunt ? i : i se folosesc mpreun n construcii
de forma:
exp1 ? exp2 : exp3
Evaluarea se face astfel:
se evalueaz expresia exp1;
dac exp1 este diferit de zero, atunci valoarea i tipul expresiei
condiionale sunt egale cu valoarea i tipul expresiei exp 2; altfel cu expresia
exp3.
Exemplu: procesul de determinare a maximului a dou numere a i b este:
dac a>b
atunci
max=a
altfel
max=b
sfdac
n limbajul C se poate realiza acest proces cu ajutorul operatorilor
condiionali astfel:
max= a>b ? a : b
Dac a>b atunci expresia condiional are valoarea i tipul lui a altfel
expresia condiional are valoarea i tipul lui b.
Operatorul virgul
Operatorul , este folosit pentru gruparea mai multor expresii ntr-una
singur.
Cu ajutorul acestui operator (care are prioritatea cea mai mic) se
construiesc expresii de forma:
exp1, exp2,. . ., expn
Aceast expresie are valoarea i tipul ultimei expresii (deci a lui expn).
Exemplu:
k= (i=10, j=j+5; i+j)
Se execut pe rnd cele dou atribuiri de la stnga la dreapta din
parantezele rotunde apoi se face suma i+j i n final se atribuie aceast sum
lui k,

- 19 -

BORLAND C Manual de utilizare

- 20 -

BORLAND C Manual de utilizare

LECIA 4.
INTRRI / IEIRI STANDARD
Limbajul C nu posed instruciuni de intrare / ieire. Aceste operaii se
realizeaz prin apeluri de funcii din bibliotecile standard ale mediului de
programare. De obicei astfel de funcii asigur interfaa programului cu
terminalul de la care s-a lansat, cu imprimanta, etc. Se numesc intrri standard
i ieiri standard intrrile respectiv ieirile de la terminalul de la care s-a
lansat programul. Totodat se presupune c datele de intrare / ieire sunt
organizate n fiiere.
Unui program C i se ataeaz n mod implicit urmtoarele fiiere:
-

stdin
stdout
stderr
stdprn
stdaux

intrare standard;
ieire standard;
ieire standard pentru erori;
ieire pe imprimant;
intrare / ieire serial.

4.1. FUNCIA STANDARD printf


Funcia printf realizeaz ieiri cu format la ieirea standard stdout,
deci afiare la terminalul la care care s-a lansat programul. Funcia printf se
apeleaz printr-o instruciune cu formatul:
int printf (control, lista_expresii);
unde control este un ir de caractere care conine:
texte de scris;
specificatori de format pentru datele care se scriu din lista_expresii.
lista_expresii conine expresii; valoarea fiecrei expresii se scrie
conform unui specificator de format corespondent din parametrul control.
Parametrul
control
este
inclus
ntre
ghilimele,
iar
numrul
specificatorilor de format coincide cu numrul expresiilor din lista_expresii.
Dac dorim s scriem numai un text atunci parametrul de control nu conine nici
un specificator de format iar lista_expresii este vid (practic este absent).
Un specificator de format are formatul BNF urmtor:
%[-][d..d][.d..d][l1]l2
Dup cum se observ un specificator de format ncepe ntotdeauna cu
caracterul procent (%). Dup acest caracter poate urma una din construciile
urmtoare:
- un caracter - opional; prezena acestui caracter indic cadrarea la
stnga a datei n cmpul n care se scrie (implicit data se scrie cadrat la
dreapta);
-un ir de cifre zecimale opional, care definete lungimea minim a
cmpului n care se scrie data corespunztoare din lista_expresii; data se scrie
astfel:
n cazul n care necesit o lungime mai mic se scrie cadrat la dreapta
sau stnga (n funcie de absena sau prezena semnului -)
n cazul n care necesit o lungime mai mare se va scrie pe attea poziii
cte i sunt necesare;
-un punct urmat de un ir de cifre zecimale (dup cum se observ
opional); acest element indic precizia datei care se scrie:
dac data se scrie n virgul flotant, precizia definete numrul de
cifre aflate dup marca zecimal (deci cte zecimale);
dac data este un ir de caractere atunci indic cte caractere se scriu.
-una sau dou litere, care definesc tipul de conversie din formatul intern
n formatul extern:
prima litera poate fi l, ceea ce semnific conversia din formatul intern
long n formatul extern definit de specificator;
a doua liter este obligatorie ntotdeauna i are semnificaiile de mai
jos:
- 21 -

BORLAND C Manual de utilizare

litera
tipul de conversie realizat
d
- din int intern n zecimal extern
o
- din int intern n octal extern
x
- din int intern n hexazecimal extern (litere mici pentru
cifrele mai mari ca 9 deci a,b,c,d,e,f,)
X
- din int intern n hexazecimal extern (litere mici pentru
cifrele mai mari ca 9 deci A,B,C,D,E,F)
u
- din unsigned intern n zecimal extern fr semn
c
- din binar intern (cod ASCII) n caracterul corespunztor
s
- din ir de coduri ASCII ntr-un ir de caractere (atenie
ultimul cod este NUL (adic \0)
f
- din float sau double intern n d...d.d...d (implicit 6 cifre
zecimale la partea fracionar dac nu e prezent precizia)
e
- din float sau double intern n d.d...deddd (implicit 6
cifre zecimale la partea fracionar dac nu e prezent precizia)
E
- din float sau double intern n d.d...dEddd (implicit 6
cifre zecimale la partea fracionar dac nu e prezent precizia)
g
- se aplic una din conversiile definite de literele f i e
alegndu-se aceea care are un numr minim de poziii
G
- se aplic una din conversiile definite de literele f i E
alegndu-se aceea care are un numr minim de poziii
Literele d, o, x, u pot fi precedate de litera l conversia
realizndu-se din formatul intern long n loc de int.
Observaie.
1o. Dac caracterul % nu este urmat de una din construciile de mai sus
atunci nu reprezint un specificator de format.
Funcia printf ntoarce lungimea total n octei a datelor scrise
la terminal sau valoarea simbolic EOF n caz de eroare. Precizm c EOF este
definit n fiierul header stdio.h astfel:
#define EOF 1.
Totodat funcia printf poate fi testat i astfel:
EOF= = printf (control, lista_expresii)
Dac are valoarea adevrat atunci la scrierea datelor s-a produs o eroare.
Exemple:
1)
#include<stdio.h>
#include<math.h>
void main(void)
{ int i=10; long j=11;
float a=1.2, b=1.3;
double A=1.4; B=1.5;
clrscr();
// inceputul instructiunilor executabile; se sterge ecranul
printf ("\ni*j = %d",i*j);
// incep afisarile
printf ("\ni*j = %5d",i*j);
printf ("\ni*j = %-5d",i*j);
printf ("\ni*j = %5.5d",i*j);
printf ("\ni*j = %05d",i*j);
printf ("\na*b = %10.1f",a*b);
printf ("\nA*B = %10.5lf",A*B);
printf ("\nradical(a*b) = %lf",sqrt((double) a*b));
printf ("\nradical(A*B) = %15.10lf",sqrt(A*B));
printf ("\nradical(A*B) = %25.17lf",sqrt(A*B));
printf ("\nradical(A*B) = %25.19lf",sqrt(A*B));
getche(); // asteapta citirea unui caracter de la terminal
}
Rezultatele execuiei programului sunt:
i*j = 110
i*j = 00110
i*j = 110
a*b = 1.6
i*j = 110
A*B = 2.10000
i*j = 00110
radical(a*b) = 1.249000
- 22 -

BORLAND C Manual de utilizare

radical(A*B) = 1.4491376746
radical(A*B) = 1.44913767461894372
2)
#define sir PC WORLD
void main (void)
{ printf(*%10s*,sir);
printf(*%-10s*,sir);
printf(*%10.5s*,sir);
printf(*%-10.5s*,sir);
}
Rezultatele execuiei programului sunt:
* PC WORLD*
*PC WORLD *
* PC WO*
*PC WO *

radical(A*B) = 1.4491376746189437200

4.2. FUNCIA STANDARD scanf


Funcia de bibliotec scanf realizeaz intrri cu format de la intrarea
standard stdin (intrare de la terminalul de la care s-a lansat programul) i
poate fi apelat printr-o instruciune de apel de forma:
scanf (control, lista_adrese);
Ca i n cazul funciei printf, parametrul control este delimitat de
ghilimele i poate conine texte i specificatori de format. Caracterele albe
din parametrul control sunt neglijate. Celelalte caractere care nu fac parte
dintr-un specificator de format, trebuie s existe la intrare n poziii
corespunztoare. Ele se folosesc n scopul realizrii unor verificri asupra
datelor care se citesc.
Un specificator de format ncepe i n acest caz prin caracterul
procent, apoi:
un caracter * opional;
un ir de cifre, opional, care definete lungimea maxim a cmpului din
care se citete data de sub controlul specificatorului de format;
una sau dou litere care definesc tipul conversiei din formatul extern n
formatul intern.
Cmpul controlat de un specificator de format ncepe cu primul caracter
care nu este alb i se termin:
fie la caracterul dup care urmeaz un caracter alb;
fie la caracterul dup care urmeaz un caracter care nu corespunde
specificatorului de format care controleaz acel cmp;
fie la caracterul prin care se ajunge la lungimea maxim indicat n
specificatorul de format.
Condiia c) este absent n definirea cmpului dac n specificatorul de
format nu este indicat lungimea maxim a cmpului.
Literele care termin un specificator de format sunt asemntoare cu
cele utilizate la funcia printf. n acest caz este realizat conversia invers
fa de cea realizat de funcia printf.
Litera
Tipul conversiei realizate
d - data din cmpul de intrare este un ir de cifre zecimale, precedat
eventual de un semn i se convertete din zecimal extern n binar de tip int
o - ca i n cazul literei d, dar din octal extern n binar de tip int.
x - ca i n cazul literei d, dar din hexazecimal extern n binar de tip
int; se utilizeaz literele mici a-f sau mari A-F pentru cifrele mai mari ca 9.
X - ca i n cazul literei x;
u - data este un ir de cifre zecimale care formeaz un numr ntreg fr
semn i se convertete din zecimal extern n binar tipul unsigned.
c - data se consider format din caracterul curent de la intrare i
parametrului corespunztor i se atribuie codul ASCII al acestui caracter; n
acest caz nu se face avans peste caracterele albe, ca i n cazul celorlali
specificatori.
s - data se consider c este ir de caractere; irul ncepe, conform
regulii generale, cu primul caracter care nu este alb i se termin la
caracterul dup care urmeaz un caracter alb sau cnd s-au citit attea
caractere cte indic dimensiunea maxim din specificatorul de format;
- 23 -

BORLAND C Manual de utilizare

f - data de intrare reprezint un numr flotant; deci conversie din


flotant extern n virgul flotant simpl precizie; data care se citete conine
un punct sau un exponent, sau att punct ct i exponent.
Literele d, o, x i u pot fi precedate de litera l i n acest caz
conversia se realizeaz spre long, n loc de int.
De asemenea, litera f va fi precedat de litera l pentru a face conversii
spre formatul virgul flotant dubl precizie.
Lista_adrese conine adresele zonelor receptoare ale datelor citite prin
intermediul funciei scanf. Fiecare dintre parametri reprezint adresa unei zone
receptoare sub forma:
&nume
Ea determin adresa zonei de memorie rezervat variabilei nume. Caracterul
& din construcia de mai sus reprezint un operator unar, numit operatorul
adres. El are aceeai prioritate ca i ceilali operatori unari din limbajul C.
Exemplu:
void main (void)
{ int i;
long n;
float x;
scanf ( %d %ld %f ,&i,&n,&x);
// citeste datele din stdin si le
atribuie lui i,n,x.
scanf( %d %*ld %f , &i,&x);
// caracterul * indica faptul ca
valoarea pentru variabila n nu se citeste
}
Funcia scanf returneaz numrul de cmpuri citite corect din fiierul
stdin. Dac apare o eroare la citire (din diverse motive de exemplu
neconcordan dintre specificatorul de format i datele din fiierul stdin)
atunci funcia nu va returna numrul total de cmpuri; citirea se va ntrerupe
n locul detectrii erorii i scanf va returna numrul de cmpuri citite pn n
acel moment. Deci de multe ori pentru a valida formal intrarea datelor (atenie
nu e o validare calitativ) se va folosi o construcie de forma:
nr=scanf(...)
Prin construcia de mai sus se poate pune n eviden sfritul de fiier,
deoarece n acest caz scanf returneaz valoarea EOF. Sfritul de fiier se
poate genera de la tastatur acionnd n acelai timp tastele CTRL i Z (deci
CTRL / Z). Deorece funcia scanf citete datele de la intrarea standard prin
intermediul unei zone de memorie intermediare (numit zon tampon sau buffer),
ea are acces la caracterele din zona tampon numai dup acionarea tastei ENTER
(RETURN). De aceea dup acionarea combinaiei CTRL / Z se va tasta i ENTER.
Totodat aceast intermediere face posibil eventuale corecturi nainte de a
aciona tasta ENTER.
Exemplu:
Vom citi un ntreg de cinci cifre de la intrarea standard i vom afia
cifrele respective precedate fiecare de dou spaii.
void main (void)
{ int c1,c2,c3,c4,c5;
// c1,c2,c3,c4,c5 sunt cifrele intregului citit
scanf(%1d %1d %1d %1d %1d, &c1,&c2,&c3,&c4,&c5);
// se citesc cifrele intregului in cele 5 variabile cu %1d
printf(%3d%3d%3d%3d%3d,c1,c2,c3,c4,c5);
}
Pentru a citi iruri de caractere se va folosi funcia scanf fr a mai
pune operatorul de adres n faa numelui irului de caractere, deoarece numele
unui tablou reprezint un pointer (deci conine o adres i anume adresa
primului element de tablou).

- 24 -

BORLAND C Manual de utilizare

Exemplu:
Vom citi numele i prenumele unei persoane i le afim pe ecran.
#define MAX 20
void main(void)
{ char nume[MAX+1], prenume[MAX+1]; //declararea tablourilor de caractere
scanf (%20s %20s,nume, prenume); //nu s-a mai pus operatorul de adresa
printf (\nnumele: %s, prenumele: %s,nume,prenume);
}
4.3. FUNCIA STANDARD putchar
Funcia standard putchar se poate utiliza pentru a scrie un caracter n
fiierul standard de ieire stdout, n poziia curent a cursorului. Ea se
apeleaz folosind o instruciune de apel de forma:
putchar (expresie);
unde expresie este codul ASCII al caracterului care se scrie la ieirea
standard.
Practic putchar nu este o funcie n sensul definiiei ce am dat-o
n lecia 1, ci este un macrou definit n fiierul header stdio.h, care
folosete o funcie special destinat prelucrrii fiierelor, funcia putc,
astfel:
#define putchar(c) putc(c,stdout)
Exemplu:
void main (void)
{ putchar (A); // scrie caracterul A in fisierul de iesire in poziia
curenta a cursorului
putchar (A+2) // scrie caracterul de cod ASCII A+2=65+2=67, adica
litera C
putchar (\n); // scrie caracterul newline; deci inceput de linie nou
}
4.4. FUNCIA STANDARD getchar
Aceast funcie citete de la intrarea standard, stdin, caracterul curent
i returneaz codul ASCII al caracterului citit. Tipul valorii returnate este
int. La ntlnirea sfritului de fiier (CTRL/Z) se returneaz valoarea EOF
(adic -1). Ca i putchar, getchar este un macrou definit n fiierul header
stdio.h, cu ajutorul unei funcii speciale, getc destinate prelucrrii
fiierelor, astfel:
#define getchar() getc(stdin)
De obicei getchar se folosete n expresii de atribuire de forma:
c=getchar();
Dup citirea caracterului curent de la intrarea standard se atribuie
variabilei c codul ASCII al caracterului cititi sau EOF la ntlnirea
sfritului de fiier.
Exemple:
1)
#include <stdio.h>
void main (void)
{ putchar(getchar() A + a);
ca litera mica }

// citeste o litera mare si o rescrie

2) exemplul urmtor testeaz dac s-a citit o liter mare i numai n


acest caz aplic transformarea ei n liter mic. n cazul n care la intrare nu
se afl o liter mare se rescrie caracterul respectiv.
#include <stdio.h>
void main (void)
{ intc c;
putchar(((c = getchar() )>= A && c<= Z) ? c-A+a :c);
}
- 25 -

BORLAND C Manual de utilizare

4.5. FUNCIILE STANDARD getche I getch


Funcia getche citete de la intrarea standard caracterul curent i
returneaz codul ASCII al caracterului citit. Aceast funcie are acces direct
la caracter dup ce a fost tastat i are forma:
getche();
Funcia getch este similar cu getche cu singura condiie c citirea
se face fr ecou (deci caracterul tastat nu se reafieaz pe terminal). De fapt
prezena/absena sufixului e precizeaz c funcia e sau nu cu ecou. Cele dou
funcii fac citiri fr intermedierea zonei tampon.

- 26 -

BORLAND C Manual de utilizare

LECIA 5.
I N S T R U C I U N I
5.1. SCURT ISTORIC AL METODELOR DE PROGRAMARE
Vom prezenta n continuare cteva metode de programare dar nu exhaustiv, nefiind
aici cadrul adecvat (eventual ntr-un curs de Software Engineering). O clasificare
cronologic a ceea ce vrem s prezentm ar fi urmtoarea:
programarea artizanal;
programarea procedural;
programarea modular;
programarea structurat;
programarea prin abstractizarea datelor;
programarea orientat spre obiecte.

5.1.1. Programare artizanal


Aceast metod de fapt nu este o metod propriu-zis ci este prima modalitate de
programare odat cu apariia calculatoarelor. Intuiia i experiena programatorului
joac un rol important. Fiecare programator i are propriile reguli de programare.
Programele sunt monolitice (un singur corp de instruciuni), lungi i greu de neles de
alt programator. nsui cel ce a elaborat un astfel de program ntmpin dificulti de
nelegere a propriului program dup un timp oarecare.

5.1.2. Programare procedural


Odat cu apariia primelor limbaje de nalt nivel se utilizeaz programarea
procedural. Necesitatea ca anumite secvene de program s fie folosite de mai multe ori
duce la organizarea acestora n uniti distincte de program numite n diverse limbaje
subprograme, subrutine, proceduri, etc. De multe ori procedurile trebuie s fie generale
deci procesarea s fac abstractizare de valorile datelor. De exemplu o procedur de
calcul al radicalului de ordinul 2 trebuie s calculeze acest lucru din orice numr real
pozitiv iar pentru cele negative s semnaleze eroare. Procedurile trebuie deci
parametrizate cu anumite variabile numite parametri formali. Valorile de la apel ale
parametrilor formali se numesc parametri efectivi. Programarea procedural are la baz
deci utilizarea procedurilor, iar acestea realizeaz o abstractizare prin parametri. La
apelare o procedur funcioneaz dup principiul cutiei negre (black box): se cunosc
intrrile i ieirile rezultate din acestea dar nu i modul de transformare care nu e
important n acest moment.
n majoritatea limbajelor procedurale de programare se consider 2
categorii de proceduri:
proceduri care definesc o valoare de revenire (denumite i funcii);
proceduri care nu definesc o valoare de revenire.
n limbajele C i C++ procedurile de ambele categorii se numesc funcii.

5.1.3. Programarea modular


Pe msur ce complexitatea aplicaiilor a crescut, a aprut ideea de a descompune
problemele n subprobleme mai simple care la rndul lor pot fi descompuse n altele mai
simple i aa mai departe. n felul acesta se ajunge la o descompunere arborescent a
problemei date n subprobleme mai simple. Programarea subproblemelor devine o problem
mai simpl i fiecare subproblem are o anumit independen fa de celelalte
subprobleme. De asemenea, interfaa ei cu celelalte subprobleme este limitat i bine
precizat prin procesul de descompunere a problemei iniiale. De obicei, programarea unei
subprobleme, component a descompunerii arborescente a problemei iniiale, conduce la
realizarea unui numr relativ mic de proceduri (funcii). Aceste funcii pot prelucra n
comun anumite date. Unele dintre ele sunt independente de funciile realizate pentru alte
subprobleme componente ale descompunerii arborescente. Altele realizeaz chiar interfaa
cu subproblemele nvecinate.
Despre funciile obinute n urma programrii unei subprobleme se obinuiete s
se spun c sunt nrudite. De obicei, aceste funcii, mpreun cu datele pe care le
prelucreaz, se pstreaz ntr-un fiier i se compileaz independent.
O colecie de funcii nrudite, mpreun cu datele pe care le prelucreaz n comun
formeaz un modul. n felul acesta, problema iniial se realizeaz printr-un program
alctuit din module.
Programarea modular are la baz elaborarea programelor pe module.
O parte din datele utilizate n comun de funciile modulului, sau chiar toate
datele modulului, nu sunt necesare i n alte module. Aceste date pot fi protejate sau
cum se mai spune, ascunse n modul.
Limbajul C i C++, permite ascunderea datelor n modul folosind date care au clasa
de memorie static. Mai mult, pot fi declarate i funciile ca statice i atunci ele vor
fi ascunse n modul (nu pot fi apelate din afara modului). Ascunderea funciilor n modul
se face pentru acele funcii care nu se utilizeaz la realizarea interfeei modulului cu

- 27 -

BORLAND C Manual de utilizare

celelalte module. Ascunderea datelor i funciilor n module permite protejarea datelor


i prentmpin utilizarea eronat a funciilor.

5.1.4. Programarea structurat


Descompunerea unei probleme n subprobleme mai simple se poate face succesiv n
mai multe etape, pn cnd subproblemele sunt direct programabile sub forma unor
proceduri sau module. Aceast descompunere succesiv se mai numete rafinare pas cu pas
(stepwise refinement).. Evident c se obine o descompunere arborescent. Procedurile se
pot organiza sau nu n module. n cadrul procedurilor se folosesc anumite structuri de
control a execuiei. Aceasta impune o anumit disciplin a programrii. Structurile de
control de sunt:
secvena;
iteraia (pretestat, posttestat, cu numr prestabilit de ciclri);
alternativa (simpl, complet, generalizat).
Instruciunea de baz (primitiv) n cadrul acestor structuri de control este
instruciunea de atribuire.
Aceast abordare a programrii s-a nscut din necesitatea eliminrii instruciunii
de control GO TO care face saltul necondiionat la o instruciune precizat, alta dect
instruciunea urmtoare ei. Profesorul Dijsktra de la Universitatea din Eindhoven spunea,
prin anul 1965, calitatea unui programator este invers proporional cu numrul de
instruciuni GO TO folosite i a impus D-structurile de control:
secvena;
iteraia pretestat;
alternativa simpl.
D-structurile se regsesc n toate limbajele procedurale. Corespondena ar fi:
secvena este echivalent cu execuia instruciunilor n ordinea scrierii lor n
programul surs;
b) iteraia pretestat echivalent cu WHILE ... DO;
c) alternativa simpl echivalent cu IF ... THEN.
S-a demonstrat ulterior (Bohm i Jacopini) c orice algoritm se poate descrie doar
cu D-structurile dar pentru o mai bun lizibilitate i nelegere a programelor surs sau adugat i iteraia postestat (REPEAT ... UNTIL), iteraia cu numr prestabilit de
ciclri (FOR ... DO), alternativa complet (IF ... THEN ... ELSE) i alternativa
generalizat (CASE ... OF).
n unele limbaje se folosesc i alte structuri pe lng cele de mai sus pentru o
ct mai fidel reflectare a algoritmului.

5.1.5. Programarea prin abstractizarea datelor


n toate aceste tehnologii anterioare se urmrete mai mult organizarea
programului i mai puin rezolvarea ct mai natural a problemei. Programarea prin
abstractizarea datelor i programarea orientat spre obiecte propun metodologii n care
conceptele deduse din analiza problemei s poat fi reflectate ct mai fidel n program
i s se poat manevra cu instanieri ale acestor concepte ct mai natural. Se realizeaz
o mai mare fidelitate a programului fa de problem. De exemplu dac ntr-o problem n
care se proceseaz numere complexe e nevoie s se lucreze ntr-o form ct mai apropiat
cu forma matematic se poate introduce tipul COMPLEX (tip care nu exist n limbajele de
programare) i apoi se pot declara variabile de acest tip. Mai mult ar trebui s se poat
face toate operaiile matematice asupra datelor de tip COMPLEX. n general un TAD (Tip
Abstract de Date) are dou componente fundamentale:
datele membru (reflect reprezentarea tipului);
funciile membru (reflect comportamentul tipului).

5.1.6. Programarea orientat spre obiecte


Un neajuns al programrii prin abstractizarea datelor este faptul c nu permite
exprimarea legturilor dintre diferite concepte (TAD-uri). Singura legtur dintre
concepte care se poate exprima, este aceea c datele membru ale unei clase pot fi obiecte
ale unei alte clase. Acest lucru nu este suficient n cazul n care conceptele sunt
strns dependente ntre ele formnd structuri ierarhice. Exprimarea ierarhiilor conduce
la atribute suplimentare cum sunt cele de motenire. Aceste atribute conduc la un nou
model de programare pe care l numim programare orientat obiect.
n vrful unei ierarhii se afl fenomenul sau forma de existen care are
trsturi comune pentru toate celelalte componente ale ierarhiei respective. Pe nivelul
urmtor al ierarhiei se afl componentele care pe lng trsturile comune de pe nivelul
superior, mai au i trsturi suplimentare, specifice. O ierarhie, de obicei, are mai
multe nivele, iar situarea unui element pe un nivel sau altul al ierarhiei este uneori o
problem deosebit de complex. Dm n exemplul urmtor o ierarhie arborescent pentru
conceptele de paralelogram, dreptunghi, romb i ptrat.

- 28 -

BORLAND C Manual de utilizare

Dac paralelogramul se afl n vrful ierarhiei atunci pe nivelul imediat inferior


se aeaz dreptunghiul (paralelogramul cu un unghi drept) dar i rombul (paralelgramul cu
2 laturi alturate congruente). Apoi ptratul se poate defini fie ca un dreptunghi cu
laturile congruente fie ca un romb cu un unghi drept. Conceptul de pe fiecare nivel se
observ c motenete proprietile conceptului imediat superior din care este derivat.
La ora actual, toate ramurile cunoaterii tiinfice sunt pline de
ierarhii rezultate n urma clasificrii cunotinelor acumulate n perioada lung de
observare a fenomenelor i formelor de existen a lumii materiale i spirituale.
Clasificrile ierarhice ale cunotinelor pot fi ntlnite att n domeniile care pleac
de la cele mai concrete forme ale lumii materiale, cum sunt botanica, zoologia, biologia,
etc ct i n domenii care studiaz concepte dintre cele mai abstracte, cum ar fi
matematica sau filozofia.
Aceste ierarhii sunt rezultatul definirii conceptelor dup regula includerii
genul proxim i diferena specific.
Limbajul C dispune de un set bogat de instruciuni care permit scrierea de:
programe structurate,
programe flexibile,
programe compacte.
Totodat limbajul C permite aplicarea metodelor de programare procedural,
programare modular i programare structurat. Pe lng aceste metodologii limbajul C++
permite i programarea prin abstractizarea datelor i programarea orientat spre obiecte.
Vom descrie n continuare instruciunile limbajului C. Ca o caracteristic
sintactic toate instruciunile limbajului se termin prin caracterul ;, excepie
fcnd instruciunile care se termin cu acolada nchis.
Limbajul C dispune de un set bogat de instruciuni care permit scrierea de:
programe structurate,
programe flexibile,
programe compacte.
Totodat limbajul C permite aplicarea metodelor de programare procedural,
programare modular i programare structurat. Pe lng aceste metodologii limbajul C++
permite i programarea prin abstractizarea datelor i programarea orientat spre obiecte.
Vom descrie n continuare instruciunile limbajului C. Ca o caracteristic
sintactic toate instruciunile limbajului se termin prin caracterul ;, excepie
fcnd instruciunile care se termin cu acolada nchis.

5.2. INSTRUCIUNEA VID


Instruciunea vid se reduce la caracterul ;. Ea nu are nici un efect.
Adesea este nevoie de ea la construcii n care se cere prezena unei
instruciuni, dar nu este necesar s se execute nimic n punctul respectiv.

deci:

5.3. INSTRUCIUNEA EXPRESIE


Instruciunea expresie se obine scriind punct i virgul dup o expresie,
expresie;

Exist cazuri particulare ale instruciunii expresie:


expresia de atribuire, care de altfel este cel mai important caz
particular al instruciunii expresie:
expresie;
apelul unei funcii:
nume_funcie (par1, par2, . . . parn);
incrementrile i decrementrile pre i post fixate:
variabil++; ++variabil;
variabil- -; - - variabil;
Exemplu:
void main (void)
{ int i;
float f;
double d;
i=10;
// instructiune de atribuire
i++;
// i se mareste cu 1
f=i;
// instructiune de atribuire (valoarea lui i se converteste in
float)
d=++f;
// incrementare lui f si atribuirea valorii lui d
putchar(a);
// instructiune de apel
}
- 29 -

BORLAND C Manual de utilizare

5.4. INSTRUCIUNEA COMPUS


Instruciunea compus este o succesiune de declaraii urmate de
instruciuni, succesiune inclus ntre acolade:
{
declaraii
instruciuni
}
Pot lipsi declaraiile sau instruciunle dar nu n acelai timp. Dac
delaraiile sunt prezente, atunci ele definesc variabile care sunt valabile
numai n instruciunea compus respectiv.
Exemplu:
. . .
{ int i=100;// variabila i este definita in aceasta instructiune compusa
i++; // i are valabilitate doar intre acolade; dupa acolada inchisa i isi
printf (i=%d\n,i);
// pierde valabilitatea
}
Observaii:
1o. Dup acolada inchis a unei instruciuni compuse nu se pune ;.
2o. Corpul unei funcii are aceeai structur ca i instruciunea compus,
deci o funcie are formatul:
antetul funciei
instruciune compus
5.5. INSTRUCIUNEA if
Instruciunea if permite s realizm o ramificare a execuiei n funcie
de valoarea unei expresii. Ea are dou formate ce permit aplicarea structurii de
alternativ simpl i compus.
Formatul 1:
if (expresie) instructiune;
Efectul:
se evalueaz expresia din paranteze;
dac valoarea expresiei este diferit de zero (deci conform conveniei are
valoarea adevrat), atunci se execut instructiune, altfel se trece la
instruciunea urmtoare.
Formatul 2:
if (expresie)

instructiune_1;
else

instructiune_2;
Efectul:
se evalueaz expresia din paranteze;
dac valoarea expresiei este diferit de zero (deci conform conveniei are
valoarea adevrat), atunci se execut instructiune_1, altfel se execut
instructiune_2; apoi n ambele cazuri se trece la instruciunea urmtoare.
Observaii:
1o. Se pot folosi instruciuni if imbricate, nivelul de imbricare fiind
oarecare (deci nu exist o limitare a numrului de imbricri).
2o. Pentru mai multe imbricri se folosete regula asocierii if-lui cu
else astfel:
un else se pune n coresponden cu primul if care se afl naintea lui n
textul surs i nu este inclus n instruciunea care l precede pe el i nici nu
i corespunde deja un else.
Exemple
void main (void)
{ float x,y,a;
x=-5;
y=10;
if (x<0)
// ultimul else se asociaza cu primul if iar
if (y<0) a=1; // penultimul else se asociaza cu cel de-al doilea if
else a=2;
else a=0;
}
- 30 -

BORLAND C Manual de utilizare

void main (void)


{ float x,y,a;
x=-5;
y=10;
if (x<0)
// ultimul else se asociaza cu primul if deoarece cel de-al
{ if (y<0) a=1; }
//
de-al
doilea
if
este
inclus
in
instructiunea compusa care
else a=0;
// il precede pe if
}
void main (void) // citeste trei intregi si scrie minimul dintre ei
{int i,j,k,min;
scanf (\ndati i=%d, &i);
scanf (\ndati j=%d, &j);
scanf (\ndati k=%d, &k);
if (i>j)
min=j;
else
min=i;
if (k<min)
min=k;
printf (min(%d,%d,%d)= %d\n,i,j,k,,min);
}
5.6. INSTRUCIUNEA while
Instruciunea while are urmtorul format:
while (expresie) instructiune;
Cu ajutorul instruciunii while se realizeaz structura repetitiv
pretestat (condiionat anterior).
Efectul:
se evalueaz valoarea expresiei din paranteze;
dac expresia are valoarea diferit de zero, atunci se execut
instructiune i se reia punctul 1), altfel se trece la instruciunea urmtoare
instruciunii while.
Deci instructiune se execut repetat atta timp ct expresia din parantez
este diferit de zero. Se observ c dac expresia are valoarea zero de la
nceput, atunci instructiune nu se execut niciodat.
Antetul ciclului while este construcia while (expresie) iar instructiune
formeaz corpul ciclului. n cazul n care este necesar s se execute repetat
mai multe instruciuni, se utilizeaz o instruciune compus format din
instruciunile respective.
Exemplu:
Vom crea un program care citete un ntreg n i scrie n!. Algoritmul n
pseudocod este urmtorul:
Citeste n

f=1
i=2
CtTimp

Programul n C este:

#include<stdio.h>
void main (void)
execut
{ int n,i;
f=f*i;
double f;
i=i+1
f=1.0;
i=2;
SfritCtTimp
printf(\n dati n= );
Scrie n,f
scanf(%d,&n);
while (i<=n)
{ f=f*i;
i++;
}
printf(\nn=%d,
n!=%g\n,n,f);
}
Corpul ciclului while se poate scrie mai compact astfel:
while (i<=n) f*=i++;
i<=n

- 31 -

iar

BORLAND C Manual de utilizare

5.7. INSTRUCIUNEA for


Instruciunea for, ca i instruciunea while, se utilizeaz pentru
realiza o structur repetitiv pretestat. Formatul instruciunii este:

for(exp1; exp2; exp3) instructiune;


Antetul ciclului este definit de for(exp1; exp2; exp3) iar instructiune
formeaz corpul ciclului. Prima expresie exp1 constituie partea de iniializare
a ciclului, iar exp3 este partea de reiniializare a ciclului. Condiia de
continuare a ciclului este exp2. De obicei exp1 i exp3 reprezint atribuiri.
Efectul:
se execut secvena de iniializare definit de expresia exp1;
se evalueaz exp2; dac exp2 are valoarea zero, atunci se iese din ciclu,
adic se trece la instruciunea urmtoare instruciunii for, altfel se execut
instruciunea din corpul ciclului;
se execut apoi secvena de reiniializare definit de exp 3, apoi se reia
secvena de la punctul 2).
Observaii:
1o. Ca i n cazul instruciunii while, instruciunea din corpul ciclului
for poate s nu se execute niciodat dac exp 2 are valoarea zero chiar la prima
evaluare.
2o. Expresiile din antetul instruciunii for pot fi i vide; totui
caracterele ; vor fi ntotdeauna prezente.
3o. Comparnd instruciunile for i while observm c instruciunea for cu
formatul anterior se poate realiza cu secvena urmtoare folosind while:
exp1;
while (exp2)
{ instructiune;
exp3;
}
Invers, o instruciune while de forma:
echivalent cu urmtoarea instruciune for:
for(; exp; ) instructiune.

while

(exp)

instructiune

este

Autorii limbajului C propun ca instruciunea for s se foloseasc cu


prioritate pentru ciclurile care au pas.
Exemple:
Vom da o secven de instruciuni care nsumeaz elementele unui tablou:
s=0;
for(i=0; i<n; i++) s=s+tab[i];
sau scris mai compact:
for (s=0, i=0; i<n; i++) s+=tab[i];
n continuare vom da un mic program care afieaz numrul caracterelor
citite de la intrarea standard stdin.
#include <stdio.h>
void main(void)
{ long n;
for (n=0; getchar()!=EOF; n++);
printf (\nnumarul caracterelor citite =%ld\n,n);
}
sau scris cu instruciunea while
#include <stdio.h>
void main(void)
{ long n=0;
while (getchar()!=EOF) n++;
printf (\nnumarul caracterelor citite =%ld\n,n);
}

- 32 -

BORLAND C Manual de utilizare

5.8. INSTRUCIUNEA do-while


Aceast
instruciune
realizeaz
structura
repetitiv
condiionat
posterior (posttestat) dar modificat fa de REPEAT .. UNTIL. Aceast
instruciune s-a introdus pentru o mai mare flexibilitate n scrierea
programelor. Formatul ei este:
do
instructiune;
while (exp);
Efectul:
se execut instruciunea instructiune;
se evalueaz expresia exp din paranteze;
dac valoarea expresiei este zero se trece la instruciunea urmtoare
instruciunii do-while; altfel se revine i se execut din nou instructiune.
Observaii:
1o. Structura realizat de instruciunea do-while poate fi realizat
printr-o secven n care se folosete instruciunea while astfel:
instructiune;
while (exp) instructiune;
2o. Se observ c n cazul instruciunii do-while, corpul ciclului se
execut cel puin odat, spre deosebire de ciclurile while i for unde corpul
ciclului poate s nu se execute niciodat.
Exemplu:
Vom da un program care calculeaz rdcina ptrat dintr-un numr real
a>=0.
#include<stdio.h>
#define EPS 1e-10
void main (void)
{ double x1,x2,y,a;
clrscr();
// sterge ecranul
printf(\ndati un numar real pozitiv a=);
if (scanf(%lf,&a) !=1 || a<0)
printf
(numarul
citit
nu
este
pozitiv\n);
else {
x2 = 1.0;
do {
x1 = x2;
x2 = 0.5 *(x1+a/x1);
// formula de iteratie
if ((y=x2-x1) < 0) y = -y;
}
while (y >= EPS);
printf (radacina patrata din:%g este: %.2lf\n,a,x2);
// 2 zecimale
} //sfirsit else
}
5.9. INSTRUCTIUNEA switch
Instruciunea
switch
permite
realizarea
structurii
alternativa
generalizat. Ea este echivalent cu o imbricare de structuri de alternativ
simple. Utilizarea instruciunii switch face n schimb programul mult mai clar.
Formatul instruciunii switch este urmtorul:
switch (exp)
{ case c1: sir1
break;
case c2:
sir2
break;
. . .
case cn:
sirn
break;
default:
sir
}
unde: c1,. . . cn sunt constante sau constante simbolice;
sir1, . . . ,sirn, sir sunt iruri de instruciuni.
- 33 -

BORLAND C Manual de utilizare

Efectul:
se evalueaz expresia din parantez;
se compar pe rnd valoarea expresiei cu valorile constantelor c 1, . . . ,
cn;

dac valoarea expresiei coincide cu valoarea lui ck, se execut secvena


de instruciuni definit prin sirk; n cazul n care valoarea expresiei nu
coincide cu nici una din constantele c1, . . . , cn, se execut secvena de
instruciuni definit prin sir;
dup execuia secvenei sirk sau sir se trece la instruciunea urmtoare
instruciunii switch, adic la prima instruciune aflat dup acolada nchis
care termin instruciunea switch respectiv; evident, acest lucru are loc dac
irul care se execut nu impune, el insui, un alt mod de continuare a
execuiei, de exemplu o revenire din funcia respectiv, un salt la o anumit
instruciune, etc.
Observaii:
1o. Ramura default nu este obligatorie. n lipsa ei, dac valoarea
expresiei nu coincide cu nici una din constantele c1,. . . , cn, instruciunea
switch respectiv nu are nici un efect.
2o.Construcia break reprezint o instruciune. Ea termin fiecare ramur
de instruciuni sir1, . . . , sirn, provocnd saltul la instruciunea urmtoare
instruciunii switch sau, cum se mai spune, realizeaz ieirea din instruciunea
switch.
3o. Instruciunea break nu este obligatorie. n cazul n care este
absent, se execut secvenial urmtoarea ramur. De exemplu dac avem secvena:
switch (exp)
{
case c1: sir1
case c2: sir2
}
ea se execut n felul urmtor:
dac valoarea expresiei este egal cu c1 se execut sir1 i apoi sir2;
dac valoarea expresiei este egal cu c2 se execut sir2;
daca valoarea expresiei difera de valorile c1 i c2 instruciunea switch de
mai sus nu este efectiv, se trece la instruciunea urmtoare care urmeaz dup
switch.
secvena de mai sus se putea realiza i astfel:
if (exp = = c1)
{ sir1
sir2
}else if (exp = = c2) sir2
Exemplu:
Vom citi din fiierul de intrare construcii de forma: op 1 operator op2,
unde op1 i op2 sunt numere ntregi (operanzi ntregi) iar operator este un
operator aritmetic {+, -, *, /}. La ieire se va scrie valoarea
expresiei citite. De exemplu dac se citete secvena 100/3 se va afia
rezultatul 33. Programul permite citirea i evaluarea mai multor astfel de
expresii, pn la ntlnirea sfritului de fiier.
#include <stdio.h>
void main (void)
{ int op1,op2,operator,rezultat,i;
while (( i=scanf(%d %c %d, &op1,&operator, &op2)) != EOF)
if (i = = 3 )
// ramura adevarat inseamna ca s-au citit 3
campuri corecte
{ switch (operator)
{ case +: rezultat = op1 + op2 ; // avem adunare
break;
case - : rezultat = op1 op2;
// avem scadere
break;
case * : rezultat = op1 * op2;
// avem inmultire
break;
case / :
// avem impartire intreaga
if (op2 = = 0)
{ printf (divizor nul\n);
rezultat = 0;
- 34 -

BORLAND C Manual de utilizare

} else rezultat = op1 / op2;


break;
default : printf (operator eronat\n);
rezultat = 0;
} // sfarsit switch
printf (%d %c %d %d\n, op1, operator, op2, rezultat);
} else
printf (expresie eronat\n);
// sfarsit

while

if

si

}
5.10. INSTRUCIUNEA break
Formatul instruciunii este urmtorul:
break;
De obicei instruciunea break se folosete pentru a iei dintr-un ciclu.
Dac exist mai multe cicluri imbricate instruciunea break va trece controlul
la ciclul de nivel imediat superior (deci imbricarea rmne, nu se iese din
toate ciclurile). O alt utilizare este n instruciunea switch, dup cum am
observat n paragraful anterior.
Un alt exemplu de utilizare frecvent este ieirea dintr-un ciclu
infinit de forma:
for ( ; ; )
{. . .
if (exp) break;
. . .
}
5.11. INSTRUCIUNEA continue
Formatul instruciunii este urmtorul:
continue;
Efectul:
n ciclurile while i do-while ea realizeaz saltul la evaluarea expresiei
care decide asupra continurii ciclului;
n ciclul for ea realizeaz saltul la pasul de reiniializare.
Observaie:
1o. Instruciunea continue se utilizeaz numai n corpul unui ciclu,
permind, dup caz, s se treac la pasul urmtor al ciclului sau s se ias
din ciclu.
5.12. INSTRUCIUNEA goto
Conform principiilor programrii structurate instruciunea goto nu ar fi
necesar. Dar ea a fost introdus n limbaj, deoarece, n anumite cazuri, se
dovedete a fi util, asigurnd o flexibilitate mai mare n programare. De multe
ori ieirea dintr-un ciclu imbricat n alte cicluri se realizeaz mai simplu cu
ajutorul instruciunii goto. n lipsa ei ar trebui s folosim mai muli
indicatori i teste asupra valorilor acestora pentru ieirea din ciclu. Saltul
fcut de goto se face la o instruciune care este prefixat de o etichet.
Prin etichet vom nelege un nume urmat de caracterul :.
Etichetele sunt locale unei funcii.
Instruciunea goto are urmtorul format:
goto eticheta;
Efectul:
se realizeaz saltul la instruciunea prefixat de eticheta al crei nume
se afl scris dup cuvntul cheie goto.

- 35 -

BORLAND C Manual de utilizare

5.13. APELUL I REVENIREA DINTR-O FUNCIE


5.13.1. Apelul unei funcii
n limbajul C funciile sunt de dou tipuri:
funcii care returneaz o valoare la revenirea din ele;
funcii care nu returneaz nici o valoare la revenirea din ele.
O funcie care nu returneaz nici o valoare la revenirea din ea se
apeleaz printr-o instruciune de apel. Ea are urmtorul format:
nume (lista_parametrilor_efectivi);
(*)
unde:
nume este numele funciei;
lista_parametrilor_efectivi este fie vid, fie se compune din una sau mai
multe expresii separate prin virgul.
Instruciunea de apel este un caz particular al instruciunii expresie.
Parametrii efectivi (de la apel) trebuie s corespund cu cei formali (de la
definirea funciei) prin ordine, tip i numr.
n cazul n care o funcie returneaz o valoare, ea poate fi apelat fie
printr-o instruciune de apel, fie sub forma unui operand al unei expresii.
Observaii:
1o. Dac nu dorim s utilizm valoarea returnat de funcia respectiv,
apelul se face printr-o instruciune de apel.
2o. Dac dorim s utilizm valoarea returnat de funcie, vom folosi
apelul funciei drept operand ntr-o expresie, operandul avnd formatul (*).
Exemple de apeluri de funcii folosite pn acum sunt apelurile funciilor
standard printf, scanf, getchar i putchar. Funciile printf i putchar au fost
apelate prin instruciuni de apel, valorile returnate de ele nefiind utilizate.
n schimb funciile scanf i getchar au fost apelate n ambele moduri, att prin
instruciuni de apel, ct i ca operanzi n diferite expresii.
5.13.2. Prototipul unei funcii
O funcie poate fi apelat dac ea este definit n fiierul surs nainte
de a fi apelat. Dup cum am prezentat n lecia 1 nu ntotdeauna este posibil
acest lucru i n astfel de cazuri apelul funciei trebuie s fie precedat de
prototipul ei.
Prototipul unei funcii are ca scop s informeze compilatorul despre:
tipul valorii returnate de funcie;
tipurile parametrilor.
n felul acesta, la apelul unei funcii, compilatorul poate face teste cu
privire la tipul expresiilor care reprezint parametrii efectivi, precum i
unele conversii necesare asupra valorii returnate de funcie.
Observaii:
1o. Tipurile parametrilor pot s lipseasc. n acest caz, compilatorul nu
controleaz tipurile parametrilor efectivi, singura informaie coninut de
prototip fiind tipul valorii returnate de funcia respectiv.
2o. Absena att a prototipului unei funcii, ct i a definiiei funciei
nainte de a fi apelat este posibil; n acest caz se presupune c funcia
returneaz o valoare de tip int.
3o. n practic se recomand utilizarea prototipurilor pentru toate
funciile nainte de a fi apelate. n acest scop, ele vor fi scrise la nceputul
fiierelor surs.
Formatele posibile ale unui prototip sunt:
formatul 1: tip nume (lista_declaratiilor_de_parametri);
formatul 2: tip nume (lista_ tipurilor_parametrilor);
formatul 3: tip nume (void);
formatul 4: tip nume ();
Formatul 2 este cel mai utilizat. Formatul 3 se poate folosi pentru orice
funcie care nu are parametri. Formatul 4 se poate folosi pentru orice funcie
la al crei apel nu se doresc teste referitoare la tipul parametrilor efectivi.
Funciile din biblioteca standard a limbajului C au prototipurile definite
n fiierele de tip .h.
- 36 -

BORLAND C Manual de utilizare

5.13.3. Apel prin valoare i apel prin referin


La apelul unei funcii, fiecrui parametru formal i se atribuie valoarea
parametrului efectiv care-i corespunde. Deci, la apelul unei funcii se
transfer valorile parametrilor efectivi. Din aceast cauz se spune c apelul
este prin valoare (call by value). n anumite limbaje de programare, la apel nu
se transfer valorile parametrilor efectivi ci adresele acestora. n acest caz
se spune c apelul este prin referin (call by refference).
ntre cele dou tipuri de apeluri exist o diferen esenial i
anume: n cazul apelului prin valoare funcia apelat nu poate modifica
parametrii efectivi din funcia apelant, neavnd acces la ei. n cazul apelului
prin referin, funcia apelat, dispunnd de adresele parametrilor efectivi, i
poate modifica.
n limbajul C apelul se realizeaz implicit prin valoare. n cazul
c un parametru este numele unui tablou atunci transferul se realizeaz prin
referin deoarece numele unui tablou este un pointer i conine adresa primului
element al tabloului. Transferul prin referin se realizeaz cu ajutorul
variabilelor de tip pointer i cu ajutorul operatorului de adres (&).
5.13.4. Revenirea dintr-o funcie
Revenirea dintr-o funcie se poate face n dou moduri:
la ntlnirea instruciunii return;
dup execuia ultimei sale instruciuni, adic a instruciunii
precede acolada nchis ce termin corpul funciei respective.
Instruciunea return are dou formate:
return;
sau
return expresie;

care

Primul format se utilizeaz


cnd funcia nu returneaz o valoare,
iar cel de-al doilea cnd funcia returneaz o valoare. n acest ultim caz,
funcia returneaz valoarea expresiei specificate.
Observaie:
1o. Cnd revenirea se face dup execuia ultimei instruciuni a funciei
nu se returneaz o valoare; revenirea n acest caz, se face ca i cum acolada
nchis de la sfritul corpului funciei ar fi precedat de instruciunea
return.
Exemplu: vom da un exemplu de apel al funciei care determin rdacina
ptratic dintr-un numr nenegativ.
#include<stdio.h>
double radacina_2 (double)
// prototipul functiei
void main (void)
// functia principala care citeste d
// si afiseaza radacina patrata din d
{ double d;
clrscr();
// sterge ecranul
if (scanf (%lf,&d) != || d<0)
printf (numarul dat este eronat\n);
else
printf (d=%f, radacina patrata = %.10g\n, d, radacina_2(d));
#define EPS 1e-10
double radacina_2 (double x)
{ double x1,x2,y;
x2 = 1.0;
do { x1 = x2;
x2 = 0.5 *(x1+x/x1);
// formula de iteratie
if ((y=x2-x1) < 0) y = -y;
}
while (y >= EPS);
return x2;
}
Observaie:
1o. Limbajul C dispune de o bibliotec matematic n care sunt incluse o
serie de funcii pentru calculul valorilor funciilor elementare. Exist o
funcie numit sqrt (cu prototipul double sqrt (double);). Fiierul care conine
biblioteca matematic se numete math.h i trebuie inclus n fiierul surs de
lucru dac se dorete utilizarea funciilor definite n el.
- 37 -

BORLAND C Manual de utilizare

- 38 -

BORLAND C Manual de utilizare

LECIA 6.
P O I N T E R I
Un pointer este o variabil care are ca valori adrese. Pointerii se
folosesc pentru a face referire la date cunoscute prin adresele lor. Astfel,
dac p este o variabil de tip pointer care are ca valoare adresa zonei de
memorie alocat pentru variabila ntreag x atunci construcia *p reprezint
chiar valoarea variabilei x.
n construcia de mai sus, *p, caracterul * se consider ca fiind un
operator unar care furnizeaz valoarea din zona de memorie a crei adres este
coninut n p. Operatorul unar * are aceeai prioritate ca i ceilali
operatori unari din limbajul C.
Dac p conine adresa zonei de memorie alocat variabilei x, vom
spune c p pointeaz spre x sau c p conine adresa lui x.
Pentru a atribui unui pointer adresa unei variabile, putem folosi
operatorul unar &. Astfel, dac dorim ca p s pointeze spre x, putem utiliza
construcia:
p = &x;
n limba romn se utilizeaz i alte denumiri pentru noiunea de
pointer: referin, localizator; reper; indicator de adres.
6.1. DECLARAIA DE POINTER
Un pointer se declar ca orice variabil cu deosebirea c numele
pointerului este precedat de caracterul *. Astfel, dac, de exemplu, dorim s
declarm variabila p utilizat anterior pentru a pstra adresa variabilei
ntregi x, vom folosi declaraia urmtoare:
int *p;
Tipul int stabilete n acest caz faptul c p conine adrese de zone
de memorie alocate datelor de tip int. Declaraia lui p se poate interpreta n
felul urmtor: *p reprezint coninutul zonei de memorie spre care pointeaz p,
iar acest coninut are tipul int.
n general, un pointer se declar prin:
tip *nume;
ceea ce nseamn c nume este un pointer care pointeaz spre o zon de
memorie ce conine o dat de tipul tip.
Comparnd declaraia de pointer anterioar cu una obinuit:
tip nume;
putem considera c:
tip *
dintr-o declaraie de pointer reprezint tip dintr-o declaraie obinuit.
De aceea, construcia
tip *
se spune c reprezint un tip nou, tipul pointer.
Exist cazuri n care dorim ca un pointer s fie utilizat cu mai
multe tipuri de date. n acest caz, la declararea lui nu dorim s specificm un
tip anume. Aceasta se realizeaz folosind cuvntul cheie void:
void *nume;
Exemple:
1)
void main (void)
{ int x,y;
int *p;
y=x+10;
// aceast atribuire este echivalenta cu secventa urmatoare
p=&x;
y=*p+100;
x=y;
p=&x;
(*p)++;

// este echivalenta cu secventa

- 39 -

BORLAND C Manual de utilizare

2) funcia permutare de mai jos realizeaz transferul parametrilor prin


adres:
void permutare (int *x, int *y)
// x si y sunt pointeri
{ int temp;
temp = *x;
// temp ia valoarea ce se afla la adresa continuta in x
*x=*y;
// in zona a carei adresa se afla in x se
transfera continutul
// zonei a carei adresa se afla in y
*y=temp;
// in zona a carei adresa se afla in y se transfera valoarea
// lui temp
}
Apelul funciei permutare se face astfel:
permutare (&a, &b);
pentru a schimba valorile lui a cu b.
6.2. LEGTURA DINTRE POINTERI I TABLOURI
Numele unui tablou este un pointer deoarece el are ca valoare adresa
primului su element. Totui exist o diferen ntre numele unui tablou i o
variabil de tip pointer, i anume unui nume de tablou nu i se poate atribui
alt adres. Deci numele unui tablou trebuie considerat ca fiind un pointer
constant.
Dac x este un parametru formal ce corespunde unui parametru efectiv
care este un nume de tablou, x poate fi declarat fie ca tablou fie ca pointer
spre tipul tabloului.
Exemplu:
Fie funcia cu antetul urmtor:
unsigned lungime (char x[ ]);
S presupunem c aceast funcie determin lungimea unui ir de caractere
i se poate apela prin:
l=lungime(tablou);
unde tablou este de tip caracter.
Antetul funciei lungime poate fi schimbat n felul urmtor:
unsigned lungime (char *x);
Cele dou declaraii sunt identice deoarece declaraia:
char x[ ];
definete pe x ca numele unui tablou de tip caracter; dar atunci el este
un pointer spre caractere deci se poate declara prin:
char *x;
6.3. OPERAII CU POINTERI
Asupra pointerilor se pot face diferite operaii. Deoarece ei conin
adrese atunci operaiile se realizeaz cu adrese.
6.3.1. Incrementare i decrementare
Operatorii
de
incrementare
i
decrementare
se
pot
aplica
variabilelor de tip pointer.
Efectul:
operatorul de incrementare aplicat asupra unui operand de tip pointer spre
tipul tip mrete adresa coninut de operand cu numrul de octei necesari
pentru a pstra o dat de tipul tip.
operatorul de decrementare se execut n mod analog, cu singura diferen
c n loc s se mreasc adresa, ea se micoreaz cu numrul corespunztor de
octei.
De obicei decrementrile i incrementrile adreselor sunt mai rapide ca
execuie cnd se au n vedere prelucrri de tablouri.

- 40 -

BORLAND C Manual de utilizare

Exemplu:

tablou
6.3.2.
Dac p
p+n i
unde n

int tab[10];
int *p;
int i=0;
p=&tab[i];
p++;
// p contine adresa lui tab[1]
// cu p se pot face referiri la orice element de

Adunarea i scderea unui ntreg dintr-un pointer


este un pointer, sunt corecte expresiile de forma:
p-n
este de tip ntreg.

Efectul:
expresia p+n mrete valoarea lui p cu n*nr_tip, unde nr_tip este numrul
de octei necesari pentru a memora o dat de tipul tip spre care pointeaz p;
analog expresia p-n micoreaz valoarea lui p cu n*nr_tip.
Dac x este un tablou de tipul tip, atunci x este pointer, deci o expresie
de forma:
x+n;
este corect i deoarece x este un pointer spre primul su element x[0],
x+n va fi un pointer spre elementul x[n]. Rezult c valoarea elementului x[n]
se poate reprezenta prin expresia:
*(x+n);
Astfel variabilele cu indici se pot nlocui prin expresii cu
pointeri. Aceasta permite ca la tratarea tablourilor s se foloseasc expresii
cu pointeri n locul variabilelor cu indici. Versiunile cu pointeri sunt de
obicei optime n raport cu cele realizate prin intermediul indicilor.
6.3.3. Compararea a doi pointeri
Doi pointeri care pointeaz spre elementele aceluiai tablou pot fi
comparai folosind operatorii de relaie i de egalitate. Astfel, dac p i q
sunt doi pointeri care pointeaz spre elementele tab[i], respectiv tab[j] ale
tabloului tab, expresiile urmtoare au sens:
p<q
p!=j p= =q.
Observaii:
1o. Pointerii nu pot fi comparai dect n condiiile amintite mai sus
(deci dac sunt pointeri spre elementele aceluiai tablou).
2o. Operatorii = = i != permit compararea unui pointer i cu o constant
simbolic special avnd numele NULL. Aceste comparaii permit s stabilim dac
un pointer conine o adres sau nu. Astfel, dac expresia:
p= = NULL
este adevrat, p nu conine o adres. Dac expresia respectiv are
valoarea fals atunci p conine o adres. Constanta simbolic NULL este definit
n fiierul stdio.h
.
6.3.4. Diferena a doi pointeri
Doi pointeri care pointeaz spre elementele aceluiai tablou pot fi
sczui. Rezultatul diferenei a doi pointeri este definit astfel: fie t un
tablou de un tip oarecare i p i q doi pointeri, p conine adresa elementului
t[i] iar q conine adresa elementului t[i+n]. Atunci diferena q-p are valoarea
n.
6.3.5. Exemple
Vom da cteva funcii asupra irurilor de caractere:
funcia lungime
unsigned lungime (char*x)
{ int i;
for (i=0; *x != \0; i++) x++; // sau for (i=0; *x++; i++);
- 41 -

BORLAND C Manual de utilizare

return i;
}
funcia copiaz
void copiaza(char *x, char *y)// copiaza din zona de adresa y
// in zona de adresa x
{ while(*x++ = = *y++); }
funcia concateneaza
void concateneaza (char *x, char *y)
// concateneaza sirul de adresa y la sfarsitul sirului
// de adresa x
{ while (*x) x++;
// avans de adresa pana la sfarsitul
sirului x
while (*x++= *y++);
}
funcia compara
int compara (char *x, char *y)
{ while (*x= = *y)
{ if (*x= = \0) return 0;
x++;
y++;
return *x - *y;
// daca diferenta caracterelor este
// negativa atunci x<y altfel x>y
}
}
6.4. ALOCAREA DINAMIC A MEMORIEI
Biblioteca standard a limbajului C pune la dispoziia utilizatorului
funcii care permit alocarea de zone de memorie n timpul execuiei programului.
O astfel de zon de memorie poate fi utilizat pentru a pstra date temporare.
Zona respectiv poate fi eliberat n momentul n care nu mai sunt necesare
datele care au fost pstrate n ea. Alocarea de zone de memorie i eliberarea
lor n timpul execuiei programelor permite gestionarea optim a memoriei de
ctre programator. Un astfel de mijloc de gestionare a memoriei l vom numi
alocare dinamic a memoriei.
Vom indica dou funcii din bibloteca limbajului C utilizate
frecvent n alocarea dinamic a memoriei. Prototipurile lor se afl n fiierele
standard alloc.h i stdlib.h, deci pentru a le utiliza vom include unul din
aceste fiiere.
Funcia malloc permite alocarea unui bloc de memorie a crui
dimensiune se specific n octei. Funcia returneaz un pointer spre nceputul
zonei alocate. ntruct acest pointer trebuie s permit memorarea oricrui tip
de dat n zona alocat, el este de tip void *.
Prototipul funciei este:
void *malloc (unsigned n);
unde n este numrul de octei al zonei de memorie care se aloc. n cazul
n care n este prea mare, funcia returneaz pointerul NULL.
Funcia free elibereaz o zon de memorie alocat prin malloc.
Prototipul ei este:
void free (void *p);
unde p este pointerul returnat de malloc la alocare, deci este pointerul
spre nceputul zonei care se elibereaz.
Exemplu:
Funcia memchar memoreaz un ir de caractere ntr-o zon de memorie
alocat prin funcia malloc. Ea returneaz adresa de nceput a zonei n care s-a
salvat irul de caractere, deci returneaz un pointer spre tipul char.
#include <stdio.h>
#include <alloc.h>
#include <string.h>
char *memchar (char *s)
{
char *p;
if ((p=(char *)malloc(strlen(s)+1) ) != NULL
{
strcpy (p,s);
return p;
} else
- 42 -

BORLAND C Manual de utilizare

return NULL;
}
Observaii:
1o. n fiierul stdio.h exist definiia constantei NULL.
2o. Fiierul alloc.h s-a inclus deoarece conine prototipul funciei
malloc.
3o. Fiierul string.h conine prototipurile funciilor strlen i strcpy.
4o. Funcia malloc se apeleaz pentru a rezerva strlen(s)+1 octei; strlen
returneaz numrul de octei cuplai de caracterele proprii ale lui s (fr
caracterul NULL). Cum n zona de memorie rezervat prin malloc se pstreaz i
caracterul NULL, lungimea returnat de funcia strlen s-a mrit cu 1.
5o. Pointerul returnat de malloc a fost convertit spre char *, deoarece el
este de tip void *. Acest pointer se atribuie lui p, deci p pointeaz spre
nceputul zonei de memorie alocate prin apelul funciei malloc. Se testeaz dac
acest pointer este diferit de NULL (deci dac s-a putut aloca memoria de
dimensiunea cerut). n caz afirmativ, se transfer irul prin apelul funciei
strcpy, returnndu-se apoi valoarea pointerului p.
6.5. POINTERI SPRE FUNCII
Numele unei funcii este un pointer spre funcia respectiv. El poate fi
folosit ca parametru efectiv la apeluri de funcii. n felul acesta, o funcie
poate transfera funciei apelate un pointer spre o funcie. Aceasta, la rndul
ei, poate apela funcia care i-a fost transferat n acest fel.
Exemplu:
Un exemplu matematic n care este nevoie de un astfel de transfer este cel
cu privire la calculul aproximativ al integralelor definite. S presupunem c
dorim s calculm integrala definit din funcia f(x), ntre limitele a i b,
folosind formula trapezului:
I= h((f(a)+f(b))/2 +f(a+h)+f(a+2h)+. . . +f(a+(n-1)h)
unde
h=(b-a)/h.
n continuare construim o funcie care calculeaz partea dreapt a
acestei relaii. Numim aria_trapez aceast funcie.
Observaii:
1o. Deoarece funcia f(x) din relaia de mai sus nu este definit n acest
moment, ea trebuie s figureze printre parametrii funciei aria_trapez, mpreun
cu limitele de integrare i valoarea lui n.
2o. Funcia aria_trapez returneaz valoarea aproximativ a integralei i
ea se va apela printr-o expresie de atribuire, de exemplu:
aria=aria_trapez (a, b, n, f);
3o. Funcia aria_trapez returneaz o valoare flotant n dubl precizie.
De asemenea, i funcia f(x) returneaz o valoare flotant n dubl precizie. De
aici rezult c prototipul funciei aria_trapez este urmtorul:
double aria_trapez (double a, double b, int n, double (*f)());
sau
double aria_trapez (double, double, int , double (*)());
4o. Este necesar ca naintea apelului funciei aria_trapez funcia f(x) s
fie definit sau s fie prezent prototipul ei , de exemplu:
double f();
5o. Construcia double (*f) () se interpreteaz n felul urmtor:
- *f
nseamn c f este un pointer;
- (*f)()
nseamn c f este un pointer spre o funcie;
- double (*f) () nseamn c f este un pointer spre o funcie care
returneaz o valoare flotant n dubl precizie.
6o. Trebuie s se includ *f ntre paranteze, deoarece construcia double
*f(); este corect, dar nseamn altceva, parantezele rotunde fiind prioritare
operatorului unar *. n acest caz, se declar f ca o funcie ce returneaz un
pointer spre o valoare flotant n dubl precizie.
7o.
Ultimul
parametru
formal
al
funciei
aria_trapez
corespunde
parametrului efectiv f i deci el trebuie declarat ca i pointer spre o funcie
ce returneaz o valoare flotant n dubl precizie. Conform observaiei 5), dac
p este numele parametrului formal ce corespunde parametrului efectiv f, atunci p
se declar astfel:
double (*p)();
- 43 -

BORLAND C Manual de utilizare


o

8 . n corpul funciei aria_trapez va trebui s apelm funcia f(x) pentru


a calcula valorile:
f(a), f(b), f(a+h), . . . , f(a+(n-1)h).
n momentul programrii funciei aria_trapez, nu se cunoate numele
funciei concrete, ci numai pointerul p spre ea. De aceea, vom nlocui numele
funciei prin *p, deci vom folosi apelurile:
(*p)(a), (*p)(b), (*p)(a+h), . . . ,(*p)(a+(n-1)h)
double aria_trapez(double x, double y, int m, double(*p)());
{
double h,s;
int i;
h=(y-x)/m;
for (i=1, s=0.0; i<m; i++) s+=(*p)(x+i*h);
s+=((*p)(x) + (*p)(y))/2;
s=h*s;
return s;
}
Vom utiliza funcia aria_trapez pentru a calcula integrala definit din
funcia sin(x2) pe intervalul [0,1], cu o eroare mai mic dect 10 -8. Vom nota cu
In urmtoare sum:
In= h((f(a)+f(b))/2 +f(a+h)+f(a+2h)+. . . +f(a+(n-1)h)
Paii algoritmului sunt urmtorii:
Pasul 1. Se alege o valoare iniial pentru n, de exemplu 10.
Pasul 2. Se calculeaz In.
Pasul 3. Se calculeaz I2n prin dublarea lui n.
Pasul 4. Dac |In-I2n| < 10-8, algoritmul se ntrerupe i valoarea
integralei, cu precizia admis, este I2n; altfel se dubleaz n, se pune In=I2n; n,
i se trece la pasul 3.
#define A 0.0
#define B 1.0
#define N 10
#define EPS 1e-8
#include <stdio.h>
#include <math.h>
double sinxp(double);
// prototipul functiei sin(x*x)
double aria_trapez(double, double, int, double (*)());
void main (void)
// functia principala
{ int n=N;
double in, i2n, vabs;
in=aria_trapez (A, B, n, sinxp);
do {
n=n*2;
i2n=aria_trapez(A, B, n, sinxp);
if ((vabs= in-i2n) < 0) vabs = -vabs;
in=i2n;
} while (vabs >= EPS);
printf (valoarea integralei este : %g.10\n,i2n);
}
double aria_trapez(double x, double y, int m, double(*p)());
{
double h,s;
int i;
h=(y-x)/m;
for (i=1, s=0.0; i<m; i++)
s+=(*p)(x+i*h);
s+=((*p)(x) + (*p)(y))/2;
s=h*s;
return s;
}
double sinxp (double x)
{ return sin (x*x); }

- 44 -

BORLAND C Manual de utilizare

6.6. TRATAREA PARAMETRILOR DIN LINIA DE COMAND


n linia de comand folosit la apelul execuiei unui program se pot
utiliza diferii parametri. Aceti parametri pot fi utilizai folosind
parametrii argc i argv ai funciei principale.
Parametrul argc este de tip ntreg i indic numrul de parametri din
linia de comand.
Parametrul argv este un tablou de pointeri spre zonele n care sunt
pstrai parametrii liniei de comand. Acetia se consider iruri de caractere.
Astfel antetul funciei principale va fi :
main (int argc, char *argv[ ])
Exemplu:
Considerm c la lansarea programului prog s-au furnizat parametrii:
MARTIE 1956
n acest caz argc=4, iar tabloul argv conine pointerii:
- argv[0] - pointer spre numele programului (calea, numele i extensia
.EXE
- argv[1] - pointer spre irul 31;
- argv[2] - pointer spre irul MARTIE;
- argv[3] - pointer spre irul 1991.
Observaii:
1o. Lansarea unui program se face cu prima instruciune a funciei
principale. Deci parametrii argc i argv au deja n acest moment valorile
indicate mai sus, putnd fi analizai chiar cu prima instruciune executabil.
2o. n mod frecvent, aceti parametrii reprezint diferite opiuni ale
programului, date calendaristice, nume de fiiere, etc.
3o. argv[0] este ntotdeauna pointerul spre numele fiierului cu imaginea
executabil a programului.
void main ( int argc, char *argv[])
// va afisa parametrii din linia
de comanda
{ int i;
for (i=0; i<argc; i++;)
printf (%s\n,argv[i]);
}
6.7. MODIFICATORUL const
Am vzut anterior c o constant se definete prin caracterele care intr
n compunerea ei. De asemenea, n acelai capitol s-a artat c putem atribui un
nume unei constante printr-o construcie #define. Un astfel de nume se spune c
este o constant simbolic i el se substituie prin irul de caractere care i
corespunde, n faza de preprocesare.
Un alt mod de a defini o constant este acela de a folosi
modificatorul const ntr-o declaraie. Printr-o astfel de declaraie, unui nume
i se poate atribui o valoare constant. n acest caz, numele respectiv nu mai
este tratat de preprocesor i el poate fi folosit n program n mod analog cu
numele variabilelor. Unui astfel de nume declarat cu ajutorul modificatorului
const nu i se poate schimba valoarea printr-o expresie de atribuire, ca i unei
variabile obinuite.
Formatele declaraiei cu modificatorul const sunt urmtoarele:
tip const nume = valoare;
const tip nume = valoare;
tip const nume;
const tip nume;
const nume = valoare;
const nume;
Exemplu:
void main (void)
{ const i=10;
// i devine egal cu 10; nu este posibila o atribuire i=0
const pi = 3.1415926
char *const s=martie;// s este un pointer constant spre zona in care este
// pastrat sirul de caractere martie. Valoarea lui s
// nu poate fi schimbata dar continutul zonei spre
// care pointeaza s poate fi schimbat
*s= 1;
// schimba litera m cu 1
*(s+1)=2
// schimba litera a cu 2
char const *s=aprilie;
// s este un pointer spre o zona constanta.
- 45 -

BORLAND C Manual de utilizare

// valoare lui s poate schimbata dar sirul aprilie


// nu poate fi modificat
const char *s=aprilie// este identica cu declaratia de mai sus.
}
Modificatorul const se folosete frecvent la declararea
formali de tip pointer. O astfel de declaraie are formatul:
const tip *nume_parametru_formal;
Un parametru formal declarat prin construcia :

parametrilor

tip *nume_parametru_formal;
corespunde unui parametru efectiv a crui valoare este o adres. La apel,
valoarea parametrului formal devine egal cu aceast adres. Datorit acestui
fapt, funcia apelat poate s modifice data aflat la adresa respectiv. Dac
se folosete modificatorul const utilizat la declararea unui astfel de parametru
formal atunci se interzice funciei apelate s modifice data de la adresa
recepionat la apel de ctre parametrul formal corespunztor. Acest mecanism
este folosit frecvent n cazul funciilor de tratare a irurilor de caractere.
De exemplu funcia strlen din biblioteca standard a limbajului C are
prototipul:
unsigned strlen (const char *s);
Ea se apeleaz prin expresii de atribuire de forma:
i=strlen(x);
unde x este un pointer spre o zon de memorie n care se afl un ir de
caractere.
Funcia strlen determin lungimea irului aflat la adresa recepionat de
ctre parametrul s. Ea nu are voie s modifice irul respectiv i din aceast
cauz parametrul s se declar folosind modificatorul const.
6.8. STIVA
Prin stiv (stack n englez) nelegem o mulime ordonat de elemente la
care accesul se realizeaz conform principiului ultimul venit primul servit. n
englez stiva se mai numete i list LIFO (Last In First Out).
O modalitate simpl de a implementa o stiv este pstrarea elementelor ei
ntr-un tablou unidimensional. n acest tablou se vor pstra elementele stivei
unul dup altul. De asemenea, ele se pot scoate din tablou n ordinea invers
pstrrii lor. La un moment dat se poate scoate ultimul element pus pe stiv i
numai acesta.
Despre ultinul element pus n stiv se spune c este vrful stivei,
iar despre primul element c este baza stivei.
Accesul este pemis doar la vrful stivei:
un element se poate pune pe stiv numai dup elementul aflat n vrful
stivei i dup aceast operaie el ajunge vrful stivei;
se poate scoate de pe stiv numai elementul aflat n vrful stivei i dup
aceast operaie n vrful stivei rmne elementul care a fost pus pe stiv
naintea lui.
Vom numi stack tablou de tip int afectat stivei i next variabila care
indic prima poziie liber din stiv. Deci stack[0] este baza stivei iar
stack[n] va fi vrful stivei. Vom defini mai multe funcii asociate tabloului
stack:
- push
funcia care pune un element n stiv;
- pop funcia care scoate un element din stiv;
- clear
funcia de iniializare a stivei; dup apelul ei stiva devine
vid;
#define MAX 1000
static int stack[1000];
static next = 0;
// indicele pentru baza stivei
void push(int x)
// pune pe stiva valoarea lui x
{ if (next < MAX)
stack [next++]=x;
else
printf (stiva este depasita\n);
}
int pop() // scoate elementul din varful stivei si returneaza valoarea lui
{ if (next >0)
- 46 -

BORLAND C Manual de utilizare

else

return stack [--next];


{ printf (stiva este vida\n);
return 0;
}

}
void clear(void)
{
next=0;
}

// videaza stiva

LECIA 7.
RECURSIVITATE
Spunem c o funcie C este recursiv dac ea se autoapeleaz nainte de a
se reveni din ea. Funcia se poate reapela fie direct, fie indirect (prin
intermediul altor funcii).
La fiecare apel al unei funcii, parametrii i variabilele locale se aloc
pe stiv ntr-o zon independent. De asemenea, orice apel recursiv al unei
funcii va conduce la o revenire din funcie la instruciunea urmtoare apelului
respectiv. La revenirea dintr-o funcie se realizeaz curarea stivei, adic
zona de pe stiv afectat la apel parametrilor i variabilelor automatice se
elibereaz.
Un exemplu simplu de funcie apelata recursiv este funcia de calcul al
factorialului. Putem defini recursiv funcia factorial astfel:
factorial(n)= 1,
dac n=0
factorial(n)=n*factorial(n-1),
dac n>0
n limbajul C avem :
double factorial (int)
{ if (n= = 0)
return 1.0;
else
return n*factorial(n-1);
}
Observaii:
1o. n general, o funcie recursiv se poate realiza i nerecursiv, adic
fr s se autoapeleze.
2o. De obicei, recursivitatea nu conduce nici la economie de memorie i
nici la execuia mai rapid a programelor. Ea permite ns o descriere mai
compact i mai clar a funciilor. Acest lucru rezult i din exemplul de mai
sus de calcul al factorialului.
3o. n general, funciile recursive sunt de preferat pentru procese care
se definesc recursiv. Exist i excepii. De exemplu algoritmul de generare a
permutrilor de n obiecte poate fi descris recursiv astfel: avnd n memorie
toate cele (n-1)! permutri, atunci permutrile de n obiecte se genereaz
nsernd pe n n toate poziiile posibile ale fiecrei permutri de n-1 obiecte.
Dar ne aducem aminte c 10!=3628800 i capacitatea stivei se depete repede.
Exemple:
Programul determin recursiv cmmdc (algoritmul lui Euclid) a dou numere
ntregi (de tip long):
cmmdc (a,b) = b,
dac a%b =0 (restul mpririi lui a la b e zero)
cmmdc (a,b) = cmmdc (b,a%b), n caz contrar.
#include <iostream.h>
#include <conio.h>
long cmmdc(long a, long b)
{ if (!(a % b))
return b;
else
return cmmdc(b, a % b);
}
void main(void)
{ long x,y;
clrscr();
cout << "dati un numar natural=";
- 47 -

BORLAND C Manual de utilizare

cin >> x;
cout << "dati alt numar natural=";
cin >> y;
cout << "cmmdc(" << x << "," << y << ")=" << cmmdc (x,y);

}
Am folosit funciile de intrare / ieire cin i cout, imediat se observ
modul lor de utilizare.
Programul determin recursiv suma unor elemente de tablou unidimensional
a[1]+a[2]+ . . . + a[n]
#include <iostream.h>
#define MAX 100
int a[MAX];
// suma(n)= 0,
daca n=0
// suma(n)=suma(n-1) + a[n]
daca n>0
int suma(int n)
{ if (!n)
return 0;
else
return a[n]+suma(n-1);
}
void main(void)
{int n,i;
cout << "dati n= ";
cin >> n;
for (i=1; i<=n; i++)
{
cout << "a[" << i << "]= ";
cin >> a[i];
}
cout << "suma numerelor este " << suma(n);
}
Programul determin recursiv termenul al n-lea din irul lui Fibonacci
definit dup cum urmeaz:
fibonacci[0]=0
fibonacci[1]=1
fibonacci[n]=fibonacci[n-1]+fibonacci[n-2],

dac n>1

#include<iostream.h>
long fibonacci (long n)
{if (!n)
return 0;
else if (n==1)
return 1;
else
return fibonacci(n-1) + fibonacci(n-2);
}
void main (void)
{ long n;
cout << "dati n = ";
cin >> n;
cout << "fibo(" << n << ") =" << fibonacci (n);
}
Programul determina maximul dintr-un vector de numere astfel:
M(n)= a[1]
dac n=1
M(n)= max { M(n-1),a[n] }
#include<iostream.h>
#define MAX(x,y) (x > y ? x : y)
int a[100];

dac n>1

int M(int n)
{ if (n= =1)
return a[1];
else
return MAX (M(n-1), a[n]);
}
- 48 -

BORLAND C Manual de utilizare

void main(void)
{int n,i;
cout << "dati n=";
cin >> n;
for (i=1; i<=n; i++)
{
cout << "a[" << i << "]= ";
cin >> a[i];
}
cout << "maximul este " << M(n);
}
5) Programul afiseaz un ir de caractere n mod recursiv, caracter cu
caracter,
considernd
c
irul
de
caractere
este
format
din
primul
caracter(capul) + restul irului de caractere (coada).
#include <iostream.h>
#include <conio.h>
#define max 100
char sir [max];
int n;
void afis (int m)
{ if (m = = n+1) return;
else
{ cout << sir[m];
afis(m+1);
}
}
void main (void)
{int i;
do { cout << "\ndati lungimea sirului =";
cin >> n;
}
while ( (n< 0) || (n > max));
for(i=1; i<=n; i++)
{
cout << "sir[" << i << "]=";
cin >> sir[i];
}
afis(1);
getch();
}
6) Programul ce urmeaz e oarecum asemntor cu exemplul anterior doar c
afieaz irul de caractere de la sfrit spre nceput.
#include <iostream.h>
#include <conio.h>
#define max 100
char sir [max];
void afis (int m)
{ if (m==0)
return;
else
{ cout << sir[m];
afis(m-1);
}
}
void main (void)
{int n,i;
do
{cout << "\ndati lungimea sirului ="), cin >> n;}
while ( (n< 0) || (n > max));
for(i=1; i<=n; i++)
{
cout << "sir[" << i << "]=";
cin >> sir[i];
}
afis(n);
getch();
}
7) Programul sorteaz prin metoda quicksort un vector de numere ntregi:
- 49 -

BORLAND C Manual de utilizare

#define dim 50
#include <stdio.h>
#include <conio.h>
int x[dim+1],i,n;
void tipsir ()
{ for (i=1; i<=n; i++)
{
printf("%3d",x[i]);
if (!(i % 20)) printf ("\n");
}
}
void quik(int st, int dr)
{int i,j,y;
i=st; j=dr; y=x[i];
do { while ((x[j] >= y) && (i<j)) j - -;
x[i]=x[j];
while ((x[i] <= y) && (i<j)) i++;
x[j]=x[i];
}
while (i != j);
x[i]=y;
if (st < i-1)
quik(st,i-1);
if (i+1 < dr)
quik(i+1,dr);
x[j]=x[i];
}
void citire (void)
{ int cod = 0;
n = dim+1;
while ( n <= 0 || n > dim || ! cod )
{
printf ("\ndati dim. sir:");
cod=scanf ("%d",&n);
}
i = 1;
while (i<=n)
{ printf ("x[%2d]=",i);
scanf ("%d", &x[i]);
i++;
}
}
void main(void)
{ clrscr();
citire();
clrscr();
printf ("\n\nsir initial\n");
tipsir();
quik(1,n);
printf ("\n\nsir sortat\n");
tipsir();
getche();
}

- 50 -

BORLAND C Manual de utilizare

LECIA 8.
STRUCTURI, TIPURI UTILIZATOR
Dup cum am vzut datele de acelai tip se pot grupa n tablouri.
Limbajul C permite gruparea unor date de tipuri diferite sub alte forme de
organizare numite structuri.
Tablourile au un tip i anume tipul comun elementelor lor. Astfel,
distingem tablouri de tip ntreg, de tip caracter, de tip flotant, etc. n cazul
structurilor, nu mai avem un tip comun. Fiecare structur reprezint un nou tip
de date, tip care se introduce prin declaraia structurii respective.
Un exemplu simplu de structur este data calendaristic, cu
componentele urmtoare:
ziua;
luna;
anul.
unde: ziua i anul sunt date de tip ntreg iar luna este un tablou de
caractere.
Structura ca i tabloul, este o muline ordonat de elemente. n
exemplul de mai sus se consider c ziua este primul ei element, luna este al
doilea iar anul este ultimul ei element. Trebuie s precizm c referirea la
componentele unei structuri nu se mai face cu ajutorul indicilor ci prin
calificare.
8.1. DECLARAIA DE STRUCTUR
O structur se poate declara n mai multe feluri, astfel:
Formatul 1:
struct nume_structura
{ lista_declaratii
};
Cu ajutorul acestui format se introduce un nou tip de dat cu numele
nume_structur. Lista de declaraii este format din declaraii obinuite. Tipul
data_calendaristica l putem introduce astfel:
struct data_calendaristica
{ int ziua;
char luna[11];
int anul;
};
O astfel de declaraie se numete declaraie de tip. S reinem c unui
nou tip de date nu i se aloc memorie, el este doar contabilizat ca un nou tip
utilizator pe lng tipurile predefinite ale limbajului C.
Formatul 2:
struct nume_structura
{ lista_declaratii
}lista_variabile;
Un astfel de format introduce tipul utilizator nume_structura i declar o
list de varibile n care fiecare element din list are tipul nume_structur.
Prin exemplu urmtor se introduc variabilele dc1 i dc2 ca date elementare de
tipul data_calendaristica i tabloul dc de 13 componente.
- 51 -

BORLAND C Manual de utilizare

struct data_calendaristica
{ int ziua;
char luna[11];
int anul;
} dc1, dc2, dc[13];
Formatul 3:
struct
{ lista_declaraii
} lista_variabile;
Acest format se foloseste dac nu vrem sa dm nume noului tip structurat
i totodat dac nu mai vrem s-l folosim. Deci nu vom mai pute declara alte
date de tipul structurat nou introdus pentru c tipul nu are nume.
Exemplu:
struct
{ int ziua;
char luna[11];
int anul;
} dc1, dc2, dc[13];
S-au declarat varibilele dc1, dc2 i tabloul dc avnd noul tip structurat
utilizator dar nu se mai dorete s declarm alte date de acest tip.
Observaii:
1o. Dac se folosete formatul 1 atunci pentru a declara date de tipul
utilizator nou introdus se folosete o construcie de forma:
struct nume_ structura lista_variabile;
Compilatorul aloc memorie varibilelor din lista de variabile, tratnd
aceast construcie ca i declaraiile obinuite.
2o. Componentele unei structuri pot fi ele nsele date structurate. O
component care nu este structurat se numete component elementar.
3o. Ca i n cazul celorlalte tipuri de variabile se pot defini structuri
globale, statice sau automatice. Structurile statice se declar precednd
declaraiile lor prin cuvntul static, iar cele externe prin cuvntul cheie
extern.
4o. Elementele unei date de tip structur pot fi iniializate dup modelul
iniializrii variabilelor care au tipuri predefinite.
Exemple:
1) Introducem tipul utilizator data_calendaristica astfel:
struct data_calendaristica
{ int ziua;
char luna[11];
int anul;
};
pentru a iniializa o dat de tipul data_calendaristic vom scrie:
struct data_calendaristica dc1={31, martie, 1956};
2) Dac declarm un nou tip date_personale i n care vrem s folosim
tipul data_calendaristica, vom scrie:
struct date_personale
{ char nume[30];
char adresa[50];
struct
data_calendaristica
data_angajarii;
};

data_nasterii,

8.2. ACCESUL LA ELEMENTELE UNEI STRUCTURI


Pentru a avea acces la componentele unei date structurate va trebui s
folosim o calificare de forma:
nume_data_structurata.nume_componenta
- 52 -

BORLAND C Manual de utilizare

Astfel dac avem tipul structurat data_calendaristica


exemplele anterioare i declarm data dc astfel:
struct data_calendaristica dc;
atunci pentru a ne referi la componentele
construciile:
dc.ziua
dc.anul
dc.luna (atenie este pointer spre caractere)

datei

dc

introdus

vom

in

folosi

Dac avem declarat un tablou astfel:


struct data_calendaristica tdc[10];
atunci pentru fiecare component i ne vom referi astfel:
tdc[i].ziua
tdc[i].anul
tdc[i].luna (este pointer)
tdc[i].luna[0], tdc[i].luna[1], . . . , tdc[i].luna[11]
Ca i tablourile structurile se pot transfera prin parametrii,
transfernd un pointer spre data structurat respectiv, adic adresa de nceput
a zonei alocate structurii. Deci, printr-un apel de forma:
functie(&data_structurata);
se transfer funciei functie adresa de nceput a zonei alocate structurii
data_structurata. Dac data_structurata este o structura de tipul tip, atunci
antetul funciei functie este urmtorul:
void functie(tip *p)
unde p este pointer spre tipul structurat tip.
Pentru data structurat dc de tipul data_calendaristica antetul funciei
functie este:
void functie(struct data_calendaristica *p)
iar apelul pentru data dc se face
functie(&dc);
Printr-un astfel de apel, funcia apelat nu are acces la numele
datei structurate transferate, ci numai la pointerul spre ea. De aceea se pune
problema accesului la componentele datei structurate prin pointerul la ea. n
acest caz numele datei structurate se va nlocui prin *p. Deci, n cazul datei
structurate dc, transferate ca i mai sus, n locul construciei
dc.zi
vom scrie:
(*p).zi
nlocuind numele datei structurate dc prin *p, unde p este un pointer spre
dc.

Observaie:
1o. Parantezele rotunde din construcia de mai sus sunt obligatorii,
deoarece punctul este un operator prioritar operatorului unar *.
2o. Construcia de mai sus poate fi nlocuit prin p->zi care este
identic cu ea. Simbolul -> se compune din caracterele - i > scrise unul
dup cellalt fr spaiu ntre ele. El se numete sgeat i este considerat a
fi un operator cu aceeai prioritate ca i punctul, deci de prioritate maxim.
8.3. ATRIBUIRI DE NUME PENTRU TIPURI DE DATE
Dup cum tim tipurile de baz ale limbajului C, numite i tipuri
predefinite se identific printr-un cuvnt cheie (int, char, float, etc).
Totodat prin instruciunea struct, programatorul poate s introduc un tip nou.
- 53 -

BORLAND C Manual de utilizare

Programatorul poate s atribuie un nume unui tip (predefinit sau utilizator) cu


ajutorul construciei:
typedef tip nume_nou_tip;
unde:
tip este numele unui tip predefinit sau al unui tip utilizator (introdus
cu struct);
nume_nou_tip este noul nume atribuit tipului respectiv.
Dup ce s-a atribuit un nou nume unui tip, numele respectiv poate fi
utilizat pentru a declara date de acel tip, la fel cum se utilizeaz n
declaraii cuvintele cheie int, char, float, etc.
Observaii:
1o. De obicei numele atribuit unui tip se scrie cu litere mari.
2o. Un exemplu de astfel de nume exist n fiierul stdio.h pentru tipul
fiier, cruia i s-a atribuit numele FILE.
Exemple:
Fie declaraiile:
typedef int INTREG;
typedef float REAL;
n continuare, denumirile INTREG i REAL se pot folosi la fel ca i
cuvintele cheie int i float. Cu alte cuvinte, declaraia:
INTREG i, j, tablou[10];
este identic cu declaraia urmtoare:
int i, j, tablou[10];
Analog:

REAL x, y, z;

este identic cu declaraia:


float x, y, z;
typedef struct data_calendaristica
{
int
ziua;
char luna[11];
int
anul;
} DC;
Prin aceast declaraie se atribuie denumirea DC tipului structurat
data_calendaristica. n continuare putem declara date de tip DC:
DC data_nasterii, data_angajarii;
DC data_curenta ={31,august,1998};
typedef int *PI;
Prin aceast declaraie se introduce un sinonim pentru tipul pointer spre
ntregi: int *.
Putem s declarm n continuare pointeri spre ntregi astfel:
PI p;
care este echivalent cu:
int *p;
4) Declaraia
{
double real;
double imaginar;
} COMPLEX;

typdef struct

introduce numele COMPLEX pentru datele de tip complex.


Funcia urmtoare returneaz modulul unui numr complex:
- 54 -

BORLAND C Manual de utilizare

typedef struct
double real;
double imaginar;
} COMPLEX;
#include <math.h>
double modul (COMPLEX *x)
// returneaza modulul numarului
// spre care pointeaza x
{ return sqrt (x->real * x->real + x->imaginar * x->imaginar);
}
{

8.4. UNIUNE
Limbajul C ofer utilizatorului posibilitatea de a folosi aceeai
zon de memorie pentru a pstra date de tipuri diferite n momente diferite ale
execuiei programului. Astfel, de exemplu, putem utiliza o zon de memorie
pentru a pstra la un moment dat o dat flotant, iar ulterior s reutilizm
aceeai zon pentru o dat ntreag sau de tip pointer. Reutilizrile zonelor de
memorie conduc la utilizarea mai eficient a acesteia, uneori putndu-se obine
o economie substanial a spaiului de memorie alocat programului.
O uniune se declar printr-o construcie asemntoare declaraiei de
structur. Deosebirea const n nlocuirea cuvntului struct prin union:
union nume
{ tip_membru_1;
. . .
tip_membru_2;
}
Exemplu:
union u
{ int i;
float f;
double d;
};
Prin aceast declaraie s-a definit tipul de date u. n continuare, putem
declara date de tipul u printr-o declaraie de forma:
union u u1;
unde u1 este o dat de tip u creia i se aloc o zon de memorie care
poate fi utilizat pentru a pstra date de tipurile int, float sau double.
Deoarece tipul double necesit memoria cea mai mare se aloc 8 octei. Astfel
zona u1 poate pstra pe oricare din celelalte componente ale uniunii dar n
momente diferite ale execuiei programului.
Accesul la componentele unei uniuni se face la fel ca i n cazul
structurilor. Astfel, pentru a ne referi la componenta i a uniunii u1 definit
n exemplul anterior folosim construcia:
u1.i
sau dac p este pointer spre tipul u declarat prin
union u *p;
atunci construcia
p -> i
permite accesul la componenta i a uniunii spre care pointeaz p.
Pentru a evita erorile legate de evidena n fiecare moment a datei
care se prelucreaz se ataeaz unei uniuni o dat menit s indice componenta
curent. Aceast dat este specificat pentru fiecare uniune. De exemplu pentru
- 55 -

BORLAND C Manual de utilizare

uniunea u1 definit anterior este important s se tie dac zona de memorie


conine un ntreg, un flotant n simpl precizie sau un flotant n dubl
precizie. Se definesc trei constante simbolice:
#define INTREG 1
#define F_SIMPLU 2
#define F_DUBLU 3
Modificm tipul u atand data tip_curent de tip int astfel:
struct u
{int tip_curent;
union {
int
i;
float
f;
double d;
} uu;
};
Declarm structura us astfel:
struct u us;
n acest caz, n momentul n care se pstreaz o dat n zona
rezervat uniunii, se atribuie componentei tip_curent una din constantele
definite anterior:
INTREG, dac se pstreaz un ntreg;
F_SIMPLU dac se pstreaz un flotant n simpl precizie;
F_DUBLU dac se pstreaz un flotant n dubl precizie.
Astfel cnd se folosete componenta de tip int se va asocia atribuirea:
us.tip_curent=INTREG;
Analog se vor folosi i atribuirile
componentele de tip float sau de tip double:
us.tip_curent=F_SIMPLU;
respectiv:
us.tip_curent=F_DUBLU;

urmtoare

cnd

se

vor

folosi

n felul acesta, se poate testa, n fiecare moment, tipul de dat


prezent n zona rezervat. Aceasta se poate face printr-o secven de
instruciuni if sau prin intermediul instruciunii switch.
if (us.tip_curent = = INTREG)
us.uu.i
else if (us.tip_curent = = FSIMPLU)
else if (us.tip_curent = = FDUBLU)
else eroare

//

se

foloseste

// se foloseste us.uu.f
// se foloseste us.uu.d

sau folosind switch avem o construcie mai clar de forma:


switch (us.tip_curent)
{ case INTREG:
// se foloseste us.uu.i
break;
case FSIMPLU:
// se foloseste us.uu.f
break;
case FDUBLU
// se foloseste us.uu.d
break;
default:
// eroare
}
Programul urmtor calculeaz ariile pentru urmtoarele figuri geometrice:
cerc;
dreptunghi;
ptrat;
triunghi.
- 56 -

BORLAND C Manual de utilizare

Programul citete datele pentru o figur geometric, calculeaz aria


figurii respective i scrie rezultatul:
La intrare se folosesc urmtoarele formate:
- pentru cerc
C raza;
- pentru dreptunghi
D lungime laime;
- pentru ptrat
P latur;
- pentru triunghi T latur latur latur;
- sfrit fiier
EOF.
n cazul triunghiului, se utilizeaz formula lui HERON pentru calculul
ariei:
aria = sqrt (p*(p-a)(p-b)(p-b))
unde p este semiperimetrul, iar a, b, c sunt cele 3 laturi.
#include <stdio.h>
#include <math.h>
#define PI 3.14159265
#define EROARE -1
#define CERC 1
#define PATRAT 2
#define DREPT 3
#define TRIUNGHI 4
typedef struct
{
int tip;
// tipul figurii
union
{ double raza
// cerc
double lp ;
// patrat
double ld[2] ;
// dreptunghi
double lt[3] ;
// triunghi
} fig;
}FIG;
void main (void)
// calculeaza arii
{
double aria,p;
int i;
char car[2];
FIG zfig;
for(; ;)
// citeste primul caracter,el defineste
tipul figurii geometrice
{ printf(se cere o litera mare\n);
if ((i = scanf("%1s",car)) == EOF) break;
if (i != 1)
{ printf (" se cere o litera mare\n");
continue;
}
zfig.tip = EROARE;
switch(car[0])
{case 'C':
// cerc
printf("se cere raza cercului in flotanta\n");
i = scanf("%lf", &zfig.fig.raza);
if(i != 1)
{ printf("se cere raza cercului in flotanta\n");
break;
}
zfig.tip = CERC;
// se pastreaza tipul figurii
break;
case 'P':
// patrat
printf("se cere latura patratului in flotanta\n");
i = scanf("%lf",&zfig.fig.lp);
if( i !=1)
{ printf("se cere latura patratului in flotanta\n");
break;
}
zfig.tip = PATRAT;
break;
- 57 -

BORLAND C Manual de utilizare

case 'D':
// dreptunghi
printf("se cer laturile dreptunghiului in flotanta\n");
i = scanf("%lf %lf",&zfig.fig.ld[0],&zfig.fig.ld[1]);
if(i != 2)
{ printf("se cer laturile dreptunghiului in flotanta\n");
break;
}
zfig.tip = DREPT;
break;
case 'T':
// triunghi
printf("se cer laturile triunghiului in flotanta\n");
i
=
scanf("%lf
%lf
%lf",
&zfig.fig.lt[0],
&zfig.fig.lt[1],&zfig.fig.lt[2]);
if(i != 3)
{ printf("se cer laturile triunghiului in flotanta\n");
break;
}
zfig.tip =TRI;
break;
printf("laturile nu formeaza un triunghi\n");
break;
default:
printf("se cere una din literele urmatoare\n");
printf("C pentru cerc\n");
printf("P pentru patrat\n");
printf("D pentru dreptunghi\n");
printf("T pentru triunghi\n");
} // sfarsit switch
switch (zfig.tip)
{case CERC:
// aria cercului
printf("raza=%g
aria=%g\n",
zfig.fig.raza,
PI*zfig.fig.raza*zfig.fig.raza);
break;
case PATRAT:
// aria patratului
printf("latura
=%g
aria=%g\n",zfig.fig.lp,
zfig.fig.lp*zfig.fig.lp);
break;
case DREPT:
// aria dreptunghiului
printf("lungimea =%g latimea =%g\n", zfig.fig.ld[0], zfig.fig.ld[1]);
printf("aria=%g\n", zfig.fig.ld[0]*zfig.fig.ld[1]);
break;
case TRIUNGHI:
// aria triunghiului
p=(zfig.fig.lt[0] + zfig.fig.lt[1] + zfig.fig.lt[2])/2;
if(p>zfig.fig.lt[0] && p>zfig.fig.lt[1] && p>zfig.fig.lt[2])
{p=p*(p-zfig.fig.lt[0])*(p-zfig.fig.lt[1])* (p-zfig.fig.lt[2]);
printf("a=%g b=%g c=%g\n", zfig.fig.lt[0], zfig.fig.lt[1],
zfig.fig.lt[2]);
printf("aria = %g\n",sqrt(p));
}
else {
printf ( laturile nu formeaza un triunghi);
break;
}
default :
// avans pana la newline sau EOF
while ((i = getchar()) != \n && i != EOF);
} // sfarsit switch
if (i = = EOF) break;
}
// sfarsit for
}
// sfarsit main
8.5. CAMP

- 58 -

BORLAND C Manual de utilizare

Limbajul C permite utilizatorului definirea i prelucrarea datelor pe


bii. Utilizarea datelor pe bii este legat de folosirea indicatorilor care de
obicei sunt date care iau numai dou valori 0 sau 1.
Nu este justificat ca un astfel de indicator s fie pstrat ca un
ntreg pe 16 bii i nici mcar pe un octet. Indicatorul poate fi pstrat pe un
singur bit. n acest scop, limbajul C ofer posibilitatea de a declara date care
s se aloce pe bii (unul sau mai muli bii). Acest lucru i gsete aplicare
n programele de sistem. Astfel, de exemplu, atributele variabilelor dintr-o
tabel de simboluri pot fi pstrate pe bii, ceea ce conduce la o economisire
substanial a memoriei ocupate de tabela respectiv.
Prin camp nelegem un ir de bii adiaceni coninui ntr-un
cuvnt calculator. Cmpurile se grupeaz formnd o structur.
Un cmp se declar ca i o component a unei structuri i el are
tipul unsigned (ntreg fr semn). Totodat n declaraia cmpului se indic i
dimensiunea lui n bii.
n general, o structur cu componente cmpuri are forma:
struct
{ camp1;
. . .
campn;
} nume;
unde campi (i=1,...,n) are unul din formatele de mai jos:
unsigned nume : lungime_n_bii
sau
: lungime_n_bii
Exemplu:

struct
{ unsigned a:1;
unsigned b:1;
unsigned c:2;
unsigned d:2;
unsigned e:3;
} indicatori;
Data indicatori se aloc ntr-un cuvnt calculator, adic pe 16
bii. Componentele ei sunt:
a un bit;
b un bit;
c doi bii;
d doi bii;
e trei bii.
La cmpuri ne putem referi la fel ca i la componentele oricrei
structuri. Deci la indicatorii de mai sus ne putem referi prin urmtoarele
construcii:
indicatori.a
indicatori.b
indicatori.c
indicatori.d
indicatori.e
Alocarea biilor este dependent de calculator. De obicei biii se aloc
de la dreapta spre stnga ca n figura de mai jos:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
a
b
c
d
e
- 59 -

BORLAND C Manual de utilizare

Observaii:
1o. Dac un cmp nu poate fi alocat n limitele unui cuvnt, el se aloc
n ntregime n cuvntul urmtor.
2o. Nici un cmp nu poate avea o dimensiune mai mare dect 16 bii.
3o. Formatul fr nume (al doilea format) pentru cmp se folosete pentru
cadraje. Acest lucru este util atunci cnd sunt zone de bii neutilizate n
cadrul unui cuvnt. De asemenea, utilizarea formatului cu lungime egal cu zero
permite ca alocarea cmpurilor urmtoare lui s se fac n cuvntul urmtor.
4o. O structur care are i componente cmpuri poate avea i componente
obinuite.
5o. Nu se pot defini tablouri de cmpuri.
6o. Unui cmp nu i se poate aplica operatorul adres.
Cmpurile se utilizeaz frecvent la scrierea unor programe de sistem, cum
ar fi : drivere pentru periferice, compilatoare, etc.
Utilizarea cmpurilor poate conduce la programe cu o portabilitate
redus. Totodat, accesul la date pe bii conduce la creterea numrului de
operaii, fiind necesare deplasri i operaii pe bii suplimentare, fapt ce
poate conduce att la creterea timpului de execuie a programelor, ct i la
creterea memoriei utilizate. Ori datele pe bii se folosesc chiar n ideea de a
economisi memorie.

8.6. TIPUL ENUMERAT


Tipul enumerat permite utilizatorului s foloseasc n program nume
sugestive n locul unor valori numerice. De exemplu, n locul numrului unei
luni calendaristice, se poate folosi denumirea ei:
ian
feb
mar
n locul valorilor 0 i 1 se pot folosi cuvintele FALS i ADEVRAT.
Prin aceasta, se introduce o mai mare claritate n programe, deoarece
valorile numerice sunt nlocuite prin diferite sensuri atribuite lor.
Un tip enumerat se introduce printr-o declaraie de forma:
enum nume {nume0, nume1, . . . , numen};
Prin aceast declaraie se definete tipul enumerat nume, iar numei are
valoarea i. O form mai general a declaraiei de mai sus permite
programatorului s foreze valorile numelor din acolad. n acest scop, se pot
folosi construcii de forma:
numei= eci
unde eci este o expresie constant de tip int.
Cu alte cuvinte, unui nume i se poate atribui o valoare sau valoarea
lui coincide cu a numelui precedent mrit cu 1. Dac primului nume din acolad
nu i se atribuie o valoare, el are valoarea 0. Numele nume 0, nume1,. . . , numen
trebuie s fie nume diferite. Ele sunt constante i valoarea lor se stabilete
prin declaraia n care au fost scrise. Domeniul lor de valabilitate este
definit de domeniul de valabilitate al declaraiei prin care se definesc:
instruciunea compus care conine declaraia;
fiierul surs n care este scris declaraia, dac este extern oricrei
funcii.
Valorile atribuite lui nume0, nume1, . . . , numen sunt de obicei diferite,
dar unele pot s i coincid.
Dup ce s-a introdus un tip enumerat, se pot declara date de tipul
respectiv printr-o declaraie de forma:
enum nume lista_de_variabile;
Datele de tip enumerat se consider de tip int i se pot utiliza n
program oriunde este legal s apar o dat de tip int.
- 60 -

BORLAND C Manual de utilizare

Observaii:
1o. Se pot utiliza, ca i n cazul structurilor, construcii de forma:
enum nume {nume0, nume1,. . . , numen} lista_de_variabile;
sau
enum { nume0, nume1,. . . , numen} lista_de_variabile;
2o. De asemenea, se poate utiliza construcia typedef pentru a atribui un
nume unui tip enumerat:
typedef enum nume {nume0, nume1,. . . , numen} NUME;
n continuare se pot declara date de tipul NUME, astfel:
NUME lista_de_variabile;
Exemple:
enum luna{ian=1,feb,mar,apr,mai,iun,iul,aug,sep,oct,nov,dec};
enum luna luna_calendaristica
Prin prima declaraie se introduce tipul enumerat luna. Mulimea de
valori asociate acestui tip este format din numerele ntregi 1,2, . . . , 12.
Se pot utiliza denumirile:
ian ia valoarea 1
feb ia valoarea 2
. . .
dec ia valoarea 12
A doua construcie declar data luna_calendaristica de tipul luna. Ei i se
pot atribui valori prin expresii de atribuire de forma:
luna_calendaristica = mar sau
luna_calendaristica = mai + 4
typedef enum {luni, marti,miercuri,joi,vineri,sambata,duminica} ZI;
ZI z;
Variabila z este de tip ZI. Se poate utiliza n expresii de forma:
z=marti;
if(z<sambata)
// trateaza ziua de lucru
else
// trateaza zi de odihna

- 61 -

BORLAND C Manual de utilizare

LECIA 9.
L I S T E
9.1. DATE STRUCTURATE DEFINITE RECURSIV
Limbajul C permite definirea de tipuri structurate recursiv
(autorefereniate). Acest lucru se face cu ajutorul pointerilor, i anume un
element al structurii poate s fie un pointer spre tipul de dat introdus prin
structura respectiv:
struct nume
{ declaratii
struct nume *p;
declaratii
};
Un tip definit ca mai sus se spune c este un tip autoreferit sau
recursiv. O dat structurat declarat printr-un astfel de tip se spune c este
autoreferit sau recursiv. Datele structurate recursive au numeroase aplicaii
n prelucrarea listelor nlnuite i arborescente.
Dou tipuri structurate t1 i t2 pot s conin fiecare un pointer
spre celalalt. n acest caz se va proceda ca mai jos:
struct t1;
poate

// o declaratie inainte fara de care nu se

// declara tipul t2
struct t2
{ declaratii
struct t1 *pt1;
declaratii
};
struct t1
{ declaratii
struct t2 *pt2;
declaratii
};
9.2. LISTE NLNUITE
- 62 -

BORLAND C Manual de utilizare

Datele structurate se pot organiza n tablouri sau n structuri


recursive introducnd n tipul structurat unul sau mai muli pointeri spre tipul
structurat respectiv. Astfel se stabilete o relaie de ordine (uneori chiar mai
multe) ntre elementele mulimii de date structurate; de asemenea, mulimea
rescpectiv se poate organiza n mod dinamic, adugnd elemente noi sau
suprimndu-le pe cele care nu mai sunt necesare.
Definiie O mulime dinamic de structuri recursive de acelai tip i care
satisfac una sau mai multe relaii de ordine introduse prin pointeri se numete
list nlnuit. Elementele listei se mai numesc noduri.
Cele mai utilizate tipuri de list sunt:
lista simplu nlnuit;
lista circular simplu nlnuit;
lista dublu nlnuit;
lista circular dublu nlnuit;.
9.3. LISTA LINIAR SIMPLU NLNUIT
O list simplu nlnuit; este o list nlnuit; ale crei noduri
satisfac o singur relaie de ordine introdus prin pointeri.
Tipul unui nod dintr-o list simplu nlnuit; se poate declara n dou
moduri:
struct tnod
{ declaratii
struct tnod *urmator;
declaratii
};
typedef struct tnod
{ declaratii
struct tnod *urmtor;
declaratii
} TNOD;
Observaii
1o. Varianta b) este mai folosit.
2o. Pointerul urmtor introduce o relaie de ordine ntre nodurile de tip
TNOD.

3o. Ultimul nod al listei va avea pointerul urmator = NULL.


4o. Pentru nodurile interioare ale listei pointerul urmator va avea valori
adrese; dac urmator din nodul a pointeaz spre nodul b, spunem c nodul b este
succesorul lui a.
Operaiile ce se pot efectua asupra unei liste simplu nlnuit;
crearea listei;
accesul la un nod al listei;
inserarea unui nod nlnuit;
tergerea unui nod dintr-o list;
tergerea unei liste.
Memorarea listelor se poate face:
dinamic (n memoria intern);
static (n fiiere).
Pentru modul dinamic se va folosi funcia malloc la crearea listei ct i
la inserarea de noduri, iar la tergerea de noduri funcia free.
9.4. CREAREA I AFIAREA UNEI LISTE
Vom crea o list ce conine n noduri informaii despre numere
ntregi i ptratele lor. Avem dou funcii: una de creare care ntoarce adresa
capului listei i o funcie de afiare a informaiei din noduri. Vom comenta
instruciunile importante din program.
#include <stdio.h>
#include <alloc.h>
typedef struct nod
{
int nr;
int patrat;

// definirea tipului NOD

- 63 -

BORLAND C Manual de utilizare

struct nod* leg;


} NOD;
NOD *creaza(void)
// functia de creare, intoarce adresa capului
{ NOD *cap,*p,*pc;
int i,lung;
printf("\n\n\n\ creare lista simplu inlantuita\n\n");
lung = sizeof(NOD);
pc=(NOD *)malloc(lung);
// pc este un pointer curent, in el se vor
pune adresel noi
cap=pc;
printf("dati informatia elementului : ");
scanf ("%d",&i);
while (i>0)
// crearea listei se termina la numar
negativ
{ p=pc;
// pointer ce pastreaza adresa noua
p->nr=i;
// incarcarea informatiei
p->patrat=i*i;
pc=(NOD *)malloc(lung);
// se cere o noua adresa de memorie
p->leg=pc;
// se leaga pointerul leg la noua adresa
printf("dati informatia elementului : ");
scanf ("%d",&i);
}
p->leg=NULL;
// ultimul nod al listei are pointerul leg =
NULL
free(pc);
// eliberarea ultimei adrese care de fapt nu face
parte din lista
return cap;
// returneaza adresa capului listei
}
void afisare(NOD *p)
// functia de afisare a listei
{
while (p != NULL)
// cat timp n-am ajuns la ultimul nod
{ printf ("\n numarul %d si patratul sau %d", p->nr,p->patrat);
p=p->leg;
// trecerea la urmatorul nod al listei
}
}
void main (void)
{ NOD *capul;
clrscr();
capul=creaza();
afisare(capul);
getch();
}

// functia principala
// lista e cunoscuta prin adresa capului

- 64 -

BORLAND C Manual de utilizare

LECIA 10.
PRELUCRAREA FIIERELOR
10.1. FIIERE
n general, prin fiier nelegem o colecie ordonat de elemente numite
nregistrri, care sunt pstrate pe diferite suporturi de memorie extern.
Suportul de memorie extern cel mai folosit este suportul magnetic (de obicei
discuri sub forma de flopy i hardiscuri sau band magnetic care e din ce n ce
mai rar folosit). Suportul magnetic este reutilizabil deoarece zona utilizat
pentru a pstra nregistrrile unui fiier poate fi ulterior reutilizat pentru
a pstra nregistrrile altui fiier.
Datele introduse de la un terminal se consider c formeaz un fiier de
intrare. nregistrarea n acest caz, de obicei, este format din datele tastate
la terminal pe un rnd deci caracterul de rnd nou (newline) este terminator de
nregistrare. n mod analog, datele care se afieaz pe terminal formeaz un
fiier de ieire. nregistrarea poate fi format din caracterele unui rnd.
Un fiier are o nregistrare care marcheaz sfritul de fiier. n cazul
fiierelor de intrare de la tastatur sfritul de fiier se genereaz prin:
CTRL/Z
El poate fi pus n eviden folosind constanta simbolic EOF definit n
fiierul stdio.h.
Prelucrarea fiierelor implic un numr de operaii specifice acestora.
Dou operaii sunt absolut necesare la prelucrarea oricrui fiier:
deschiderea fiierului;
nchiderea fiierului.
Aceste operaii de deschidere i nchidere a unui fiier se pot realiza
prin intermediul unor funcii speciale din biblioteca standard a limbajului C.
Alte operaii privind prelucrarea fiierelor sunt:
crearea unui fiier;
consultarea unui fiier;
actualizarea unui fiier;
adugarea de nregistrri ntr-un fiier;
poziionarea ntr-un fiier;
tergerea unui fiier.
Prelucrarea fiierelor se poate face la dou nivele. Primul nivel face
apel direct la sistemul de operare i se numete nivelul inferior de prelucrare
al fiierelor. Cel de-al doilea nivel de prelucrare se realizeaz prin
utilizarea unor proceduri specializate n prelucrarea fiierelor care, printre
altele, pot rezerva i gestiona automat zone tampon necesare realizrii
operaiilor de intrare/ieire, i se numete nivelul superior de prelucrare al
fiierelor
10.2. NIVELUL INFERIOR DE PRELUCRARE AL FIIERELOR
La acest nivel de prelucrare se folosesc 5 funcii:
open (creat)- pentru deschiderea fiierelor;
read - pentru citirea din fiier;
write - pentru citirea din fiier;
lseek - pentru poziionarea n fiier;
close - pentru nchiderea fiierului.
10.2.1. Deschiderea unui fiier
Orice fiier nainte de a fi prelucrat trebuie deschis. Aceast operaie
se realizeaz prin intermediul funciei open al crui prototip este urmtorul:
int open (const char *cale, int acces);
unde:
cale este un pointer spre un ir de caractere care definete calea spre
fiierul care se deschide (n cea mai simpl form este numele fiierului dac
se afl n directorul curent)
acces este o variabil de tip ntreg care poate lua una din valorile:
- O_RDONLY
- fiierul se deschide numai n citire (consultare);
- O_WRONLY
- fiierul se deschide numai n scriere (creare);
(sau O_CREAT)
- O_RDWR
- fiierul se deschide n citire/scriere;
- 65 -

BORLAND C Manual de utilizare

- O_APPEND
- O_BINARY
- O_TEXT

- fiierul se deschide la sfrit pentru adugare;


- fiierul se prelucreaz binar;
- fiierul este de tip text.

Unele valori din cele de mai sus se pot combina cu ajutorul operatorului
|. De exemplu O_RDWR | O_BINARY pentru deschiderea fiierului n scriere/citire
binar.
Observaii:
1o. Funcia open ntoarce descriptorul de fiier care este o valoare
intreag ce va identifica fiierul n toate celelate operaii care se vor
realiza asupra lui. Dac deschiderea unui fiier nu reuete (de obicei unul din
parametrii este eronat) atunci funcia open returneaz valoarea 1.
2o. Pentru a putea utiliza funcia open trebuie incluse fiierele header
io.h i fcntl.h.
3o. Pentru a crea un fiier nou se va folosi funcia creat n locul
funciei open cu prototipul:
int creat (const char *cale, int mod);
unde:
- cale are aceeai semnificaie ca i la funcia open;
- mod este un ntreg care poate fi definit prin constantele simbolice de
mai jos:
S_IREAD
- se poate citi fiierul;
S_IWRITE
- se poate scrie n fiier;
S_IEXEC
- se poate executa programul coninut n fiier.
Utilizarea funciei presupune includerea fiierelor io.h i stat.h
4o. Implicit fiierul se consider c este de tip text.
Exemple:
char nume_fisier[ ]=fis1.dat;
int df;
df = open (nume_fisier, O_RDONLY);
Prin apelul de mai sus se deschide
directorul curent.

citire

fiierul

fis1.dat

din

int df;
df = open (c:\\borlandc\\help.txt,O_APPEND);
Se deschide n adugare fiierul help.txt din directorul borlandc de pe
discul C.
10.2.2. Citirea dintr-un fiier (consultare)
Funcia folosit pentru operaia de citire dintr-un fiier n memorie se
numete read i are prototipul urmtor:
int read (int df, void *buf, unsigned lung);
unde:
- df este descriptorul de fiier a crui valoare a fost definit la
deschidere;
- buf este pointerul spre zona de memorie n care se recepioneaz
nregistrarea care se citete;
- lung este lungimea n octei a inregistrrii citite.
Observaii:
1o. La fiecare apel funcia returneaz nregistrarea curent. La primul
apel se citete prima nregistrare din fiier, la al doilea apel se citete a
doua, etc. Ordinea nregistrrilor n fiier este cea definit la crearea
fiierului.
2o. La un apel al funciei read se citesc cel mult lung octei
nregistrarea avnd definit lungimea la scrierea n fiier. Funcia rentoarce
numrul de octei citii, 0(zero) la sfrit de fiier, sau 1 la eroare. De
obicei se folosesc frecvent nregistrri de 512 octei sau chiar mai mari.
3o. Funcia read poate fi folosit pentru a citi de la intrarea standard.
n acest caz, descriptorul de fiier este 0 (stdin are 0, stdout are 1, stderr
are 2 stdprn are 3 stdaux are 4). Programatorul nu trebuie s deschid fiierele
standard deoarece ele sunt deschise automat la lansarea n execuie a
programului.
4o. Utilizarea funciei read, presupune includerea fiierului io.h.
- 66 -

BORLAND C Manual de utilizare

10.2.3. Scrierea ntr-un fiier (creare, actualizare, adugare)


Pentru a scrie ntr-un fiier se folosete funcia write. Se presupune c
fiierul este deschis n prealabil prin funcia creat sau open. Ea este
asemntoare cu funcia read, doar c realizeaz transferul invers, adic din
memorie n fiier i are prototipul:
int write (int df, void *buf, unsigned lung);
Observaii:
1o. Funcia returneaz numrul octeilor scrii n fiier. Acesta este
egal cu lung i definete lungimea nregistrrii scrise n fiier. n cazul n
care numrul returnat de funcia write difer de parametrul lung scrierea a fost
eronat i se rentoarce valoarea 1.
2o. Utilizarea funciei write implic includerea fiierlui io.h.
10.2.4. Poziionarea ntr-un fiier
Pentru a avea acces aleator la nregistrrile unui fiier se folosete o
funcie de poziionare n fiier pe anumite nregistrri dorite. Pe fiierele
care au suporturi magnetice este posibil poziionarea cu ajutorul funciei
lseek care are prototipul urmtor:
long lseek (int df, long deplasament, int origine)
unde:
- df este descriptorul de fiier;
- deplasament definete numrul de octei peste care se va deplasa capul
de scriere/citire al discului;
- origine are una din valorile:
0 deplasamentul se consider de la nceputul fiierului;
1 deplasamentul se consider din poziia curent a capului de
scriere/citire;
2 deplasamentul se consider de la sfritul fiierului.
Observaii:
1o. Funcia returneaz poziia capului de citire/scriere fa de nceputul
fiierului n numr de octei sau 1L la eroare.
2o. Funcia nu realizeaz nici un transfer de informaie ci doar
poziioneaz capul de citire/scriere n fiier. Deci pentru transfer e nevoie de
funciile read sau write.
3o. Utilizarea funciei presupune includerea fiierului io.h.
4o. Apelul lseek (df, 0L, 0) permite o poziionare la nceput de fiier
iar apelul lseek (df, 0L, 2) permite o poziionare la sfrit de fiier.
10.2.5. nchiderea unui fiier
La sfritul prelucrrii unui fiier acesta trebuie nchis. Acest lucru se
realizeaz automat dac programul se termin prin apelul funciei exit.
Programatorul poate nchide un fiier folosind funcia close. Se recomand
nchiderea unui fiier de ndat ce s-a terminat prelucrarea lui. Aceasta din
cauz c numrul fiierelor ce pot fi deschise simultan este limitat. Limita
este dependent de sistemul de operare i ea variaz, de obicei, n intervalul
15-25. De obicei numrul de buffere (zone tampon) asociate fiierelor se
precizeaz n fiierul autoexec.bat. Menionm c fiierele standard din
limbajul C nu se nchid de programator.
Funcia close are prototipul urmtor:
int close (int df);
unde
df este descriptorul fiierului care se nchide.
Observaii:
1o. La o nchidere normal, funcia returneaz valoarea 0 i 1 n caz de
incident.
2o. Utilizarea funciei close implic includerea fiierului io.h.
Exemple
Vom deschide fiierul fis1.dat n creare i vom scrie n el dou
nregistrri.

- 67 -

BORLAND C Manual de utilizare

#include<io.h>
#include<fcntl.h>
void main (void)
{ int df,i;
df = open("fis1.dat", O_CREAT);// se deschide fisierul fis1.dat in creare
if (df != -1)
// se testeaza daca fiserul s-a deschis corect
{ write (df,"cioban vasyle\n", 14);// se scriu doua inregistrari
write (df,"cioban andrei\n", 14);
} else printf (nu s-a deschis fisierul);
close (df);
// se inchide fisierul
}
Se afieaz coninutul fiierului fis1.dat
#include<io.h>
#include<fcntl.h>
#include <stdio.h>
#include <conio.h>
void main (void)
{int df;
char s[14];
df = open("fis1.dat", O_RDONLY);
// se deschide fisierul n citire
if (df != -1)
// se testeaza daca deschiderea e corecta
{ read (df, s, 14);
printf ("%.14s",s);
read (df, s, 14);
printf ("%.14s",s);
} else printf (nu s-a deschis fisierul);
close (df);
getch();
// se asteapta un caracter de la tastatura
}
programul urmtor copiaz intrarea standard la ieierea standard folosind
o zon tampon de 80 de caractere:
#define LZT 80
#include <io.h>
void main (void)
// copiaza intrarea standard la iesirea standard
{ char zona_tampon[LZT];
int i;
while ((i = read (0, zona_tampon, LZT)) > 0) write (1, zt, i);
}
10.3. NIVELUL SUPERIOR DE PRELUCRARE A FIIERELOR
Dup cum am amintit, la acest nivel fiierele se prelucreaz cu ajutorul
unor proceduri specializate.
Deschiderea unui fiier
Funcia fopen se utilizeaz pentru deschiderea unui fiier. Ea returneaz
un pointer spre tipul FILE (tipul fiier), tip definit n fiierul stdio.h.
Tipul FILE este un tip structurat i el depinde de sistemul de operare. n caz
de eroare, funcia fopen returneaz pointerul NULL. Prototipul funciei fopen
este urmtorul:
FILE *fopen (const char *cale, const char *mod);
unde:
cale are aceeai semnificaie ca i n cazul funciilor open i creat.
mod este un pointer spre un ir de caractere care definete modul de
prelucrare al fiierului dup deschidere. Acest ir de caractere se definete n
felul urmtor:
- r
- deschidere n citire (read);
- w
- deschidere n scriere (write);
- a
- deschidere pentru adugare;
- r+
- deschidere pentru modificare (citire sau scriere);
- rb
- citire binar;
- wb
- scriere binar;
- r+b
- citire/scriere binar.
- 68 -

BORLAND C Manual de utilizare

Observaii:
1o. Dac se deschide un fiier inexistent cu modul w sau a, atunci el
este deschis n creare.
2o. Dac se deschide un fiier existent cu modul w, atunci coninutul
vechi al fiierului se pierde i se va crea unul nou cu acelai nume.
3o. Menionm c, stdin, stdout, stderr, stdaux i stdprn sunt pointeri
spre tipul FILE i permit ca funciile de nivel superior de prelucrare a
fiierelor s poat trata intrarea standard i ieirile standard pe terminal i
imprimant la fel ca i fiierele pe celelalte suporturi. Singura deosebire
const n aceea c aceste fiiere nu se deschid i nici nu se nchid de ctre
programator. Ele sunt deschise automat la lansarea n execuie a programului i
se nchid la apelul funciei exit.
4o. Apelul funciei se realizeaz prin construcia:
FILE *pf;
pf = fopen (FIS1.DAT,w);
10.3.2. Prelucrarea pe caractere a unui fiier
Fiierele pot fi scrise i citite caracter cu caracter, folosind dou
funcii simple:
putc pentru scriere;
getc pentru citire.
Funcia putc are prototipul:
int putc (int c, FILE *pf);
unde:
c este codul ASCII al caracterului care se scrie n fiier;
pf este pointerul spre tipul FILE a crui valoare a fost returnat de
funcia fopen la deschiderea fiierului n care se scrie; pf poate fi i stdout,
sdterr, stdaux, stdprn.
Funcia putc returneaz valoarea lui c respectiv 1 n caz de eroare.
Funcia getc are prototipul:
int getc (FILE *pf);
unde:
pf este pointerul spre tipul FILE a crui valoare a fost returnat de
funcia fopen la deschiderea fiierului; n particular pf poate fi stdin.
Funcia getc returneaz codul ASCII al caracterului citit sau EOF la
sfrit de fiier sau eroare.
nchiderea unui fiier se realizeaz cu ajutorul funciei fclose care are
prototipul:
int fclose (FILE *pf);
unde:
pf este pointerul spre tipul FILE a crui valoare a fost definit la
deschiderea fiierului prin intermediul funciei fopen.
Funcia fclose returneaz:
0 la nchiderea normal a fiierului;
1 n caz de eroare.
Exemple:
Programul urmtor copiaz intrarea standard la ieirea standard stdout,
folosind funciile getc i putc.
#include <stdio.h>
void main (void)
{ int c;
while (( c = getc (stdin)) != EOF) putc (c, stdout);
}
Programul urmtor copiaz intrarea standard la imprimant.
#include <stdio.h>
void main (void)
{ int c;
while (( c = getc (stdin)) != EOF) putc (c, stdprn);
}
- 69 -

BORLAND C Manual de utilizare

Programul urmtor scrie la ieirea stdout caracterele unui fiier a crui


cale este argumentul din linia de comand. Dac nu exist un argument n linia
de comand, atunci se citete de la intrarea standard.
#include <stdio.h>
void main (int argc, char *argv[ ] )
{ FILE *pf;
int c;
if (argc = = 1)
pf = stdin; // nu exista argument in linia de comanda
else
// se deschide fisierul a carui cale se afla in argv[1]
if (( pf = fopen (*++argv,r)) = = NULL)
{ printf (nu se poate deschide fisierul %s\n,*argv);
exit (1);
}
while (( c = getc (pf)) != EOF)
putchar(c);
exit (0);
}
Operaiile de intrare-ieire cu format
Biblioteca standard a limbajului C conine funcii care permit realizarea
operaiilor de intrare/ieire cu format. Astfel se pot utiliza funciile fscanf
i fprintf, prima pentru citire cu format dintr-un fiier, iar a doua pentru
scriere cu format ntr-un fiier.
Funcia fscanf este asemntoare cu funcia scanf. Ea are un parametru n
plus fa de scanf. Acest parametru este un pointer spre tipul FILE i el
definete fiierul din care se face citirea. Acest pointer este primul parametru
al funciei fscanf. Funcia poate fi apelat printr-o expresie de atribuire de
forma:
nr = fscanf (pf, control, lista_de_parametrii );
unde :
pf este un pointer spre tipul FILE i valoarea lui a fost definit prin
apelul funciei fopen; definete fiierul din care se face citirea;
ceilali parametri sunt identici cu cei utilizai la apelul funciei
scanf.
Funcia fscanf, ca i funcia scanf, returneaz numrul cmpurilor citite
din fiier. La ntlnirea sfritului de fiier se returneaz valoarea EOF
definit n fiierul stdio.h. Pentru pf = stdin, funcia fscanf este identic cu
scanf.
Funcia fprintf , ca i funcia printf, returneaz numrul caracterelor
scrise n fiier sau 1 n caz de eroare. Pentru pf = stdout, funcia fprintf
este identic cu printf. De asemenea, se pot utiliza pointerii standard
obisnuii: stderr, stdaux, stdprn.
Exemplu:
Vom scrie un program cu ajutorul cruia se va crea un fiier cu numele
"FIS.DAT" i care conine nregistrri cu numele, prenumele i adresa unor
persoane.
#include <stdio.h>
void main(void)
{
int n=0, i=1;// n este numarul de nregistrari ce se va scrie in fisier
char nume[25], prenume[30], adresa[50];
FILE *pf;
printf("\n Dati numarul de inregistrari n= ");
scanf("%d",&n);
pf=fopen("FIS.DAT","w");
if (pf = = NULL)
{ printf ("Eroare la deschidere");
return;
}
do
{
printf("\n Nume : ");
scanf("%s",nume);
printf("\n Prenume : ");
- 70 -

BORLAND C Manual de utilizare

scanf("%s",prenume);
printf("\n Adresa : ");
scanf("%s",adresa);
fprintf(pf,"%s %s %s", nume, prenume, adresa);
i++;
} while (i<=n);
fclose(pf);
}
10.3. 5. Intrri-ieiri de iruri de caractere
Biblioteca standard a limbajului C conine funciile fgets i fputs care
permit citirea respectiv scrierea ntr-un fiier ale crui nregistrri sunt
iruri de caractere.
Funcia fgets are prototipul:
char *fgets (char *s, int n, FILE *pf);
unde:
s este pointerul spre zona n care se face citirea caracterelor;
n-1 este numrul maxim de caractere care se citesc;
pf este pointerul spre tipul FILE care definete fiierul din care se face
citirea.
De obicei s este numele unui tablou de tip char de dimensiune cel puin n.
irul se termin cu \0 (caracterul NUL). La ntlnirea caracterului \n,
citirea se oprete. n acest caz, n zona receptoare se transfer caracterul
\n i apoi caracterul NUL (\0).
n mod normal, funcia returneaz valoarea pointerului s. La ntlnirea
sfritului de fiier se returneaz valoarea NULL.
Funcia fputs scrie ntr-un fiier un ir de caractere care se termin
prin \0. Ea are prototipul:
int fputs (const char *s, FILE *pf);
unde:
s este pointerul spre zona care conine irul de caractere care se scrie;
pf este pointerul spre zona care conine irul de caractere care se scrie.
Funcia fputs returneaz codul ASCII al ultimului caracter scris sau 1 n
caz de eroare.
Aceste funcii sunt realizate folosind funcia getc pentru fgets i putc
pentru fputs.
Pentru a citi de la intrarea standard stdin, se poate folosi funcia gets,
care nu mai are parametrii pf i n. Parametrul pf este implicit stdin. Funcia
gets citete caracterele de la intrarea standard pn la ntlnirea caracterului
\n care nu mai este pstrat n zona spre care pointeaz s. irul de caractere
citit se termin i n acest caz prin \0.
n mod analog, pentru a scrie la ieirea standard stdout se poate folosi
funcia puts, care nu mai are parametrul pf, acesta fiind implicit stdout. n
rest, funcia puts este la fel ca i funcia fputs.
10.3.6. Poziionarea ntr-un fiier
Cu ajutorul funciei fseek se poate deplasa capul de citire/scriere al
discului n vederea prelucrrii nregistrrilor fiierului ntr-o ordine
oarecare, diferit de cea secvenial (acces aleator). Aceast funcie este
asemntoare cu funcia lseek. Ea are prototipul urmtor:
int fseek (FILE *pf, long deplasament, int origine);
unde:
pf este pointerul spre tipul FILE care definete fiierul n care se face
poziionarea capului de citire/scriere;
deplasament i origine au aceeai semnificaie ca i n cazul funciei
lseek.
Funcia fseek returneaz valoarea zero la poziionare corect i o valoare
diferit de zero n caz de eroare.
Funcia ftell indic poziia capului de citire n fiier. Ea are
prototipul:
long ftell (FILE *pf);
unde:
pf este pointerul spre tipul FILE care definete fiierul n cauz.
- 71 -

BORLAND C Manual de utilizare

Funcia returneaz o valoare de tip long care definete poziia curent a


capului de citire/scriere, i anume reprezint deplasamentul n octei a
poziiei capului fa de nceputul fiierului.
10.3.7. Prelucrarea fiierelor binare
Fiierele organizate ca date binare (octeii nu sunt considerai ca fiind
coduri de caractere) pot fi prelucrate la acest nivel folosind funciile fread
i fwrite. n acest caz se consider c nregistrarea este o colecie de date
structurate numite articole. La o citire, se transfer ntr-o zon special,
numit zon tampon, un numr de articole care se presupune c au o lungime fix.
n mod analog, la scriere se transfer din zona tampon un numr de articole de
lungime fix. Cele dou funcii au prototipurile de mai jos:
unsigned fread (void *ptr, unsigned dim, unsigned nrart, FILE *pf);
unde:
- ptr este pointerul spre zona tampon ce conine articolele citite
(nregistrarea citit);
- dim
este un ntreg ce reprezint lungimea unui articol;
- nrart
este un ntreg ce reprezint numrul articolelor care se
transfer;
- pf este un pointer spre tipul FILE care definete fiierul din care se
face citirea.
unsigned fwrite (const void *ptr, unsigned dim, unsigned nrart, FILE *pf);
Parametrii funciei fwrite au aceeai semnificaie ca i parametrii
funciei fread.
Ambele funcii returneaz numrul articolelor transferate sau 1 n caz de
eroare.
Exemplu:
Programul urmtor citete de la intrarea standard stdin datele ale cror
formate sunt definite mai jos i le scrie n fiierul miscari.dat din directorul
curent.
tip
denumire
um
cod
pret
cantitate
1
TELVIZOR
buc
0001
3000000
200
#include <stdio.h>
#define MAX 60
typedef struct { char tip[2];
char den[MAX];
int val;
char unit[3];
long cod;
float pret;
float cant;
} ARTICOL;
// 6 articole in zona tampon
union {
ARTICOL a[6];
char zt[6*sizeof(ARTICOL)];
}buf;
int cit (ARTICOL *str) // citeste datele de la intrarea standard si
{
// le scrie in structura spre care pointeaza str
int nr,c;
float x,y;
while ((nr = scanf("%1s %60s %3d %2s %ld", str -> tip, str ->den,
&str ->val, str -> unit,&str -> cod)) != 5|| scanf("%f %f",
&x,&y) != 2)
{
if(nr = = EOF) return (EOF);
printf ("rind eronat ; se reia\n");
// avans pina la newline
while ((c = getchar ()) != '\n' && c != EOF);
if (c == EOF) return (EOF);
- 72 -

BORLAND C Manual de utilizare

}
str -> pret = x;
str -> cant = y;
return (nr);
}

// sfarsit while

// sfarsit cit

void main (void) // creaza fisierul miscari.dat cu datele citite de la


intrarea standard
{
FILE *pf;
ARTICOL a;
int i,n;
if((pf = fopen("miscari.dat", "wb")) == NULL)
{
printf("nu se poate deschide in creare fisierul miscari.dat\n");
exit(1);
}
for ( ; ; )
{
// se umple zona tampon a fisierului
for (i = 0 ;i<6 ; i++)
{
if((n=cit(&a)) == EOF) break;
buf.a[i]=a;
}
// se scrie zona tampon daca nu este vida
if(i !=0 )
if(i!=fwrite(buf.zt, sizeof(ARTICOL), i, pf))
{ printf("eroare la scrierea in fisier\n");
exit(1);
}
if(n = = EOF) break;
}
fclose(pf);
}
10.4. TERGEREA UNUI FIIER
Un fiier poate fi ters apelnd funcia unlink. Aceasta are prototipul:
int unlink (const char *cale);
unde:
- cale
este un pointer spre un ir de caractere identic cu cel
utilizat la crearea fiierului n funcia creat sau fopen.
Funcia unlink returneaz valoarea zero la o tergere reuit,
respectiv -1 n caz de eroare.

- 73 -

BORLAND C Manual de utilizare

LECIA 11.
FUNCII STANDARD
Vom descrie cteva clase de funcii, numite clase de funcii
standard aflate n bibliotecile mediului BORLAND C. Funciile i macrourile
utilizate frecvent n majoritatea aplicaiilor se pot grupa n urmtoarele
clase:
funcii de prelucrare a fiierelor;
funcii de alocare dinamic a memoriei;
macrouri de clasificare;
macrouri de transformare a simbolurilor;
funcii care realizeaz conversii;
funcii de prelucrare a irurilor de caractere;
funcii de calcul;
funcii pentru controlul proceselor;
funcii de gestiune a datei i a orei;
funcii de gestiune a ecranului.
Funciile de la punctele a) i b) au fost descrise n lecii anterioare.
11.1. MACROURI DE CLASIFICARE
n aceast clas distingem un numr de macrouri simple care au o utilizare
larg n prelucrarea simbolurilor. Definiiile acestor macrouri se afl n
fiierul ctype.h
Unul dintre macrouri este denumit isascii i are prototipul:
int isascii (int c);
Macroul returneaz o valoare diferit de zero dac valoarea lui c aparine
intervalului de numere ntregi [0,127] i zero n caz contrar. Acest macrou
permite s se testeze dac valoarea parametrului su reprezint un cod ASCII sau
nu.
Celelalte macrouri au prototipul urmtor:
int nume (int c);
unde nume este unul din urmtoarele:
isalpha
dac c este codul unei litere;
isalnum
dac c este codul unei litere sau cifre;
isdigit
dac c este codul unei cifre;
isgraph
dac c este codul unui caracter imprimabil inclusiv spaiul;
islower
dac c este codul unei litere mici;
isprint
dac c este codul unui caracter imprimabil inclusiv spaiu;
isspace
dac c reprezint spaiu, tabulator, retur de car, rnd nou,
tabulator vertical, salt la nceput de pagin de imprimant.
isupper
dac c este codul unei litere mari;
isxdigit
dac c este codul unei cifre hexazecimale.
Exemplu:
Programul urmtor citete un fiier i l rescrie schimbnd literele mari
cu litere mici. Cile spre cele dou fiiere (surs i destinaie) sunt
argumente n linia de comand:
argv[1]
este un pointer spre fiierul surs;
argv[2]
este un pointer spre fiierul destinaie.
#include <stdio.h>
#include <ctype.h>
void main ( int argc, char *argv[ ] )
{ FILE *pf1, *pf2;
int c;
if (argc != 3)
{ printf (linia de comanda eronata\n);
exit(1);
}
if (( pf1 = fopen (argv[1],r) ) = = NULL
{ printf (nu se poate deschide fisierul%s\n, argv[1]);
exit(1);
}
- 74 -

BORLAND C Manual de utilizare

if (( pf2 = fopen (argv[2],w) ) = = NULL


{ printf (nu se poate deschide fisierul%s\n, argv[2]);
exit(1);
}
while (( c = getc (pf1)) != EOF)
if (isascii(c) && isupper (c))
putc (c - A + a, pf2);
//
c
este
codul
unei
litere mari
else
putc(c, pf2);
// c este codul unei litere mici
fclose (pf1);
fclose (pf2);
// afisarea fisierului destinatie
if (( pf2 = fopen (argv[2], r) = = NULL)
{ printf (nu se poate deschide in citire:%s\n, argv[2]);
exit(1);
}
while ((c = getc(pf2)) != EOF)
putchar (c);
fclose (pf2);
}
11.2. MACROURI DE TRANSFORMARE A SIMBOLURILOR
n aceast clas distingem macrouri definite tot n
Prototipurile acestor macrouri sunt:
int toascii (int c);
returneaz ultimii 7 bii
reprezint un cod ASCII);
int tolower (int c);
transform pe c din liter mare
int toupper (int c);
transform pe c din liter mic

fiierul ctype.h.
ai

lui

(care

n liter mic;
n liter mare.

11.3. CONVERSII
O dat are un format extern i un format intern. Prin conversie nelegem
o transformare a unei date dintr-un format al ei n cellalt. Conversiile se pot
face sub controlul unui format sau fr format. Dintre funciile care realizeaz
conversii sub controlul formatelor amintim:
printf;
fprintf;
scanf;
fscanf;
Aceste funcii au fost descrise n leciile anterioare. Vom da n
continuare cteva funcii care realizeaz conversii fr format i care sunt
utilizate mai frecvent. Aceste funcii au prototipurile n fiierul stdlib.h.
Funcia atoi are prototipul:
int atoi (const char *ptr);
unde:
ptr este un pointer spre o zon de tip caracter ce conine cifre zecimale
care sunt, eventual, precedate de semnul minus;
Efectul:
irul de cifre spre care pointeaz ptr este convertit din ntreg zecimal
n ntreg binar de tip int.
Observaie:
1o. Funcia returneaz rezultatul acestei conversii.
Funcia atol are prototipul:
long atol (const char *ptr);
unde:
ptr este un pointer spre o zon de tip caracter ce conine cifre zecimale
care sunt, eventual, precedate de semnul minus;
Efectul:
irul de cifre spre care pointeaz ptr este convertit din ntreg zecimal
n ntreg binar de tip long.
Observaie:
1o. Funcia returneaz rezultatul acestei conversii.
Funcia atof are prototipul:
double atof (const char *ptr);
unde:
ptr este un pointer spre o zon de tip caracter ce conine cifre zecimale
care sunt, eventual, precedate de semnul minus (poate conine marca zecimal);
- 75 -

BORLAND C Manual de utilizare

Efectul:
irul de cifre spre care pointeaz ptr este convertit n virgul flotant
dubl precizie.
Observaie:
1o. Funcia returneaz rezultatul acestei conversii.
Funcia itoa are prototipul:
char *itoa (int val, char *sir, int baza)
Efectul:
valoarea parametrului val se convertete din ntreg binar de tip int n
baza de numeraie definit de parametrul baza i se pstreaz n zona spre care
pointeaz sir.
Observaie:
1o. Funcia returneaz pointerul sir.
Funcia ltoa are prototipul:
char *ltoa (long val, char *sir, int baza)
Efectul:
valoarea parametrului val se convertete din ntreg binar de tip long n
baza de numeraie definit de parametrul baza i se pstreaz n zona spre care
pointeaz sir.
Observaie:
1o. Funcia returneaz pointerul sir.
11.4. FUNCII DE PRELUCRARE A IRURILOR DE CARACTERE
Funciile din aceast clas implic includerea fiierului string.h.
Indicm mai jos funciile din aceast clas, utilizate mai frecvent. O parte din
aceste funcii au mai fost utilizate n diferite exemple din leciile
anterioare.
Funcii de copiere:
char *strcpy (char *dest, const char *sursa);
char *strncpy (char *dest, const char *sursa, unsigned n);
prima funcie copiaz irul de caractere spre care pointeaz sursa n zona
spre care pointeaz dest;
a doua funcie realizeaz acelai lucru, dar copiaz cel mult primii n
octei din surs;
ambele funcii returneaz valoarea pointerului dest.
Funcii de concatenare:
int strcmp (const char *dest, const char *sursa);
char *strncat (const char *dest, const char *sursa, unsigned n);
prima funcie copiaz irul spre care pointeaz sursa la sfritul irului
din zona spre care pointeaz dest;
a doua funcie realizeaz acelai lucru, dar se copiaz cel mult primii n
octei din zona spre care pointeaz sursa;
ambele funcii returneaz valoarea pointerului dest.
Funcii de comparare:
int strcmp (const char *sir1, const char *sir2);
int stricmp (const char *sir1, const char *sir2);
int strncmp (const char *sir1, const char *sir2, unsigned n);
int strnicmp (const char *sir1, const char *sir2, unsigned n);
aceste funcii compar irurile de caractere din zonele spre care
pointeaz pointerii sir1 i sir2;
ele returneaz o valoare:
negativ, dac irul spre care pointeaz sir1 este mai mic dect cel spre
care pointeaz sir2;
zero, dac cele dou iruri sunt egale;
pozitiv, dac irul spre care pointeaz sir1, este mai mare dect cel
spre care pointeaz sir2;
- 76 -

BORLAND C Manual de utilizare

prezena literei i (ignore) n numele funciei nseamn c nu se face


distincie ntre literele mari i mici;
prezena literei n n numele funciei nseamn c se realizeaz comparaia
pe cel mult n octei.
Observaie:
1o. Fie irurile s1 i s2 de lungime l1 i l2. Atunci cele dou iruri sunt
egale dac:
l1=l2 ( au aceeai lungime);
s1[k] = s2 [k] pentru k=0,1,...,l1
2o. irul s1 este mai mic dect irul s2 dac exist un j, j 0 i j min
(l1, l2), astfel nct:
s1[j] < s2[j];
s1[k] = s2[k], pentru k=0,1, . . . , j-1.
3o. irul s1 este mai mare dect irul s2 dac exist un j, j 0 i j
(l1, l2), astfel inct:
s1[j] > s2[j];
s1[k] = s2[k], pentru k=0,1, . . . , j-1.
Funcia lungime:
unsigned strlen (const char *sir);
returneaz lungimea irului de caractere spre care pointeaz sir;
caracterul NUL care termin irul nu este numrat.
11.5. FUNCII DE CALCUL
Majoritatea funciilor matematice au prototipurile n fiierul math.h.
Multe dintre acestea se utilizeaz la calculul valorilor funciilor elementare
i au prototipul:
double nume (double x);
unde nume este unul din urmtoarele:
acos
asin
atan
cos
sin
exp
log
log10
sqrt

-arccos;
-arcsin;
-arctg;
-cos;
-sin;
-ex;
-ln;
-lg;
-rdcina ptrat;

ceil

-returneaz cel mai mare ntreg


mai mare sau egal cu x (partea
ntreag);
floor -returneaz cel mai mare ntreg
mai mic sau egal cu x;
fabs -valoarea absolut;
sinh -sinus hiperbolic;
cosh -cosinus hiperbolic;
tanh -tangent hiperbolic;

Alte funcii:
double atan2 (double y, double x); - returneaz arctg(y/x);
double pow (double x, double y);
- returneaz xy;
double cabs (struct complex z);
- returneaz modulul nr. complex;
double poly (double x, int n, double c[ ] )
returneaz
valoarea
polinomului de grad n n punctul x, coeficienii sunt c[0], . . . c[n].
Funciile care urmeaz au prototipul n fiierele stdlib.h i math.h:
int abs (int n);
- returneaz valoarea absolut din ntregul n;
long labs (long n); - returneaz valoarea absolut din ntregul long n;
11.6. FUNCII PENTRU CONTROLUL PROCESELOR
Aceste funcii au prototipurile n fiierul stdlib.h i n process.h i
realizeaz controale asupra programelor:
void abort (void);
- termin un program n caz de eroare;
void exit (int stare)
- termin un program i returneaz o stare;
stare este 0 pentru terminare normal i diferit de zero pentru o terminare
anormal; videaz buferele fisierelor, nchide toate fiierele;
int system (const char *comanda)
- execut o comand DOS definit
prin sirul de caractere spre care pointeaz comanda; returneaz 0 la succes si
1 la eroare. Aceste funcii au prototipurile n stdlib.h i n process.h.
- 77 -

BORLAND C Manual de utilizare

11.7. FUNCII PENTRU GESTIUNEA DATEI I OREI


Dm mai jos prototipurile a patru funcii pentru citirea/setarea datei i
orei. Ele implic includerea fiierului dos.h.
void getdate(struct date *d);
- ncarc structura de tip date spre
care pointeaz d cu datele corespunztoare furnizate de sistemul de operare;
void gettime(struct time *t);
- ncarc structura de tip time spre
care pointeaz t cu datele corespunztoare furnizate de sistemul de operare;
void setdate (struct date *t);
- seteaz data curent n conformitate
cu datele de tip date;
void settime (struct time *t);
- seteaz ora curent n conformitate
cu datele de tip time spre care pointeaz t.
Tipurile date i time sunt definite n fiierul dos.h. astfel:
struct date {
int da_year;
int da_day;
int da_mon;
};
struct time {
unsigned char ti_min;
unsigned char ti_hour;
unsigned char ti_hund;
unsigned char ti_sec;
};
Exemplu:
void main (void)
// afiseaza data si ora
{
struct date d;
struct time t;
getdate (&d);
gettime (&t);
printf (\n\t%02d/%02d/%04d,d.da_day, d.da_mon, d.da_year);
printf (\tora %02d:%02:%02\n, t.ti_hour, t.ti_min, t.ti_sec);
}
11.8. ALTE FUNCII DIVERSE DE UZ GENERAL
void clrscr (void);
- terge fereastra activ sau tot
prototipul n conio.h
void delay(unsigned i); - suspend execuia programului pentru o
de i milisecunde;
void sleep(unsigned i); - suspend execuia programului pentru o
de i secunde;
void nosound (void);
- oprete difuzorul calculatorului;
void sound(unsigned h); - pornete difuzorul calculatorului cu un
cu h Hz.

LECIA 12.
- 78 -

ecranul;
perioad
perioad
ton egal

BORLAND C Manual de utilizare

GESTIUNEA ECRANULUI N MOD TEXT


Biblioteca standard a limbajelor C i C++ conine funcii pentru gestiunea
ecranului. Acesta poate fi gestionat n 2 moduri:
modul text i
modul grafic.
Modul text presupune c ecranul este format dintr-un numr de linii i
coloane. De obicei exist dou variante:
25 de linii x 80 de coloane = 2000 de carctere sau
25 de linii x 40 de coloane = 1000 de caractere.
Poziia pe ecran a unui caracter se definete printr-un sistem de
coordonate ntregi (x,y)
unde:
x - reprezint numrul coloanei n care este situat caracterul;
y - reprezint numrul liniei n care este situat caracterul.
Colul din stnga sus are coordonatele (1,1) iar colul din dreapta jos
(80,25) sau (40,25).
n mod implicit funciile de gestiune a ecranului n mod text au acces la
tot ecranul. Accesul poate fi limitat la o parte din ecran utiliznd aa
numitele ferestre. Fereastra este un dreptunghi care este o parte a ecranului i
care poate fi gestionat independent de restul ecranului.
Un caracter de pe ecran, pe lng coordonate, mai are i urmtoarele
atribute:
culoarea caracterului afiat;
culoarea fondului;
clipirea caracterului.
Aceste atribute sunt dependente de adaptorul grafic utilizat. Cele mai
utilizate adaptoare sunt:
placa MDA, care este un adaptor monocrom;
placa HERCULES, care este un adaptor color;
placa CGA, care este un adaptor color;
placa EGA, care este un adaptor color;
placa VGA, care este un adaptor color de mare performan.
Pentru adaptoarele de mai sus se pot utiliza 8 culori de fond i 16 culori
pentru afiarea caracterelor.
Atributul unui caracter se definete cu ajutorul formulei:
atribut = 16 * culoare_fond + culoare_caracter + clipire
(*)
unde:
culoare_fond (background) = cifr ntre 0 i 7; (8 culori)
culoare_caracter (foreground) = ntreg ntre 0 i 15; (16 culori)
clipire = 128 (clipire) sau 0 (fr clipire)
Tabel cu numele culorilor:
Culoare
Constant simbolic
negru
BLACK
albastru
BLUE
verde
GREEN
turcoaz
CYAN
rou
RED
purpuriu
MAGENTA
maro
BROWN
gri deschis
LIGHTGRAY
gri nchis
DARKGRAY
albastru deschis
LIGHTBLUE
verde deschis
LIGHTGREEN
turcoaz deschis
LIGHTCYAN
rou dechis
LIGHTRED
purpuriu magenta
LIGHTMAGENTA
galben
YELLOW
alb
WHITE
clipire
BLINK
12.1. SETAREA ECRANULUI N MOD TEXT
- 79 -

Valoare
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
128

BORLAND C Manual de utilizare

Setarea (punerea) se realizeaz cu ajutorul funciei textmode care are


prototipul:
void textmode (int modtext);
unde: modtext poate fi exprimat numeric sau simbolic n felul urmtor:
Modul text activat
alb/negru 40 coloane
color 40 coloane
alb/negru 80 coloane
color 80 coloane
monocrom
color 43 linii pentru EGA
i 50 linii pentru VGA
modul precedent

Constant simbolic
BW40
C40
BW80
C80
MONO

Valoare
0
1
2
3
7

C4350
LASTMODE

64
-1

Modul MONO se poate seta pe un adaptor monocolor. Celelalte moduri se pot


seta pe adaptoare color.
12.2. DEFINIREA UNEI FERESTRE
Dac dorim s partajm ecranul n zone care s poat fi gestionate
independent trebuie s definim ferestre.
O fereastr este o zon dreptunghilar de pe ecran care se poate defini cu
funcia window al crei prototip este:
void window (int stanga, int sus, int dreapta, int jos);
unde:
-(stanga, sus) = coordonatele colului din stnga al ferestrei;
-(dreapta, jos) = coordonatele colului din dreapta jos.
La un moment dat o singur fereastr este activ i anume aceea definit
de ultimul apel al funciei window. Funciile de gestionare a ecranului n mod
text acioneaz ntotdeauna asupra ferestrei active. Dup setarea modului text
cu ajutorul funciei textmode este activ tot ecranul.
Menionm c funcia window nu are nici un efect dac parametrii de la
apel sunt eronai.
12.3. TERGEREA UNEI FERESTRE
Fereastra activ se poate terge cu ajutorul funciei clrscr cu
prototipul:
void clrscr(void);
fereastra activ (sau tot ecranul) devine activ; fondul are culoarea
definit prin culoarea de fond curent;
clrscr poziioneaz cursorul n poziia (1,1) a fiecrei ferestre.
12.4. GESTIUNEA CURSORULUI
Programatorul poate plasa cursorul pe un caracter al ferestrei folosind
funcia gotoxy al crei prototip este:
void gotoxy (int coloana, int linie);
unde: (coloana, linie) sunt coordonate relative la fereastra activ, dac
sunt nafara ferestrei active apelul este ignorat;
Poziia cursorului se poate determina cu ajutorul funciilor wherex i
wherey care au prototipurile:
int wherex (void); -returneaz numrul coloanei n care se afl cursorul
int wherey (void); -returneaz numrul liniei n care se afl cursorul.
Exist cazuri cnd se dorete ascunderea cursorului. Acest lucru se poate
realiza printr-o secven special n care se utilizeaz funcia geninterrupt.
void ascundcursor (void)
{ _AH = 1;
_CH = 0x20;
geninterrupt (0x10);
}

// face invizibil cursorul

Cursorul poate fi reafiat apelnd funcia de mai jos:


- 80 -

BORLAND C Manual de utilizare

void afiscursor (void) // face vizibil cursorul


{ _AH = 1;
_CH = 6;
_CL = 7;
geinterrupt (0x10);
}
AH, CH, CL reprezint unii din regitrii microprocesorului.
12.5. DETERMINAREA PARAMETRILOR ECRANULUI
Utilizatorul are posibilitatea s obin parametrii cureni ai ecranului
prin apelarea funciei gettextinfo al crui prototip este:
void gettextinfo (struct text_info *p);
unde structura text_info este definit n fiierul conio.h astfel:
struct text_info
{ unsigned char winleft; // amplasarea colturilor ferestrei
unsigned char wintop;
unsigned char winright;
unsigned char winbottom;
unsigned char attribute;// culoarea fondului, a caracterelor si
unsigned char normattr;
// clipirea
unsigned char currmode;
unsigned char screenheight; // dimensiunea ecranului
unsigned char screenwidth;
unsigned char curx;
// pozitia cursorului
unsigned char cury;
};
12.6. MODURILE VIDEO ALB/NEGRU
Exist dou moduri (intens i normal) care se pot activa cu funciile
highvideo i lowvideo ale cror prototipuri sunt:
void highvideo (void);
void lowvideo (void);
Intensitatea iniial este de obicei cea normal. Se poate reveni la
intensitatea normal dac se apeleaz funcia normvideo cu acelai prototip ca
al celorlalte dou funcii.
Exemplu:
Vom scrie un program care afieaz parametrii ecranului:
#include <stdio.h>
#include <conio.h>
void main (void)
{ struct text_info par_ecran;
gettextinfo (&par_ecran)
;
printf (\nstanga: %u sus: %u dreapta: %u jos: %u\n,
par_ecran.winleft,
par_ecran.wintop,
par_ecran.winright,
par_ecran.winbottom);
printf (atribut: %d mod curent: %d\n,
par_ecran.normattr, par_ecran.currmode);
printf (inaltimea ecranului: %d latimea ecrnului: %d\n,
par_ecran.screenheight, par_ecran.screenwidth);
printf (coloana cursorului: %d linia cursorului: %d\n,
par_ecran.curx, par_ecran.cury);
}
12.7. SETAREA CULORILOR
- 81 -

BORLAND C Manual de utilizare

Culoarea fondului se seteaz cu ajutorul funciei textbackground cu


prototipul urmtor:
void textbackground (int culoare);
unde: culoare este un ntreg cuprins ntre 0 i 7 cu semnificaia din
tabelul anterior al culorilor.
Culoarea caracterelor se seteaz cu ajutorul
prototipul urmtor:
void textattr (int culoare);
unde: culoare este un ntreg ntre 0 i 15.

funciei

textcolor

cu

Se pot seta ambele culori, precum i clipirea caracterului folosind


funcia textattr de prototip:
void textattr (int atribut);
unde: atribut e definit cu ajutorul relaiei (*) de la nceputul leciei.

12.8. GESTIUNEA TEXTELOR


Pentru afiarea caracterelor colorate n conformitate cu atributele
definite prin relaia:
atribut = 16 * culoare_fond + culoare_caracter + clipire
se pot folosi funciile:
putch
- pentru afiarea unui caracter;
cputs
- pentru afiarea color a unui ir de caractere (acelai
prototip ca puts);
cprintf
- pentru afiarea color sub controlul formatelor.
Alte prototipuri de funcii:
void insline (void);
- insereaz o linie cu spaii n fereastr,
liniile de sub poziia cursorului se deplaseaz n jos cu o poziie;
void clreol (void)
- terge sfritul liniei ncepnd cu poziia
cursorului;
void delline (void)
- terge toat linia pe care este poziionat
cursorul;
int movetext ( int stanga, int sus, int dreapta, int jos,
int stanga_dest, int dreapta_dest );
- copiaz un text dintr-o poziie n alta;
returneaz: 1 dac textul s-a copiat cu succes i o n caz de eroare.
Textele dintr-o zon dreptunghiular a ecranului pot fi salvate sau
citite dintr-o zon de memorie cu ajutorul funciilor puttext i gettext i au
prototipurile:
int gettext (int stanga, int sus, int dreapta, int jos, void *destinatie);
unde
primii patru parametrii definesc fereastra unde se afl textul de salvat;
destinatie este pointerul spre zona de memorie n care se salveaz textul.
i
int puttext (int stanga, int sus, int dreapta, int jos, void *sursa);
unde
primii patru parametrii definesc fereastra unde se va scrie pe ecran
textul preluat din memorie;
sursa este pointerul spre zona de memorie din care se transfer textul.
Ele returneaz:
1 la copiere cu succes;
0 la eroare.
Observaie:
1o. Fiecare caracter de pe ecran se pstreaz pe doi octei:
pe un octet codul caracterului;
pe octetul urmtor atributul caracterului.
Exemple:
Programul urmtor seteaz o fereastr i modurile video alb/negru.
- 82 -

BORLAND C Manual de utilizare

#include <conio.h>
void main (void)
{ textmode (BW80);
window (10,4,60,4);
clrscr ();
lowvideo ();
cputs(lowvideo);
normvideo ();
cputs (normvideo);
textmode (LASTMODE);
cprintf (\n\r Acionai o tast pentru a continua:);
getch ();
}
Programul urmtor afieaz toate combinaiile de culori posibile pentru
fond i caractere (adaptor EGA/VGA).
#include <conio.h>
#include <stdio.h>
void main (void)
{ static char *tculoare [ ] = { 0 BLACK
negru,
1 BLUE
albastru,
2 GREEN
verde,
3 CYAN
turcoaz,
4 RED
rosu,
5 MAGENTA
purpuriu,
6 BROWN
maro,
7 LIGHTGRAY
gri deschis,
8 DARKGRAY
gri inchis,
9 LIGHTBLUE
albastru deschis,
10 LIGHTGREEN verde deschis,
11 LIGHTCYAN
turcoaz deschis,
12 LIGHTRED
rosu dechis,
13 LIGHTMAGENTA
purpuriu magenta,
14 YELLOW
galben
,
15 WHITE
alb};
int i,j,k;
struct text_info atribut;
gettextinfo (&atribut);
for (i = 0; i < 8; i++ )
// i alege culoarea fondului
{ window (3,2,60,20);
k=2;
textbackground (i);
clrscr();
for (j=0; j <10; j++, k++)
// j alege culoarea caracterului
{ textcolor (j);
gotoxy (2,k);
if (i = = j) continue;
cputs (tculoare[j]);
}
gotoxy (1,18);
printf (actionati o tasta pentru contiuare\n);
getch();
}
window
(atribut.winleft,
atribut.wintop,
atribut.winright,
atribut.winbottom);
textattr (atribut. attribute);
clrscr();
}

- 83 -

BORLAND C Manual de utilizare

LECIA 13.
- 84 -

BORLAND C Manual de utilizare

GESTIUNEA ECRANULUI N MOD GRAFIC


Modul grafic presupune c ecranul este format din puncte luminoase
(pixeli). Numrul acestora depinde de adaptorul grafic i se numete rezoluie.
O rezoluie este cu att mai bun cu ct este mai mare. Adaptorul CGA are o
rezoluie de 200 rnduri x 640 de coloane iar EGA de 350 de rnduri x 640 de
coloane. Adaptorul VGA i SVGA ofer rezoluii n funcie de mrimea ecranului.
Astfel adaptorul VGA i SVGA ofer rezoluii de pn la 768 de rnduri x 1024 de
coloane pentru ecranul de 14 (inches).
Pentru gestiunea ecranului n mod grafic se pot utiliza peste 60 de
funcii
standard
aflate
n
biblioteca
sistemului.
Aceste
funcii
au
prototiopurile n fiierul graphics.h. Totodat ele folosesc pointeri de tip far
(de 32 de bii).
13.1. SETAREA MODULUI GRAFIC
Modul grafic se seteaz cu ajutorul funciei initgraph. Aceast funcie
poate fi folosit singur sau mpreun cu o alt funcie numit detectgraph care
determin parametrii adaptorului grafic. Prototipul ei este:
void far detectgraph (int far *graphdriver, int far *graphmode);
unde:
n zona spre care pointeaz graphdriver se pstreaz una din valorile:
valoare
CGA
MCGA
EGA
EGA64
EGAMONO
IBM8514
HERCMONO
ATT400
VGA
PC3270

simbol

n zona spre care pointeaz graphmode se memoreaz una din valorile:


pentru CGA
valoare
simbol
CGAC0
CGAC1
CGAC2
CGAC3
corespunznd toate pentru o rezoluie de 320*200 de pixeli i permit 4

culori

CGAHI
are o rezoluie de 640*200 puncte i lucreaz numai alb/negru.
pentru EGA
valoare

simbol

EGALO are 640*200 i 16 culori


EGAHI are 640*350
pentru VGA
valoare
0
1
2

simbol
VGALO are 640*200
VGAMED
are 640*350
VGAHI are 640*480

Valorile spre care pointez graphdriver definesc nite funcii standard


corespunztoare adaptorului grafic. Aceste funcii se numesc drivere. Ele se
afl n subdirectorul BGI.
- 85 -

BORLAND C Manual de utilizare

Funcia detectgraph detecteaz adaptorul grafic prezent la calculator i


pstreaz valoarea corespunztoare acestuia n zona spre care pointeaz
graphdriver. Modul grafic se definete n aa fel nct el s fie cel mai
performant pentru adaptorul grafic curent. Cele mai utilizate adaptoare sunt de
tip EGA (calculatoare mai vechi) i VGA i SVGA (calculatoarele mai noi).
Apelul funciei detectgraph trebuie s fie urmat de apelul funciei
initgraph. Aceasta seteaz modul grafic n conformitate cu parametrii stabilii
de apelul prealabil al funciei detectgraph.
Funcia initgraph are prototipul:
void far initgraph (int far * graphdriver, int far *graphmode, char far
*cale);
unde:
graphdriver i graphmode sunt pointeri cu aceeai semnificaie ca n cazul
funciei detectgraph;
cale este un pointer spre irul de caractere care definesc calea
subdirectorului BGI (Borland Graphic Interface), de exemplu:
C:\\BOLANDC\\BGI
Exemplu:
Setarea n mod implicit a modului grafic:
int driver, mod_grafic;
. . .
detectgraph (&driver, &mod_grafic);
initgraph(&driver, &mod_grafic, C:\\BORLANDC\\BGI);
Dup apelul funciei initgraph se pot utiliza celelalte funcii
standard de gestiune grafic a ecranului.
Din modul grafic se poate iei apelnd funcia closegraph care are
prototipul:
void closegraph (void);
Funcia initgraph mai poate fi apelat i folosind
simbolic DETECT astfel:
int driver, mod_grafic;
. . .
driver = DETECT;
initgraph (&driver, &mod_grafic, C:\\BORLANDC\\BGI);

constanta

Constanta simbolic DETECT este definit n fiierul graphics.h,


alturi de celelalte constante simbolice care definesc driverul. Aceasta are
valoarea zero.
Prin apelul de mai sus, funcia initgraph apeleaz funcia
detectgraph pentru a defini parametrii implicii ai adaptorului grafic.
Utilizatorul poate defini el nsui parametri pentru iniializarea
modului grafic.
13.2. GESTIUNEA CULORILOR
Adaptoarele grafice sunt prevzute cu o zon de memorie n care se
pstreaz date specifice gestiunii ecranului. Aceast zon de memorie poart
denumirea de memorie video.
n mod grafic, ecranul se consider format, dup cum am precizat, din
puncte luminoase numite pixeli. Poziia pe ecran a unui pixel se definete
printr-un sistem de coordonate (x,y) cu x coloana i y linia n care este afiat
pixelul.
n cazul adaptoarelor color, unui pixel i corespunde o culoare. Culoarea
pixelilor se pstreaz pe bii n memoria video. Memoria video necesar pentru a
pstra starea ecranului setat n mod grafic, se numete pagin video.
Adaptoarele pot conine mai multe pagini video. Gestiunea culorilor este
dependent de tipul de adaptor grafic existent la microprocesor.
Numrul maxim de culori pentru adaptoarele EGA este de 64 (numerotate de
la 0 la 63). Cele 64 de culori nu pot fi afiate simultan pe ecran. n cazul
adaptorului EGA se pot afia simultan 16 culori. Mulimea culorilor care pot fi
- 86 -

BORLAND C Manual de utilizare

afiate simultan pe ecran se numete palet. Culorile din componena unei palete
pot fi modificate de utilizator prin intermediul funciilor standard. La
iniializarea modului grafic se seteaz o palet implicit.
Pentru adaptorul EGA exist un tablou de 64 de culori (cu coduri ntre 0
i 63) din care se selecteaz cele 16 culori pentru palet. Exist i constante
simbolice foarte sugestive cu numele culorilor n englez. Funciile de gestiune
a culorilor pot avea ca parametri nu numai codurille culorilor ci i aceste
constante simbolice.
Culoarea fondului este ntotdeauna cea corespunztoare indicelui 0 din
palet. Culoarea pentru desenare este cea corespunztoare indicelui 15.
Culoarea de fond poate fi modificat cu ajutorul funciei setbkcolor care
are prototipul:
void far setbkcolor (int culoare);
unde:
culoare = index n tabloul care definete paleta.
Exemplu:

setbkcolor (BLUE); seteaz culoarea de fond pe albastru.

Pentru a cunoate culoarea de fond curent se poate apela funcia


getbkcolor de prototip:
int far getbkcolor (void);
Ea returneaz
culoarea de fond.

indexul

tabloul

care

definete

Culoarea pentru desenare poate fi modificat


setcolor de prototip:
void far setcolor(int culoare);
unde:
culoare = index n tabloul care definete paleta.
Exemplu:

paleta

folosind

pentru
funcia

setcolor (YELLOW); seteaz culoarea pentru desenare n galben.

Culoarea pentru desenare se poate determina apelnd funcia getcolor


de prototip:
int far getcolor (void);
Ea returneaz indexul n tabloul care definete paleta relativ la
culoarea pentru desenare.
Paleta curent poate fi modificat cu funciile setpalette i
setallpalette. Prima funcie se folosete pentru a modifica o culoare din paleta
curent i are prototipul:
void far setpalette (int index, int cod);
unde:
index este un ntreg din {0,. . . , 15} i reprezint indexul n tabloul
care definete paleta pentru culoarea care se modic;
cod este un ntreg din intervalul {0, 1,. . . , 63} i reprezint codul
culorii care o nlocuiete n palet pe cea veche.
Exemplu:
setpalette (DARKGRAY, 45);
corespunztoare
indicelui DARKGRAY (adic 8) prin
culoarea de cod 45.

modific

culoarea

Funcia setallpalette permite modificarea simultan a mai multor


culori din compunerea paletei i are prototipul:
void far setallpalette (struct palettetype far *paleta);
unde:
palettetype este un tip definit n fiierul graphics.h astfel
struct palettetype
{ unsigned char size;
- 87 -

BORLAND C Manual de utilizare

unsigned char colors [MAXCOLOR+1];


};
cu
- size dimensiunea paletei
colors tablou ale crui elemente au ca valori codurile componente ale
paletei care se definete.
Modificarea paletei curente cu ajutorul funciilor setpalette i
setallpalette conduce la schimbarea corespunztoare a culorilor afiate pe ecran
n momentul apelului funciilor respective.
Pentru a determina codurile culorilor componente ale paletei curente
se va folosi funcia getpalette de prototip:
void far getpalette (struct palettetype far *paleta);
Paleta
implicit
poate
fi
determinat
getdefaultpalette de prototip:
struct palettetype *far getdefaultpalette(void);

folosind

funcia

Numrul culorilor dintr-o palet poate fi obinut apelnd funcia


getmaxcolor de prototip:
int far getmaxcolor (void);
Funcia returneaz numrul maxim de culori diminuat cu 1. Deci n
cazul adaptorului EGA funcia returneaz valoarea 15.
O alt funcie care determin
getpalettesize cu prototipul:
int far getpalettesize (void);

dimensiunea

paletei

Funcia returneaz numrul culorilor componente ale


adaptorului EGA funcia returneaz valoarea 16.

este

funcia

paletei. n

cazul

Exemplu:
Programul urmtor afieaz codurile culorilor pentru paleta implicit:
#include <graphics.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
void main (void)
{ int gd = DETECT, gm, i;
struct palettetype far *pal = (void *) 0;
initgraph (&gd, &gm, C:\\BORLANDC\\BGI);
pal = getdefaultpalette ();
for (i=0; i<16; i++)
{ printf (colors[%d]=%d\n, i, pal -> colors[i]);
getch ();
}
closegraph();

13.3. STAREA ECRANULUI


n mod grafic ecranul se compune din n*m pixeli. Pixelul din stnga-sus
are coordonatele (0,0), iar pixelul din dreapta-jos are coordonatele (n-1,m-1).
n BGI exist mai multe funcii care permit utilizatorului s obin
informaii despre:
coordonata maxim pe orizontal;
coordonata maxim pe vertical;
poziia curent (pixelul curent);
etc.
int far getmaxx (void); returneaz abscisa maxim;
int far getmaxy (void); returneaz ordonata maxim;
- 88 -

BORLAND C Manual de utilizare

int
pixelului
int
pixelului

far getx (void);


curent;
far gety (void);
curent.

returneaz poziia pe orizontal (abscisa)


returneaz poziia pe vertical (ordonata)

Exemplu:
#include <graphics.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
void main (void)
{ int gd = DETECT, gm, cul_fond, cul_desen, curent_x,curent_y, maxx, maxy;
initgraph (&gd, &gm, C:\\BORLANDC\\BGI);
cul_fond = getbkcolor();
cul_desen = getcolor();
maxx = getmaxx();
maxy = getmaxy();
curent_x = getx();
curent_y = gety();
closegraph();
printf (culoarea fondului = %d\n, cul_fond);
printf (culoare desenare = %d\n, cul_desen);
printf (abscisa maxima = %d\n, maxx);
printf (ordonata maxima = %d\n, maxy);
printf (abscisa curenta = %d\n, curent_x);
printf (ordonata curenta = %d\n, curent_y);
printf (acionai o tasta pentru terminare);
getch();
}

- 89 -

BORLAND C Manual de utilizare

- 90 -

BORLAND C Manual de utilizare

LECIA 14.
PROBLEME DIVERSE
De multe ori suntem pui n faa unor probleme pe care le nelegem uor dar
nu tim cum s le rezolvm ct mai simplu i elegant. V propunem cteva metode
care bine nsuite pot duce, uneori, la o rapid rezolvare a problemelor dificile.
Evident c, nu toate problemele pot fi ncadrate n aceste tipare propuse dar
fiecare programator poate s-i formeze un astfel de "portofoliu" de metode cu
care s poate aborda orice problem. Metodele prezentate n continuare pot
constitui un nceput.
14.1. GENERAREA COMBINRILOR
Fie o mulime oarecare de n elemente care poate fi pus ntr-o coresponden
biunivoc cu mulimea A={1,...,n}. Ne propunem s determinm toate m-combinrile
(mn) ale mulimii A (submulimi de m elemente ale mulimii A). Vom rezolva
problema, nerecursiv, pornind de la m-combinarea V=(1,2,...,m) determinnd
succesiv toate m-combinrile ordonate lexicografic cresctor.
Fie V=(v1,v2,...,vm) o m-combinare oarecare, atunci m-combinarea
urmtoare n ordine lexicografic cresctoare se obine astfel:
se determin cel mai mare indice i satisfcnd relaiile:
vi<n-m+i, vi+1=n-m+i+1,..., vm-1=n-1, vm=n. (1)
se trece la vectorul urmtor:
(v1,...,vi-1,vi+1,vi+2,...,vi+n-i+1);
dac nu exist un astfel de indice i (care s satisfac relaiile (1))
nseamn c vectorul V conine ultima m-combinare i anume: (n-m+1,n-m+2, ...,n).
Dm n continuare o funcie C care genereaz o m-combinare cu n elemente
avnd ca parametru cod o variabil boolean care pentru valoarea 0 genereaz prima
m-combinare iar pentru valoarea 1 genereaz urmtoarea m-combinare. Funcia comb
rentoarce valoarea 1 dac s-a generat o m-combinare oarecare i valoarea 0 dac
s-a generat ultima m-combinare (n acest caz cod are valoarea 0). Se va folosi un
vector global v n care se genereaz m-combinrile.
#define dim 50
#include <stdio.h>
int v[dim+1], n, m;
// functia generatoare a m-combinarilor
int comb(cod)
int cod;
{
int i,j;
// generarea primei m-combinari 1,...,m
if (cod == 0)
{
for (i=1; i<=m; v[i]=i++);
return (1);
}
i=m+1;
// cautarea indicelui i pentru satisfacerea relaiilor
(1)

do { i-- }
while (v[i] >= n-m+i);
if (i)
{
v[i]=v[i]+1;
for (j=i+1; j<=m; v[j]=v[j-1]+1,j++);
return (1);
}
else return (0);
- 91 -

BORLAND C Manual de utilizare

}
void main(void)
{
int kod,i;
printf("\ndati n: ");
scanf ("%d",&n);
printf("\ndati m: ");
scanf ("%d",&m);
comb(0);
kod=1;
while (kod)
{ printf("\n");
for (i=1;i<=m;printf ("%3d",v[i++]));
kod = comb(kod);
}
getche();
}
14.2. METODA GREEDY
Se aplic problemelor n care se d o mulime A coninnd n date (de orice
natur i structur) de intrare cerndu-se s se determine o submulime B (BA)
care s ndeplineasc anumite condiii pentru a fi acceptat. Cum, n general,
exist mai multe astfel de submulimi (numite soluii posibile) se mai d i un
criteriu conform cruia dintre aceste submulimi s alegem una singur (numit
soluie optim) ca rezultat final. Foarte multe probleme de cutare se nscriu n
acest tip.
Menionm c, n general, soluiile posibile au urmtoarele proprieti:
- se presupune c este soluie posibil;
- dac B este soluie posibili CB atunci i C este soluie posibil;
Vom da n continuare o variant a tehnicii greedy (denumire care n
traducere nseamnn lcomie, nghiire) n care se pornete de la mulimea vid.
Apoi se alege pe rnd, ntr-un anumit fel, un element din A neales nc. Dac
adugarea lui la soluia parial anterior construit conduce la o soluie
posibil, atunci se adaug, altfel se alege un nou element. Tot acest procedeu se
repet pentru toate elementele din A. Dm n continuare n pseudocod o procedur:
procedure GREEDY (n,A,B)
B:=;
for i=1,n do
call ALEGE (A,i,x);
call POSIBIL (B,x,cod);
if cod=1 then
call ADAUG (B,x);
endif;
endfor;
return;
end procedure
Despre procedurile apelate din GREEDY precizm urmtoarele:
procedura ALEGE furnizeaz n x un element din A aj{ai,...,an} i
interschimb ai cu aj; dac la fiecare pas se cerceteaz ai atunci procedura se
simplific;
procedura POSIBIL verific dac elementul x poate fi adugat sau nu mulimii
pariale construit pn la pasul curent furniznd o valoare boolean cod cu
semnificaia:
cod = 1, dac B U {x}, este soluie posibil
cod = 0, altfel
procedura ADAUG nlocuiete pe B cu B{x}.
Obs. Procedurile de mai sus nu sunt necesare ntotdeauna, acest fapt
depinznd de complexitatea problemei. Oricum trebuie reinut cadrul de rezolvare
al acestui tip de problem.

- 92 -

BORLAND C Manual de utilizare

Problem rezolvat
Se d o mulime de valori reale X={x1, . . .,xn}. Se cere submulimea YX
astfel ca y /yY, s fie maxim.
Evident c problema este foarte simpl (n Y trebuie introduse elementele
strict pozitive din X; evitm s mai construim procedurile ALEGE, POSIBIL, ADAUG)
i vom da rezolvarea ei n pseudocod:
procedure SUMA (n,X,Y,k)
integer n,X(n),Y(n),k
k:=0;
for i=1,n do
if x(i) > 0 then k:=k+1;
y(k):=x(i)
endif;
endfor;
return;
end procedure
Probleme propuse
14.2.1.
Se dau n iruri S1,S2,...,Sn ordonate cresctor, de lungimi L1,L2, ...,Ln. S
se obin un ir S de lungime L1+L2+...+Ln cu toate elementele celor n iruri
ordonate cresctor (problem de interclasare).
Indicaie: Vom interclasa succesiv cte dou iruri n final obinnd irul
ordonat cresctor. Complexitatea interclasrii a dou iruri A i B de lungimi a
i b depinde direct proporional de a+b (pentru c se fac a+b deplasri de
elemente). Se pune problema gsirii ordinii optime n care trebuie efectuate
aceste interclasri astfel ca numrul total de deplasri s fie minim.
Vom da un exemplu pentru a lmuri mai bine lucrurile:
fie 3 iruri de lungimi (90,40,10). Interclasm irul S1 cu S2 apoi irul
rezultat cu S3; putem nota acest lucru formal prin (S1+S2)+S3. Se obin (90+40) +
(130+10)=270 deplasri. Dac vom interclasa irurile n ordinea (S2+S3)+S1 vom
obine (40+10)+ (50+90)=190 de deplasri. De aici concluzia c ntotdeauna vom
interclasa irurile de lungimi minime din irurile rmase.
14.2.2.
Gsii tripletele de numere pitagorice din Nn x Nn x Nn (prin Nn notat
mulimea {0,1,2,...,n}). ncercai optimizarea timpului de execuie a programului.
14.2.3.
Fie mulimea m-combinrilor luate din n elemente i fie k<m un numr
natural. S se dea un algoritm i apoi s se scrie un program C astfel nct s se
determine o submulime de m-combinri cu proprietatea c oricare dou m-combinri
au cel mult k elemente comune.
14.2.4.
S se determine mulimile interior stabile (MIS) ale unui graf oarecare dat
prin matricea sa de adiacen.
14.3. METODA BACKTRACKING (CUTARE CU REVENIRE)
Aceast metod se aplic problemelor ce pot fi reprezentate sub forma unui
arbore finit iar cutarea soluiei presupune parcurgerea arborelui n adncime
(DF=Depth First).
Problemele de acest tip au n general soluia de forma x=(x1, . . . ,xn)
S1x . . . xSn, fiecare Sk fiind o mulime finit. Mai facem cteva precizri
preliminare:
a) pentru fiecare problem sunt date anumite relaii ntre componentele x1,
. . . ,xn ale lui
x numite condiii interne;
- 93 -

BORLAND C Manual de utilizare

b) produsul cartezian S=S1x...xSn se mai numete spaiul soluiilor


posibile, iar soluiile
posibile care satisfac condiiile interne se numesc soluii rezultat;
c) n general se cer dou lucruri n astfel de probleme:
- determinarea tuturor soluiilor rezultat;
- determinarea doar a acelor soluii care optimizeaz o funcie obiectiv
dat.
Cum rezolvm astfel de probleme? Exist dou modaliti de rezolvare:
1) tehnica direct (numit i tehnica forei brute) prin care se genereaz
toate elementele spaiului de soluii posibile i apoi se verific fiecare dac
este sau nu o soluie rezultat; aceast tehnic necesit un timp prohibitiv (dac
fiecare Si are doar 2 componente complexitatea este O(2n); totodat ar fi necesar
imbricarea a n cicluri cu n aprioric necunoscut).
2) backtracking care evit generarea tuturor soluiilor posibile.
S dm n continuare cteva repere ale rezolvrii:
soluia este construit progresiv, component cu component;
lui xk i se atribuie o valoare (evident c numai din Sk) dac i numai dac
x1, . . . ,xk-1 au deja valori;
se verific condiiile de continuare (strns legate de condiiile interne)
dac are sens trecerea la xk+1;
dac nu are sens (adic condiiile de continuare nu sunt ndeplinite atunci
facem o nou alegere pentru xk sau dac am epuizat valorile din Sk atunci k:=k-1
i se face o nou alegere pentru xk-1; .a.m.d.
2. dac are sens atunci k:=k+1 i se testeaz dac k>n:
21) dac inegalitatea este adevrat atunci se afieaz soluia
astfel determinat
i k:=k-1 continund procesul de la punctul 1;
22) dac inegalitatea este fals se continu procesul de la punctul
1.
Procedura rezolvrii unor astfel de probleme este:
procedure BT(n,x)
integer n;
array x(n);
k:=1;
while k>0 do
cod:=0;
while ([mai exist o valoare din Sk netestat] and cod=0)
x(k):=;
if k(x(1),...,x(k)) then cod:=1;
endif;
endwhile;
if cod=0 then
k:=k-1
else
if k=n then write (x(1),...,x(n))
else k:=k+1
endif
endif;
endwhile;
return;
end procedure
Vom face cteva precizri:
1o. Predicatul k(x1, . . . , xk) reprezint condiiile de continuare pentru
x1, . . . , xk;
2o. Cod este o valoare ce indic ndeplinirea/nendeplinirea condiiilor de
continuare;
3o. Dac predicatul k(x1, . . . , xk) este adevrat k {1,...,n} atunci
se vor afla toi vectorii din S;
4o. Backtracking poate fi uor reprezentat pe un arbore construit astfel:
- nivelul 1 conine rdcina;
- din orice nod de pe nivelul k pleac sk muchii spre nivelul k+1,
etichetate cu cele
sk elemente ale lui Sk;
- nivelul n+1 va conine s1*s2*. . .* sn noduri frunz;
- 94 -

BORLAND C Manual de utilizare

- pentru fiecare nod de pe nivelul n+1 etichetele muchiilor coninute


n drumul ce

leag rdcina de acest nod reprezint o soluie posibil;

Dac mulimile Sk reprezint progresii aritmetice atunci algoritmul


general se modific astfel:
procedure BTA(n,a,b,h)
integer n;
array primul(n),ultimul(n),ratia(n),x(n);
k:=1;
x(1):=primul(1)-ratia(1);
while k>0 do
cod:=0;
while ( x(k)+ratia(k) ultimul(k) and cod=0 )
x(k):=x(k)+ratia(k);
if k(x(1),...,x(k)) then cod:=1 endif;
endwhile;
if cod=0 then
k:=k-1
else
if k=n then write (x(1),...,x(n))
else k:=k+1
x(k):=a(k)-h(k)
endif
endif;
endwhile;
return;
end procedure
unde:
aritmetice;
aritmetice;

primul(n)

reprezint

vectorul

primilor

termeni

ai

progresiilor

- ultimul(n) reprezint vectorul ultimilor termeni ai progresiilor


- ratia(n) reprezint vectorul raiilor progresiilor aritmetice;

De reinut cele dou avantaje ale acestui procedeu:


evitarea imbricrii unui numr oarecare de cicluri aprioric variabil (n
algoritmul propus se imbric doar dou cicluri pretestate while);
evitarea construirii spaiului tuturor soluiilor posibile S1xS2x . . . xSn.
Problem rezolvat
n cte moduri se pot aranja 8 dame pe tabla de ah astfel nct s nu se
"bat" reciproc. S se foloseasc al doilea algoritm dintre cei menionai
anterior.
Prima variant
Acest program respect algoritmul anterior cu unele mici modificri. Facem
precizarea c vectorul x conine n componenta x[i] numrul coloanei de pe tabla
de ah pe care se va afla dama de pe linia i. Tiprirea va reprezenta o permutare
(din cele 8! soluii posibile). Se vor afla 92 de soluii. Lsm pe seama
cititorului s deduc analogiile i diferenele ntre algoritm i program.
#include <stdio.h>
#include <math.h>
void main (void)
{ int x[9],cod,k,i,nr;
k=1; x[1]=0;nr=0;
while (k>0)
{ cod=0;
- 95 -

BORLAND C Manual de utilizare

while (((x[k]+1)<=8)&&(cod= =0))


{ x[k]++;
if ((k= =1) && (x[k]= =1)) cod=1;
else { i=1; cod=1;
while ((cod==1)&&(i<k))
{ if ((x[i]==x[k])||(abs(x[i]-x[k])==k-i)) cod=0;
i++;
}
}
}
if (cod==0) k--;
else {if (k==8)
{ printf("\n%3d. ",++nr);
for (i=1;i<9;printf("%d ",x[i++]));
}}
else x[++k]=0;
}
}
}
A doua variant:
#include <stdio.h>
#include <math.h>
#define n 100
int x[100],cod,k,nc,nsol;
int Verifica(void)
{ int i,cod1;
// cod1=1 conditiile de continuare
cod1=1;
// sunt verificate
if (k>1)
// cod1=0 in caz contrar;
for(i=1; i<= (k-1); i++)
{ if (x[k]= =x[i]) cod1=0;
if (abs(x[k]-x[i]) = = k-i) cod1=0; // (*)
}
return cod1;
}
void ScrieSolutie(void)
{ int i;
printf("\n%3d. ",++nsol);
for (i=1; i<=nc; printf("%3d",x[i++]));
}
void CitesteDate(void)
{ int i;
nsol=0;
clrscr();
nc=n+1;
while ((nc>n) || (nc<0))
{ printf ("Dati n = ");
scanf ("%d",&nc);
};
}
void main (void)
{ CitesteDate();
k=1; x[1]=0;
while (k>0)
{ cod=0;
while (((x[k]+1) <= nc) && (cod= =0))
{x[k]++;
cod=Verifica();
}
if (cod= =0) k--;
else {if (k==nc) ScrieSolutie();
- 96 -

BORLAND C Manual de utilizare

else x[++k]=0;
}
}

A doua variant este modular, mai uor de neles i generalizeaz problema


damelor pn la tabla de ah de 100x100. Lsm pe seama cititorului modificarea
funciei ScrieSolutie pentru a afla n mod grafic tabla de ah.
Dac n funcia Verifica se terge instruciunea notat cu (*) atunci
se obin toate permutrile de n obiecte.
Probleme propuse
14.3.1
S se rezolve problema turelor de ah dup al doilea algoritm. n cte
moduri se pot aranja n turnuri pe tabla de ah astfel nct s nu se "bat"
reciproc.
14.3.2.
S se afieze poziiile succesive ale unui cal pe tabla de ah, pornind
dintr-o poziie dat, astfel nct s fie atinse toate csuele tablei de ah.
14.3.3.
Avnd un fiier cu o mulime de cuvinte din limba romn de aceeai lungime
k s se scrie un program C care afieaz toate careurile rebusiste fr puncte
negre. ( Problema e fascinant implicnd i cunotine gramaticale dar i
cunoscnd faptul c nu s-au construit careuri de 10x10 fr puncte negre manual i
nici cu ajutorul calculatorului; se poate ncerca apoi i cu k:=11,12, . . .).
14.3.4.
Un intreprinztor dispune de un capital C i are n variante de investiii.
Pentru fiecare investiie i cunoate fondurile de investiie fi precum i
beneficiile bi. Se cere un program care s deduc toate variantele posibile de
investiii al intreprinztorului. Se mai dau i condiiile Cci i {1, . . .
,n}.
14.3.5.
Avnd un graf neorientat caracterizat prin matricea costurilor s
determine prin bactraking circuitul de cost minim pornind dintr-un vrf dat.

se

14.3.6.
Avnd un graf neorientat caracterizat prin matricea de inciden
vrfurilor s se determine prin bactraking mulimile interior stabile maximale.

14.3.7.
S se determine toate cuvintele binare de lungime 10 care conin exact 5
cifre de 1.
14.3.8.
S se determine toate cuvintele binare de lungime 10 care conin cel mult 5
cifre de 1.
14.3.9.
S se determine toate cuvintele din {a,b,c}* (mulimea tuturor cuvintelor
peste alfabetul se noteaz cu * ) de lungime 10 care conin exact 2 simboluri
'a'; 3 simboluri 'b' i 5 simboluri 'c'.
14.3.10.
S se determine toate cuvintele din {a,b,c}* de lungime n care conin exact
na simboluri 'a'; nb simboluri 'b' i nc simboluri 'c' (cu condiia n=na+nb+nc).
14.3.11.
S se determine toate tripletele (x1,x2,x3) de numere astfel ca:
x1+x2+x3suma
x1*x2*x3produs
- 97 -

BORLAND C Manual de utilizare

cu valorile suma i produs date iar x1S1, x2S2 i x3S3 ; S1, S2 i S3 fiind
trei progresii aritmetice date deasemenea.
14.3.12.
S se determine toate variantele de pronosport cu 13 rezultate din {1,x,2}
care conin exact n1 simboluri '1'; nx simboluri 'x' i n2 simboluri '2' (cu
condiia n1+nx+n2=13).
14.3.13.
S se determine toate variantele de pronosport cu 13 rezultate din {1,x,2}
care conin cel mult n1 simboluri '1'; cel mult nx simboluri 'x' i simboluri '2'
n rest (cu condiia n1+nx13).
14.4. METODA DIVIDE ET IMPERA (DIVIDE I STPNETE)
Aceast modalitate de elaborare a programelor const n mprirea repetat
a unei probleme de dimensiune mai mare n dou sau mai multe subprobleme de
acelai tip urmat de combinarea soluiilor subproblemelor rezolvate pentru a
obine soluia problemei iniiale.
Se d un vector A=(a1,...,an) i trebuie efectuat o prelucrare
oarecare asupra elementelor sale.
Presupunem c:
p,q{1,...,n} cu 1 p < q m{p,p+1,...,q-1} a.. prelucrarea
secvenei {ap,...,aq} se poate face prelucrnd subsecvenele:
{ap,...,am} i {am+1,...,aq} i apoi combinnd rezultatele pentru a obine
prelucrarea ntregii secvene {ap,...,aq}.
Dac se reuete o astfel de formalizare a problemei atunci ea poate fi
rezolvat cu ajutorul acestei metode.
Vom da n continuare o procedur recursiv n pseudocod:
procedure DI (p,q,)
if q-p eps then
call PREL (p,q,)
else
call IMPARTE (p,q,m) ;
call DI (p,m,);
call DI (m+1,q,);
call COMB (,,);
endif;
return;
end procedure

final;

Cteva precizri se impun:


procedura trebuie apelat prin call DI (1,n,) n obinndu-se rezultatul

eps este lungimea maxim a unei secvene {ap,...,aq} notat prin (p,q) pentru
care se face prelucrarea direct fr a mai fi necesar mprirea n subprobleme;
procedura PREL realizeaz prelucrarea direct a secvenelor (p,q);
procedura COMB realizeaz combinarea rezultatelor i ale prelucrrii a
dou secvene vecine (p,m) i (m+1,q) obinnd rezultatul al prelucrrii
ntregii secvene (p,q);
prin procedura IMPARTE se obine valoarea lui m.
Vom da ca exemplu problema sortrii cresctoare a unui ir de ntregi
prin interclasare.
deoarece secvenele (i,i+1) sunt uor de ordonat acestea vor constitui
secvenele ce se vor prelucra, deci eps = 1;
- m se va calcula ca (p+q)/2, deci nu mai e nevoie de procedura special
IMPARTE;
procedura COMB va interclasa ntotdeauna dou secvene (p,m) i (m+1,q)
ordonate cresctor;
vom folosi un vector x drept structur global i vom face toate
prelucrrile pe elementele sale nemaiavnd nevoie de zonele ,;
pentru zona vom folosi un vector local y n procedura COMB acesta
coninnd elementele corespondente din x dar ordonate cresctor; tot n procedura
COMB se vor copia apoi elementele lui y din poriunea (p,q) n x;
- 98 -

BORLAND C Manual de utilizare

evident c procedurile din schema general a algoritmului sunt funcii C


cititorul fcnd analogiile necesare.
#include <stdio.h>
#include <conio.h>
#define nrelem 100
int x[nrelem];
int n;
void PREL (int p, int q)
{int aux;
if ((p<q) && (x[p] > x[q])) {
aux=x[p];
x[p]=x[q];
x[q]=aux;
}
}
void COMB (int inf, int mijloc, int sup)
{int i,j,k,l;
int y[nrelem];
i=k=inf;
j=mijloc+1;
while (i<=mijloc && j<=sup)
{ if (x[i] <= x[j])
y[k++]=x[i++];
else
y[k++]=x[j++];
}
for(l=i; l<=mijloc; y[k++]=x[l++]);
for(l=j; l<=sup; y[k++]=x[l++]);
for(k=inf; k<=sup; x[k++]=y[k]);
}
void DI (int p, int q)
{ int m;
if ((q-p) <= 1)
PREL (p,q);
else
{m=(p+q)/2;
DI (p,m);
DI (m+1,q);
COMB (p,m,q);
}
return;
}
void main(void)
{int i;
clrscr();
printf ("dati nr de elemente\n");
scanf ("%d",&n);
for (i=1; i<=n; i++)
{printf("x[%d]=",i);
scanf("%d",&x[i]);
}
DI (1,n);
printf("\nsirul sortat crescator este:\n");
for (i=1; i<=n; i++) printf("x[%d]=%d\n",i,x[i]);
getch();
}

- 99 -

BORLAND C Manual de utilizare

14.5. METODA PROGRAMRII DINAMICE


Aceast metod este aplicabil problemelor de optim n care soluia poate fi
privit ca rezultatul unui ir de decizii d1, . . . ,dn. Fiecare decizie depinde de
deciziile deja luate i nu este unic determinat (spre deosebire de tehnica greedy
unde fiecare decizie care se ia trebuie s fie unic). Totodat este necesar s
fie satisfcut una din variantele principiului optimalitii pentru a putea fi
aplicat aceast metod.
Vom formaliza acest principiu al optimalitii:
fie d1,...,dn un ir optim de decizii (SOD) care transform starea s o n
starea sn, trecnd prin strile intermediare s1, . . . ,sn-1; vom nota acest fapt
prin (d1,dn) este SOD pentru perechea de stri (so,sn);
grafic procesul este descris ca n figura urmtoare:
d1
d2
dn
*----->*---->*------>* . . . *------>*
so
s1 s2
sn-1 sn
Vom da acum mai multe variante ale principiului optimalitii:
dac (d1,dn) este SOD pentru (so,sn) atunci (d2,dn) este SOD pentru (s1,sn);
2) dac (d1,dn) este SOD pentru (so,sn) atunci i din {1, . . . ,n-1} avem
a) (d1,di) este SOD pentru (so,si) SAU
b) (di+1,dn) este SOD pentru (si,sn).
3) dac (d1,dn) este SOD pentru (so,sn) atunci i din {1, . . . ,n-1} avem
a) (d1,di) este SOD pentru (so,si) I
b) (di+1,dn) este SOD pentru (si,sn).
Ultima variant este cea mai general i mai complet. Odat verificat
o form a principiului optimalitii, metoda programrii dinamice const n a
scrie relaiile de recuren i apoi de a le rezolva. n general relaiile de
recuren sunt de 2 tipuri :
fiecare decizie di depinde de di+1,...,dn - relaii de recuren nainte,
deciziile vor fi luate n ordinea dn, dn-1, . . . ,d1;
fiecare decizie di depinde de d1, . . . ,di-1 - relaii de recuren napoi,
deciziile vor fi luate n ordinea d1, d2, . . . , dn.
Problem rezolvat
Fie G=(X,) un 1-graf orientat cruia i atam matricea costurilor,
(fiecare arc (i,j) este etichetat cu o valoare real strict pozitiv). Se pune
problema gsirii drumului de valoare minim (DVM) ntre oricare 2 vrfuri i i j.
Rezolvare
Verificm prima variant a principiului optimalitii:
- fie i, i1, i2, . . . , im, j DVM ntre i i j atunci evident c i1, . . . ,
im, j este DVM ntre i1 i
j;
- notm prin L(i,k) lungimea DVM dintre i i k, kX;
- notm deasemenea dkj valoarea arcului (k,j);
- ecuaiile de recuren sunt:
L(i,j) = min {L(i,k) + dkj)}
(k,j)
#include<stdio.h>
#include<values.h>
#define nn 10
int d[nn+1][nn+1],i,j,n;
int L(int i,int j)
- 100 -

BORLAND C Manual de utilizare

{
int m=MAXINT;
int k,x=0;
if (i= =j) m=0;
else
for (k=1;k<=n;k++)
if (d[k][j] < MAXINT)
{ x=L(i,k)+d[k][j];
if (x<m) m=x;
}
return m;
}
void citestematrice(void)
{int i,j;
printf("\ndati dimensiunea matricii distantelor : ");
scanf("%d",&n);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{ printf("d[%d,%d]= ",i,j);
scanf ("%d",&d[i][j]);
}
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) if (d[i][j]= = -1) d[i][j]=MAXINT;
}
void citeste(void)
{ printf("\ndati varful initial : ");
scanf("%d",&i);
printf("\ndati varful final : ");
scanf("%d",&j);
}
void afiseaza(int val)
{ printf("\nvdlm intre varful %d si %d este %d",i,j,val);
}
void main(void)
{ int vdlm;
clrscr();
citestematrice();
citeste();
vdlm=L(i,j);
afiseaza(vdlm);
getch();
}
Probleme propuse
14.5.1.
Se d o matrice A=(aij), i=1,...,n; j=1,...,m cu elementele din mulimea
{0,1,2}. Dou elemente din A aij i akl se numesc 4-vecine dac i-k+j-l = 1.
Notm cu So, S1 i S2 submulimile formate din elementele matricii egale cu
0, 1 respectiv 2. Submulimea S1 se mparte n grupuri astfel: aij i akl fac parte
din acelai grup dac sunt 4-vecine sau dac apq S1 : aij i apq sunt 4-vecine
iar apk i akl sunt din acelasi grup. Un element akl So l vom numi spion al
grupului G S1 dac aij G a.. akl i aij s fie vecine. Un spion este perfect
dac are toi vecinii din G.
Se cere:
a) cel mai numeros grup (S1) care are un singur spion (dac exist).
b) toate grupurile care au cel puin doi spioni perfeci.
14.5.2.
- 101 -

BORLAND C Manual de utilizare

Se d o matrice cu elemente care au valori din {d,o}, care reprezint un


teren cu drumuri {d} i obstacole {o}. n acest teren se afl un tanc i o int.
Acest tanc poate primi comenzi pentru rotirea evii (cu 90o n ambele sensuri),
pentru deplasare (n direcia evii cu o linie sau cu o coloan) sau pentru
tragere (n direcia evii pentru a nimeri inta) n cazul n care ntre tanc i
int nu exist nici un obstacol. Considernd c deplasarea nu se poate efectua
prin obstacole, se cere cel mai scurt drum necesar tancului pentru a putea
distruge inta i irul comenzilor efectuate n cazul n care exist un astfel de
drum.
14.5.3.
Se d o matrice cu elemente din {0,1,2,3}, reprezentnd o pdure cu capcane
(0) i crri (1). n aceast pdure se afl o vulpe (2) i mai muli lupi (3).
Fiecare lup ncearc s se apropie de vulpe fr a ti unde se afl capcanele, iar
n cazul n care cade ntr-o capcan, moare. Vulpea ncearc s se ndeprteze de
cel mai apropiat lup, avnd ns posibilitatea s descopere i capcanele i s le
ocoleasc. Att vulpea ct i lupii i pot modifica poziia doar cu o linie sau cu
o coloan n fiecare moment. S se spun dac vulpea reuete s scape de lupi.
14.5.4.
Se consider un teren dreptunghiular sub forma unei matrici A de m linii i
n coloane. Elementele aij ale matricii conin cotele (nlimile) diferitelor
poriuni astfel obinute. Se presupune c o bil se gsete pe o poriune (i o,jo)
avnd cota a(io,jo).
Se cere un program care s precizeze toate traseele (ncepnd cu (io,jo) )
posibile pe care le poate urma bila spre a iei din teren, tiind c bila se poate
deplasa n orice poriune de teren 4-nvecinat cu o cot strict inferioar cotei
terenului pe care se gsete bila.
14.5.5.
Se cere un program care rezolv problema labirintului (nerecursiv).
O matrice de m linii i n coloane reprezint un labirint dac:
a(i,j) = o - semnificnd culoar;
a(i,j) = 1 - semnificnd zid.
Un traseu de ieire pornind de la o poriune (io,jo) trebuie s fie o
succesiune de perechi (io, jo), (i1, j1) . . . (ik, jk) astfel nct 2 perechi
nvecinate s fie 4-vecine i a(ip,jp)=0
p=0, . . . ,k.

- 102 -

BORLAND C Manual de utilizare

ANEX
UN MEMENTO AL SINTAXEI LIMBAJULUI C
SINTAXA LIMBAJULUI C
n descrierea sintaxei limbajului vom folosi urmtoarele notaii:
a) ::= cu semnificaia "prin definiie este";
b) pentru a separa alternativele unei definiii sintactice;
c) < > pentru definirea unor metavariabile;
d) [ ] pentru delimitarea elementelor opionale;
e) .. pentru a indica elementele care se pot repeta.
Exemplu: Pentru a defini un "ntreg_zecimal" ca o succesiune de cifre
semnificative vom scrie:
<ntreg_zecimal> ::= <Cifr_nenul> [<Cifr>] ..
A. Atomi lexicali
<Cuvinte_cheie> ::= autobreakcasecharconstcontinuedefaultdodouble|
elseenumexternfloatforgotoifint|longregister |
returnshortsignedsizeofstatic|struct switchtypedef
unionunsignedvoidvolatilewhile
<Nume> ::= <Liter>[<Liter><Cifr>] ..
<Liter> ::= abcdefghijklmnopqrstuvwxyz
BCDEFGHIJKLMNOPQRS TUVWXYZ_
<Cifr> ::= 0123456789
<Constant> ::= <Constant_ntreag><Constant_real>
<Constant_enumerare><Constant_caracter>
<Constant_ntreag> ::= <Numr_ntreg>[<Sufix_ntreg>
<Numr_ntreg> ::= <ntreg_zecimal><ntreg_hexazecimal><ntreg_octal>
<ntreg_zecimal> ::= <Cifr_nenul>[<Cifr>] ..
<Cifr_nenul> ::= 123456789
<ntreg_hexazecimal> ::= 0x<Cifr_hexa> ..
<Cifr_hexa> ::= <Cifr>abcdefABCDEF
<ntreg_octal> ::= 0[<Cifr_octal>] ..
<Cifr_octal_> ::= 01234567
<Sufix_ntreg>
<Sufix_long>[<Sufix_unsigned>]

::=

<Sufix_unsigned>[<Sufix_long>]

<Sufix_unsigned> ::= Uu
<Sufix_long> ::= Ll
<Constant_real> ::= <Constant_fract>[<Exponent>][<Sufix_real>]
<Cifr> .. <Exponent>[<Sufix_real>]
<Constant_fract> ::= [<Cifr>] .. . <Cifr>..<Cifr>.. .
<Exponent> ::= Ee[+-]<Cifr> ..
- 103 -

BORLAND C Manual de utilizare

<Sufix_real> ::= FfLl


<Constant_enumerare> ::= <Nume>
<Constant_caracter> ::= '<Caracter_C> ..'L'<Caracter_C>'
<Caracter_C> ::= <Orice_caracter_tipribil_cu excepia: ' i \>
<Secven_escape>
<Secven_escape> ::= \"\'\?\\\a\b\f\n\r\t\v
\<Cifr_octal>[<Cifr_octal>[<Cifr_octal>]] \x<Cifr_hexa> ..
<ir_de_caractere> ::= "[<Caracter_S> ..]"
<Caracter_S>
<Secvena_escape>

::=

<Orice_caracter_tipribil_cu

excepia:

'

\>

<Operatori_i_semne_de_punctuaie >::=
+-*/%^&~!=->+=-=*=
/=%=^=&=!=<<>><<=>>== =<=
>=<>&&!!++--,()[]{};?:...
B. Declaraii
<Unitate_de_compilare> ::= <O_declaraie> ..
<O_declaraie> ::= <Def_funcie><Declaraie>;
<Declaraie> ::= [<Specificatori>][<List_declaratori>]
<Specificatori> ::= <Specificator> ..
<Specificator> ::= <Clas_memorare><Tip>typedef
<Clas_memorare> ::= autoregisterstaticextern
<Tip> ::= <Tip_simplu><Nume_typedef><Calificator>
<Descriere_tip_enumerare><Descriere_tip_neomogen>
<Tip_simplu> ::= charshortintlongsignedunsignedfloatdouble void
<Nume_typedef> ::= <Nume>
<Descriere_tip_enumerare> ::= enum<Nume>enum[<Nume>]{<Lista_enum>}
<Lista_enum> ::= <Enumerator>[,<Enumerator>] ..
<Enumerator> ::= <Nume>[=<Expr_constant_>{]
<Descriere_tip_neomogen> ::= <Tip_neomogen><Nume>
<Tip_neomogen>[<Nume>]{<List__cmpuri>}
<Tip_neomogen> ::= structunion
<List_cmpuri> ::=

<Decl_cmpuri>;[<Decl_cmpuri>;] ..

<Decl_cmpuri> ::= [<Specificatori>][<Cmp>[,<Cmp>] ..]


<Cmp> ::= <Declarator>[<Nume>]:<Expr_constant>
<List_declaratori> ::= <Decl_init>[,<Decl_init>] ..
- 104 -

BORLAND C Manual de utilizare

<Decl_init> ::= <Declarator>[<Iniializare>]


<Declarator> ::= [<Indirect>..]<Denumire>[<Decl_F_T>]
<Indirect> ::=

*[<Calificator> ..]

<Denumire> ::= <Nume>(<Declarator>)


<Decl_F_T> ::= ([<L_declar_par>])<Decl_tablou> ..
<Decl_tablou> ::= [][<Expr_constant>]
<L_declar_par> ::= <Decl_par>[,<Decl_par>] .. [, ..]
<Decl_par> ::= <Tip>..<Declarator><Decl_tip>
<Decl_tip> ::= <Tip>..[<Indirect>..][(<Decl_tip>)][<Decl_F_T>]
<Iniializare> ::= =<Expr> ={<List_init>[,]}
<List_init>::=<Expr>[,<List_init> ..{<List_init>}[,<List_init>] ..
<Def_funcie>

::=

[<Specif_funcie>

..]<Declarator>[<Declaraie>;]

..

<Bloc>
<Specif_funcie> ::=

externstatic<Tip>

C. Expresii
<Expr> ::= <Expresie>[,<Expresie>] ..
<Expresie> ::= <Expr_condiional>|<Expr_unar><Oper_atribuire><Expresie>
<Oper_atribuire> ::= +*=/=%=+=-=<<=>>=&=^=!=
<Expr_condiional> ::= <Expr_SAU_logic>
<Expr_SAU_logic> ? <Expr> : <Expr_condiional>
<Expr_SAU_logic> ::= <Expr_I_logic><Expr_SAU_logic> !! <Expr_I_logic>
<Expr_I_logic> ::=

<Expr_SAU><Expr_I_logic> && <Expr_SAU>

<Expr_SAU> ::= <Expr_SAU_exclusiv><Expr_SAU><Expr_SAU_exclusiv>


<Expr_SAU_exclusiv> ::= <Expr_I><Expr_SAU_exclusiv> ^ <Expr_I>
<Expr_I> ::= <Expr_egalitate><Expr_I> & <Expr_egalitate>

<Expr_egalitate> ::= <Expr_relaional><Expr_egalitate>==Expr_relaional>


<Expr_egalitate> != <Expr_relaional>

<Expr_relaional>
<Expr_deplasare>

::=

<Expr_deplasare>

<Expr_relaional>

<

<Expr_relaional> > <Expr_deplasare>


<Expr_relaional> <= <Expr_deplasare>
<Expr_relaional> >= <Expr_deplasare>
<Expr_deplasare> ::= <Expr_aditiv> <Expr_deplasare> << <Expr_aditiv>
<Expr_deplasare> >> <Expr_aditiv>
- 105 -

BORLAND C Manual de utilizare

<Expr_aditiv>
<Expr_multiplicativ>

::=

<Expr_multiplicativ><Expr_aditiv>

<Expr_aditiv> - <Expr_multiplicativ>

<Expr_multiplicativ>::=

<Expr_multiplicativ> * <Expr_prefixat>
<Expr_multiplicativ> / <Expr_prefixat>
<Expr_multiplicativ> % <Expr_prefixat>

<Expr_prefixat> ::= <Expr_unar>(<Decl_tip>)<Expr_prefixat>


<Expr_unar> ::= <Expr_postfixat><Op_unar><Expr_prefixat>
++<Expr_unar> --<Expr_unar>sizeof<Expr_unar>
sizeof(<Decl_tip>)
<Op_unar> ::= &*+-~!

<Expr_postfixat> ::= <Termen><Expr_postfixat>[<Expr>]


<Expr_postfixat>(<List_Expresii>) <Expr_postfixat> . <Nume>
<Expr_postfixat> -> <Nume><Expr_postfixat> ++ <Expr_postfixat>-<Termen> ::= <Nume><Constant><ir_de_caractere>(<Expr>)
<List_Expresii> ::= [<Expr>] ..
<Expr_constant> ::= <Expr_condiional>
D. Instruciuni
<Instr>::=
<Instr_etichetat><Instr_compus>
Instr_de_selecie>
<Instr_de_ciclare><Instr_de_salt>

<Instr_expresie>

<Instr_etichetat> ::= <Nume>:<Instr>case <Expr_constant { :<Instr>


default : <Instr>
<Instr_compus> ::= <Bloc>
<Bloc> ::= {[<Declaraie>;] .. [<Instr>] ..}
<Instr_expresie> ::= [<Expr>];
<Instr_de_selecie>
<Instr>

::=

if

(<Expr>)

<Instr>if

(<Expr>)

<Instr>

switch (<Expr>) <Instr>

<Instr_de_ciclare> ::=

while (<Expr>)<Instr>;
do <Instr> while (<Expr>);
for ( [<Expr>];[<Expr>];[<Expr>] ) [<Instr>];

<Instr_de_salt> ::= goto <Nume>;continue;break;return [<Expr>];

- 106 -

else

BORLAND C Manual de utilizare

- 107 -

CUPRINS

BIBLIOGRAFIE
Brian W.Kerninghan, Dennis M. Ritchie, The C Programming Language, INC.
Englewood Cliffs, New Jersey, 1978.
Liviu Negrescu, Limbajul C, Editura Libris, Cluj-Napoca, 1997.
G. Moldovan, M. Lupea, V.Cioban, Probleme pentru programare n limbajul
C, Litografia Universitii Babe-Bolyai, Cluj-Napoca, 1995.

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