Sei sulla pagina 1di 111

Adrian DEACONU

PROGRAMARE PROCEDURAL

2009 - 2010

Cuvnt nainte

Cartea de fa se dorete a fi, n principal, un ghid pentru studenii din domeniul


Informatic, dar, evident, ea poate fi util tuturor celor care vor s nvee s programeze
procedural n limbajul C.
La fiecare capitol, sunt date exemple sugestive, care ilustreaz din punct de vedere
practic elemente de noutate. Este bine ca aceste exemple s fie nelese i, acolo unde este
nevoie, s fie scrise i rulate de ctre cititor. Programele din aceast carte nu conin erori,
deoarece ele au fost nti testate i abia apoi introduse n lucrare.
n general, tot ceea ce este prezentat n aceast carte (teorie i aplicatii) este recunoscut
att de compilatorul C al firmei Borland, ct i de compilatorul Visual C al companiei
Microsoft.

Autorul.

Introducere

Limbajul C a fost lansat n anul 1972 n laboratoarele Bell de ctre Dennis Ritchie pentru
sistemul de operare Unix. n anul 1973 limbajul C a ajuns suficient de puternic nct mare parte
din sistemul Unix a fost rescris n C.
Limbajul C s-a extins rapid pe mai multe platforme i s-a bucurat nc de la nceput de un
real succes datorit uurinei cu care se puteau scrie programe.
La sfritul anilor 1980 a aprut limbajul C++ ca o extensie a limbajului C. C++ preia
facilitile oferite de limbajul C i aduce elemente noi, dintre care cel mai important este
noiunea de clas, cu ajutorul creia se poate scrie cod orientat pe obiecte n adevratul sens al
cuvntului.
n anul 1989 este finalizat standardul ANSI C. Standardul ANSI (American National
Standards Institute) a fost adoptat n 1990 cu mici modificri i de ctre ISO (International
Organization for Standardization).
Exist multe compilatoare de C/C++. Dintre acestea, de departe cele mai cunoscute sunt
compilatoarele medii de programare integrate produse de firmele Borland i Microsoft.
Prima versiune a bine-cunoscutului mediu de programare Turbo C a fost lansat de ctre
firma Borland n anul 1987. Standardul ANSI C / ISO C a constituit baza elaborrii de ctre
firma Borland a diferitelor sale versiuni de medii de programare, dintre care ultima a fost
Borland C++ 5.02. n prezent firma Borland dezvolt mediul de programare Borland C++
Builder i mediile Turbo C++ Professional i Explorer, dintre care ultimul este gratuit ncepnd
cu anul 2006.
n anul 1992 firma Microsoft a lansat prima versiune a mediului su de programare
Visual C++, iar n anul 2002 a fost lansat prima versiune Visual C++ pentru platforma .NET.
n aceast carte vor fi prezentate limbajele C i C++ dintr-o perspectiv att Borland, ct
i Microsoft. Pe alocuri vor fi punctate micile diferene dintre cele dou compilatoare.

Obiectivele cursului
Cursul intitulat Programare procedural are ca obiectiv principal familiarizarea
studenilor cu modul de gndire orientat pe proceduri n general i cu programare
din C n particular.

Resurse
Parcurgerea unitilor de nvare aferente ambelor module necesit instalarea unui
mediu de programare C, este de preferat Visual C 2008.

Structura cursului
Cursul este alctuit dintr-un singur modul, care cuprinde patrusprezece uniti de
nvare. La rndul ei, fiecare unitate de nvare cuprinde: obiective, aspecte
teoretice privind tematica unitii de nvare respective, exemple, teste de
autoevaluare precum i probleme propuse spre discuie i rezolvare.
La sfritul unitilor de nvare sunt indicate teme de control. Rezolvarea acestor
teme de control este obligatorie. Temele vor fi trimise de ctre studeni prin e -mail.

Modulul 1. Programarea n C
Cuprins
Introducere ................................ ................................ ................................ ................................ ...
Competene ................................ ................................ ................................ ................................ ..
U1. Structura unui program C
U2. Tipuri numerice de date
U3. Funcii de scriere i citire n C
U4. Instruciuni de decizie, instruciuni repetitive, tipul char
U5. Pointeri, tablouri de elemente
U6. Funcii n C
U7. String-uri
U8. Structuri i pointeri ctre structuri
U9. Uniuni i seturi de constante
U10. Fiiere n C
U11. Fluxuri standard n C i variabile statice
U12. Funcii cu list variabil de argumente
3

U13. Utilizarea modului text de afiare


U14. Grafic n C

Introducere
n acest modul vom face o preentare a limbajului C.
Temele atinse in acest modul:
1. Structura unui program C
1.1. Includeri
1.2. Constante. Macrocomenzi
1.3. Asocieri de nume unor tipuri de date
1.4. Funcia main
2. Tipuri numerice de date
2.1. Tipuri ntregi de date
2.2. Operatorii din C pentru valori ntregi
2.3. Tipuri reale de date
2.4. Operatorii C pentru valori reale
2.5. Ali operatori n C
3. Funcii de scriere i citire n C
3.1. Funcia printf
3.2. Funcia scanf
4. Instruciuni de decizie
4.1. Instruciunea if
4.2. Instruciunea switch
5. Instruciuni repetitive
5.1. Instruciunea for
5.2. Instruciunea while
5.3. Instruciunea do while
6. Tipul char
7. Pointeri. Tablouri de elemente
7.1. Alocarea static a memoriei
7.2. Alocarea dinamic a memoriei
8. Funcii n C
9. String-uri
10. Structuri
11. Pointeri ctre structuri. Liste nlnuite.
12. Uniuni

13. Seturi de constante (tipul enum)


14. Fiiere n C
14.1. Funcii de lucru cu fiiere
15. Fluxuri standard n C
16. Variabile statice
17. Funcii cu list variabil de argumente
18. Utilizarea modului text de afiare al adaptorului video
19. Grafic n C
19.1. Iniializarea modului grafic
19.2. Instruciuni pentru desenare de linii drepte
19.3. Instruciuni pentru desenare de curbe eliptice
19.4. Instruciuni pentru afiare de texte n modul grafic
19.5. Instruciuni pentru desenare de figuri umplute
19.6. Instruciuni pentru paleta de culori
19.7. Pagini grafice
19.8. Citire / scriere zon de memorie video
19.9. Ferestre grafice
De asemenea, la sfaritul modului sunt atasate dou anexe (utilizarea mouse-ului
i, respectiv, urmrirea execuiei unei aplicaii pas cu pas ) i o bibliografie.
Aceste elemente ale limbajului C vor fi prezentate pe larg n cele ce urmeaz.

Competene
La sfritul acestui modul studenii vor:
i vor crea un mod de gndire orientat pe proceduri;
fi familiarizai cu noiunea de pointer;
fi familiarizai cu alocarea dinamic a memoriei;
fi familiarizai cu iruri NULL-terminate;
fi familiarizai cu transmiterea parametrilor n funcii ;
ti s lucreze cu fiiere;
fi familiarizai cu limbajul C n general;
stpni elemente avansate de programare.

Unitatea de nvare M1.U1. Structura unui program C


Cuprins
Obiective ................................ ................................ ................................ ................................ ...........
5

Introducere ................................ ................................ ................................ ................................ .......


U1.1. Includeri................................ ................................ ................................ ................................ ...
U1.2. Constante. Macrocomenzi. ................................ ................................ ................................ ......
U1.3. Asocieri de nume unor tipuri de date ................................ ................................ ......................
U1.4. Funcia main ................................ ................................ ................................ ............................
Obiectivele unitii de nvare
Ne propunem s vedem cum se scrie un program n limbajul C, ce seciuni
apar, unde i cum se redacteaz.

Durata medie de parcurgere a unitii de nvare este de 2 ore.

Introducere
Un program C se salveaz de obicei cu extensia C i, implicit, compilarea se va face cu
compilatorul C. Dac, ns, programul este salvat cu extensia CPP, atunci compilarea se va face
folosind compilatorul C++.
Un program C obinuit are urmtoarea structur:
/* includeri
definitii macrocomenzi
definitii de tipuri de date
declaratii de variabile globale
definitii de constante globale
definitii de functii sau/si descrierea unor functii */
void main()
{
/* corpul functiei principale */
}
/* descriere functii care au definitia (antetul) deasupra functiei main */
Ordinea de apariie a includerilor, a definiiilor de macrocomenzilor, a tipurilor de date, a
variabilelor i a constantelor globale este opional. Mai mult, pot aprea mai multe grupuri de
includeri, macrocomenzi, definiii de tipuri de date, variabile i constante. Astfel, de exemplu,
putem avea declaraii de variabile, apoi includeri, apoi iar declaraii de variabile etc.
De regul la nceputul unui program C se pun includerile, dar, dup cum am spus, nu este
obligatoriu.

S facem observaia c ntre /* i */ n C se pun comentariile (aa cum se poate vedea


n programul de mai sus). Cu alte cuvinte, tot ce apare ntre aceste semne nu este luat n
considerare la compilare.
Spre exemplificare prezentm un program simplu care afieaz un mesaj de salut:
# include <stdio.h> /* includerea fiierului antet stdio.h */
void main()
{
printf("HELLO WORLD!");
/* functia printf are antetul in fisierul stdio.h */
}
Facem observaia c n C se face distincie ntre litere mari i mici, spre deosebire de
limbajul Pascal, de exemplu, unde nu conteaz dac redactm codul cu litere mari sau cu litere
mici. Astfel, n programul de mai sus, dac scriam funcia printf cu litere mari, ea nu era
recunoscut la compilare i obineam un mesaj de eroare.

U1.1. Includeri
La nceputul unui program C sau C++ se includ de obicei fiiere antet. Un fiier antet se
recunoate uor prin faptul c are de obicei extensia h. Se pot include i fiiere cu extensia C sau
CPP, care conin cod C, respectiv cod C++.
Fiierele antet conin n general numai definiiile unor funcii a cror implementare
(descriere) se regsete separat n fiiere cu extensiile C, CPP, obj sau lib. Fiierele *.obj conin
cod C sau C++ n forma compilat cu compilatorul Borland C/C++. Fiierele *.lib conin
biblioteci de funcii C i C++. Odat cu mediul de programare C/C++ se instaleaz i o mulime
de biblioteci de funcii mpreun cu fiiere antet ce conin definiiile acestor funcii.
Cele mai des incluse fiiere antet din C sunt stdio.h i conio.h, care conin definiiile
funciilor standard de intrare / ieire (citiri, scrieri), respectiv definiii de funcii consol I/O (de
exemplu funcia getch(), care ateapt apsarea unui buton de la tastatur).
Includerea unui fiier ncepe cu semnul # (diez), urmat de cuvntul include i de numele
fiierului care este dat ntre semnele < (mai mic) i > (mai mare), sau ntre ghilimele. Numele
fiierului inclus poate fi precedat de eventuala cale unde se gsete el pe disc.
Dac fiierul ce se include nu este precedat de cale i numele su este dat ntre ghilimele,
atunci el este cutat n calea curent sau n directorul cu fiierele antet ce se instaleaz odat cu
mediul de programare.
Dac fiierul inclus nu este precedat de cale i numele lui este dat ntre semnele < i >,
atunci el este cutat numai n directorul cu fiierele antet ale mediului de programare C/C++.
Pentru limbajul C o parte dintre funcii sunt incluse implicit (compilatorul C le cunoate
fr a fi nevoie includerea vreunui fiier). Totui, n funcie de compilator, pot fi generate mesaje
de atenionare (warning) dac nu facem includerile. n exemplul de mai sus dac se salveaz
programul cu extensia C (i implicit se folosete compilatorul C), atunci includerea fiierului
antet stdio.h nu este neaprat necesar. Dac salvm ns fiierul cu extensia CPP, atunci
includerea lui stdio.h este obligatorie.
Iat n final i cteva exemple de includeri:
# include <stdio.h>
# include "conio.h"
# include "c:\bc\test\test.cpp"

U1.2. Constante. Macrocomenzi.


n C o constant obinuit se poate defini folosind cuvntul rezervat const astfel:
const tip_date c=expresie_constanta;
Dac lipsete tipul de date de la definirea unor constante, se consider implicit tipul int.
Iat i cteva exemple:
const int x=1+4;
const a=1,b=2*2; /* tot constante intregi ! */
const double pi=3.14159

Macrocomanda reprezint o generalizare a conceptului de constant, n sensul c putem


defini expresii constante, care se nlocuiesc n codul executabil n momentul compilrii.
Definirea unei macrocomenzi ncepe cu semnul # (diez) urmat de cuvntul define.
Dm cteva exemple de macrocomenzi:
#
#
#
#

define
define
define
define

N 100
PI 3.14159
suma(x,y) x+y
alipire(a,b) (a##b)

Primele dou macrocomenzi definesc constante obinuite, N este o constant de tip


ntreg, iar PI este una de tip real.
Ultimele dou macrocomenzi de mai sus definesc cte o expresie constant. ntr-un
program care cunoate a treia macrocomand, un apel de forma suma(1.7, a) se va nlocui la
compilare cu 1.7+a. nlocuirea se face n fiecare loc n care este apelat macrocomanda. De
aceea, macrocomanda poate fi considerat o generalizare a conceptului de constant, dei apelul
ei seamn cu cel al unei funcii.
Comportamentul macrocomenzilor poate conduce la erori de programare pentru cei care
nu cunosc modul lor de funcionare. De exemplu, valoarea expresiei suma(1,2)*5 este 11 i nu
15, deoarece nlocuirea direct a apelului suma(1,2) la compilare cu 1+2 conduce la expresia
1+2*5, care are evident valoarea 11 i nu la expresia ( 1+2)*5 cu valoarea 15.
n exemplul de mai sus la ultima macrocomand s-a folosit operatorul ## care alipete
(concateneaz) doi tokeni. Astfel, un apel de forma alipire(x,yz) se nlocuiete cu xyz, care poate
fi o variabil, numele unei funcii etc.
Este important de observat c datorit comportamentului diferit de cel al funciilor,
macrocomenzile sunt contraindicate pentru a fi folosite prea des ntr-un program, deoarece
fiecare apel de macrocomand se nlocuiete n memorie cu corpul macrocomenzii, ceea ce
conduce la mrirea codului executabil. n concluzie, cnd se lucreaz cu macrocomenzi codul C
sau C++ se poate reduce ca lungime, dar codul n fo rm compilat poate crete.
Frumuseea macrocomenzilor const n faptul c nu lucreaz cu tipuri de date prestabilite.
Astfel, n exemplul de mai sus macrocomanda suma va putea fi folosit pentru orice tip de date,
atta timp ct ntre x si y se poate aplica operatorul +. Din cauz c la definire nu se specific
tipul de date al parametrilor, macrocomenzile pot fi vzute ca un rudiment de programare
generic oferit de limbajul C.
n limbajul C++ pot fi scrise funcii i clase ablon pentru care unul sau mai multe tipuri
de date sunt nespecificate, identificarea acestor tipuri fcndu-se n momentul compilrii

programului. abloanele reprezint un suport pentru programare generic n adevratul sens al


cuvntului. Asupra abloanelor vom reveni.

U1.3. Asocieri de nume unor tipuri de date


n C putem asocia un nume unui tip de date cu ajutorul cuvntului rezervat typedef astfel:
typedef tip_de_date nume_asociat;
Dm n continuare dou exemple ilustrative:

typedef int intreg;


typedef struct nume_structura nume_structura;

Tipului numeric int i se asociaz numele intreg. Dup aceast asignare, putem folosi
cuvntul intreg, n loc de int.
n al doilea exemplu tipului de date de tip structur struct nume_structura (care trebuie s
existe anterior definit) i se asociaz denumirea nume_structura (fr struct). Acest lucru este des
folosit n C pentru simplificarea scrierii tipului structur. Aceast asociere nu este necesar n
C++, unde tipul struct nume_structura poate fi folosit i fr cuvntul struct, fr o definire
prealabil cu typedef.
Asocierile de nume unor tipuri de date se pot face att n exteriorul, ct i n interiorul
funciilor.

1.4. Funcia main


n orice program C/C++ trebuie s existe o unic funcie main (principal), din interiorul
creia ncepe execuia aplicaiei.
Pentru a nelege mai bine modul de definire al funciei main vom prezenta pe scurt
cteva generaliti legate de modul de definire al unei funcii oarecare.
n C i C++ nu exist proceduri, ci numai funcii. n definiia unei funcii tipul returnat se
pune naintea numelui funciei. Dac n momentul definirii funciei se omite tipul returnat, nu
este greit i se consider implicit tipul returnat ca fiind int. O funcie care are ca tip returnat void
(vid) se apeleaz ca o procedur. Dac o funcie nu are parametri, dup nume se pun paranteze
rotunde sau se pune cuvntul rezervat void ntre paranteze rotunde n momentul definirii ei.
Funcia main poate avea ca tip returnat void sau int (care se pune naintea cuvntului
main). Dac tipul returnat este int, atunci n interiorul funciei main pot aprea instruciuni de
forma return val_int care au ca efect ntreruperea execuiei programului i returnarea ctre
sistemul de operare a valorii ntregi val_int. n aceast situaie, ultima instruciune din funcia
main este de obicei return 0, ceea ce nseamn c programul s-a terminat cu succes. Dac apare
vreo eroare pe parcursul execuiei programului care nu poate fi tratat (memorie insuficient,
imposibilitate de deschide a unui fiier etc.), programul se prsete n general cu o instruciune
de forma return val_int, unde val_int este o valoare ntreag nenul. Astfel, semnalm sistemului
de operare faptul c execuia programului s-a ncheiat cu insucces (cu eroare).
Funcia main poate s nu aib nici un parametru, sau poate avea 2 parametri. Dac funcia
main are doi parametri, atunci primul este de tip int i reine numrul de parametri n linie de
comand cu care s-a executat programul, iar al doilea este un ir de string-uri, n care sunt
9

memorai parametrii de apel n linie de comand. n primul string (pe poziia 0 n vector) se
reine numele executabilului (al aplicaiei), dup care urmeaz parametrii de apel n linie de
comand.
Presupunem c avem programul C test care are urmtoarea funcie main:
void main(int narg,char argv *arg[])
{
/* .... */
}
Apelm programul test n linie de comand cu doi parametri:
test param1 param2
n aceast situaie, n funcia main a programului test vom avea:

narg va avea valoarea 3


arg[0] va fi test.exe
arg[1] va fi param1
arg[2] va fi param2.

Asupra modului de definire i descriere a funciilor o s revenim.

Rezumat
naintea funciei main pot aprea niciuna, una sau mai multe seciuni de tipul:
-

includeri. Pot fi incluse n general fiiere antet (cu extensia .h), dar pot aprea i fiiere cu
extensia .c sau .cpp. Aceste fiiere conin n general antete (definiii) de funcii, definiii de
tipuri de date i constante, macrocomenzi, dar pot aprea i implementri de funcii, variabile
globale etc.
definiii de macrocomenzi. Macrocomanda reprezint o generalizare a conceptului de
constant. O macrocomand este o expresie constant. Fiecare apel de macrocomand este
nlocuit la compilare cu corpul macrocomenzii. O macrocomand se descrie dup #define.
definiii de tipuri de date. Unui tip nou de date definit de programator i se poate da un nume
folosind declaraia care incepe cu cuvntul rezervat typedef.
declaraii de variabile.
definiii de constante globale. Constantele n C se definesc dup cuvntul rezervat const. O
constant obinuit poate fi definit i ca o macrocomand.
definiii sau/i descrieri de funcii. Funciile programului C se declar deasupra funciei
main i se implementeaz dup funcia main, sau se descriu n ntregime deasupra funciei
main.

Funcia main poate avea ca tip returnat tipul void sau tipul int. Funcia main poate s nu
aib nici argumente sau poate avea dou argumente de apel, argumente care memoreaz
parametrii de apel n linie de comand ai aplicaiei.

Teme de control
10

1. Folosind operatorul ?: (vezi subcapitolul 2.5) scriei o macrocomand pentru maximul dintre
dou numere.
2. Scriei o macromand pentru maximul dintre trei valori.
3. Folosind prima macrocomand scriei o macromand pentru maximul dintre patru valori.
4. Ce trebuie s conin parametrii narg i argv pentru o aplicaie care ar calcula media
aritmetic n linie de comand a orictor valori reale ?

Unitatea de nvare M1.U2. Tipuri numerice de da te


Cuprins
Obiective ................................ ................................ ................................ ................................ ...........
Introducere ................................ ................................ ................................ ................................ ........
U2.1. Cum se scrie un program n C ................................ ................................ ................................
U2.2. Includeri ................................ ................................ ................................ ................................ ...
U2.3. Constante. Macrocomenzi. ................................ ................................ ................................ ......
U2.4. Asocieri de nume unor tipuri de date ................................ ................................ .......................
U2.5. Funcia main ................................ ................................ ................................ ............................
Obiectivele unitii de nvare
Ne propunem s facem cunotiin cu tipurile numerice de date ale
limbajului C, modul lor de reprezentare n memorie, domeniul de valori, operatorii
specifici acestor tipuri de date i ali operatori pe care i ntlnim n C.

Durata medie de parcurgere a unitii de nvare este de 2 ore.

Introducere
n C i C++ avem dou categorii de tipuri numerice de date: tipuri ntregi i reale. Cu cele
dou clase de tipuri numerice se lucreaz diferit (la nivel de procesor). Reprezentarea informaiei
n memorie este diferit, avem operatori diferii.

U2.1. Tipuri ntregi de date


n tabelul de mai jos sunt prezentate tipurile numerice ntregi cu semn (signed) i fr
semn (unsigned) din C. Facem observaia c numrul de octei pe care se reprezint n memorie
11

valorile ntregi i implicit domeniile de valori din tabelul urmtor sunt cele pentru Windows, mai
exact, cele din Visual C:

(signed) char
unsigned char
enum
short (signed) (int)
short unsigned (int)
(signed) int

Numr
octei
1
1
2
2
2
4

unsigned int
(signed) long

4
4

unsigned long

Denumire tip

Domeniu de valori
-128 la 128
0 la 255
-32.768 la 32.767
0 la 65.535
-32.768 la 32.767
-2.147.483.648 la
2.147.483.647
0 la 4.294.967.295
-2.147.483.648 la
2.147.483.647
0 la 4.294.967.295

S facem cteva observaii:


i.
ii.
iii.

iv.

v.

n Visual C tipul enum coincide cu tipul short int, iar tipul int coincide cu long.
Tot ceea ce apare ntre paranteze rotunde n tabelul de mai sus este opional.
Tipurile numerice de date au o dubl utilizare n C i C++: pentru valori numerice
(numere) i pentru valori booleene. Astfel, o valoare numeric nenul (ntreag
sau real) corespunde n C/C++ valorii booleene de adevrat (true), iar o valoare
numeric nul corespunde valorii booleene de fals (false)
Tipurile char i unsigned char n C i C++ au o tripl ntrebuinare: pentru valori
ntregi pe un octet, pentru valori booleene i pentru caractere. Valoarea ntreag
de tip char reprezint codul ASCII al unui caracter. Astfel, constanta de tip char
a reprezint valoarea ntreag 97, care este de fapt codul ASCII al caracterului a.
Cu alte cuvinte, n C a este acelai lucru cu 97 !
n Visual C pentru caractere Unicode este definit tipul wchar_t pe doi octei.

U2.2. Operatorii din C pentru valori ntregi


Operatorul = (egal) este folosit pentru atribuirea valorii unei expresii ntregi unei
variabile ntregi:
i = expresie;
Operatorul returneaz valoarea atribuit variabilei i, valoare rezultat n urma evalurii
expresiei i conversiei la tipul variabilei i, n cazul nostru fiind vorba de tipul int. Astfel, de
exemplu i = 1 + sqrt(2) este o expresie care are valoarea 2.
Pentru tipurile ntregi de date sunt definii operatorii aritmetici binari: + (adunare), (scdere), * (nmulire), / (ctul mpririi), % (restul mpririi), +=, -=, *=, /=, %=, unde
expresia x += y este echivalent cu x = x+y.
Operatori aritmetici unari definii pentru tipurile ntregi de date sunt: ++ i --. Ei
realizeaz incrementarea, respectiv decrementarea unei variabile ntregi. Astfel, x++ este
echivalent cu x = x+1, iar x-- cu x = x-1. Cei doi operatori unari se folosesc sub dou forme:
x++, x--, adic forma postincrementare, respectiv postdecrementare, iar ++x, --x sunt sub forma
preincrementare, respectiv predecrementare. S explicm acum care este diferena dintre cele
dou forme de utilizare a operatorului de incrementare.
12

Presupunem c variabila y reine valoarea 1. Pentru o expresie de forma x = ++y, nti se


incrementeaz y i apoi noua valoare a lui y se atribuie lui x i, n consecin, x devine 2. Dac
operatorul ++ se folosete n forma postincrementat, adic x = y++, atunci lui x nti i se
atribuie valoarea variabilei y i abia dup aceea se face incrementarea lui y. n aceast situaie
variabila x va fi iniializat cu valoarea 1. Operatorul de decrementare -- funcioneaz n mod
similar ca i ++, tot sub dou forme, predecrementare i postdecrementare.
Operatorii relaionali sunt: < (mai mic), <= (mai mic sau egal), > (mai mare), >= (mai
mare sau egal), == (egalitate), != (diferit). Cu alte cuvinte, cu ajutorul acestor operatori, dou
valori ntregi se pot compara.
Operatorul ! (semnul exclamrii) aplicat unei valori numerice are efectul not, adic din
punct de vedere boolean i schimb valoarea (din False n True, respectiv din True n False).
Astfel, !x are valoare 0 dac i numai dac x este nenul.
Operatori la nivel de bit aplicabili numai pe valori ntregi sunt: & (i pe bii), | (sau pe
bii), ^ (sau exclusiv), >> (shift-are bii la dreapta), << (shift-are bii la stnga), ~ (not pe bii).
Pentru a nelege cum funcioneaz aceti operatori dm urmtorul exemplu:
- Fie a i b dou variabile ntregi pe un octet, a reprezentat pe bii este
(1,0,1,1,0,1,1,1) i b = (0,1,1,1,0,0,1,0).
- Avem: a & b = (0,0,1,1,0,0,1,0), a | b = (1,1,1,1,0,1,1,1), a ^ b =
(1,1,0,0,0,1,0,1), a >> 1 = (0,1,0,1,1,0,1,1), a << 1 = (0,1,1,0,1,1,1,0), ~a =
(0,1,0,0,1,0,0,0).
Facem observaia c dac a este ntreg cu semn (de tip char), atunci a >> 1 =
(1,1,0,1,1,0,1,1), deoarece cel mai semnificativ bit (cel mai stnga) reprezint semnul numrului
ntreg i n consecin dup shift-are la dreapta rmne tot 1 (corespunztor semnului minus). S
observm c shift-area cu n bii a unei valori ntregi este echivalent cu o mprire la 2n. n cazul
exemplului nostru a >> 1 este echivalent cu a = a / 2.
Pentru operatorii pe bii avem i variantele combinate cu atribuire: &=, |=, ^=, <<=, >>=,
unde x &= y este echivalent cu x = x & y etc.

U2.3. Tipuri reale de date


n tabelul de mai jos sunt trecute tipurile numerice reale (n virgul mobil) din C
(denumirea, numrul de octei pe care se reprezint n memorie i domeniul de valori n valoare
absolut):
Denumire tip

Numr octei

float
double
long double

6
8
10

Domeniu de valori n
valoare absolut
3,410-38 la 3,41038
1,710-308 la 1,710308
3,410-4932 la 1,1104932

Desigur, este important i precizia cu care lucreaz fiecare din tipurile numerice reale de
mai sus (numrul maxim de cifre exacte). Precizia cea mai bun o are tipul long double i cu cea
mai sczut precizie este tipul float.

U2.4. Operatorii C pentru valori reale


Pentru tipurile reale de date n C sunt definii operatorii:
13

Operatorul de atribuire =.
Operatorii aritmetici binari: + (adunare), - (scdere), * (nmulire), / (mprire).
Operatorii aritmetici binari combinai cu atribuire +=, -=, *=, /=.
Operatorii relaionali, not i de incrementare, respectiv decrementare
funcioneaz i pentru valori reale.

Operatorii pe bii nu funcioneaz pentru valori reale!

U2.5. Ali operatori n C


Operatorii logici: && (i), || (sau), ! (not). Dm un exemplu de expresie logic: (a &&
!(b%2) && (a>b || b<=0)).
Operatorul ?: este singurul operator ternar (funcioneaz cu trei operanzi) din C i se
folosete astfel: var = (expresie_logic) ? val1:val2 cu semnificaia: se evalueaz
expresie_logic, dac expresia are valoare de adevrat (diferit de 0), atunci variabila var ia
valoarea val1, altfel var primete valoarea val2.
Operatorul [] este pentru acces la elementul unui vector. De exemplu, a[1] reprezint al
doilea element al irului a, deoarece n C indicii vectorilor ncep cu 0. Este interesant faptul c n
C dac scriem 1[a] nseamn acelai lucru !
Operatorul () este folosit pentru a realiza o conversie de tip (exemplu: (float)n
convertete valoarea din variabila n la tipul float, dac acest lucru este posibil).
Operatorii . (punct) i > sunt pentru acces la membrul unei structuri, uniuni sau clase
(al doilea pentru cazul n care se lucreaz cu pointeri).
Operatorul sizeof d dimensiunea n octei pe care o ocup n memorie valoarea
rezultat n urma evalurii unei expresii. De exemplu, expresia sizeof 1+2.5 are valoarea 6,
deoarece rezultatul expresiei 1+2.5 este o valoare de tip float, care se reprezint n memorie pe 6
octei. n C exist i funcia sizeof(tip) care returneaz numrul de octei necesari pentru stocarea
n memorie a unei valori de tipul tip. De exemplu, sizeof(short) returneaz valoarea 2.
float x;
char s[100];
printf("%d == %d\n",sizeof x,sizeof(float));
printf("%d != %d\n",sizeof s,sizeof(char*));

n exemplul de mai sus sizeof x i sizeof(float) au aceeai valoare, adic 6, deoarece


amndou reprezint numrul de octei pe care este reprezentat n memorie un numr real de tip
float. n schimb, cu toate c char* este tipul variabilei s, sizeof s returneaz numrul de octei
rezervai pentru irul s, adic 100, iar sizeof(char*) returneaz valoarea 4, adic numrul de
octei pe care se reprezint n memorie o adres (un pointer) ctre tipul char.
Operatorul # (diez) este folosit pentru directive preprocesor (a se vedea discuia
referitoare la macrocomenzi).
Operatorul ## realizeaz alipirea a doi tokeni (a fost menionat tot la discuia legat de
macrocomenzi).
Operatorul , (virgul) se aplic ntre dou expresii care se evalueaz dup regula: se
evalueaz nti prima expresie i apoi a doua (cea din dreapta), rezultatul returnat de operator
fiind valoarea ultimei expresii. De exemplu, expresia x = 2, x 4 are valoarea 2. De obicei, o
expresie n care apare operatorul virgul se pune ntre paranteze pentru eliminarea eventualelor
ambiguiti. Dac folosim de mai multe ori operatorul virgul: expr1, expr2, , exprn, atunci
14

execuia se face de la stnga spre dreapta. De exemplu, expresia x=1, x+4, x*2 are valoarea 2, iar
expresia x=1, x+=4, x*2 are valoarea 10.

Rezumat

Tipurile ntregi de date ale limbajului C sunt: (signed) char, unsigned char,
enum, short (signed) (int), short unsigned (int), (signed) int, unsigned int, (signed) long i
unsigned long. De departe cel mai cunoscut i utilizat tip de date din C este int, care se
reprezint pe doi sau patru octei, n funcie de compilator i de sistemul de operare. Operatorii
aritmetici binari pentru valori ntregi sunt: + (adunare), - (scdere), * (nmulire), / (ctul
mpririi) i % (restul mpririi).
Tipurile ntregi de date pot fi folosite i pentru a reine caractere. Practic, valoarea
numeric ntreag n C se identific cu cara cterul avnd codul ASCII acea valoare numeric.
Tipurile reale de date din C sunt: float, double i long double. Operatorii aritmetici
binari pentru valori reale sunt: + (adunare), - (scdere), * (nmulire) i / (mprire).
Tipurile numerice de date (ntregi i reale) n C sunt i tipuri booleane. Orice valoare
numeric diferit de zero corespunde valorii booleane de adevrat, iar orice valoare numeric
nul (zero) corespunde valorii booleane de fals.

Teme
1. Folosind operatorul sizeof calculai media artmetic a numrului de octei pe care se
reprezint cele nou tipuri ntregi de date.
2. Aceeai problem pentru cele trei tipuri reale de date.

Unitatea de nvare M1.U3. Funcii de scriere i citire n C


Cuprins
Obiective ................................ ................................ ................................ ................................ ...........
Introducere ................................ ................................ ................................ ................................ ........
U3.1. Funcia printf ................................ ................................ ................................ ..........................
U3.2. Funcia scanf ................................ ................................ ................................ ...........................
Obiectivele unitii de nvare
Ne propunem s vedem cum putem n C afia mesaje pe ecran i cum
putem prelua date de la tastatur pentru variabile.

15

Durata medie de parcurgere a unitii de nvare este de 2 ore.

Introducere
Definiiile funciilor pentru scrierea i citirea datelor n limbajului C le gsim n fiierul
antet stdio.h.

U3.1. Funcia printf


Funcia printf este folosit pentru afiarea formatat a unui mesaj pe ecranul monitorului.
Ea are urmtoare structur:
printf(constanta_sir_de_caractere, lista_expresii);
Funcia printf afieaz pe ecranul monitorului constanta_sir_de_caractere n care toi
descriptorii de format se n locuiesc cu valorile expresiilor, nlocuirea fcndu-se de la stnga
spre dreapta.
Dm un exemplu:
# include <stdio.h>
void main()
{
int n=10;
float x=5.71;
printf("Un nr. intreg: %d si un nr. real: %f\n",n,x);
}

n C, n momentul declarrii variabilelor, ele pot fi i iniializate (aa cum am procedat n


exemplul de mai sus pentru n i x).
%d i %f sunt specificatori (descriptori) de format pentru tipurile de date int i respectiv
float. Descriptorii specific faptul c n locul n care se afl n irul de caractere ce se afieaz pe
ecran vor aprea valori de tipul indicat, valori ce vor fi luate din lista de expresii aflat dup irul
de caractere. n exemplul nostru lista de expresii este alctuit din valorile n i x.
nlocuirea descriptorilor n constanta de tip ir de caractere (primul parametru al funciei
printf) se face de la stnga spre dreapta. n exemplul de mai sus %d va fi nlocuit cu valoarea
reinut n variabila n, adic 10, iar %f se nlocuiete cu valoarea lui x, adic 5.71.
Dac tipurile expresiilor ce se nlocuiesc nu corespund cu descriptorii de format, sau dac
numrul descriptorilor nu este egal cu cel al expresiilor ce se nlocuiesc, nu se semnaleaz
eroare, nici mcar atenionare la compilare, dar afiarea va fi eronat!
Dm n continuare lista cu descriptorii de format sau descriptorii de tip, cum se mai
numesc:
%c
%s

caracter (char)
ir de caractere ncheiat cu caracterul \0 (string)
16

%d
%u
%ld
%lu
%x

ntreg cu semn (int)


ntreg fr semn (unsigned int)
ntreg lung (pe 4 octei) cu semn (long)
ntreg lung (pe 4 octei) fr semn ( unsigned long)
ntreg n baza 16 fr semn (int) (cifrele n hexazecimal pentru 10, 11, 12, 13, 14, 15
sunt litere mici, adic a, b, c, d, e i f)
%X la fel ca %x, numai ca cifrele n hexazecimal pentru sunt litere mari
%o
ntreg n baza 8 fr semn (int)
%f
real pe 6 octei (float), notaie zecimal (fr exponent)
%e
real pe 6 octei (float), notaie exponenial, tiinific (litera e de la exponent este mic)
%E
la fel ca %e, numai c pentru litera de la exponent este mare
%g
real pe 6 octei (float), notaie zecimal sau exponenial, care este mai scurt, iar dac
se afieaz exponenial, atunci litera de la exponent este e
%G real pe 6 octei (float), notaie zecimal sau exponenial, care este mai scurt, iar dac
se afieaz exponenial, atunci litera de la exponent este E
%lf
real pe 8 octei (double), notaie zecimal
%le real pe 8 octei (double), notaie exponenial (litera exponent e este mic)
%lE la fel ca la %le, numai litera exponent E este mare
%lg real pe 8 octei (double), notaie zecimal sau exponenial, care e mai scurt, dac e
cazul se folosete liter mic pentru exponent
%lG real pe 8 octei (double), notaie zecimal sau exponenial, care e mai scurt, dac e
cazul se folosete liter mare pentru exponent
%Lf real pe 10 octei (long double), notaie zecimal
%Le real pe 10 octei (long double), notaie exponenial (litera de la exponent este mic,
adic e)
%LE real pe 10 octei (long double), notaie exponenial (litera de la exponent este mare,
adic E)
%Lg real pe 10 octei (long double), notaie zecimal sau exponenial, care este mai scurt,
liter mic pentru exponent
%LG real pe 10 octei (long double), notaie zecimal sau exponenial, care este mai scurt,
liter mare pentru exponent
%p
adresa n hexazecimal (pentru pointeri).
La afiarea folosind funcia printf se pot face formatri suplimentare, pornind de la un
descriptor elementar. Formatrile se refer la numrul de caractere pe care se face afiarea unei
valori, tipul alinierii, caracterele ce se completeaz n locurile libere (spaii, zerouri) etc. Dm n
acest sens cteva exemple:
%50s realizeaz afiarea unui string pe 50 caractere cu aliniere la dreapta, iar %-50s face
acelai lucru, dar cu aliniere la stnga. De obicei string -urile se aliniaz la stnga.
%4d realizeaz afiarea unui numr ntreg pe 4 caractere cu aliniere la dreapta, iar %-4d
face acelai lucru, dar cu liniere la stnga. De obice i valorile numerice se aliniaz la dreapta.
%10.2f realizeaz afiarea unui numr real pe 10 caractere cu 2 cifre exacte dup virgul,
cu aliniere la dreapta, iar %-10.2f face acelai lucru, dar cu aliniere la stnga.
%010.2f realizeaz afiarea unui numr real pe 10 caractere cu 2 cifre exacte dup
virgul, cu aliniere la dreapta, iar spaiile goale (din faa numrului) se completeaz cu zerouri.
De exemplu, numrul 1.4 se va afia sub forma 0000001.40. Dac nu se pune 0 n faa lui 10.2f,
atunci n loc de zerouri se completeaz implicit spaii.
n programul de mai sus (afiarea unui ntreg i a unui numr real), dup afiarea pe ecran
a mesajului, se sare la nceputul liniei urmtoare, deoarece irul s-a ncheiat cu \n. Combinaia de
caractere \n este una dintre aa numitele secvene escape.
17

Lista secvenelor escape recunoscute de limbajul C este:


\n salt la linie nou (nu neaprat la nceputul lui)
\r salt la nceput de rnd
\t deplasare la dreapta (tab)
\b deplasare la stnga cu un caracter (backspace)
\f trecere pe linia urmtoare (formfeed)
\ apostrof
\ ghilimele
\\ backslash
\xcc afiarea unui caracter avnd codul ASCII n hexazecimal dat de cele dou cifre de
dup \x (fiecare c reprezint o cifr n baza 16). De exemplu, \x4A este caracterul cu codul ASCII
4A(16) = 74 (10), adic litera J.
Este bine de reinut faptul c ntr-un ir constant de caractere, semnul \ (backslash)
trebuie dublat. Asta se ntmpl mai ales cnd este vorba de ci de fiiere. De asemenea, semnele
(ghilimele) i (apostrof) trebuiesc precedate de semnul \ (backslash).
n C pentru a trimite un mesaj n fluxul standard de erori stderror folosim funcia perror,
n loc de printf. Mesajul de eroare ajunge tot pe ecranul monitorului, dar pe alt cale. Datorit
faptului c funcia perror nu suport formatare aa cum face printf, n exemplele pe care o s le
dm n aceast carte vom folosi funcia printf pentru afiarea mesajelor de eroare.

U3.2. Funcia scanf


Funcia scanf este folosit pentru preluarea formatat de la tastatur a valorilor pentru
variabile. Funcia are urmtoarea structur:
scanf(const_sir_caractere, lista_adrese_var_citite);
constanta_sir_caractere este un string care conine numai descriptorii de tip ai
variabilelor ce se citesc. Descriptorii sunt cei elementari pe care i-am prezentat mai sus (vezi
funcia printf), adic: %c, %s, %d, %u, %ld, %lu, %x, %X, %o, %f, %e, %E, %g, %G, %lf, %le,
%lE, %lg, %lg, %Lf, %Le, %LE, %Lg, %LG, %p.
n exemplul urmtor apar cteva citiri de la tastatur:
# include <stdio.h>
void main()
{
int n;
float f;
char s[10]; /* sir de caractere */
scanf("%d%f%s",&n,&f,s);
printf("Am citit: %d, %f,%s",n,f,s);
}

Facem observaia c prin &var se nelege adresa la care se afl reinut n memorie
variabila var. n C valorile se returneaz prin adres prin intermediul parametrilor unei funcii.
Variabila s este deja un pointer ctre zona de memorie n care se memoreaz un ir de
caractere, aadar nu este necesar s punem semnul & (i) n faa lui s la citire. Dac se pune
18

totui semnul & n faa variabilei s la citire, nu se semnaleaz eroare nici mcar atenionare,
pleonasmele n C n general sunt ignorate de compilator. Vom reveni cu mai multe explicaii
cnd vom vorbi despre pointeri i tablouri (iruri).
Pentru funciile printf i scanf exist i variantele pentru scriere, respectiv citire n/dintrun string sau fiier text.
Numele funciilor pentru string-uri ncep cu litera s (sprintf, respectiv sscanf) i
funcioneaz absolut la fel ca cele obinuite numai c destinaia scrierii, respectiv sursa citirii
este un string. n consecin mai apare un parametru suplimentar (variabila ir de caractere) n
faa celor pe care i au funciile printf i scanf.
Numele funciilor de scriere i citire pentru fiiere text ncep cu litera f (fprintf, respectiv
fscanf). Aceste funcii au un parametru suplimentar (variabila pointer ctre tipul FILE).
Asupra acestor funcii o s revenim atunci cnd o s discutm despre string-uri, respectiv
fiiere.
n Borland C pentru DOS exist variantele cprintf, respectiv cscanf ale funciilor printf,
respectiv scanf pentru scriere i citire formatat ntr-o fereastr text (creat cu funcia window).
Facem observaia c schimbarea culorii textului i a fundalului pe care se afieaz un text are
efect n cazul utilizrii funciei cprintf, dar nu are efect atunci cnd se folosete funcia printf. De
asemenea, pentru salt la nceputul unei linii trebuie s punem pe lng \n i secvena escape \r, ca
s se revin la nceputul rndului, ceea ce nu era necesar n cazul funciei printf, secvena escape
\n fiind suficient.
Trebuie precizat faptul c funcia printf nu ine cont de marginile ferestrei text definite cu
window. Ca parametri, funcia window primete cele 4 coordonate ecran text ale colurilor
stnga-sus i respectiv dreapta-jos ale ferestrei.

Rezumat
Afiarea formatat a mesajelor pe ecran se face cu ajutorul funciei printf, iar preluarea
formatat a datelor de la tastatur se face folosind funcia scanf. Pentru a utiliza aceste funcii
trebuie s includem fiierul antet stdio.h.

Teme
1. Afiai pe ecranul monitorului cele dou tabele cu tipurile numerice de date de la capitolul
anterior.
2. De la tastatur citii datele unor persoane (nume i prenume, vrst i salariu). Afiai tabelar
aceste date pe ecran dup modelul urmtor:
--------------------------------------------------------------|Nr. | NUMELE SI PRENUMELE
|Varsta|Salariu|
|crt.|
|
|
|
|----+-----------------------------------------+------+-------|
|
1|Ionescu_Monica
|
19| 520.17|
|
2|Aionesei_Adrian_Ionel
|
23| 884.25|
|
3|Popescu_Gigel
|
19| 443.10|
|
4|Popescu_Maria
|
28|1155.00|
|----------------------------------------------+------+-------|
| Medie
| 22.25| 750.63|
19

---------------------------------------------------------------

Unitatea de nvare M1.U4. Instruciuni de decizie, instruciuni


repetitive, tipul char
Cuprins
Obiective ................................ ................................ ................................ ................................ ..........
Introducere ................................ ................................ ................................ ................................ .......
U4.1. Instruciunea if ................................ ................................ ................................ ........................
U4.2. Instruciunea switch ................................ ................................ ................................ ................
U4.3. Instruciunea for ................................ ................................ ................................ .....................
U4.4. Instruciunea while ................................ ................................ ................................ .................
U4.5. Instruciunea do while ................................ ................................ ................................ .......
U4.6. Tipul char ................................ ................................ ................................ ...............................
Obiectivele unitii de nvare
Ne propunem s vedem cum se redactez o instruciunile de decizie i cele
repetitive n C. De asemenea, ne propunem s vedem ce funcii avem n C pentru
prelucrarea caracterelor.

Durata medie de parcurgere a unitii de nvare este de 2 ore.

Introducere
n C exist dou instruciuni de decizie: if else i instruciunea de decizie multipl (cu
oricte ramuri) switch case. De asemenea, exist trei instruciuni repetitive: for, while si
dowhile.

U4.1. Instruciunea if
n C o instruciune de tipul dac atunci altfel are urmtoarea structur:
if (conditie)
{
/* grupul de instructiuni 1 */
20

}
else
{
/* grupul de instructiuni 2 */
}
Semnificaia instruciunii este: dac este adevrat condiia, atunci se execut grupul de
instruciuni 1, altfel se execut grupul de instruciuni 2. Ramura else poate lipsi.
Un grup de instruciuni n C se delimiteaz cu ajutorul acoladelor {}. Dac un grup este
format dintr-o singur instruciune, atunci acoladele pot lipsi.
Dm un exemplu ilustrativ pentru instruciunea if :
float x=2.2, y=4;
int a=25, b=85;
if (x>y) max=x; else max=y;
if (a)
{
printf("Restul impartirii este: %d\n",b%a);
printf("Catul impartirii este: %d",b/a);
}
else perror("Impartire prin 0!");

U4.2. Instruciunea switch


switch este o instruciune decizional multipl (cu mai multe ramuri). Structura ei este
urmtoarea:
switch (expresie_intreaga)
{
case val1:
/* grupul de instructiuni
break;
case val2:
/* grupul de instructiuni
break;
/* .... */
case valn:
/* grupul de instructiuni
break;
default:
/* grupul de instructiuni
}

1 */

2 */

n */

n+1 */

Semnificaia instruciunii este: Se evalueaz expresia expresie_intreaga care trebuie sa


aib o valoare ntreag. Avem urmtoarele situaii:

Dac valoarea expresiei este egal cu val1, atunci se execut grupul de instruciuni 1.
Dac valoarea expresiei este egal cu val2, atunci se execut grupul de instruciuni 2.
.
Dac valoarea expresiei este egal cu valn, atunci se execut grupul de instruciuni n.
21

Dac valoarea obinut n urma evalurii expresiei nu este egal cu nici una dintre
valorile val1, , valn, atunci se execut grupul de instruciuni n+1.
S facem cteva observaii:
1) La instruciunea switch grupurile de instruciuni de pe ramuri nu trebuiesc
delimitate cu acolade. Nu este greit ns dac le delimitm totui cu acolade.
2) Dup fiecare grup de instruciuni punem n general instruciunea break. n lipsa
instruciunii break se execut i instruciunile de pe ramurile de mai jos pn la
sfritul instruciunii switch (inclusiv cele de pe ramura default) sau pn se
ntlnete primul break. Instruciunea break ntrerupe execuia instruciunii switch
i a celor repetitive (for, while i do ... while).
3) Ramura default poate lipsi.
4) Dac exist ramura default, nu este obligatoriu s fie ultima.
5) Valorile val1, val2, , valn trebuie s fie constante ntregi i distincte dou cte
dou.

Spre exemplificare considerm o secven de program pentru calcularea ntr-un punct a


valorii unei funcii f cu trei ramuri:

1, dac x 0

f : Z R, f ( x) 2, dac x 1
.
x 1, dac x 1 i x 2

int x;
printf("Dati un numar ntreg: ");
scanf("%d",&n);
printf("Valoarea functiei este f(%d)=",x);
switch (x)
{
case 0:
printf("-1"); break;
case 1:
printf("-2"); break;
default:
printf("%d",x+1); break;
}

Rezumat
n C avem dou instruciuni de decizie: instruciunea if, care are una sau dou ramuri
(ramura else poate lipsi) i instruciunea switch (cu oricte ramuri). Expresia dup care se face
selecia ramurii case trebuie s aib o valoare ntreag. De asemenea, de reinut este i faptul c
n principiu, fiecare ramur a instruciunii switch se termin cu un apel break.

22

U4.3. Instruciunea for


n C, instruciunea repetitiv for este destul complex. Ea are urmtoarea structur:
for (expresie_1; expresie_2; expresie_3)
{
/* grup de instructiuni */
}
Semnificaia instruciunii este:
1) Se evalueaz expresie 1. Aceast expresie conine n general iniializri de variabile.
2) Ct timp valoarea expresiei 2 este adevrat (nenul), se execut grupul de
instruciuni. Aceast expresie reprezint condiia de oprire a ciclrii.
3) Dup fiecare iteraie se evalueaz expresie 3. Aceast expresie conine n general
actualizri ale unor variabile (incrementri, decrementri etc.).
Prezentm cteva caracteristici ale instruciunii for:
1) Oricare dintre cele 3 expresii poate lipsi. Lipsa expresiei 2 este echivalent cu valoarea 1
(de adevr). Prsirea ciclului for n aceast situaie se poate face n general cu break.
2) n prima expresie pot aprea mai multe iniializri, care se dau cu ajutorul operatorului
virgul (vezi subcapitolul dedicat operatorilor). De asemenea, ultima expresie poate
conine mai multe actualizri desprite prin virgul.
Ca aplicaie pentru instruciunea for, calculm suma primelor n numere ntregi pozitive
(valoarea lui n este citit de la tastatur) i cel mai mare divizor comun pentru dou numere
ntregi (preluate tot de la tastatur) folosind algoritmul lui Euclid:
long s,i,n,a,b,x,y;
printf("n="); scanf("%ld",&n);
for (s=0,i=0; i<n; i++) s+=i; /* Calculare: 1+2+...+n */
printf("Suma primelor %ld numere intregi pozitive este %ld\n",n,s);
printf("Dati doua numere intregi: ");
scanf("%ld%ld",&a,&b);
for (x=a,y=b; y; r=x%y,x=y,y=r); /* Calculare Cmmdc(a,b) */
printf("Cmmdc(%ld,%ld)=%ld\n"),a,b,x);
printf("Cmmmc(%ld,%ld)=%ld\n"),a,b,a/x*b);

U4.4. Instruciunea while


Instruciunea while are urmtoarea structur:
while (conditie)
{
/* grup de instructiuni */
}

23

Semnificaia instruciunii este: ct timp condiia este adevrat, se execut grupul de


instruciuni. Prsirea ciclrii se poate face forat cu break.
Calcularea celui mai mare divizor comun a dou numere ntregi folosind instruciunea
while poate fi scris astfel:
long a,b,x,y,r;
printf("Dati doua numere ntregi: ");
scanf("%ld%ld",&a,&b);
x=a; y=b;
while (y) { r=x%y; x=y; y=r; }
printf("Cmmdc(%ld,%ld)=%ld\n"),a,b,x);
printf("Cmmmc(%ld,%ld)=%ld\n"),a,b,a/x*b);

U4.5. Instruciunea do while


Are urmtoarea structur:
do
{
/* grup de instructiuni */
}
while (conditie);
Semnificaia instruciunii este: se execut grupul de instruciuni ct timp condiia este
adevrat. Prsirea ciclrii se poate face forat de asemenea cu break.
Instruciunea dowhile din C este echivalent instruciunii repetitive repetpn cnd
din pseudo-cod, deosebirea esenial const n faptul c la instruciunea din C ciclarea se oprete
cnd condiia devine fals, pe cnd la instruciunea din pseudo-cod ciclarea se ncheie cnd
condiia devine adevrat. Cu alte cuvinte condiia din instruciunea dowhile este negaia
condiiei de la instruciunea repetpn cnd.
Lum ca exemplu sortarea cresctoare unui ir prin metoda bulelor (BubbleSort). Despre
tablouri de elemente (vectori, matrici) o s vorbim mai trziu. Ceea ce ne intereseaz acum,
pentru a nelege exemplul de mai jos, este faptul c indicii vectorilor se dau ntre paranteze
ptrate [], iar n momentul declarrii unui vector putem enumera elementele sale ntre acolade.
int ok, n=5, a[5]={4, 2, 5, 7, 0};
do
{
ok=1;
for (i=0;i<n-1;i++)
if (a[i]>a[i+1])
{
aux=a[i];
a[i]=a[i+1];
a[i+1]=aux;
ok=0;
}
}
while (!ok);

24

Rezumat
n C exist trei intruciuni repetitive: for, while i do.while.
Implementarea instruciunii for este destul de complex, n sensul c putem face mai
multe iniializri, putem avea o condiie complex de terminare a ciclrii i putem avea mai
multe actualizri. Aici se utilizeaz practic operatorul virgul.
Instruciunea do.while este cu test final. Cu ajutorul ei putem implementa o instruciune
pseudocod repeat.until.

Teme
1. Se citete de la tastatur un numr ntreg. S se verifice dac este prim.
2. Afiai primele n numere naturale prime, unde n este citit de la tastatur.
3. Se citete de la tastatur un numr natural. S se verifice dac este palindrom. Un numr
natural este palindrom dac cifrele lui citite de la stnga spre dreapta sunt aceleai cu situaia
n care le citim de la dreapta spre stnga.
4. De la tastatur se citesc dou numere naturale n i k. S se calculeze i s se afieze pe ecran
valoarea expresiei:
n

S (n, k ) i k .
i 1

U4.6. Tipul char


Tipul char a fost prezentat la capitolul dedicat tipurilor ntregi de date. Informaia
reinut ntr-o valoare de tip char poate fi interpretat n C ca un caracter al tabelei ASCII. De
acest lucru o s ne ocupm n acest capitol.
Definiiile principalelor funcii de lucru cu caractere n C le gsim n fiierul antet
ctype.h. Dintre aceste funcii o s le prezentm numai pe cele mai importante i mai utile. Facem
observaia c toate funciile de mai jos returneaz o valoare de tip int i primesc ca argument un
caracter:
1) isalnum(c) returneaz valoare de adevrat (nenul) dac c este un caracter alfa-numeric
(litera mic, liter mare sau cifr), altfel se returneaz 0.
2) isalpha(c) returneaz valoare de adevrat (nenul) dac c este o liter, altfel se
returneaz 0.
3) isdigit(c) returneaz valoare de adevrat (nenul) dac c este o cifr, altfel returneaz
0.
4) isxdigit(c) returneaz valoare de adevrat (nenul) dac c este cifr hexazecimal (0, 1,
2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, a, b, c, d, e, f), altfel se returneaz 0.
5) islower(c) returneaz valoare de adevrat (nenul) dac c este liter mic, altfel
returneaz 0.
6) isupper(c) returneaz valoare de adevrat (nenul) dac c este liter mare, altfel
returneaz 0.
25

7) tolower(c) returneaz transformarea caracterului c n litera mic dac este liter mare,
altfel se returneaz valoarea lui c nemodificat.
8) toupper(c) returneaz transformarea caracterului c n litera mare dac este liter mic,
altfel se returneaz valoarea lui c nemodificat.
i n fiierul antet conio.h ntlnim cteva funcii legate de tipul char:
1) getch() citete un caracter de la tastatur, fr ecou pe ecranul monitorului. Funcia
returneaz caracterul citit fr a-l afia pe ecran.
2) getche() citete un caracter de la tastatur, se returneaz caracterul citit dup ce este
afiat pe ecran (cu ecou).
3) putch(c) afieaz pe ecran caracterul c primit ca argument de funcie. Se ine cont de
eventuala fereastr text definit cu funcia window.
4) kbhit() verific dac n buffer-ul de intrare de la tastatur exist caractere. Cu alte
cuvinte se verific dac s-a apsat un buton de la tastatur. Dac buffer-ul este nevid, atunci se
returneaz o valoare nenul.
Programul urmtor afieaz codul ASCII pentru o liter mic preluat de la tastatur:
char c;
c=getch();
if (97<=c && c<=z)
printf("Litera mica %c cu codul ASCII %d!\n",c,c);
while (kbhit()) getch(); /* golire buffer */
printf("Apasati Escape pentru a parasi programul");
do c=getch();
while (c!=27 && c!=13); /* se paraseste daca se apasa
Esc sau Enter */
if (c==27) exit(0); /* Functia exit intrerupe executia
programului */

Rezumat
Tipul caracter coexist n C cu tipul ntreg de date. Funciile special scrise pentru tipul
caracter au antetele definite n fiierul ctype.h.

Tem de control
S se afieze pe ecran cele 256 caractere ale tabelei ASCII.

Unitatea de nvare M1.U5. Pointeri, tablouri de elemente


Cuprins
Obiective ................................ ................................ ................................ ................................ ..........
26

Introducere ................................ ................................ ................................ ................................ ........


U1.1. Alocarea static a memoriei ................................ ................................ ................................ ...
U1.2. Alocarea dinamic a memoriei ................................ ................................ ...............................
Obiectivele unitii de nvare
Ne propunem s nelegem n acest capitol cea mai important noiune a
limbajului C. Este vorba de pointer.

Durata medie de parcurgere a unitii de nvare este de 2 ore.

Introducere
Pentru a stpni modul de funcionare al limbajului C, trebuie neleas foarte bine
noiunea de pointer.
O variabil de tip pointer reine o adres de memorie la care se afl o informaie (un
caracter, un ntreg, un ir etc.).
O variabil de tip pointer se declar sub forma: tip *numepointer. De exemplu, o
variabil de tip pointer ctre tipul int se declar astfel: int *pint. Variabila pint va reine adresa de
memorie la care se afl stocat o dat de tip int.
Revenind la declaraia general tip *numepointer, numepointer este o variabil de tipul
tip* i memoreaz o adres de memorie, la care este reinut o informaie de tipul tip. O adres
se memoreaz pe 4 octei i n consecin sizeof(tip*) este 4.
Putem aplica operatorul * unei valori de tip pointer pentru a afla valoarea care se afl la
adresa reinut de pointer. Astfel, *numepointer reprezint valoarea de tipul tip aflat n memorie
la adresa numepointer.
Adresa la care se afl zona de memorie rezervat unei variabile se poate afla folosind
operatorul &. Cu alte cuvinte, operatorul & este inversul operatorului *. n consecin, pentru o
variabil var de tipul tip are sens o atribuire de forma numepointer=&var. De asemenea, se poate
face atribuirea var=*numepointer. Operatorul * anuleaz pe & i & anuleaz pe *, adic *&var
este totuna cu var, iar &*numepointer este acelai lucru cu numepointer.
Pentru valori de tip pointer funcioneaz operatorii: =, +, -, +=, -=, ++, -- i !. De exemplu
putem scrie numepointer+=10, sau numepointer=&var-1.
Dup aplicarea operatorului += pointerului numepointer sub forma numepointer+=10,
pointerul va reine adresa aflat cu 10 csue mai la dreapta n memorie fa de adresa iniial. O
csu de memorie are sizeof(tip) octei, unde tip este tipul de dat ctre care pointeaz
numepointer. Cu alte cuvinte, n urma atribuirii numepointer+=10, variabila numepointer va
reine adresa de memorie aflat cu 10*sizeof(tip) octei la dreapta adresei de memorie iniiale din
numepointer.
De reinut este i faptul c pentru valori de tip pointer nu funcioneaz operatorii: *, /, %,
adic pointerii nu se pot nmuli, mpri cu alte valori.

27

U5.1. Alocarea static a memoriei


n C exist posibilitatea alocrii memoriei att mod static, ct i dinamic. Prin alocare
static nelegem faptul c memoria este alocat automat nc de la pornirea execuiei
instruciunilor unei funcii, iar eliberarea memoriei se face tot automat la prsirea funciei. Cu
alte cuvinte, cnd se intr ntr-o funcie (inclusiv funcia main) se face alocarea static a
memoriei, iar eliberarea se face la prsirea acelei funcii. Lungimea zonei de memorie alocate
static este constant, adic de fiecare dat cnd se intr cu execuia ntr-o funcie, se aloc
automat acelai numr de octei.
Spre deosebire de alocarea static, n cazul alocrii dinamice stabilim noi momentul
alocrii memoriei i lungimea zonei de memorie alocate. De asemenea, putem decide momentul
n care s se fac eliberarea memoriei.
Pentru un vector putem aloca memorie n mod static sub forma tip
numevector[lungimev], unde lungimev este o constant numeric care reprezint numrul de
elemente (csue de memorie) al vectorului.
Dm cteva exemple de alocri statice de memorie pentru vectori:
# define N 100
....
float a[10],b[N];
int i,n,vect[N+1];

Elementele unui vector n C au indici ntre 0 i lungimev-1. De exemplu, vectorul a


definit mai sus are elementele: a[0], a[1], , a[9].
Dac se trece de capetele 0 i lungimev-1 ale vectorului a, n C nu se semnaleaz n
general eroare. Astfel se poate accesa elementul a[-1] (zona de memorie aflat cu o csu n
stnga lui a[0]) sau se poate accesa a[lungime]. Acest lucru poate conduce la blocarea
programului sau la alterarea altor date reinute n memorie la adresele respective, pe care le-am
accesat greit!
n declaraia numevector[lungimev], numevector este un pointer care reine adresa de
nceput a zonei de memorie alocate static pentru vector (elementele vectorului se rein n csue
succesive de memorie). Cu alte cuvinte, pointerul a reine adresa la care se afl memorat primul
element a[0] al vectorului a, iar a+1 este adresa la care se afl elementul a[1], a+2 este adresa
lui a[2] etc. De asemenea, *a este tot una cu a[0], *(a+1) este a[1] etc. n general, a[k]
reprezint o scriere simplificat pentru *(a+k).

U5.2. Alocarea dinamic a memoriei


Alocarea dinamic a memoriei n C se poate face cu ajutorul funciilor malloc, calloc i
realloc, ale cror definiii le gsim n fiierul antet malloc.h. Cele 3 funcii pentru alocare
dinamic returneaz toate tipul pointer ctre void, adic void*. De aceea, n momentul folosirii
acestor funcii trebuie fcut o conversie de tip. Oricare dintre cele trei funcii de alocare
returneaz valoarea NULL (constanta NULL are valoarea 0) n cazul n care alocarea de memorie
nu s-a putut face (nu este suficient memorie liber sau lungimea zonei de memoriei ce se
dorete a fi alocat nu este valid, adic este negativ).
Funcia malloc primete un parametru de tip ntreg, care reprezint numrul de octei de
memorie ce se dorete a fi alocai. De exemplu, pentru un vector de numere ntregi scurte trebuie
s definim un pointer ctre tipul int, pointer care va reine adresa ctre zona de memorie alocat:

28

int i,*a,n,m;
printf("Dati lungimea vectorului: ");
scanf("%d",&n);
a=(int*)malloc(n*sizeof(int)); /* alocare memorie pentru n
elemente de tip int */
if (a==NULL)
{
perror("Memorie insuficienta!"); /* mesaj eroare */
exit(1); /* parasire program cu cod de eroare */
}
for (i=0;i<n;i++)
{
printf("a[%d]=",i);
scanf("%d",&a[i]);
}

Funcia malloc returneaz tipul void*, care trebuie convertit n exemplul de mai sus la
tipul int*, adic la tipul variabilei a.
Funcia calloc are doi parametri. Primul parametru reprezint numrul de blocuri ce se
aloc, iar al doilea este lungimea unui bloc. Alocarea memoriei pentru vectorul a din exemplul
de mai sus poate fi rescris folosind funcia calloc astfel:
a=(int*)calloc(n,sizeof(int));
Spre deosebire de funcia malloc, funcia calloc iniializeaz zona de memorie alocat cu
0, adic toi octeii sunt setai la valoarea 0.
Funcia realloc este folosit pentru ajustarea lungimii unei zone de memorie deja alocate,
copiind coninutul memoriei anterior alocate dac este necesar la o nou adres. Funcia are doi
parametri. Primul reprezint adresa zonei de memorie pentru care se dorete s se fac
realocarea, iar al doilea este noua lungime (n octei) a memoriei ce se vrea a fi realocat.
Dac lungimea memoriei realocate este mai mic sau egal dect lungimea zonei de
memorie iniiale, atunci adresa rmne nemodificat (i este returnat), eventuala diferen de
memorie se elibereaz.
Dac memoria realocat este mai mare dect cea iniial, atunci se aloc o nou zon de
memorie n care se copiaz informaia din zona iniial, dup care prima zona de memorie se
elibereaz, n final returnndu-se noua adres. n exemplul urmtor realocm memorie pentru un
vector a cu elemente ntregi:
printf("Dati noua lungime a vectorului: ");
scanf("%d",&m);
a=(int*)realloc(a,m*sizeof(int));
if (a==NULL)
{
printf("Memorie insuficienta!");
exit(1);
}

Eliberarea memoriei alocate cu malloc, calloc i realloc se face cu ajutorul funciei free,
care primete ca parametru pointerul spre zona de memorie alocat. Pentru exemplele de mai sus
eliberarea memoriei pentru vectorul a se face cu free(a).
29

Alocarea memoriei pentru o matrice se poate face, de asemenea, att static ct i dinamic.
Varianta static este: tip a[nl][nc];, unde nl reprezint numrul de linii, iar nc este numrul de
coloane al matricii.
n continuare prezentm dou moduri n care se poate face alocare dinamic de memorie
pentru o matrice a de valori reale (float) de dimensiuni m i n. n C, o matrice alocat dinamic
este un vector (de lungime m) de vectori (fiecare de lungime n). Pentru aceasta trebuie s definim
variabila a care va fi de tipul float**, adic pointer ctre pointer ctre tipul float. Pointerul a va fi
adresa ctre zona de memorie n care se reine vectorul cu adresele de nceput ale fiecrei linii
ale matricii. nti va trebui s alocm memorie pentru vectorul de adrese de lungime m. Apoi
vom aloca memorie necesar stocrii celor m x n elemente ale matricii. n final vom face
legturile ntre vectorul de adrese i zona de memorie unde vor fi stocate elementele matricii. n
figura 1 este prezentat schema de alocare dinamic de memorie descris:
a[0]

a[1]

a[m-1]

a
a[0][0]

a[0]

a[0][n-1]

a[1][0]

a[1]

. a[m-1][0]

. a[m-1][n-1]

a[m-1]

Fig. 1: Prima schem de alocare dinamic a memoriei pentru o matrice

Codul C de alocare dinamic a memoriei pentru o matrice este:

int i,j,m,n;
float **a;
printf("Dati dimensiunile matricii: ");
scanf("%d%d",&m,&n);
a=(float**)calloc(m,sizeof(float*));
if (a==NULL)
{
printf("Memorie insuficienta!");
exit(1);
}
a[0]=(float*)malloc(m*n,sizeof(float));
if (a[0]==NULL)
{
printf("Memorie insuficienta!");
exit(1);
}
for (i=1;i<m;i++) a[i]=a[i-1]+n; /* adresele de inceput ale
liniilor */
....
free(a[0]); /* eliberarea memoriei ocupata de matrice */
free(a);

nti se aloc memorie pentru vectorul de adrese al liniilor (a este un vector de elemente
de tipul float*). Apoi se aloc memorie necesar stocrii tuturor elementelor matricii a (se aloc
m x n blocuri de lungime sizeof(float)), iar adresa ctre zona alocat se depune n a[0]. a[1] va fi
30

adresa ctre zona de memorie aflat cu n csue (fiecare de lungime sizeof(float)) dup a[0] etc.
Cu alte cuvinte la adresa a[0] se gsesc elementele primei linii, apoi n continuare elementele
celei de-a doua linii care ncep s fie memorate de la adresa a[1], apoi a treia linie la adresa a[2]
.a.m.d., iar la sfrit la adresa a[n-1] avem elementele ultimei linii.
Eliberarea zonei de memorie ocupate de matricea a se face n doi pai: nti se elibereaz
vectorul cu cele m x n elemente de tip float (aflat la adresa a[0]), iar apoi se elibereaz memoria
ocupat cu vectorul de adrese (vector aflat la adresa a).
Dezavantajul alocrii dinamice de mai sus const n faptul c se ncearc alocarea unei
zone continue de memorie de lungime total m x n x sizeof(float) i s-ar putea s nu dispunem de
o zon continu de memorie liber de o asemenea dimensiune. Acest dezavantaj n prezent nu
poate fi considerat major, pentru c astzi calculatoarele dispun de memorie RAM de capaciti
mari. Marele avantaj al alocrii dinamice de mai sus este dat de viteza mare de execuie datorat
faptului c se fac numai dou alocri i tot attea eliberri de memorie.
O alternativ la alocarea de mai sus este alocarea separat a memoriei pentru fiecare linie
a matricii:
int i,j,m,n;
float **a;
printf("Dati dimensiunile matricii: ");
scanf("%d%d",&m,&n);
a = (float**)calloc(m,sizeof(float*));
if (a==NULL)
{
printf("Memorie insuficienta!");
exit(1);
}
for (i=0;i<m;i++)
{
a[i] = (float*)calloc(n,sizeof(float));
if (a[i]==NULL)
{
printf("Memorie insuficienta!");
exit(1);
}
}
....
for (i=0;i<m;i++) free(a[i]); */ eliberarea memoriei */
free(a);

n exemplul de mai sus se fac m+1 alocri de memorie pentru m+1 vectori. Primul vector
alocat (de lungime m), ca i la prima variant de alocare a memoriei pentru o matrice, va reine
adresele ctre fiecare din cele m linii ale matricii. Apoi se ncearc m alocri de vectori de
lungime n, vectorii cu elementele fiecrei linii a matricii. Astfel, a[0], a[1], , a[m-1] sunt
adresele ctre fiecare linie obinute n urma alocrilor. Eliberarea memoriei alocate pentru
matricea a se face tot n m+1 pai: nti se elibereaz cele m zone de memorie n care sunt
reinute elementele matricii i n final se elibereaz zona de memorie ocupat de vectorul cu
adresele de nceput ale liniilor.

31

S facem observaia c n urma alocrii statice sau a oricrei alocri dinamice de mai sus,
referirea la elementul matricii a aflat pe linia i i coloana j se face sub forma a[i][j].
a[0]

a[1]

a[m-1]

a
a[0][0]

a[0][1]

a[0][n-1]

a[1][0]

a[1][1]

a[1][n-1]

a[m-1][n-1]

a[0]

a[1]

.
a[m-1][0]

a[m-1][1]

a[m-1]
Fig. 2: A doua schem de alocare a memoriei pentru o matrice

n continuare dm o secven de cod n care citim elementele unei matrici alocate static
sau dinamic:
for (i=0;i<m;i++)
for (j=0;j<n;j++)
{
printf("a[%d,%d]=",i+1,j+1);
scanf("%f",&a[i][j]);
}

S facem n final cteva observaii:


1) n mod similar se poate aloca dinamic memorie pentru matrici de ordin superior (3, 4
etc.). Lsm ca exerciiu cititorului scrierea codului C de alocare dinamic i eliberare a
memoriei pentru o matrice tridimensional.
2) Procednd n mod asemntor cu alocarea dinamic a unei matrici putem aloca memorie
pentru vectori de vectori, n sensul c fiecare dintre vectorii de la adresele a[0], a[1], ,
a[m-1] pot avea lungimi diferite:
int i,j,m,*n;
float **a;
printf("Dati numarul de vectori: ");
scanf("%d",&m);
n=(int*)calloc(m,sizeof(int));
if (n==NULL)
{
printf("Memorie insuficienta!");
exit(1);
32

}
printf("Dati numarul de elemente al fiecarui vector:\n");
for (i=0;i<m;i++)
{
printf("n[%d]=",i+1);
scanf("%d",&n[i]);
}
a=(float**)calloc(m,sizeof(float*));
if (a==NULL)
{
printf("Memorie insuficienta!");
exit(1);
}
for (i=0;i<m;i++)
{
a[i]=(float*)calloc(n[i],sizeof(float));
if (a[i]==NULL)
{
printf("Memorie insuficienta!");
exit(1);
}
}
printf("Dati elementele vectorilor:\n");
for (i=0;i<m;i++)
for (j=0;j<n[i];j++)
{
printf("a[%d,%d]=",i+1,j+1);
scanf("%f",&a[i][j]);
}
....
for (i=0;i<m;i++) free(a[i]); /* eliberarea memoriei */
free(a);
free(n);

Rezumat
Un pointer reine o adres de memorie la care se afl memorat o anumit dat (un ntreg,
un numr real etc.). Pentru a obine valoarea de la adresa reinut n pointer se aplic operatorul *
pointerului. Pentru a obine adresa la care se afl memorie alocat pentru o variabil folosim
operatorul &.
Alocarea dinamic a memoriei n C se face cu ajutorul funciilor calloc, malloc i
realloc, ale cror antete se gsesc n fiierul malloc.h. Eliberarea memoriei alocate dinamic n C
se face cu ajutorul funciei free.
n C putem aloca memorie pentru un tablou (vector, matrice etc.) att n mod static ct i
dinamic (n timpul rulrii aplicaiei). Alocarea dinamic a memoriei pentru o matrice
bidimensional se face n dou etape: nti alocm memorie pentru a reine adresele de nceput
ale liniilor matricei i apoi alocm memorie pentru a reine elementele matricei. n consecin,
eliberarea memoriei se face tot n dou etape, dar n ordine invers: eliberm nti memoria

33

alocat anterior dinamic pentru a reine elementele matricei i apoi eliberm memoria ocupat de
vectorul de adrese de nceput a liniilor matricei.

Teme
1. De la tastatur se citete un numr natural nenul n. S se aloce dinamic memorie pentru o
matrice triunghiular de numere reale (prima linie are un element, a doua are dou elemente,
a treia trei elemente .a.m.d.). S se citeasc de la tastatur elementele matricei, s se
calculeze i s se afieze mediile aritmetice pe linii. n final se va elibera memoria alocat
dinamic pentru stocarea matricei.
2. De la tastatur se citesc trei numre naturale nenule m, n i p. S se aloce dinamic memorie
pentru o matrice tridimensional de dimensiuni m, n i p. S se citeasc de la tastatur
elementele matricei. S se gseasc cel mai mare i cel mai mic element al matricei. n final
s se elibereze memoria alocat dinamic pentru stocarea matricei.
3. Construii dinamic un vector n care s depunei primele n numere naturale prime, unde n
este citit de la tastatur.
4. De la tastatur se citesc dou numre naturale nenule m i n. S se aloce dinamic memorie
pentru o matrice de dimensiuni m i n. S se citeasc de la tastatur elementele matricei. S
se depun elementele matricei luate n spiral ntr-un vector alocat dinamic. n final s se
elibereze toate zonele de memorie alocate dinamic.
De exemplu, pentru matricea:

1 2 3 4

5 6 7 8
9 10 11 12

vectorul rezultat este (1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7).

Unitatea de nvare M1.U6. Funcii n C


Cuprins
Obiective ................................ ................................ ................................ ................................ ..........
Introducere ................................ ................................ ................................ ................................ .......
U1.1. Funcii n C ................................ ................................ ................................ .............................
Obiectivele unitii de nvare
Ne propunem s vedem cum se redacteaz o funcie n C i cum se transmit
parametrii funciei.

34

Durata medie de parcurgere a unitii de nvare este de 2 ore.

Introducere
n C, C++ i Java (limbajele ce au la baz standardul ANSI C) ca subprograme nu avem
dect funcii, o procedur putnd fi implement ca o funcie care returneaz tipul void (vid).
n C, o funcie care returneaz alt tip dect void poate fi apelat att ca o funcie (n
cadrul unei expresii), ct i ca o procedur (ignorndu-se valoarea returnat). De exemplu,
funcia printf returneaz valoarea int, care reprezint numrul de octei care s-au afiat pe ecran.
De cele mai multe ori (dup cum am vzut i n exemplele de mai sus) funcia printf este apelat
ca o procedur, ignorndu-se valoarea returnat.

U6.1. Funcii n C
Dup cum am mai spus i n primul capitol, funciile pot fi descrise att la nceputul
programului, deasupra funciei principale, ct i dup aceasta, situaie n care definiiile funciilor
trebuie totui s apar deasupra funciei principale.
Structura unei funcii n C este urmtoarea:
tip nume_functie(argumente)
{
/* corpul functiei (instructiuni) */
}
Definiia funciei ncepe cu tip, care este tipul valorii pe care o returneaz funcia. Dac
tip nu este void, atunci funcia va conine de regul cel puin o instruciune return expresie. Dac
execuia programului ajunge la o astfel de instruciune, atunci se evalueaz expresia a crei
valoare trebuie s fie de tipul tip sau unul compatibil i valoarea obinut se returneaz, execuia
programului continund cu instruciunile de dup locul n care a fost apelat funcia.
Dac o funcie ce returneaz o valoare de un tip diferit de void nu se termin cu o
instruciune return, atunci la compilare vom obine mesajul de atenionare Warning 5: Function
should return a value.
Spre exemplificare vom scrie o funcie care returneaz ca valoare a funciei media
aritmetic a dou numere reale primite ca parametri:
float medie(float x,float y)
{
return (x+y)/2;
}
void main()
{
float x,y;
printf("Dati doua numere reale: ");
scanf("%f%f",&x,&y);
printf("Media aritmetica: %f",medie(x,y)); /* apel
35

functie */
}

Rescriem programul de mai sus cu descrierea funciei medie dup funcia principal:
float medie(float,float);
void main()
{
float x,y;
printf("Dati doua numere reale: ");
scanf("%f%f",&x,&y);
printf("Media este: %f",medie(x,y));
}
float medie(float x,float y)
{
return (x+y)/2;
}

Dup cum se poate observa mai sus, cnd descriem funcia medie dup funcia principal,
la definiie nu este obligatoriu s dm numele argumentelor funciei, iar definiia se ncheie cu
caracterul punct i virgul.
n C parametrii ce se returneaz din funcie (variabilele de ieire) se transmit prin adres.
n acest sens dm un exemplu n care media aritmetic este returnat printre parametrii funciei:
void medie2(float x,float y,float *m)
{
*m=(x+y)/2;
}
void main()
{
float x,y,med;
printf("Dati doua numere reale: ");
scanf("%f%f",&x,&y);
medie2(x,y,&med); /* apel functie */
printf("Media este: %f",med);
}

La apelul unei funcii valorile parametrilor de intrare, cei transmii prin valoare (aa cum
este cazul parametrilor x i y), sunt copiate n zone de memorie noi i de aceea, dac le
modificm, la prsirea funciei, valorile modificate se pierd, zonele de memorie alocate pentru
aceti parametri n funcie fiind eliberate.
Parametrul m al funciei medie2 este transmis prin adres. Mai exact, n funcie se
transmite adresa la care este alocat memorie pentru variabila med din funcia principal. n
funcia medie2 se modific valoarea de la adresa m, adres care coincide cu cea a variabilei med
i de aceea valoarea calculat rmne n variabila med dup ce se prsete funcia.

36

Dac vrem ca o variabil transmis prin adres s nu poat fi modificat, punem n faa ei
cuvntul rezervat const. n general, dac se ncearc modificarea unei variabile declarate cu
const (a unei constante), atunci se semnaleaz eroare la compilare.
Variabilele de tip tablou sunt pointeri, de aceea valorile de la adresele indicate de ele se
transmit prin adres i eventualele modificri n interiorul funciei asupra elementelor tabloului
pstrndu-se i la prsirea funciei.
n continuare prezentm o funcie care calculeaz media aritmetic a elementelor unui ir
de numere reale:
float mediesir(int n,const float *a)
{
int i;
float s=0;
for (i=0;i<n;i++) s+=a[i];
return s/n;
}
void main()
{
int i,n;
float a[100];
printf("Dati numarul de elemente al sirului: ");
scanf("%d",&n);
puts("Dati elementele sirului:");
for (i=0;i<n;i++)
{
printf("a[%d]=",i);
scanf("%f",&a[i]);
}
printf("Media aritmetica: %f",mediesir(n,a));
}

Trebuie s fim ateni pentru a nelege corect modul de transmitere al parametrilor prin
adres. Dac modificm valoarea de la adresa reinut n pointerul - parametru al funciei, noua
valoare va fi vizibil i n variabila transmis prin adres, aa cum este cazul aplicaiei scrise
pentru funcia medie2. Ceea ce trebuie s nelegem este c un pointer se transmite prin valoare,
ca orice variabil. De aceea, dac modificm adresa (nu valoarea de la adresa reinut de pointer
!) memorat n pointer, noua adres nu se returneaz ! Cea mai des ntlnit situaie n care
adresa reinut n pointer se modific este atunci cnd alocm memorie ntr-o funcie i vrem s
returnm adresa spre zona nou alocat. n aceast situaie pointerul va trebui transmis prin adres
! Spre exemplificare, scriem o funcie care aloc memorie pentru un vector de elemente reale.
Adresa spre zona de memorie alocat se returneaz prin adres, ca parametru al funciei:
#include<stdio.h>
#include<alloc.h>
void AlocVector1(float *a,int n) /* gresit */
{
a=(float*)malloc(n*sizeof(float));
}
37

void AlocVector2(float **a,int n) /* corect */


{
*a=(float*)malloc(n*sizeof(float));
}
float* AlocVector3(int n) /* adresa noua returnata ca val. a fct. */
{
return (float*)malloc(n*sizeof(float));
}
int main()
{
int n;
float *a;
printf("n=");
scanf("%d",&n);
AlocVector1(a,n); /* nu se returneaza adresa noua */
AlocVector2(&a,n); /* pointerul a transmis prin adresa */
a=AlocVector3(n);
if (a==NULL)
{
perror("Memorie insuficienta!");
return 1; /* parasire program cu cod de eroare */
}
/* .... */
free(a);
return 0; /* executia programul s-a incheiat cu succes */
}

Cnd ntr-o funcie se modific i se dorete a fi returnat o singur adres, din


comoditate i pentru a fi mai uor de utilizat i de neles, noua adres se returneaz ca valoare a
funciei. Aa este cazul funciilor de alocare dinamic de memorie din fiierul antet alloc.h
(malloc, calloc, realloc). Fiecare dintre aceste funcii returneaz adresa zonei de memorie nou
alocate ca valoare a funciei. Rescriem i noi funcia de alocare dinamic de memorie pentru un
vector de elemente reale cu returnarea adresei spre noua zon de memorie ca valoare a funciei:
#include<stdio.h>
#include<alloc.h>
float* AlocVector3(int n) /* adresa noua returnata ca val. a fct. */
{
return (float*)malloc(n*sizeof(float));
}
int main()
{
int n;
float *a;
printf("n=");
38

scanf("%d",&n);
a=AlocVector3(n);
if (a==NULL)
{
perror("Memorie insuficienta!");
return 1;
}
/* .... */
free(a);
return 0;
}

Rezumat
Definiia unei funcii n C ncepe cu tipul returnat de ctre funcie, urmat de numele
funciei i de lista de argumente dat ntre paranteze. Dac o funcie are tipul returnat void,
atunci ea nu returneaz nici o valoare i se apeleaz practic ca o proce dur.
Parametrii de intrare n funcie se transmit prin valoare, iar cei de ieire se transmit prin
adres.

Teme
1. Scriei o funcie pentru cutare binar a unei valori ntr-un ir de numere reale sortat
cresctor.
2. Scriei o funcie pentru cutare secvenial a unei valori ntr-un ir de numere ntregi. Funcia
returneaz numrul de apariii a unei valori ntregi n ir.
3. Scriei o funcie care sorteaz cresctor un ir de numere reale folosind metoda BubbleSort.
4. Aceai problem folosind metoda QuickSort.
5. Aceai problem folosind metoda MergeSort.

Unitatea de nvare M1.U7. String -uri


Cuprins
Obiective ................................ ................................ ................................ ................................ ...........
Introducere ................................ ................................ ................................ ................................ ........
U7.1. Funcii de lucru cu string-uri n C ................................ ................................ ..........................
Obiectivele unitii de nvare
Ne propunem s studiem modul n care se memoreaz i cum se lucreaz
cu un string n limbajul C.
39

Durata medie de parcurgere a unitii de nvare este de 2 ore.

Introducere
n C, un ir de caractere care se termin cu caracterul NULL sau \0 sau pur i simplu 0
(de unde i denumirea de ir de caractere NULL terminat) este echivalentul noiunii de string din
alte limbaje (cum ar fi de exemplu limbajul Pascal). n consecin, n C o variabil string este de
fapt un pointer de tipul char. Fiind vorba de un ir, alocarea memoriei pentru un string se poate
face att static ct i dinamic.
n fiierul antet stdio.h avem definite funciile gets i puts pentru citirea unui string de la
tastatur, respectiv afiarea pe ecran a unui string. Ambele funcii primesc ca parametru o
variabil de tip pointer ctre tipul char.
Funcia gets, spre deosebire de scanf poate citi string-uri care conin spaii. n cazul
funciei scanf se consider ncheiat introducerea unei valori pentru o variabil cnd se ntlnete
caracterul spaiu sau unde s-a apsat Enter. De exemplu, dac se citete Popescu Ioan pentru un
string s de la tastatur cu gets(s), atunci la adresa s se depun caracterele Popescu Ioan\0. Dac
citirea se face ns cu scanf(%d,s), atunci la adresa s se depun caracterele Popescu\0 (citirea
lui s se ncheie la apariia spaiului).
Dac se afieaz un string s cu puts(s); atunci dup afiarea irului de la adresa s se face
salt la nceputul liniei urmtoare, ceea ce nu se ntmpl dac afiarea se face cu printf(%s,s).

U7.1. Funcii de lucru cu string-uri n C


Fiierul antet string.h conine definiiile funciilor C de lucru cu string-uri:
1) strcat(s1, s2) la sfritul string-ului s1 se adaug s2 i caracterul \0.
2) strchr(s,c) returneaz adresa de memorie ctre prima apariie a caracterului c n
string-ul s. Dac nu exist caracterul n string, se returneaz adresa nul ( NULL).
3) strcmp(s1,s2) returneaz o valoare ntreag care dac este 0, nseamn c irurile sunt
identice ca i coninut. Dac valoarea returnat este negativ, atunci nseamn c
string-ul s1 este naintea lui s2 din punct de vedere lexicografic (alfabetic). Dac ns
valoarea returnat este pozitiv, atunci nseamn c string-ul s1 este dup s2 din punct
de vedere lexicografic.
4) stricmp(s1,s2) face acelai lucru ca i strcmp, cu deosebirea c nu se face distincie
ntre litere mari i mici.
5) strcnmp(s1,s2,n) realizeaz o comparaie ntre primele cel mult n caractere ale stringurilor s1 i s2.
6) strcnmpi(s1,s2,n) realizeaz o comparaie ntre primele cel mult n caractere ale stringurilor s1 i s2 fr a se face distincie ntre litere mari i mici.
7) strcpy(s1,s2) copiaz caracterele de la adresa s2 (pn se ntlnete inclusiv caracterul
\0) la adresa s1. Cu alte cuvinte, se copiaz coninutul string-ului s2 peste string-ul
s1.
8) strlen(s) returneaz lungimea string-ului s (numrul de caractere pn la \0).
9) strlwr(s) transform literele mari din string-ul s n litere mici.
40

10) strupr(s) transform literele mici din string-ul s n litere mari.


11) strncat(s1,s2,n) adaug la sfritul string-ului s1 cel mult n caractere din string-ul s2,
dup care se adaug caracterul \0.
12) strncpy(s1,s2,n) copiaz cel mult n caractere de la nceputul string-ului s2 la adresa
s1, dup care se adaug la sfrit caracterul \0.
13) strnset(s,c,n) seteaz primele n caractere ale string-ului s la valoarea primit n
parametrul c.
14) strpbrk(s1,s2) returneaz adresa de memorie la care apare prima dat un caracter din
string-ul s2 n string-ul s1.
15) strchr(s,c) returneaz adresa la care apare ultima dat caracterul c n string-ul s.
16) strrev(s) inverseaz caracterele string-ului s (primul se schimb cu ultimul, al doilea
cu penultimul etc.).
17) strset(s,c) seteaz toate caracterele string-ului s (pn la \0) la valoarea primit n
parametrul c de tip char.
18) strstr(s1,s2) returneaz adresa de memorie la care apare prima dat string-ul s2 n s1.
Dac s2 nu apare n s1, atunci se returneaz adresa nul NULL.
19) strxfrm(s1,s2,n) nlocuiete primele cel mult n caractere ale string-ului s1 cu primele
cel mult n caractere din string-ul s2.
Ca aplicaii pentru string-uri propunem:
1. O funcie care returneaz printre parametri ei toate poziiile pe care apare un string s2
ntr-un string s1.
2. Funcie pentru nlocuirea primei apariii n s1 a string-ului s2 cu string-ul s3.
3. Funcie pentru nlocuirea tuturor apariiilor lui s2 n s1 cu string-ul s3.
Pentru aceste aplicaii vom folosi funcii din fiierul antet string.h, dar va trebui i s
lucrm direct cu adrese de memorie i asta din cauz c un string este de fapt un pointer ctre
tipul char.
#include<conio.h>
#include<stdio.h>
#include<string.h>
#include<alloc.h>
int strnfind(char *s1,char *s2,int *a) /* cautarea tuturor aparitiilor */
{
char *s,*poz;
int n=0;
s=s1;
/* s ia adresa la care se afla s1 */
poz=strstr(s,s2); /* cautare daca s2 apare in s */
while (poz!=NULL) /* daca s2 apare in s */
{
a[n]=poz-s1+1;
/* se memoreaz pozitia aparitiei */
s=poz+strlen(s2);
n++;
poz=strstr(s,s2); /* se cauta o noua aparitie */
}
return n; /* se returneaza numarul de aparitii */
}
int strreplace1(char*s1,char*s2,char*s3) /* inlocuirea primei aparitii */
{
41

char *poz,*s4;
long l;
poz=strstr(s1,s2); /* se cauta prima aparitie a lui s2 in s1 */
if (poz!=NULL)
/* daca s2 apare in s */
{
l=poz-s1; /* l este pozitia aparitiei (poate fi si 0) */
s4=(char*)malloc(strlen(s1)+1); /* aloc. mem. pt s4 */
strcpy(s4,s1);
/* se copiaza s1 in s4 */
strncpy(s1,s4,l); /* se copiaza in s1 l caract din s4 */
s1[l]='\0';
/* se transforma s1 in string */
strcat(s1,s3);
/* se adauga s3 la sfarsitul lui s1 */
strcat(s1,poz+strlen(s2)); /* adaugare la sf. lui s1 */
free(s4);
/* ramase in string-ul initial dupa s2 */
return l+1; /* se returneaza pozitia inlocuirii */
}
return 0;
}
int strreplace(char*s1,char*s2,char*s3) /* inloc. tuturor aparitiilor */
{
int n=0;
char *poz;
poz=strstr(s1,s2); /* se cauta s2 in s1 */
while (poz!=NULL) /* daca exista s2 in s1 */
{
n++;
strreplace1(s1,s2,s3);
/* se inloc. s2 cu s3 in s1 */
poz=strstr(s1,s2); /* se cauta dinnou s2 in s1 */
}
return n; /* se returneaza numarul de inlocuiri efectuate */
}
void main(void) /* testare functii */
{
char s1[100],s2[100],s3[100];
int i,n,a[20];
strcpy(s1,"Acesta este un text si numai unul !");
strcpy(s2,"un");
/* string-ul care se inlocuieste */
strcpy(s3,"1");
/* string-ul cu care se face inlocuirea */
n=strnfind(s1,s2,a);
if (n)
{
printf("'%s' apare in '%s' de %d ori, pe poz.:\n",s2,s1,n);
for (i=0;i<n;i++) printf("%d ",a[i]);
puts("\n");
printf("String-ul dupa inloc. lui '%s' cu '%s':\n",s2,s3);
strreplace(s1,s2,s3);
puts(s1);
}
else printf("'%s' nu apare in '%s'\n",s2,s1);
getch();
}

42

Rezumat
String-ul se memoreaz n C ntr-un ir de caractere obinuit. Caracterul \0 (caracterul
cu codul ASCII 0, adic NULL) marcheaz sfritul string-ului. De aceea, despre string n C se
spune c este un ir NULL terminat.
n fiierul antet string.h gsim definiiile funciilor de lucru cu string-uri n C.

Teme
1. Folosind funcia strrev scriei o funcie care verific dac un numr ntreg de tip unsigned
long primit ca parametru este palindrom. Un numr ntreg este palindrom dac cifrele lui
citite de la stnga spre dreapta sunt aceleai cu situaia n care sunt citite de la dreapta spre
stnga.
2. Scriei o funcie care returneaz numrul de cuvinte dintr-un string primit ca parametru.
Cuvintele se consider a fi grupuri de caractere desprite prin spaii.

Unitatea de nvare M1.U8. Tipul struct i l iste nlnuite


Cuprins
Obiective ................................ ................................ ................................ ................................ ...........
Introducere ................................ ................................ ................................ ................................ ........
U8.1. Structuri ................................ ................................ ................................ ................................ ..
U8.2. Pointeri ctre structuri ................................ ................................ ................................ .............
Obiectivele unitii de nvare
Vom studia n acest capitol tipul struct, adic tipul compus sau
nregistrare.
Ne propunem, de asemenea, s vedem cum se implementeaz o list
nlnuit cu ajutorul tipului struct.

Durata medie de parcurgere a unitii de nvare este de 2 ore.

43

Introducere
Pentru nceput, vom prezenta din punct de vedere teoretic noiunea de list nlnuit i
principale structuri de date de tip list nlnuit, dup care vom vedea cum putem implementa
listele nlnuite cu ajutorul pointerilor ctre structuri.
O list nlnuit este o structur format dintr-o mulime de aa numite noduri legate
ntre ele. n fiecare nod se memoreaz nite informaii (numere, caractere, string-uri etc.) i una
sau mai multe adrese ale altor noduri din list sau adrese nule (legturile). Cele mai folosite liste
nlnuite sunt cu una sau dou legturi (adrese ctre alte noduri).
Listele cu dou legturi se numesc dublu nlnuite. Fiecare nod memoreaz informaia,
iar fiecare dintre cele dou legturi este ctre un alt nod ale listei sau este o legtur vid. Iat un
posibil exemplu de list dublu nlnuit:

info

info

info

info

info

info

info

NULL

NULL
De departe cea mai folosit list dublu nlnuit este cea de tip arbore binar. Exist un
nod special denumit rdcin. Nici un nod nu are legtura ctre rdcin. Pornind din rdcin se
poate ajunge prin intermediul legturilor la orice alt nod al arborelui. Arborele binar nu are
cicluri, adic pornind dintr-un nod x oarecare nu se poate ajunge prin intermediul legturilor din
nou la nodul x .
O list simplu nlnuit este format din noduri ce conin (fiecare) o informaie i o
legtur ctre un alt nod sau o legtur nul. O list liniar simplu nlnuit are proprietatea c
exist un nod denumit cap care are o legtur nul sau este legat de un alt nod al listei, care la
rndul lui are legtura nul sau este legat de alt nod etc. Lista are proprietatea c pornind de la
nodul cap se poate ajunge prin legturi la orice alt nod al listei i pentru fiecare nod x diferit de
cap exist un singur nod y care este legat de x.
Dup modul de introducere i de scoatere a informaiilor ntr-o list liniar avem liste de
tip stiv sau coad.
O stiv este o list liniar de tip LIFO (Last In First Out), adic ultimul intrat primul
ieit. O stiv (dup cum sugereaz i numele) ne-o putem imagina cu nodurile stivuite unul peste
cellalt. Introducerea unui nou nod se face peste ultimul introdus, iar scoaterea unei informaii se
face din ultimul nod introdus n stiv. O stiv poate fi memorat printr-o list liniar simplu
nlnuit n care fiecare nod reine adresa nodului de sub el (ca legtur). Primul nod introdus n
stiv are legtura nul. Pentru o stiv se reine n permanen ntr-o variabil de tip pointer
(denumit de obicei cap) adresa ctre ultimul nod al stivei. O stiv este goal (vid) cnd
variabila cap reine adresa vid.

44

Coada este tot o list liniar, dar de tipul FIFO (First In First Out), adic primul intrat
primul ieit. Dup cum sugereaz i numele, nodurile ni le putem imagina aranjate n linie, unul
dup altul, introducerea unui nou nod se face dup ultimul introdus anterior, de scos, se scoate
primul nod introdus n coad. Coada poate fi i ea memorat cu ajutorul unei liste liniare simplu
nlnuite n care introducerea unui nod se face ntr-o parte a listei, iar scoaterea se face din
cealalt parte. Se rein n permanen adresa (ntr-o variabil de tip pointer denumit de obicei
ultim) ultimului nod introdus n list i pe cea a primului introdus (ntr-o variabil de tip pointer
denumit de obicei prim). Pentru a funciona eficient (s putem scoate rapid un nod), fiecare nod
al cozii reine adresa nodului din spatele lui (cel introdus imediat dup el n coad). Este evident
c primul nod are legtura nul.
O coad special este aceea n care primul nod n loc s aib legtura nul, el este legat
de ultimul nod al cozii. Aceast structur de date se numete coad circular.

U8.1. Structuri
Cu ajutorul structurilor putem defini tipuri noi de date, mai complexe pornind de la tipuri
de date deja existente, care alctuiesc aa numitele cmpuri ale structurii. O st ructur se definete
astfel:
struct nume
{
tip1 camp1,camp2,...,campm1;
tip2 camp1,camp2,...,campm2;
/* .... */
tipn camp1,camp2,...,campmn;
};
Dup acolada care ncheie definirea structurii trebuie neaprat s punem semnul punct i
virgul.
ntre acolada } ce ncheie definirea structurii i semnul ; (punct i virgul) putem declara
variabile care vor fi evident de tipul structurii respective.
n C denumirea tipului structur definit n exemplul de mai sus este struct nume
(denumirea structurii este precedat de cuvntul rezervat struct). n C++ nu este obligatoriu ca
nainte de nume s punem cuvntul rezervat struct.
Adesea se prefer (mai ales n C) definirea unei structuri n combinaie cu typedef. Pentru
a ilustra acest lucru definim o structur pentru memorarea unui numr complex ca o pereche de
numere reale:
typedef struct
{
double re,im;
} complex;

n final pentru a exemplifica modul de lucru cu structuri vom citi datele despre o
persoan ntr-o structur, dup care le vom afia:
struct tpers
{
char nume[50],adresa[100];
int varsta;
45

};
typedef struct tpers tpers;
void main()
{
struct tpers pers;
puts("Dati datele despre o persoana:");
printf("Nume: ");
gets(pers.nume);
printf("Adresa: ");
gets(pers.adresa);
printf("Varsta: ");
scanf("%d",&pers.varsta);
puts("Am citit:");
printf("Nume: %s\n",pers.nume);
printf("Adresa: %s\n",pers.adresa);
printf("Varsta: %d\n",pers.varsta);
}

Dup cum se poate observa mai sus, referirea la un cmp al unei structuri se face sub
forma var_structura.camp.

Rezumat
Un tip de date compus pornind de la tipurile de date deja existente n C se definete cu
ajutorul cuvntului rerervat struct. Accesul la membrul unei structuri se face ajutorul
operatorului punct sub forma variabila_tip_struct.membru.

Teme
1. De la tastatur citii stocul unei firme ntr-un ir de elemente de tip struct. n structur se vor
reine: denumirea produsului, cantitatea i preul. Sortai cresctor irul dup denumirea
produselor, dup care afiai tabelar produsele dup modelul:
--------------------------------------------------------------|Nr. | DENUMIRE PRODUS
|Cantitate| Pret |Valoare|
|crt.|
|
|
|
|
|----+------------------------------+---------+-------+-------|
|
1|Placa de baza
|
2.00| 401.44| 802.88|
|
2|Tastatura
|
1.00| 25.11| 25.11|
|
3|Mouse
|
22.00| 14.00| 308.00|
|
4|Cablu retea
|
117.50|
0.23| 27.03|
|-----------------------------------+---------+-------+-------|
| Valoare totala stoc:
1163.02|
--------------------------------------------------------------46

2. Rezolvai problema 2 de la sfritul capitolului 3 folosind un vector de structuri.

U8.2. Pointeri ctre structuri


Cu ajutorul pointerilor ctre structuri putem implementa n C listele nlnuite. Un pointer
ctre o structur se definete astfel:
struct nume
{
/* definiri de campuri impreuna cu tipurile lor */
};
/* .... */
struct nume *p; /* pointer catre structura */
Este important de reinut faptul c referirea la un cmp al unei structuri memorate la
adresa dat de pointerul p se face sub forma p->camp, ceea ce este echivalent cu a scrie
(*p).camp. Practic, n C pentru pointeri ctre structuri este introdus operatorul binar special ->
(format din caracterele minus i mai mare).
Ca aplicaie prezentm un program ce simuleaz lucrul cu o stiv de caractere folosind
pointeri ctre o structur denumit struct tstiva.
#include<stdio.h>
#include<conio.h>
#include<alloc.h>
struct tstiva
{
char info;
struct tstiva *leg;
}*cap; /*
cap este o variabila globala care va retine adresa capului
stivei */
typedef struct tstiva tstiva;
int introducere(char c) /* introducerea unui caracter in stiva */
{
struct tstiva *p;
p=(struct tstiva*)malloc(sizeof(tstiva));
if (p==NULL) return 0;
p->info=c;
p->leg=cap;
cap=p;
return 1;
}
int scoatere(char *c) /* scoatera unui caracter din stiva */
{
struct tstiva *p;
if (cap==NULL) return 0;
p=cap;
47

cap=p->leg;
*c=p->info;
free(p);
return 1;
}
void afisare() /* afisarea continutului stivei */
{
struct tstiva *p=cap;
while (p!=NULL)
{
printf("%c ",p->info);
p=p->leg;
}
}
void golirestiva()
{
struct tstiva *p;
while (cap!=NULL)
{
p=cap;
cap=p->leg;
free(p);
}
}
void main()
{
char c,inf;
cap=NULL; // setam stiva ca fiind goala
do
{
puts("1) Introducere caracter in stiva");
puts("2) Scoatere ultim caracter in stiva");
puts("3) Afisare continut stiva");
puts("4) Golire stiva\n");
puts("Esc - Parasire program\n");
c=getch();
switch (c)
{
case '1':
printf("Dati un caracter: ");
inf=getche();
if (!introducere(inf))
printf("\nMemorie insuficienta");
else printf("\nAm introdus: %c",inf);
break;
case '2':
if (!scoatere(&inf)) printf("Stiva goala!");
else printf("Am scos din stiva: %c",inf);
break;
case '3':
48

printf("Stiva contine: ");


afisare();
break;
case '4':
golirestiva();
printf("Am golit stiva!");
break;
case 27:
printf("Apasati o tasta pt. a iesi!");
break;
default:
printf("Apasati 1, 2, 3, 4 sau Escape");
}
getch();
}
while (c!=27);
golirestiva();
}

Rezumat
O list nlnuit n C se poate implementa folosind pointeri ctre tipul struct. Accesul la
membrul unei structuri aflat la adresa reinut n pointerul p se face cu ajutorul operatorului >
sub forma p>membru_structura.

Teme
1) Lucrul cu o coad (n mod asemntor cu programul de mai sus).
2) Generarea arborelui binar pornind de la irurile stg, dr, i info. Vectorii stg i dr memoreaz
indicii nodului fiu stng, respectiv fiu drept, iar n info se rein informaiile din fiecare nod.
3) Afiarea informaiei reinute n frunzele unui arbore binar.
4) Afiarea informaiei reinute pe un anumit nivel al unui arbore binar.
5) Cutarea unei informaii ntr-un arbore binar.
6) Jocul copiilor n cerc (cu o coad circular): n copii stau aezai ntr-un cerc. Se numr m
copii consecutivi pornind de la al p-lea. Al m-lea copil iese din cerc. Se continu
numrtoarea cu cel ce urmeaz dup copilul ce a prsit cercul, pn cnd rmne un singur
copil, care este declarat ctigtor. Se cere s se afieze ordinea de prsire a cercului,
precum i ctigtorul.

Unitatea de nvare M1.U9. Uniuni i seturi de constante


Cuprins
Obiective ................................ ................................ ................................ ................................ ...........
49

U9.1. Tipul union ................................ ................................ ................................ .............................


U9.2. Tipul enum................................ ................................ ................................ ...............................
Obiectivele unitii de nvare
Vom studia tipul union i utilitatea lui atunci cnd se apeleaz instruciuni
de lucru cu regitri.
De semenea, ne propunem s vedem cum se pot defini simultan mai multe
constante ntregi cu ajutorul tipului enum.

Durata medie de parcurgere a unitii de nvare este de 2 ore.

U9.1. Tipul union


Definirea unei uniuni seamn foarte mult cu cea de la structuri. n loc de cuvntul struct
avem ns cuvntul union. Iat i un exemplu:
union test
{
char c;
int i;
float f;
};

Semnul ; (punct i virgul) se pune de asemenea la sfritul definiiei. ntre acolade {} i ;


(punct i virgul) putem defini variabile de tip uniune.
Similitudinea dintre o uniune i o structur se oprete ns aici.
Pentru a reine o variabil de tip union sunt necesari 4 octei de memorie. n exemplul de
mai sus cmpurile c, i i f ale uniunii se refer toate la aceeai zon din memorie: c se refer la
primul octet (din cei patru), i se refer la primii doi octei, iar f se refer la toi cei 4 octei.
Zona de memorie rezervat unei variabile union este interpretat diferit n funcie de
tipurile cmpurilor uniunii.
Uniunile sunt folosite n C n special pentru instruciuni ce lucreaz cu regitri. n acest
scop pentru DOS (n Borland C) este definit uniunea REGS:
union REGS
{
struct WORDREGS x;
struct BYTEREGS h;
};
BYTEREGS i WORDREGS sunt dou structuri:

50

struct BYTEREGS
{
unsigned char al,ah,bl,bh;
unsigned char cl,ch,dl,dh;
};
struct WORDREGS
{
unsigned int ax,bx,cx,dx;
unsigned int si,si cflag,flags;
};
Uniunea REGS este folosit pentru transmiterea parametrilor funciei de bibliotec int86
prin intermediul creia se pot accesa funciile ROM-BIOS ale sistemului de calcul. Structura
instruciunii int86 este:
int86(nr_intrerupere,* in_regs,&out_regs);
Avem:
nr_intrerupere este numrul ntreruperii apelate
int_regs este valoarea cu care se ncarc regitrii
out_regs reprezint valoarea regitrilor de dup apel
Tipul union REGS se gsete definit n fiierul antet dos.h.
Ca exemplu pentru utilizarea tipului union REGS prezentm o secven de program care
ascunde cursorul text (se utilizeaz ntreruperea 0x10):
union REGS reg;
reg.h.ah=1;
reg.h.ch=0x20;
int86(0x10, &reg, &reg);

Pentru a face s reapar cursorul trebuiesc executate:


reg.h.ah=1;
reg.h.ch=12;
reg.h.cl=13;
int86(0x10, &reg, &reg);

Rezumat
O uniune se definete folosind cuvntul rezervat union asemntor cu o structur,
diferena esenial dintre o uniune i o structur este c membrii uniunii folosesc n comun
aceeai zon de memorie.

51

13. Seturi de constante (tipul enum)


Un tip de date enum se definete asemntor cu o structur sau uniune.
Cu ajutorul tipului enum putem defini seturi de constante ntregi. Tipul de date enum este
des folosit pentru a da denumiri diferitelor combinaii de bii din alctuirea unor ntregi de
formatare, cum ar fi de exemplu biii de formatare ai modului de introducere ntr-un flux C++
(definii n fiierul antet ios.h): ios::left, ios::right. Aceste constante sunt puteri ale lui doi pentru
c se refer fiecare numai la un anumit bit de pe o anumit poziie din ntregul de formatare.
Asupra fluxurilor C++ o s revenim la momentul potrivit.
Ca aplicaie, definim constante cu nume romneti pentru cele 16 culori ale modului text:
enum constante_culori
{
NEGRU=0,
ALBASTRU=1,
VERDE=2,
AZUR=3,
ROSU=4,
MOV=5,
MARO=6,
GRIINCHIS=7,
GRIDESCHIS=8,
ALBASTRUDESCHIS=9,
VERDEDESCHIS=10,
CYANDESCHIS=11,
ROSUDESCHIS=12,
MOVDESCHIS=13,
GALBEN=14,
ALB=15
};
//....
textcolor(GALBEN); /* numai sub DOS */
textbackcolor(ALBASTRU); /* numai sub DOS */
cprintf("Acesta este un test!");
De remarcat este faptul c avem constantele tipului enum date ntre acolade i desprite
prin virgule.

Rezumat
Folosind tipul enum putem defini un grup de constante ntregi. Constantele mpreun cu
valorile lor se enumer ntre acolade i sunt desprite prin spaii.

Teme
1. Definii un set de constante ntregi cu denumiri de plante. Presupunem c aceste constante
reprezint indicii componentelor unui vector de structuri n care se rein informaii cu privire
la diverse plante. Scriei funcii de actualizare a datelor despre plante folosind constantele pe
care le-ai definit (de exemplu putei scrie o funcie pentru actualiz area preului unei plante).
2. Aceeai problem pentru un set de constante ntregi cu nume de mrci de autoturisme.

52

Unitatea de nvare M1.U10. Fiiere n C


Cuprins
Obiective ................................ ................................ ................................ ................................ ...........
Introducere ................................ ................................ ................................ ................................ ........
U1.1. Funcii de lucru cu fiiere n C ................................ ................................ ...............................
Obiectivele unitii de nvare
Ne propunem s studiem modul de lucru cu fiiere din C, cum se deschide
un fiier, cum se scrie n el, cum se citesc date, cum se face o poziionare n fiier
etc.

Durata medie de parcurgere a unitii de nvare este de 2 ore.

Introducere
Pentru a lucra cu un fiier n C se declar o variabil tip pointer ctre tipul structur
FILE. Nu ne intereseaz n momentul n care lucrm cu un fiier ce se ntmpl cu cmpurile
structurii FILE, deoarece avem suficiente funcii care lucreaz cu fiiere. De aceea, putem spune
despre tipul FILE c este un tip abstract de date.

U10.1. Funcii de lucru cu fiiere n C


Funciile de lucru cu fluxuri n C sunt definite n stdio.h. Aa c atunci cnd lucrm cu
fiiere n C trebuie s includem acest fiier antet.
Deschiderea fiierului se face folosind funcia fopen, care are urmtoarea definiie (antet):
FILE *fopen(const char *numef,const char * mod);
Funcia primete ca argumente dou string-uri, primul trebuie s conin numele
fiierului (precedat eventual de cale) i al doilea modul de deschidere al fiierului. Se returneaz
pointerul ctre fluxul deschis (pointer ctre FILE). Dac nu s-a putut deschide fiierul, se
returneaz adresa nul (NULL).
Deschiderea unui fiier pentru operaii de scriere eueaz dac numele lui (inclusiv calea)
conine caractere invalide, fiierul este deja deschis de o alt aplicaie sau dac nu avem drepturi
de scriere n calea respectiv.
Un fiier nu poate fi deschis pentru a se citi din el informaii dect dac fiierul exist, nu
are atributul hidden (ascuns) i avem drepturi de citire asupra lui.
53

Putem deschide un fiier pentru scriere, pentru citire sau pentru adugare la sfrit
(append), n modul binar (fiierul n acest caz e interpretat ca o succesiune de octei, baii) sau n
modul text (fiierul e interpretat ca o succesiune de linii cu texte desprite prin caracterele \r i
\n).
Pentru a deschide un fiier pentru scriere, string-ul din parametrul al doilea al funciei
fopen trebuie s conin caracterul w, pentru a deschide fiierul pentru citire string-ul trebuie s
conin caracterul r, iar pentru a deschide fiierul pentru adugri la sfrit, n string trebuie s
apar caracterul a. Dac fiierul este deschis cu w, atunci se va crea un fiier nou, dac exist
un fiier cu acest nume, el este mai nti ters. Pentru a putea fi deschis un fiier cu r, el trebuie
s existe.
Pentru a deschide un fiier n modul binar, string-ul din parametrul al doilea al funciei
fopen trebuie s conin caracterul b. Dac string-ul nu conine caracterul b sau conine
caracterul t, atunci el va fi deschis n modul text.
n string-ul ce d modul de deschidere al fiierului poate s mai apar caracterul +.
Cnd apare acest caracter pentru un mod de deschidere pentru scriere (w sau a) nseamn c
vor fi suportate i operaii de citire din fiier. Dac apare caracter + la un mod de deschidere
pentru citire (r), atunci nseamn c vor fi suportate i operaii de scriere n fiier.
Iat cteva exemple de moduri de deschidere:
Fiierul se deschide numai pentru citire n modul binar
Fiierul se deschide numai pentru operaii de scriere n modul binar
Fiierul este deschis pentru adugare la sfrit n modul binar
Fiierul este deschis pentru citire n modul binar, dar sunt suportate i operaii
de scriere
wb+ Fiierul este deschis pentru scriere i citire n modul binar
ab+ fiierul este deschis pentru scriere cu adugare la sfrit n modul binar, dar se
pot face i citiri din fiier.
rb
wb
ab
rb+

Dac mai sus nu aprea caracterul b sau aprea caracterul t, atunci obineam modurile
similare text de deschidere de fiier.
Facem observaia c semnul plus + poate fi pus i ntre cele dou litere. De exemplu n
loc de ab+ putem pune a+b.
n exemplul urmtor deschidem un fiier pentru operaii de citire, dar i cu posibilitate de
scriere:
char numef[256];
FILE *fis;
printf("Numele fisierului: ");
gets(numef);
fis=fopen(numef,"rb+");
if (fis==NULL)
{
printf("Eroare ! Nu am putut deschide fisierul %s.\n",numef);
exit(1);
}

nchiderea fiierului se face cu ajutorul funciei fclose:


int fclose(FILE *fis);

54

Dac nchiderea fiierului s-a fcut cu succes, atunci se returneaz 0.


Pentru a nchide toate fiierele deschise la un moment dat putem folosi funcia:
int fcloseall();
Funcia returneaz numrul de fiiere ce au fost nchise.
Verificarea dac s-a ajuns la sfritul fiierului se face cu ajutorul funciei:
int foef(fis);
Funcia returneaz 0 dac nu s-a ajuns la sfritul fiierului sau o valoare nenul dac este
sfrit de fiier.
Exist o funcie de golire a buffer-ului n fiier (foreaz scrierea datelor din zona de
memorie RAM tampon n fiier):
int fflush(fis);
n caz de succes se returneaz 0, altfel se returneaz valoarea corespunztoare constantei
EOF definit n stdio.h.
Golirea tuturor buffer-elor tuturor fiierelor deschise se face cu:
int flushall();
Verificarea dac la un moment dat a aprut vreo eroare n prelucrarea unui fiier se face
cu ajutorul funciei ferror, care returneaz o valoare nenul dac exist erori:
int ferror(fis);
Citirea unui caracter din fiier (i se returneaz codul caracterului citit sau EOF dac s-a
ajuns la sfritul fiierului) se face cu:
int fgetc(fis);
Pentru a scrie un caracter n fiier folosim funcia:
int fputc(c,fis);
Citirea unui ir de caractere se face cu:
char *fgets(s,n,fis);
Pentru aceast funcie, fiierul este interpretat ca fiind text. Se citete un ir de caractere
de lungime maxim n, ir care se depune la adresa s. Lungimea irului depus n s este ori n (dac
nu s-a ntlnit caracterul \n ntre primele n caractere ale liniei), ori numrul de caractere pn la
sfritul liniei. La sfritul irului citit se depune caracterul \0.
Scrierea unui string ntr-un fiier text (la sfritul string-ului n fiier se pun caracterele
cu codurile 10 i 13, adic este vorba de carriage -return \r i respectiv new-line \n):
int fputs(s,fis);
Exist o funcie pentru scriere format ntr-un fiier text:
55

int fprintf(fis,...);
Instruciunea este similar cu printf numai c n loc s se afieze textul pe ecran, se
depune n fiier.
Citire formatat n modul text (varianta scanf pentru fiiere text) este:
int fscanf (fis,...);
Citire n modul binar se face cu:
size_t fread(void *p,int nb,int lb,FILE* fis);
Se citesc nb blocuri de lungime lb din fiierul indicat de pointerul fis i se depun la adresa
de memorie p. Funcia returneaz numrul efectiv de blocuri citite din fiier (size_t este un tip de
date special definit pentru dimensiuni de blocuri de memorie).
Scrierea n modul binar se face cu:
size_t fwrite(void *p,int nb,int lb, fis);
Se iau nb blocuri de lungime lb de la adresa de memorie p i se scriu n fiierul fis.
Funcia returneaz numrul efectiv de blocuri scrise n fiier.
Exist evident i o funcie pentru salt n fiier (mutarea poziiei curente):
int fseek(FILE *fis,long n,int deunde);
Se face salt cu n octei n fiierul fis din locul specificat de ultimul parametru al funciei.
Parametrul deunde poate avea valorile 0, 1 sau 2, pentru fiecare dintre aceste valori fiind definite
constante cu nume care sugereaz poziia de pe care se face saltul:
SEEK_SET
SEEK_CUR
SEEK_END

sau 0 - de la nceputul fiierului


sau 1 - de la poziia curent
sau 2 - de la sfritul fiierului.

Pentru SEEK_SET, n trebuie s fie nenegativ, deoarece saltul de la nceputul fiierului se


poate face numai spre dreapta.
Pentru SEEK_END, n trebuie s fie negativ sau 0, deoarece saltul se face napoi, de la
sfritul fiierului.
Pentru SEEK_CUR, n poate fi pozitiv, negativ sau 0. Saltul se face ori spre dreapta (dac
n > 0), ori napoi de la poziia curent (daca n < 0).
Pentru returnarea poziiei curente (n octei de la nceputul fiierului) vom folosi funcia:
long ftell(fis);
Folosind funcia ftell putem scrie o alt funcie care s returneze lungimea fiierului:
# include <stdio.h>
long flung(char *numef)
{
FILE *fis;
fis=fopen(numef,"rb");
56

fseek(fis,0,SEEK_END);
return ftell(fis);
}
void main(void)
{
printf("Fisierul 'autoexec.bat' are %ld octeti.\n",
flung("c:\\autoexec.bat"));
getch();
}

Redenumirea unui fiier se face cu ajutorul funciei:


int rename(const char *numef1,const char *numef2);
Fiierul cu numele numef1 se redenumete cu numele numef2. Numele de fiiere din
string-urile numef1 i numef2 pot fi precedate i de cale. Redenumirea nu se poate face dect pe
acelai drive. De exemplu, apelul funciei rename(c:\\fisier1.txt, a:\\fisier2.txt) se soldeaz
cu eec (nu se poate face redenumire de pe drive-ul c: pe drive-ul a:).
n cazul n care redenumirea s-a fcut cu succes, se returneaz 0, altfel se returneaz 1 i
variabila global errno se seteaz la una dintre valorile:
ENOENT
EACCES
ENOTSAM

No such file or directory (nu exist fiierul numef1, sau numef2 este un nume de
fiier invalid).
Permission denied (nu exist drepturi de scriere pe drive).
Not same device (situaia din exemplul de mai sus, n care cele dou nume de
fiiere indic drive-uri diferite).

tergerea unui fiier de pe disc se face cu:


int remove(const char *numef);
Se ncearc tergerea fiierului al crui nume (eventual precedat de cale) este memorat n
string-ul numef. n caz de succes, se returneaz valoarea 0, altfel se returneaz 1 i variabila
global errno se seteaz la una dintre valorile:
ENOENT
EACCES

No such file or directory (nu exist fisierul numef sau este invalid)
Permission denied (nu exist drepturi de scriere).

Dm n final sursele a trei programe C care lucreaz cu fiiere:


1) Concatenarea mai multor fiiere ale cror nume sunt primite n linie de comand.
Ultimul parametru primit n linie de comand se consider a fi numele fiierului
destinaie:
# include <stdio.h>
# include <conio.h>
# include <alloc.h>
# define lbuf 1024 /* lungimea buffer-ului de transfer este 1KB */

57

int main(int narg,char *argv[])


{
char *buf;
int i,n,eroare=0;
FILE *fis,*fisd;
buf=(char*)malloc(lbuf);
if (buf==NULL)
{
printf("Eroare! Memorie insuficienta.\n");
getch(); return 1;
}
if (narg<3)
{
printf("Eroare! Structura comenzii este:\n\n");
printf("%s <fis1> [<fis2>...<fisn>] <fis_dest>\n\n"
,argv[0]);
printf("Se concateneaza <fis1>, <fis2> ... fisn>.\n");
printf("Fisierele se depun in <fis_destinatie>.\n");
getch(); return 1;
}
fisd=fopen(argv[narg-1],"wb");
if (fisd==NULL)
{
printf("Eroare! Nu am putut deschide %s pt. scriere.\n"
,argv[n-1]);
getch(); return 0;
}
for (i=1;i<narg-1;i++)
{
fis=fopen(argv[i],"rb");
if (fis==NULL)
{
printf("Eroare! Nu am putut deschide %s.\n"
,argv[i]);
eroare++;
}
do
{
n=fread(buf,1,lbuf,fis);
fwrite(buf,1,n,fisd);
}
while (!feof(fis));
fclose(fis);
}
fclose(fisd);
free(buf);
if (!eroare) printf("Concatenarea s-a incheiat cu succes !");
getch();
return 0;
}

2) Afiarea coninutului unui fiier text:


58

# include <stdio.h>
# include <conio.h>
# include <alloc.h>
# define maxlinie 79
int main(void)
{
char numef[100],*linie;
long n=0;
FILE *fis;
linie=(char*)malloc(maxlinie+1);
if (linie==NULL)
{
printf("Eroare! Memorie insuficienta.\n");
getch();
return 1;
}
printf("Dati numele fisierului text de tiparit pe ecran: ");
gets(numef);
fis=fopen(numef,"rt");
if (fis==NULL)
{
printf("Eroare! Nu am putut deschide %s pt. citire.\n"
,numef);
getch();
return 0;
}
while(!feof(fis))
{
fgets(linie,maxlinie,fis);
if (!feof(fis))
{
n++;
printf(linie);
if (n%24==0) getch();
}
}
fclose(fis);
free(linie);
cprintf("Am afisat: %ld linii.",n);
getch();
return 0;
}

3) Produsul a dou matrici citite din fiiere text.


# include <stdio.h>
# include <conio.h>
# include <stdlib.h>
59

# include <process.h>
# include <alloc.h>
void EroareAloc()
{
printf("Eroare! Memorie insuficienta.");
exit(1);
}
float** MatrAlloc(int m,int n)
{
int i;
float **a;
if ((a=(float**)calloc(m,sizeof(float*)))==NULL) EroareAloc();
for (i=0;i<m;i++)
if ((a[i]=(float*)calloc(n,sizeof(float)))==NULL)
EroareAloc();
return a;
}
void main(void)
{
char numef[100];
int i,j,k,m,n,n2,p;
float **a,**b,**c,f;
FILE *fis;
printf("Dati numele fisierului text cu prima matrice: ");
gets(numef);
fis=fopen(numef,"rt");
if (fis==NULL)
{
printf("Eroare! Nu am putut deschide %s pt. citire.\n"
,numef);
getch();
exit(0);
}
fscanf(fis,"%d%d",&m,&n);
a=MatrAlloc(m,n);
for (i=0;i<m;i++)
{
for (j=0;j<n;j++)
{
fscanf(fis,"%f",&f);
a[i][j]=f;
printf("%10.2lf",a[i][j]);
}
puts("");
}
fclose(fis);
printf("Dati numele fisierului text cu a doua matrice: ");
gets(numef);
fis=fopen(numef,"rt");
if (fis==NULL)
60

{
printf("Eroare! Nu am putut deschide %s pt. citire.\n"
,numef);
getch(); exit(0);
}
fscanf(fis,"%d%d",&n2,&p);
if (n!=n2)
{
fclose(fis);
printf("\nEroare! Matricile nu se pot inmulti:\n");
printf(" A(%d,%d) x B(%d,%d)\n",m,n,n2,p);
getch(); exit(0);
}
b=MatrAlloc(n,p);
for (i=0;i<n;i++)
{
for (j=0;j<p;j++)
{
fscanf(fis,"%f",&f);
b[i][j]=f;
printf("%10.2lf",b[i][j]);
}
puts("");
}
fclose(fis);
printf("Dati numele fisierului in care sa pun rezultatul: ");
gets(numef);
if (fis==NULL)
{
printf("Eroare! Nu am putut deschide %s pt. scriere.\n"
,numef);
getch();
exit(0);
}
fis=fopen(numef,"wt");
c=MatrAlloc(m,p);
for (i=0;i<m;i++)
for (j=0;j<p;j++)
{
c[i][j]=0;
for (k=0;k<n;k++) c[i][j]+=a[i][k]*b[k][j];
}
for (i=0;i<m;i++)
{
for (j=0;j<p;j++)
{
printf("%10.2f",c[i][j]);
fprintf(fis,"%10.2f",c[i][j]);
}
printf("\r\n");
fprintf(fis,"\r\n");
}
for (i=0;i<m;i++) free(a[i]);
61

for (i=0;i<n;i++) free(b[i]);


for (i=0;i<m;i++) free(c[i]);
free(a); free(b); free(c);
fclose(fis);
getch();
}

Pentru cutarea fiierelor pe disc n DOS ne folosim de funciile:


int findfirst(const char *cale, struct ffblk *ff, int atribut);
int findnext(struct ffblk *ff);
Funciile findfirst i findnext sunt definite n dir.h i dos.h.
Funcia findfirst iniiaz cutarea, iar (dac a fost gsit cel puin un fiier) findnext o
continu. Ct timp se gsesc fiiere, findnext returneaz valoarea 0.
n parametrul cale se transmite calea unde se face cutarea i structura numelor de fiier
cutate. De exemplu, dac parametrul cale conine c:\\Windows\\*.bmp, atunci se vor cuta
fiierele cu extensia bmp din directorul windows aflat pe drive-ul c:.
Variabila ff este un pointer ctre o structura ffblk n care se depun informaiile cu privire
la fiierul gsit: numele su, dimensiunea (n octei), data i ora crerii, atributul fiierului (Readonly, Hidden, Archive, System). Structura ffblk este:
struct ffblk
{
char ff_reserved[21];
char ff_attrib;
int ff_ftime;
int ff_fdate;
long ff_fsize;
char ff_name[13];
};

/*
/*
/*
/*
/*
/*

rezervat
*/
atribut fisier */
ora creare fisier */
data creare fisier */
lungime fisier */
nume fisier
*/

Al treilea parametru al funciei findfirst reprezint atributul fiierelor pentru care se


iniiaz cutarea. Acesta poate avea una dintre valorile:
FA_RDONLY - Read-only
FA_HIDDEN - Hidden
FA_ARCH - Archive
FA_SYSTEM - Sistem
FA_LABEL - Eticheta discului
FA_DIREC - Director
Ca exemplu prezentm o funcie care afieaz toate fiierele cu extensia txt din directorul
curent:
void dirtxt(void)
{
struct ffblk ff;
int gata;
puts("Fisierele *.txt din directorul curent:");
gata = findfirst("*.txt",&ff,0);
while (!gata)
62

{
printf("%16s",ff.ff_name);
gata=findnext(&ff);
}
}

Rezumat
Pentru a lucra cu un fiier n C trebuie s definim o variabil de tip pointer ctre structura
FILE. Deschiderea fiierului se face apelnd funcia fopen. Funcia fopen primete ca parametri
numele fiierului i modul n care vrem s deschidem fiierul. Dac fiierul este deschis cu
succes. Funcia fopen returnez pointerul ctre tipul FILE cu ajutorul cruia se va prelucra
fiierul. Un fiier deschis cu fopen poate fi nchis folosind funcia fclose. Scrierea/citirea n/din
fiier n modul text se poate face cu fprint, respectiv cu fscanf. Pentru modul binar folosim
funciile fwrite i fread. Poziionarea n fiier se face cu fseek.

Teme

1. Scriei o funcie care returneaz numrul de apariii a unui cuvnt ntr-un fiier text. Funcia
primete ca parametrii cuvntul i numele fiierului.
2. Dintr-un fiier text se citesc elementele unui ir de numere reale. S se sorteze cresctor irul
i s se depun dup aceea vectorul n acelai fiier.
3. Propunem s se scrie un program care s gestioneze stocul unei firme (vnzare i cumprare
cantitate dintr-un produs, adugarea unui produs nou, afiarea unui produs dup cod, cutarea
unui produs dup nume, calcularea valorii totale a stocului etc.). Un produs se va reine n
fiier ntr-o nregistrare cu urmtoarea structur:
struct tstoc
{
char cod_prod[10],den_prod[50];
double cant,pret;
};

4. S se caute i s se afieze pe ecran toate numele fiierelor text i cile la care se gsesc pe
drive-ul C: al calculatorului (cutarea se va face n toate directoarele drive -ului).

Unitatea de nvare M1.U11. Fluxuri standard n C i variabile


statice
Cuprins
Obiective ................................ ................................ ................................ ................................ ...........
63

Introducere ................................ ................................ ................................ ................................ .......


U11.1. Fluxuri standard n C ................................ ................................ ................................ ............
U11.2. Variabile statice ................................ ................................ ................................ ....................
Obiectivele unitii de nvare
Ne propunem s vedem i alte fluxuri de date pe care putem aplica funciile
prezentate la capitolul anterior.
De asemenea, ne propunem s vedem ce sunt variabilele statice, cum se
definesc i cum se utilizeaz.

Durata medie de parcurgere a unitii de nvare este de 2 ore.

U11.1. Fluxuri standard n C


n C (sub DOS) exist definite urmtoarele fluxuri standard (vezi fiierul antet stdio.h):
stdin
stdout
stderr
stdaux
stdprn

- fluxul standard de intrare - tastatura


- fluxul standard de ieire - monitorul
- fluxul standard de erori
- interfaa serial (COM1)
- imprimanta (LPT1)

Fluxurile standard nu trebuie deschise sau nchise, toate sunt n permanen deschise.
Funciile pe care le-am prezentat pentru a lucra cu fiiere funcioneaz i pentru fluxurile
standard (vezi capitolul anterior).
Ca aplicaie prezentm un program care tiprete la imprimant un fiier text primit ca
parametru n linie de comand.
# include <stdio.h>
int main(int narg, char *argv[])
{
FILE *fis;
char c;
if (narg!=2)
{
fprintf(stderr,"Eroare ! Utilizare incorecta.\n");
return 1;
}
fis=fopen(argv[1], "rb");
if (fis==NULL)
{
fprintf(stderr,"Eroare deschidere fisier.\n");
64

return 1;

// fluxul standard de erori

}
while (fread(&c,1,1,fis)!=NULL) // citire caracter din fisier
fprintf(stdprn,"%c",c);
// trimitere la imprimanta
fprintf(stdprn,"%c",12); // trimitere caracter 12 la imprimanta
fclose(fis);
return 0;
}

Declanarea efectiv a tipririi la imprimant se face trimind caracterul cu codul 12.


Dac nu trimitem acest caracter, datele transmise rmn n principiu ncrcate n buffer-ul
imprimantei i se vor fi tiprit n momentul n care imprimanta va primi caracterul de declanare
a tipririi, cel mai probabil cnd se va ncerca o nou tiprire.

Rezumat
Fluxurile standard C de sub DOS sunt: stdin (fluxul standard de intrare tastatura),
stdout (fluxul standard de ieire monitorul), stderr (fluxul standard de erori), stdaux (interfaa
serial COM1) i stdprn (portul paralel LPT1). Funciile prezentate la capitolul anterior
pentru fiiere pot fi aplicate i acestor fluxuri.

Tem
S se scrie o aplicaie care trimite i primete pe portul serial sau paralel texte introduse
de la tastatur. S se instaleze i s se testeze aceast aplicaie pe dou calculatoare conectate
prin cablu serial sau paralel (aa numita Direct Cable Conection).

U11.1. Variabile statice


n C, o variabil local ntr-o funcie poate fi declarat ca fiind static. Pentru aceast
variabil se pstrez valoarea i, cnd se reapeleaz funcia, variabila va fi iniializat cu valoarea
pe care a avut-o la apelul anterior. De fapt pentru variabila local static este alocat o zon de
memorie de la nceputul pn la sfritul execuiei programului, dar accesul la variabil nu este
posibil dect din interioul funciei n care este declarat. Iat un exemplu simplu :
#include<stdio.h>
void fct(void)
{
static int x=1;
x++;
printf("%d ",x);
}

65

void main(void)
{
int i;
for (i=0;i<10;i++) fct();
}

Variabila static x este iniializat la nceputul execuiei programului cu valoarea 1. La


fiecare apel al funciei fct variabila x se incrementez cu o unitate i se afieaz noua sa valoare.
Aadar pe ecran n urma execuiei programului va aprea:
2 3 4 5 6 7 8 9 10 11

Rezumat
O variabil local ntr-o funcie poate fi declarat ca fiind static. O variabil static i
pstrez valoare i dup prsirea funciei.

Tem de control
Folosii variabile statice ntr-o funcie n care s reinei data i ora ultimei apelri a
funciei respective.

Unitatea de nvare M1.U12. Funcii cu list variabil de


argumente
Cuprins
Obiective ................................ ................................ ................................ ................................ ..........
Introducere ................................ ................................ ................................ ................................ .......
U12.1. Redactarea funciilor cu list variabil de argumente n C ................................ ..................
Obiectivele unitii de nvare
Ne propunem s studiem unul dintre cele mai interesante capitole ale
limbajului C. Este vorba de posibilitatea de a scrie funcii ce pot fi apelate cu
numr diferit de parametri.

66

Durata medie de parcurgere a unitii de nvare este de 2 ore.

Introducere
n C putem defini funcii n care numrul de argumente (parametri) nu este fix. Putem
apela o astfel de funcie cu orici parametri. Din aceast categorie fac parte funciile printf i
scanf.

U12.1. Redactarea funciilor cu list variabil de argumente n C


Ne propunem s scriem o funcie care s poat gsi maximul orictor valori transmise ca
parametri, fr a folosi vectori.
O funcie cu list variabil de argumente se definete astfel:
tip_ret fctvarlist(tip prim, ...)
Dup numele funciei, ntre paranteze se dau tipul i denumirea primului parametru de
apel al funciei, urmate de virgul i de trei puncte. n consecin o funcie cu list variabil de
argumente trebuie s aib cel puin un parametru cnd este apelat. Primul parametru de apel d
de obicei informaii cu privire numrul de parametri de apel i eventual cu privire la tipul
parametrilor, aa cum se ntmpl i n cazul funciilor printf i scanf.
Implementarea unei funcii cu list variabil de argumente se face cu ajutorul macrourilor va_start, va_arg i va_end. Aceste macro-uri sunt definite n fiierul antet stdarg.h.
Pentru a identifica parametrii de apel, n interiorul corpului unei funcii avnd list
variabil de argumente se definete o variabil de tip va_list, care este un vector definit n fiierul
antet stdarg.h. Acest vector reine practic informaiile cu privire la transmiterea parametrilor. Pe
baza acestor informaii i cu ajutorul celor trei macro-uri (va_start, va_arg i va_end) se pot
identifica valorile parametrilor de apel ai funciei.
Macro-ul va_start seteaz vectorul va_list aa nct s indice primul parametru de apel al
funciei. El are doi parametri. Primul este vectorul de tip va_list, iar al doilea este variabila n
care se depune valoarea primului parametru de apel al funciei. Aceast variabil trebuie s fie
dat explicit ca prim argument n definiia funciei.
Apelnd succesiv macro-ul va_arg, se identific restul parametrilor de apel ai funciei (de
la al doilea pn la ultimul). Macro-ul va_arg se transform ntr-o expresie (vezi capitolul
dedicat macro-urilor) care are acelai tip i aceeai valoare cu urmtorul parametru de apel al
funciei. Expresia se genereaz pe baza celor doi parametri ai macro-ului. Primul parametru este
vectorul de tip va_list, iar al doilea este tipul la care se convertete expresia. Acest tip de dat
trebuie evident s fie cel al parametrului de apel.
Trebuie reinut faptul c datorit mecanismului promovrii din C (convertirea automat a
unui tip la unul superior din aceeai categorie) funciile cu list variabil de parametri nu
funcioneaz corect pentru tipurile de dat char, unsigned char i float.
Macro-ul va_end se apeleaz dup ce toi parametrii de apel ai funciei cu list variabil
de argumente au fost identificai. Acest macro ajut ca ieirea din funcie s se fac n condiii
bune.

67

#include <stdio.h>
#include <conio.h>
#include <stdarg.h>
double max(int n,...) /*functie cu lista variabila
de argumente */
{
va_list lista_arg;
int i;
double max=-1E10,arg;
va_start(lista_arg,n);
for (i=0;i<n;i++)
{
arg=va_arg(lista_arg,double);
if (arg>max) max=arg;
}
va_end(lista_arg);
return max;
}
void main()
{
printf("Maximul este: %lf\n",max(5, -1., 5., -3.7, 4.9, 0.));
getch();
}

S menionm faptul c dac nu se iniializeaz lista de argumente (vectorul de tip


va_list) cu un apel al macro-ului va_start, dac se apeleaz va_arg de mai multe ori dect
numrul parametrilor de apel sau dac se omite va_end, programul se poate bloca sau rezultatele
pot fi neateptate. De asemenea, trebuie s avem mare grij ca tipul parametrilor de apel s
coincid cu tipul de date transmis ca parametru macro-ului va_arg. n exemplul nostru, dac nu
transmiteam toi cei cinci ultimi parametrii de tip double, puteam obine rezultatul eronat.
Marele dezavantaj al funciilor cu list variabil de argumente este dat de faptul c nu
putem controla din corpul funciei numrul i tipul parametrilor de apel.
n final trebuie s facem observaia c limbajul C++ ofer cteva alternative mai simplu
de implementat i mai sigure la funciile cu list variabil de argumente.

Rezumat
n C este posibil s definim funcii ce pot fi apelate cu numr variabil de parametri, aa
cum este cazul funciilor printf sau scanf. Aceste funcii se implementeaz cu ajutorul tipului
va_list i a macrocomenzilor va_start i va_end, toate definite n fiierul antet stdarg.h.

Teme

68

1. S se scrie o funcie cu numr variabil de argumente care calculeaz media aritmetic a unor
valori reale.
2. S se scrie o funcie cu numr variabil de argumente care calculeaz media aritmetic dintre
maximul i minimul unor valori reale.

Unitatea de nvare M1.U13. Utilizarea modului text de afiare


Cuprins
Obiective ................................ ................................ ................................ ................................ ...........
Introducere ................................ ................................ ................................ ................................ ........
U13.1. Funcii de afiare n modul text n C ................................ ................................ ....................
Obiectivele unitii de nvare
Ne propunem s vedem care sunt funciile Borland C scrise pentru utilizarea
modului text sub MS-DOS.

Durata medie de parcurgere a unitii de nvare este de 2 ore.

Introducere
Fiecrui caracter de pe ecran n modul text i se ataeaz n memoria video cte 2 octei.
Unul dintre octei conine codul caracterului, iar al doilea conine informaii cu privire la modul
de afiare al acestuia. Astfel primii 4 bii reprezint culoarea caracterului. Cei 4 bii conduc la
valori ntregi n baza 10 ntre 0 i 15, adic valori corespunztoare celor 16 culori. Urmtorii 3
bii reprezint culoarea fundalului pe care se scrie caracterul, iar ultimul bit este rezervat pentru
clipire: 1 - cu clipire i 0 - fr.

U13.1. Funcii de afiare n modul text n C


Pentru schimbarea culorii caracterelor avem instruciunea:
void textcolor(int c);
c este o valoare ntreag ntre 0 i 15, reprezentnd una dintre cele 16 culori ale modului
text. Pentru fiecare culoare este definit cte o constant:
Denumire constant

Valoare
69

pentru culoare
BLACK
BLUE
GREEN
CYAN
RED
MAGENTA
BROWN
DARKGRAY
LIGHTGRAY
LIGHTBLUE
LIGHTGREEN
LIGHTCYAN
LIGHTRED
LIGHTMAGENTA
YELLOW
WHITE

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

Din cele 16 culori de mai sus numai primele 8 (nuanele nchise de la 0 la 7) pot fi
folosite pentru setarea culorii fundalului pe care se afieaz textul. Schimbarea culorii fundalului
se face cu funcia:
void textbackground(int c)
Toate atributele caracterelor pot fi schimbate simultan cu ajutorul instruciunii:
void textattr(int attr);
Parametrul attr poate lua o valoare ntre 0 i 255, reprezentnd toate
culori pentru text, fundal i clipire. Dm un exemplu:

combinaiile de

textattr(BLINK, YELLOW, (RED<<4));


n exemplul de mai sus se seteaz culoarea caracterelor ca fiind galben, culoarea
fundalului roie, cu clipire.
Pentru clipire este definit constanta BLINK, care are valoarea 1 28.
Putem trece de la un mod text la altul cu ajutorul funciei:
void textmode(int mod);
Exista 5 moduri text. Fiecare mod text corespunde unei valori ntregi:
Denumire
constant
BW40
C40
BW80
C80
MONO
LAST MODE

Valoare
constant
0
1
2
3
7
-1

Semnificaie
Mod text 40 caractere pe linie cu 2 culori: alb/negru
40 caractere pe linie cu 16 culori
80 caractere pe linie cu 2 culori
80 caractere pe linie cu 16 culori
80 caractere pe linie, 16 nuane de gri
Se revine la ultimul mod text

70

Definirea ferestrelor text se face cu ajutorul funciei:


void window(int x1,int y1,int x2,int y2);
Se definete o fereastr text avnd colul stnga-sus la coordonatele ecran (x1, y1) i
coltul dreapta-jos (x2, y2). Coordonatele ecranului text sunt numerotate pe orizontal de la stnga
spre dreapta (de la 1 la 40 sau 80, n funcie de modul text) i pe vertical de sus n jos (de la 1 la
25).
Funciile printf i scanf nu in cont de fereastra text definit i de culorile setate. Cnd se
dorete a se lucra cu ferestre text se utilizeaz funciile cprintf i cscanf.
Pentru returnarea poziiei cursorului pe ecran, pe orizontal, respectiv pe vertical, se
folosesc funciile:
int wherex();
int wherey();
Mutarea cursorul la coordonatele (x, y) de pe ecran se face cu funcia:
int gotoxy(x, y);
Afiarea cu intensitate sporit a caracterelor se face cu:
void highvideo();
Afiarea cu intensitate redus a caracterelor se face cu funcia:
void lowvideo();
Revenirea la modul text normal se face cu:
void normvideo();
Caracteristicile ferestrei text curente se pot obine cu ajutorul funciei:
void gettextinfo(struct text_info *info);
Structura text_info este:
struct text_info
{
unsigned char winleft;
/* coordinata stanga a ferestrei */unsigned char
wintop;
/* coordinata sus a ferestrei */unsigned char winright;
/*
coordinata dreapta a ferestrei */unsigned char winbottom;
/* coordinata jos a
ferestrei */
unsigned char attribute;
/* atributul text */
unsigned char normattr;
/* atributul normal */
unsigned char currmode;
/* mod text curent:
BW40, BW80, C40, C80, sau C4350 */
unsigned char screenheight; /* inaltimea ecranului */
unsigned char screenwidth;
/* latimea ecranului */
unsigned char curx;
/* coordonata x a cursorului */
unsigned char cury;
/* coordonata y a cursorului */
};
71

Alte funcii ale modului text (definite n conio.h):


1. void clrscr(); cur fereastra text curent.
2. void clreol(); cur linia curent ncepnd cu caracterul curent;
3. void insline(); insereaz linie nou goal pe poziia n care se afl cursorul, liniile
ncepnd cu linia curent cobornd cu o poziie n jos;
4. void movetext(int x1,int y1,int x2,int y2,int x3,int y3); mut textul aflat pe ecran n
interiorul dreptunghiului de coordonate stnga-sus (x1, y1) i dreapta-jos (x2, y2) la
coordonatele stnga-sus (x3, y3).
5. int gettext(int x1,int y1,int x2,int y2,void *buff); citete caracterele aflate n
interiorul dreptunghiului stnga-sus (x1, y1) i dreapta-jos (x2, y2) i le depune la
adresa de memorie indicat de buff. Zona de memorie alocat la adresa buff trebuie
s fie de minim: 2*(x2-x1+1)*(y2-y1+1) octei. n cazul n care citirea s-a fcut cu
succes, funcia returneaz valoarea 1, altfel returneaz va loarea 0.
6. int puttext(int x1,int y1,int x2,int y2,void *buff); de la adresa indicat de buff se iau
2*(x2-x1+1)*(y2-y1+1) octei i se afieaz n dreptunghiul de pe ecran dat de
coordonatele stnga-sus (x1, y1) i dreapta-jos (x2, y2). n cazul n care afiarea s-a
fcut cu succes, funcia returneaz o valoare nenul.
Observaie: Cele 6 funcii de mai sus in cont de fereastra text curent definit, coordonatele
fiind relativ la aceasta.

Rezumat
Curarea ecranului n modul text se face apelnd funcia clrscr(), schimbarea culorii
caracterelor ce se afieaz se face cu ajutorul funciei textcolor, schimbarea culorii fundalului se
face cu textbackground. Definirea unei ferestre text se face cu funcia window. Funciile de
afiare, respectiv de citire care in cont de fereastra text definit i de culorile curente stabilite
sunt cprintf i cscanf.

Tem
Scriei o funcie care afieaz i pregtete scrierea n interiorul unei ferestre text avnd
un contur format cu o linie dubl. Fereastra trebuie s semne cu ferestrele mediului de
programare Borland C de sub DOS.

Unitatea de nvare M1.U14. Grafic n C


Cuprins
Obiective ................................ ................................ ................................ ................................ ..........
Introducere ................................ ................................ ................................ ................................ .......
72

U14.1. Iniializarea modului grafic ................................ ................................ ................................ ..


U14.2. Instruciuni pentru desenare de linii drepte ................................ ................................ ..........
U14.3. Instruciuni pentru desenare de curbe eliptice ................................ ................................ .......
U14.4. Instruciuni pentru afiare de texte n modul grafic ................................ ..............................
U14.5. Instruciuni pentru desenare de figuri umplute ................................ ................................ .....
U14.6. Instruciuni pentru paleta de culori ................................ ................................ .......................
U14.7. Pagini grafice ................................ ................................ ................................ ........................
U14.8. Citire / scriere zon de memorie video ................................ ................................ .................
U14.9. Ferestre grafice ................................ ................................ ................................ .....................
Obiectivele unitii de nvare
Ne propunem s studiem funciile de lucru n modul grafic din Borland C
pentru sistemul de operare MS-DOS.

Durata medie de parcurgere a unitii de nvare este de 2 ore.

Introducere
n C implicit se lucreaz n modul text. Pentru reprezentri grafice trebuie s intrm n
modul grafic.
Dac folosim instruciuni ale modului grafic n modul text se semnaleaz eroare ce duce
la prsirea programului cu mesajul de eroare: BGI Error: Graphics not initialized (use
initgraph). Instruciuni din modul text pot fi ns folosite n modul grafic, fr a se semnala
eroare.
Tot ceea ce ine de modul grafic (funcii, constante, variabile globale etc.) este definit n
fiierul antet graphics.h, care trebuie inclus n programele care folosesc grafic. Funciile
modului grafic sunt implementate n biblioteca graphics.lib.
n modul grafic ecranul este interpretat ca o reea dreptunghiular de puncte (pixeli).
Punctele de pe ecran sunt numerotate de la stnga spre dreapta pe orizontal, iar pe vertical de
sus n jos. Coordonatele punctelor de pe ecran sunt numerotate
ncepnd cu valoarea 0. De
exemplu, n modul VGA 640x480, pixelii de pe ecran au coordonatele (x,y), unde x{0, 1, 2,
,639} i y{0, 1, 2, ,479}

U14.1. Iniializarea modului grafic


Pentru a putea folosi instruciunile de desenare trebuie iniializat modul grafic. Acest
lucru se face cu funcia:
initgraph(&gd,&gm,"cale");
73

gd reprezint valoarea corespunztoare plcii grafice (graphic device).


gm reprezint modul grafic n care dorim s intrm ( graphic mode).
cale este o constant tip ir de caractere corespunztoare cii spre fiierele necesare
iniializrii modului grafic.
Aceste fiiere au extensia bgi. Ele se gsesc de obicei n directorul bgi aflat n directorul
n care este instalat mediul de programare C (pentru Borland C avem de obicei calea c:\bc\bgi,
deoarece mediul Borland C se instaleaz n mod implicit n directorul bc, n rdcina
harddiscului c:). Dac lsm calea vid (stringul vid ), atunci fiierele grafice sunt cutate n
directorul curent). Este indicat chiar s se lase vid calea spre bgi i s se copieze fiierele
grafice necesare n directorul curent, aa nedepinzndu-se mediul de programare, programul
mpreuna cu fiierele grafice putnd fi copiate pe orice calculator.
Mai mult, fiierele grafice pot fi incluse direct n executabil prin transformarea acestora
n fisiere obj cu ajutorul utilitarului bgiobj.exe, aflat n directorul bgi.
n momentul iniializrii modului grafic, dac variabila gd are valoarea corespunztoare
constantei DETECT (adic 0), atunci este cutat modul grafic cel mai bun n care se poate intra.
n prezent, datorit faptului c aproape toate calculatoarele au plac video Super VGA, implicit
modul grafic gsit va fi cel VGAHI (16 culori, rezoluie 640x480). Pentru a intra n acest mod
este nevoie ca n calea n care se caut fiierele grafice s se afle fiierul egavga.bgi.
Exemplu. Iniializare grafic prin detectarea modului grafic.

int gd=DETECT,gm;
initgraph(&gd,&gm,"c:\\bc\\bgi");

Parametrii gd i gm sunt folosii i ca parametri de intrare n funcie i ca parametri de


ieire din funcie. De aceea, n exemplul de mai sus gd intr cu valoarea 0, corespunztoare
constantei DETECT i se returneaz n gd valoarea
corespunztoare constantei VGA,
adic 9, iar pentru gm se returneaz valoarea corespunztoare constantei VGAHI, adic 2.
Dac dorim s se iniializeze un anumit mod grafic, corespunztor unei anumite plci
grafice, nu avem dect s specificm acest lucru prin iniializarea
corespunztoare a
variabilelor gd i gm.
Valorile pe care le poate lua gd sunt:
Denumire constant
plac video
DETECT
CGA
MCGA
EGA
EGA64
EGAMONO
IBM8514
HERCMONO
ATT400
VGA
PC3270

Valoare
constant
0
1
2
3
4
5
6
7
8
9
10

Valorile posibile pentru gm (depinznd de placa video aleas) sunt:

74

Constant
plac video

CGA

MCGA

EGA
EGA64
EGAMONO
HERC

ATT400

VGA
PC3270
IBM8514

Constant pentru
mod grafic
CGAC0
CGAC1
CGAC2
CGAC3
CGAHI
MCGAC0
MCGAC1
MCGAC2
MCGAC3
MCGAMED
MCGAHI
EGALO
EGAHI
EGA64LO
EGA64HI
EGAMONOHI
HERCMONOHI
ATT400C0
ATT400C1
ATT400C2
ATT400C3
ATT400MED
ATT400HI
VGALO
VGAMED
VGAHI
PC3270HI
IBM8514LO
IBM8514HI

Valoare
constant
0
1
2
3
4
0
1
2
3
4
5
0
1
0
1
3
0
0
1
2
3
4
5
0
1
2
0
0
1

Rezoluie
320x200
320x200
320x200
320x200
640x200
320x200
320x200
320x200
320x200
640x200
640x480
640x200
640x350
640x200
640x350
640x350
720x348
320x200
320x200
320x200
320x200
640x200
640x400
640x200
640x350
640x480
720x350
640x480
1024x760

Paleta de
culori
C0
C1
C2
C3
2 culori
C0
C1
C2
C3
2 culori
2 culori
16 culori
16 culori
16 culori
4 culori
2 culori
2culori
C0
C1
C2
C3
2 culori
2 culori
16 culori
16 culori
16 culori
2 culori
256 culori
256 culori

Nr. pag.
grafice
1
1
1
1
1
1
1
1
1
1
1
4
2
1
1
2
2
1
1
1
1
1
1
2
2
1
1
1
1

Exemplu. Iniializare mod grafic VGAMED (16 culori, rezoluie 640x350 i 2 pagini
grafice).

int gd=VGA,gm=VGAMED;
initgraph(&gd,&gm,"c:\\bc\\bgi");

Observaie: 1) Nu se poate intra n oricare dintre modurile grafice de mai sus de pe orice
calculator! Trebuie s se ina cont de compatibilitatea dintre placa existent i cea pentru care se
ncearc iniializarea grafic. Pe orice calculator aparinnd ultimelor generaii funcioneaz n
general iniializarea grafic EGA sau VGA.
2) Despre pagini grafice vom vorbi cnd se vor prezenta funciile setvisualpage i
setactivepage.
Dac vrem s iniializm un alt mod grafic dect cele cunoscute, de exemplu un mod
Super VGA cu 256 culori (pentru care trebuie s avem fiierul svga256.bgi),
nainte de
iniializare trebuie fcut o instalare (cu DETECT nu sunt gsite modurile Super VGA). n
exemplul urmtor este artat modul n care este instalat driver-ul pentru placa Super VGA cu 256
culori.
75

void igSVGA256(int gm)


{
int eroare_grafica,gd;
gd = installuserdriver("SVGA256", NULL);
initgraph(&gd,&gm,"c:\\bc\\bgi");
eroare_grafica = graphresult();
if (eroare_grafica != grOk)
{
printf("Graphics error: %s\n", grapherrormsg(eroare_grafica));
getch();
exit(1);
}
}

Observaie: 1) Pentru modurile grafice Super VGA cu 256 culori nu exist definite constante,
deoarece ele nu au existat cnd a aprut Borland C. Modurile grafice (trimise ca parametru n
funcia igSVGA256 sunt numerotate cu 0, 1, 2, 3, 4, . , aceste valori corespunznd rezoluiilor:
320x200, 640x400, 640x480, 800x600, 1024x768 etc.).
2) La modurile Super VGA cu 256 culori exist o singur pagin grafic.
3) n anumite sisteme de operare (de exemplu Windows NT)
iniializarea
modurilor Super VGA nu este posibil. n general nu exist probleme sub DOS, Windows 95
sau Windows 98.
4) Exist drivere scrise numai pentru anumite plci video, cum ar fi Vesa16.bgi
sau S3trio64.bgi, care de asemenea trebuiesc instalate pentru a putea fi folosite. Aceste moduri
grafice nu pot fi iniializate dect pentru plcile video respective, pentru alte plci nefuncionnd.
2. getaspectratio(xx,yy);
n unele moduri grafice (cum ar fi VGAMED si VGALO) apare o alungire a imaginii pe
vertical, deoarece pixelul este mai mare pe vertical dect pe orizontal. De aceea un cerc
arat ca o elips, un ptrat ca un dreptunghi etc. Raportul def = (float)xx/yy ne indic de cte ori
e mai mare pixelul pe vertical dect pe orizontal. Pentru a desena pstrnd raportul ntre
dimensiunile figurii, ordonata la fiecare desen va fi nmulit cu raportul de deformare def.
Exemplu. afiare corect a unui disc.
int gd=VGA,gm=VGAMED,xx,yy,x=200,y=100,rx=50,ry; // rx=raza discului
float def;
/* ........................... */
getaspectratio(xx,yy);
def=(float)xx/(float)yy; // calculare raport deformare
ry=rx*def;
// rectificare raza pe verticala
fillellipse(x,y,rx,ry); // desenare disc
/* ........................... */

3. Funcia graphresult() returneaz o valoare


iniializarea modului grafic. Dac valoarea coincide
iniializarea s-a fcut cu succes, iar dac nu, atunci
graphresult putem afia mesajul corespunztor valorii
modului grafic.
76

ce indic modul n care s-a terminat


cu valoarea constantei grOk, atunci
folosind valoarea returnat de funcia
furnizate de tentativa de iniializare a

4. Mesajul de eroare generat este dat de funcia: grapherrormsg(val), unde val este
indicele erorii pentru care se afieaz mesajul.
5. Cnd terminm de lucrat n modul grafic i vrem s ne ntoarcem n modul text
folosim instruciunea de nchidere a modului grafic: closegraph();
Exemplu. Schema unui program n modul grafic, iniializare si nchidere mod grafic:
#include<graphics.h>
#include<process.h>
#include<stdlib.h>
void main(void)
{
int gd=DETECT,gm,eroare;
initgraph(&gd,&gm,"c:\\bc\\bgi");
err=graphresult();
if (eroare!=grok)
{
printf("Eroare grafica %d: %s",eroare,grapherrormsg(eroare));
exit(1);
}
...
closegraph();
}

6. getmaxx() i getmaxy() returneaz indicele pe orizontala (coloana) ultimului pixel de


pe ecran, respectiv linia ultimului pixel de pe ecran. Pixelii pe orizontala ecranului sunt
numerotai de la stnga spre dreapta, de la 0 la getmaxx(), iar pe vertical sunt numerotai de la
sus n jos, de la 0 la getmaxy().
De exemplu, n modul VGAHI (640x480), getmaxx() va returna 639, iar getmax() va
returna 479.
7. getmaxcolor() returneaz indicele ultimei culori a paletei. Pentru oricare dintre
modurile VGA, valoare returnat va fi 15 (culorile vor avea indici de la 0 la 15). Pentru fiecare
din cele 16 culori ale paletei avem definit cte o constant. Putem folosi aceleai constante ca
la modul text:
Denumire constant
pentru culoare
BLACK
BLUE
GREEN
CYAN
RED
MAGENTA
BROWN
DARKGRAY
LIGHTGRAY
LIGHTBLUE
LIGHTGREEN
LIGHTCYAN

Valoare
constant
0
1
2
3
4
5
6
7
8
9
10
11
77

LIGHTRED
LIGHTMAGENTA
YELLOW
WHITE

12
13
14
15

Valorile pentru culorile paletei VGA i EGA nu sunt ns consecutive, de aceea, dac
schimbm paleta de culori, trebuie s inem cont de acest lucru. Cele 16 culori ale paletei
corespund valorilor 1, 2, 3, 4, 5, 7, 20, 56, 57, 58, 59, 60, 61, 62 i 63. Pentru fiecare dintre
aceste culori este definit cte o constant:
Denumire constant
EGA_BLACK
EGA_BLUE
EGA_GREEN
EGA_CYAN
EGA_RED
EGA_MAGENTA
EGA_LIGHTGRAY
EGA_BROWN
EGA_DARKGRAY
EGA_LIGHTBLUE
EGA_LIGHTGREEN
EGA_LIGHTCYAN
EGA_LIGHTRED
EGA_LIGHTMAGENTA
EGA_YELLOW
EGA_WHITE

Valoare constant
0
1
2
3
4
5
7
20
56
57
58
59
60
61
62
63

Exemplu. Afiarea caracteristicilor modului grafic detectat.


#include<graphics.h>
#include<conio.h>
int main(void)
{
int gd=DETECT,gm,eroare;
char s[80];
initgraph(&gd,&gm,"c:\\bc\\bgi");
err=graphresult();
if (eroare!=grok)
{
printf("Eroare grafica %d: %s",eroare,grapherrormsg(eroare));
return 1;
}
sprintf(s,"Placa grafica %d, mod grafic %d, %d culori, rez. %d x
%d",
gd,gm,getmaxcolor()+1,getmaxx()+1,getmaxy()+1);
outtext(s); /* afisare string s la coordonatele grafice curente */
getch(); closegraph(); return 0;
}

78

8. cleardevice(); curat ecranul n modul grafic.


9. setbkcolor(c); seteaz culoarea fundalului pentru ntreg ecranul, unde c este constant
ntreag. Culoarea fundalului nu se schimb dect dup un apel al funciei cleardevice().
10. getbkcolor() funcie ce returneaz culoarea curent a fundalului.
11. moveto(x,y); mut cursorul grafic la coordonatele grafice x i y.
12. moverel(dx,dy); mut cursorul grafic la coordonatele dx i dy, relative la fostele
coordonate curente. Dac avem coordonatele curente x0 i y0, atunci n urma apelului
moverel(dx,dy); coordonatele curente devin x0+dx i y0+dy.
13. getx() i gety() returneaz coordonatele grafice curente pe orizontal, respectiv pe
vertical.
14. putpixel(x,y,c); afieaz un punct (aprinde un pixel) pe ecran la coordonatele (x,y)
avnd culoarea c.
Exemplu. Umplerea ecranului cu pixeli de culori aleatoare.
# include <stdio.h>
# include <conio.h>
# include <graphics.h>
void main(void)
{
int i,j,maxx,maxy,gd=DETECT,gm;
initgraph(&gd,&gm,"");
randomize();
maxx=getmaxx(); maxy=getmaxy();
for (i=0;i<=maxx;i++)
for (j=0;j<=maxy;j++) putpixel(i,j,random(16));
getch(); closegraph();
}

Observatie: Funcia random(n) definit n fisierul antet stdlib.h primete ca argument un


ntreg n i returneaz o valoare ntreag aleatoare ntre 0 i n-1. Funcia
randomize()
iniializeaz generatorul aleator de numere cu o valoare aleatoare depinznd de timp. Dac nu
se apeleaz funcia randomize, atunci de fiecare data cnd se ruleaz programul, se genereaz
aceleai numere aleatoare.
15. getpixel(x,y) citete culoarea pixelului aflat la coordonatele (x,y) i returneaz aceast
valoare (o valoare ntre 0 i getmaxcolor()).
Caracteristicile contururilor
16. setcolor(c); seteaz culoarea cu care se vor desena contururile desenelor (linii, curbe
etc.).
17. getcolor(); returneaz indicele culorii curente de desenare a contururilor (o valoare
ntre 0 i getmaxcolor()).
79

18. setlinestyle(stil, model_utlizator, grosime); seteaz tipului de linie cu care se vor


desena contururile.
stil d tipul liniei (contururilor), adic unul dintre cele definite n tabelul:
Constant pentru
tip linie
SOLID_LINE
DOTTED_LINE
CENTER_LINE
DASHED_LINE
USERBIT_LINE

Valoare
constant
0
1
2
3
4

Descriere
linie continu
linie punctat
linie punct
linie ntrerupt
definit de utilizator

model_utilizator este o valoare ntreag (pe 2 octei) folosit pentru definirea de ctre
programator a unui tip de linie propriu.
grosime seteaz grosimea liniilor contururilor. Acest parametru poate lua dou valori, 1
sau 3:
Constant pentru
tip linie
NORM_WIDTH
THICK_WIDTH

Valoare
constant
1
3

Descriere
linie subire (grosime 1 pixel)
linie subire (grosime 3 pixel)

Ne propunem s definim urmtorul tip de linie: ooooooooxooxxxoo , unde prin o


nelegem spaiu, iar prin x nelegem punct. Fiecare spaiu corespunde valorii 0, iar x valorii
1 (n baza 2). Modelul de mai sus corespunde, deci, numrului 0000000010011100 (2) =
27+24+23+22(10) = 156 (10) = 009C(16). Pentru a defini i folosi acest model vom scrie:
int model=156;
setlinestyle(USERBIT_LINE, model, NORM_WIDTH);

U14.2. Instruciuni pentru desenare de linii drepte


19. line(x1,y1,x2,y2); deseneaz un segment de dreapt ntre punctele de coordonate
(x1,y1) i (x2,y2). Coordonatele captului final al segmentului devin coordonatele grafice
curente, adic n punctul de coordonate (x2,y2).
20. lineto(x,y); traseaz un segment de dreapt pornind din punctul de coordonate grafice
curente pn n punctul de coordonate (x,y). Coordonatele grafice curente se mut n captul
final al segmentului, adic n punctul de coordonate (x,y).
21. linerel(x,y); traseaz un segment de dreapt pornind din punctul de coordonate
grafice curente pn n punctul obinut printr-o deplasare (dx,dy) fa de punctul curent.
Coordonatele captului final al segmentului devin coordonatele grafice curente, adic punctul de
coordonate (x+dx,y+dy).
22. rectangle(x1,y1,x2,y2); se deseneaz conturul unui dreptunghi avnd 2
diametral opuse de coordonate (x1,y1) i (x2,y2).
Exemplu. Trasarea unui ptrat folosind funciile: line, lineto, linerel, rectangle.

80

vrfuri

# include <stdio.h>
# include <conio.h>
# include <graphics.h>
void main(void)
{
int x=200,y=100,L=70,gd=DETECT,gm;
initgraph(&gd,&gm,"");
setbkcolor(BLUE);
cleardevice();
setlinestyle(SOLID_LINE,0,1);
setcolor(WHITE);
line(x,y,x+L,y);
line(x+L,y,x+L,y+L);
line(x+L,y+L,x,y+L);
line(x,y+L,x,y);
getch();
setcolor(YELLOW);
setlinestyle(DOTTED_LINE,0,3);
moveto(x,y);
lineto(x+L,y);
lineto(x+L,y+L);
lineto(x,y+L);
lineto(x,y);
getch();
setcolor(LIGHTCYAN);
setlinestyle(CENTER_LINE,0,1);
moveto(x,y);
linerel(L,0);
linerel(0,L);
linerel(-L,0);
linerel(0,-L);
getch();
setcolor(LIGHTGREEN);
setlinestyle(DASHED_LINE,0,3);
rectangle(x,y,x+L,y+L);
getch();
closegraph();
}

23. drawpoly(n,p); traseaz o linie poligonal, unde n este numrul de vrfuri al liniei
poligonale, iar n p sunt memorate coordonatele curente ale vrfurilor poligonului.
n vectorul p sunt memorate 2*n valori ntregi (coordonatele celor n vrfuri). Pentru
vrful de indice k avem coordonatele (p[2*k], p[2*k+1]), unde k [0, n-1].
Exemplu. Se citesc coordonatele vrfurilor unui poligon i se deseneaz.
# include <stdio.h>
# include <conio.h>
# include <graphics.h>
void main(void)
81

{
int k,n,p[100],gd=DETECT,gm;
clrscr();
printf(" Dati numarul de varfuri al poligonului: ");
scanf("%d",&n);
for (k=0;k<n;k++)
{
printf("x(%d)= ",k);
scanf("%d",&p[2*k]);
printf("y(%d)= ",k);
scanf("%d",&p[2*k+1]);
}
p[2*n]=p[0]; p[2*n+1]=p[1];
n++;
initgraph(&gd,&gm,"");
drawpoly(n,p);
getch(); closegraph();
}

Observaie: Pentru a nchide linia poligonal, la sfritul vectorului p a fost necesar


adugarea coordonatelor primului vrf.

U14.3. Instruciuni pentru desenare de curbe eliptice


24. circle(x,y,r); se deseneaz un cerc cu centrul n punctul de coordonate (x,y) i avnd
raza r.
Exemplu. Trasarea unor cercuri concentrice.
# include <stdio.h>
# include <conio.h>
# include <graphics.h>
void main(void)
{
int x,y,r,n=20,gd=DETECT,gm;
initgraph(&gd,&gm,"");
x=getmaxx()/2;
y=getmaxy()/2;
for (r=0;r<n;r++) circle(x,y,5*r+50);
getch();
closegraph();
}

25. arc(x,y,u1,u2,r); se deseneaz un arc de cerc cu centrul n punctul de coordonate


(x,y) i avnd raza r, ntre unghiurile u1 i u2 date n grade, n sens trigonometric.
26. ellipse(x,y,u1,u2,rx,ry); se traseaz un arc de elips cu centrul n punctul de
coordonate (x,y), de raze rx i ry, ntre unghiurile u1 i u2 date n grade, n sens trigonometric.
Pentru desenarea unei elipse ntregi putem folosi funcia sub forma ellipse(x,y,0,360,rx,ry);.
82

U14.4. Instruciuni pentru afiare de texte n modul grafic


27. outtext(s); afieaz irul de caractere memorat n variabila de tip string s, la
coordonatele grafice curente.
28. outtextxy(x,y,s); textul din stringul s este afiat la coordonatele grafice (x,y) de pe
ecran.
29. settextstyle(font,directie,dim); seteaz caracteristicile textelor ce vor fi afiate n
modul grafic.
font reprezint tipul caracterelor. Tipurile caracterelor (fonturile) sunt definite n fiie re
cu extensia chr aflate n directorul bgi. n continuare dm tabelul cu constantele pentru diferite
fonturi:

Denumire constant
DEFAULT_FONT
TRIPLEX_FONT
SMALL_FONT
SANS_SERIF_FONT
GOTHIC_FONT

Valoare
constant
0
1
2
3
4

directie poate lua 2 valorile HORIZ_DIR, adic 0, respectiv VERT_DIR, adic 1. Acest
parametru d direcia de scriere (pe orizontal, sau pe vertical).
dim este o valoare ntreag reprezentnd dimensiunea caracterelor. 1 este dimensiunea
normal (8x8 pixeli), 2 este de dou ori mai mare (16x16 pixeli), 3 de trei ori mai mare (24x24
pixeli) etc.
30. Setarea modului de afiare al textului (aliniere pe orizontal i vertical) se face cu
ajutorul funciei settextjustify(o,v);
Modurile de aliniere pe orizontal sunt:
Denumire
constant
LEFT_TEXT
CENTER_TEXT
RIGHT_TEXT

Valoare
constant
0
1
2

Descriere
Aliniere la stnga
Text centrat
Aliniere la dreapta

Modurile de aliniere pe vertical:


Denumire
constant
BOTTOM_TEXT
CENTER_TEXT
TOP_TEXT

Valoare
constant
0
1
2

Descriere
Aliniere la stnga
Text centrat
Aliniere la dreapta

Exemplu. S se deplaseze folosind butoanele direcionale (sgeile) un text pe ecranul


monitorului.

83

# include <stdio.h>
# include <conio.h>
# include <graphics.h>
void main(void)
{
char c,s[50];
int x,y,pas=5,gd=DETECT,gm;
clrscr();
printf("Dati un text: ");
gets(s);
initgraph(&gd,&gm,"");
settextstyle(GOTHIC_FONT,0,2);
settextjustify(CENTER_LINE,CENTER_LINE);
setcolor(YELLOW);
x=getmaxx()/2;
y=getmaxy()/2;
do
{
outtextxy(x,y,s);
if (kbhit())
{
c=getch();
if (kbhit())
{
c=getch();
if (c==75) x-=pas;
if (c==77) x+=pas;
if (c==72) y-=pas;
if (c==80) y+=pas;
cleardevice();
}
}
}
while (c!=27);
closegraph();
}

U14.5. Instruciuni pentru desenare de figuri umplute


31. setfillstyle(model,c); seteaz modelul i culoarea de umplere ale figurilor pline.
Valorile posibile pentru parametrul model sunt:
Denumire constant
EMPTY_FILL
SOLID_FILL
LINE _FILL
LTSLASH_FILL
SLASH_FILL

Valoare
constant
0
1
2
3
4

Descriere
Fr umplere
Umplere uniform
Haur orizontal
Haur spre stnga cu linii subiri
Haur spre stnga cu linii groase
84

BKSLASH_FILL
LTBKSLASH_FILL
HATCH_FILL
XHATCH_FILL
INTERLEAVE_FILL
WIDE_DOT_FILL
CLOSE_DOR_FILL
USER_FILL

5
6
7
8
9
10
11
12

Haur spre dreapta cu linii subiri


Haur spre dreapta cu linii groase
Haur n cruce
Haur n cruce oblig
Haur cu intretesare
Umplere cu puncte rare
Umplere cu puncte dese
Model definit de utilizator

32. setfillpattern(model,culoare); poate defini un nou model de umplere, unde model


este un ir de 8 caractere, care definete o matrice 8 x 8 bii de valori 0 i 1.
Exemplu. Definirea urmtorului model de umplere.

------
-------------------------------

-> 11111111(in baza 2) = FF(in baza 16) = 255(in baza 10)


-> 10000001(in baza 2) = 81(in baza 16) = 129(in baza 10)
-> 10000010(in baza 2) = 82(in baza 16) = 130(in baza 10)
-> 10000100(in baza 2) = 84(in baza 16) = 132(in baza 10)
-> 10001000(in baza 2) = 88(in baza 16) = 136(in baza 10)
-> 10010000(in baza 2) = 90(in baza 16) = 144(in baza 10)
-> 10100000(in baza 2) = A0(in baza 16) = 160(in baza 10)
-> 11000000(in baza 2) = C0(in baza 16) = 192(in baza 10)

Observaie:

n exemplul de mai sus - reprezint spaiu, iar reprezint punct.


int culoare=YELLOW;
char model[8]={255,129,130,132,136,144,160,192};
setfillpattern(model,culoare);

33. bar(x1,y1,x2,y2); se deseneaz un dreptunghi umplut cu culoarea i modelul curente,


fr contur, avnd coordonate a dou vrfuri diametral opuse (x1,y1) i (x2,y2).
34. bar3d(x1,y1,x2,y2,a,c); se deseneaz o bar tridimensional avnd coordonate a
dou vrfuri diametral opuse (x1,y1) i (x2,y2). Parametrul a reprezint adncimea barei (n
pixeli), iar c specific dac bara are capac (cnd c este nenul) sau nu. Barele fr capac
pregtesc supraetajare (aplicarea altor bare deasupra).
Exemplu. Sa se genereze 100 de cifre n baza 10. S se reprezinte grafic
apariii al fiecrei cifre folosind bare 3D.
# include <stdio.h>
# include <stdlib.h>
# include <conio.h>
# include <process.h>
# include <graphics.h>
void main(void)
{
int m=500,i,maxx,maxy,gd=DETECT,gm;
char buff[10];
long n[10],max;
85

numrul de

randomize();
for (i=0;i<10;i++) n[i]=0;
for (i=0;i<m;i++) n[random(10)]++; // numarul cifrelor alese aleator
max=n[0];
for (i=1;i<10;i++)
if (n[i]>max) max=n[i];
initgraph(&gd,&gm,"");
setbkcolor(15);
cleardevice();
maxx=getmaxx()/10;
maxy=getmaxy();
setfillstyle(SLASH_FILL,RED);
setcolor(MAGENTA);
outtextxy(0,0,"Cu albastru deschis este numarul de");
outtextxy(4,10,"aparitii al cifrei scrise cu verde");
outtextxy(4,20," din cinci sute de incercari");
for (i=0;i<10;i++)
{
setcolor(BLUE);
bar3d(i*maxx+maxx/4,maxy-50,(i+1)*maxx-maxx/4
,maxy-50-(long)(maxy-80)*n[i]/max,10,1);
setcolor(CYAN);
sprintf(buff,"%d",n[i]);
outtextxy(i*maxx+maxx/2-4,maxy-30,buff);
setcolor(GREEN);
sprintf(buff,"%d",i);
outtextxy(i*maxx+maxx/2,maxy-10,buff);
}
getch(); closegraph();
}

n urma execuiei programului de mai sus, pe ecran se va afia:

86

35. fillpoly(n,p); deseneaz un poligon umplut avnd i contur cu culorile i modelele


curente, unde n este numrul de vrfuri al poligonului, iar n p se memoreaz coordonatele
vrfurilor, la fel ca la drawpoly. Spre deosebire de drawpoly, funcia fillpoly nchide poligonul.
36. fillellipse(x,y,rx,ry); deseneaz o elips umplut i cu contur, cu culorile i modelele
curente avnd centrul n (x,y) i razele rx i ry.
37. pieslice(x,y,u1,u2,r); se deseneaz interiorul i conturul unui sector de cerc de raza r
i de centru (x,y), ntre unghiurile u1 i u2 (bucat dintr-o plcint), cu culorile i modelele
curente.
Exemplu. Se citesc n valori ntregi de la tastatura. S se reprezinte grafic folosind
sectoare de cerc.
#include<math.h>
#include<stdio.h>
#include<conio.h>
#include<string.h>
#include<graphics.h>
#define R 230
#define PI 3.14159
int xc(float r,float u)
{
int i=r*cos(u);
return i;
}
87

int yc(float r,float u)


{
int i=r*sin(u);
return i;
}
void main(void)
{
int i,n,gd=DETECT,gm,dx,dy,suma,a[100];
float c1,c2,u,v;
char s[5];
clrscr();
printf("Dati numarul de valori: ");
scanf("%d",&n);
for (i=0;i<n;i++)
{
printf("Valoarea %2d: ",i+1);
scanf("%d",&a[i]);
}
initgraph(&gd,&gm,"");
dx=getmaxx()/2;
dy=getmaxy()/2;
suma=a[0];
for (i=1;i<n;i++)
suma=suma+a[i];
setcolor(0);
c2=0;
u=360./suma;
for (i=0;i<n-1;i++)
{
c1=c2;
c2=c1+u*a[i];
setfillstyle(1,15-i);
pieslice(dx,dy,(int)c1,(int)c2,R);
v=PI*(c1+c2)/360;
sprintf(s,"%d",a[i]);
outtextxy(dx+xc(2*R/3,v)-strlen(s)*4,getmaxy()-dy-yc(2*R/3,v),s);
}
c1=c2;
c2=c1+u*a[n-1];
setfillstyle(1,16-n);
pieslice(dx,dy,(int)c1,360,R);
v=PI*(c1+c2)/360;
sprintf(s,"%d",a[n-1]);
outtextxy(dx+xc(2*R/3,v)-strlen(s)*4,getmaxy()-dy-yc(2*R/3,v),s);
getch();
closegraph();
}

38. sector(x,y,u1,u2,rx,ry); deseneaz un sector de elips de raze rx i ry i de centru


(x,y), ntre unghiurile u1 i u2.

88

39. floodfill(x,y,c); umple folosind culoarea i modelul curente, interiorul unui contur
avnd culoarea c, umplerea pornindu-se din punctul de coordonate (x,y). Algoritmul de umplere
cu floodfill este foarte lent.
Exemplu. S se umple un contur aleator (aflat pe ecran) cu un model.
#include<math.h>
#include<stdio.h>
#include<conio.h>
#include<string.h>
#include<graphics.h>
#define R 230
#define PI 3.14159
int xc(float r,float u)
{
int i=r*cos(u); return i;
}
int yc(float r,float u)
{
int i=r*sin(u); return i;
}
void main(void)
{
int i,n,gd=DETECT,gm,dx,dy,suma,a[100];
float c1,c2,u,v;
char s[5];
clrscr();
printf("Dati numarul de valori: ");
scanf("%d",&n);
for (i=0;i<n;i++)
{
printf("Valoarea %2d: ",i+1);
scanf("%d",&a[i]);
}
initgraph(&gd,&gm,"");
cleardevice(); setcolor(BLUE);
dx=getmaxx()/2; dy=getmaxy()/2;
suma=a[0];
for (i=1;i<n;i++) suma=suma+a[i];
setbkcolor(15);
c2=0; u=360./suma;
for (i=0;i<n-1;i++)
{
c1=c2; c2=c1+u*a[i];
setfillstyle(1,15-i);
pieslice(dx,dy,(int)c1,(int)c2,R);
v=PI*(c1+c2)/360;
sprintf(s,"%d",a[i]);
outtextxy(dx+xc(2*R/3,v)-strlen(s)*4,getmaxy()-dy-yc(2*R/3,v),s);
}
89

c1=c2; c2=c1+u*a[n-1];
setfillstyle(1,16-n);
pieslice(dx,dy,(int)c1,360,R);
v=PI*(c1+c2)/360;
sprintf(s,"%d",a[n-1]);
outtextxy(dx+xc(2*R/3,v)-strlen(s)*4,getmaxy()-dy-yc(2*R/3,v),s);
getch(); closegraph();
}

n urma execuiei programului de mai sus, pe ecran se va afia:

U14.6. Instruciuni pentru paleta de culori


40. Citirea paletei de culori curente se face cu: getpalette(&pal);
Variabila pal este de tip structur de forma:
struct palettetype{
unsigned char size;
signed char colors[maxcolors+1];
};
41. Setarea paletei de culori se face cu funcia: setallpallete(&pal);
42. Modificarea unei singure culori din paleta se face cu: setpalette(c1,c2);. Culoarea c1
este nlocuit cu culoarea c2.

90

43. setrgbpalette(c,R,V,B); Culoarea din paleta cu codul c va avea nuana


obinut
prin combinarea culorilor: rou (de intensitate R) cu verde (de intensitate G) i cu albastru (de
intensitate B). n C, intensitatea unei culori primare (rou, verde sau albastru) poate lua valori
ntre 0 i 63 (de la negru pan la cea mai deschis culoare).
Exemplu. S se umple ecranul monitorului cu bare verticale n nuane degrade de gri
(griul se obine combinnd n aceeai msur cele trei culori rou, verde i al bastru).
# include <stdio.h>
# include <conio.h>
# include <graphics.h>
void main(void)
{
int i,l,gd=DETECT,gm;
struct palettetype pal;
initgraph(&gd,&gm,"");
getpalette(&pal);
// citirea paletei
for (i=0;i<pal.size;i++)
setrgbpalette(pal.colors[i],i*4,i*4,i*4); // setarea culorii i
l=getmaxx()/pal.size;
for (i=0;i<pal.size;i++)
{
setfillstyle(SOLID_FILL,i);
bar(i*l,0,(i+1)*l,getmaxy());
}
getch();
closegraph();
}

n urma execuiei programului de mai sus, pe ecran se va afia:

91

U14.7. Pagini grafice


Paginile grafice sunt zone distincte de memorie video. Dac avem n pagini video, atunci
acestea sunt numerotate 0, 1, , n-1.
Dac modul grafic accept mai multe pagini grafice (cum ar fi modurile VGAMED sau
VGALO), atunci pagina activ (cea pe care se deseneaz) poate fi separat de cea vizual (cea
care se vede). Este alocat cate o zon distinct de memorie video pentru fiecare pagin grafic.
Oricare pagin poate fi setat ca fiind activ sau (i) vizual, dar n orice moment exist o
singur pagin activ i o singur pagin vizual (cele dou pagini pot ns coincide). Printr-o
succesiune de interschimbri de pagini grafice putem realiza o animaie profesionist eliminnd
fenomenul de clipire al ecranului monitorului la curare i reafiare.
Dac dispunem de cel puin 2 pagini vizuale pentru animaie procedm astfel: desenm
pe una dintre pagini (cea activ), iar o alta pagin o lsm vizibil pe ecran. Cnd am terminat de
desenat pe pagina activ, o facem vizibil, iar fosta pagin vizibil devine activ, pe care
urmeaz s desenm urmtorul frame. Cnd aceasta este gata o facem vizibil etc.
Un frame reprezint o singur imagine din cele care compun animaia.
Dac imaginile ce compun animaia nu sunt foarte complicate, putem obine un numr de
pn la 80 frame-uri pe secund. O animaie este considerat bun dac avem minim 26 de
frame-uri pe secund (viteza obinuit de redare a unui film).
Setarea unei pagini ca fiind activ sau vizibil, se face cu ajutorul funciilor:
44. setactivepage(pag); seteaz pagina activ.
45. setvisualpage(pag); seteaz pagina vizual.
Exemplu. S se realizeze un joc n care n partea de jos a ecranului juctorul s deplaseze
stnga-dreapta o elips plin, iar sus s se mite aleator stnga-dreapta un dreptunghi umplut.
92

Juctorul poate trage asupra inamicului (dreptunghiul de sus), care la rndul su lanseaza
proiectile asupra elipsei. Se vor folosi pagini grafice.
# include <stdio.h>
# include <conio.h>
# include <graphics.h>
# include <process.h>
# include <stdlib.h>
# include <dos.h>
# define pas_inamic 5
# define pas_nava 10
# define pas_bomba1 10
# define pas_bomba2 5
# define l_nava 40
# define l_inamic 40
void ig()
{
int err,gd=VGA,gm=VGAMED;
initgraph(&gd,&gm,"");
err = graphresult();
if (err != grOk)
{
printf("Graphics error: %s\n", grapherrormsg(err));
getch(); exit(1);
}
}
int muta_inamic,x_inamic,y_inamic,x_bomba1,y_bomba1,x_bomba2,y_bomba2,
x_nava,y_nava,maxx,maxy,pag=0,scor=0,timp=5000,vieti=5;
void inv_pag()
{
setvisualpage(pag);
if (pag) pag=0;
else pag=1;
setactivepage(pag);
}
void afis_nava()
{
setfillstyle(SOLID_FILL,BLUE);
setcolor(BLUE);
fillellipse(x_nava+l_nava/2,y_nava,l_nava/2,10);
}
void afis_bomba1()
{
if (y_bomba1<y_nava)
{
if (y_bomba1>pas_bomba1)
{
y_bomba1-=pas_bomba1;
93

setcolor(CYAN);
circle(x_bomba1,y_bomba1,3);
}
else
{
if (x_bomba1>x_inamic && x_bomba1<x_inamic+l_inamic)
{
scor+=10;
sound(800);
delay(100);
nosound();
}
y_bomba1=y_nava;
}
}
}
void afis_bomba2()
{
if (y_bomba2==y_inamic && random(10)==0 && x_inamic<x_nava+l_nava*2
&& x_inamic>x_nava-l_nava)
{
y_bomba2=y_inamic+pas_inamic;
x_bomba2=x_inamic+l_inamic/2;
}
if (y_bomba2>y_inamic)
{
if (y_bomba2+pas_bomba2<y_nava)
{
y_bomba2+=pas_bomba2;
setcolor(GREEN);
circle(x_bomba2,y_bomba2,3);
}
else
{
if (x_bomba2>x_nava && x_bomba2<x_nava+l_nava)
{
vieti--;
sound(1000);
delay(200);
nosound();
}
y_bomba2=y_inamic;
}
}
}
void afis_inamic()
{
setfillstyle(SOLID_FILL,RED);
bar(x_inamic,y_inamic,x_inamic+l_inamic,y_inamic+10);
}

94

void afis_scor()
{
char s[10];
gcvt(scor,5,s);
setcolor(BLUE);
outtextxy(0,0,"Scor:");
outtextxy(50,0,s);
}
void afis_timp()
{
char s[10];
gcvt(timp,5,s);
setcolor(MAGENTA);
outtextxy(maxx-100,0,"Timp:");
outtextxy(maxx-50,0,s);
}
void afis_vieti()
{
char s[10];
gcvt(vieti,5,s);
setcolor(LIGHTBLUE) ;
outtextxy(maxx-100,10,"Vieti:");
outtextxy(maxx-40,10,s);
}
void main(void)
{
char c='~';
ig();randomize();
maxx=getmaxx(); maxy=getmaxy();
x_nava=maxx/2;
y_nava=maxy-pas_bomba1;
y_bomba1=y_nava;
x_inamic=random(maxx-l_inamic);
y_inamic=10;
y_bomba2=y_inamic;
setvisualpage(1); setactivepage(0);
while (c!=27 && timp>0 && vieti>0)
{
delay(1); setbkcolor(15); cleardevice(); delay(1);
afis_scor();
afis_timp();
afis_vieti();
afis_nava();
afis_inamic();
afis_bomba1();
afis_bomba2();
inv_pag();
muta_inamic=(random(5)-2)*pas_inamic;
if (x_inamic+muta_inamic<=maxx-l_inamic && x_inamic+muta_inamic>=0)
x_inamic+=muta_inamic;
95

timp--;
if (kbhit())
{
c=getch();
if (kbhit())
{
c=getch();
if (c==77 && x_nava+pas_nava<=maxx-l_nava) x_nava+=pas_nava;
if (c==75 && x_nava-pas_nava>=0) x_nava-=pas_nava;
}
if (c==13) getch();
if (c==' ' && y_bomba1==y_nava)
{
x_bomba1=x_nava+l_nava/2;
y_bomba1=y_nava-pas_bomba1;
}
}
}
if (c==27) vieti=0;
closegraph();
printf(" Scor:
%d\n",scor);
printf(" Bonus:
%d\n",vieti*10);
printf("----------------------\n");
printf(" Scor final: %d\n",scor+vieti*10);
getch();
}

Scena de desfurare a jocului este:

U14.8. Citire / scriere zon de memorie video

96

46. getimage(x1,y1,x2,y2,buf); Dreptunghiul cu vrful stnga-sus n (x1,y1) i vrful


dreapta-jos n (x2,y2) este citit de pe pagina activ i depus n bufferul buf. Primii 4 octei din
buf sunt rezervai pentru dimensiunile imaginii citite.
47. putimage(x,y,buf,m); Imaginea coninut n bufferul buf este depus pe pagina
activ aa nct colul stnga-sus s fie la coordonatele (x,y). Variabila m specific modul n care
se face afiarea. Modurile de copiere (pentru m) sunt:
Denumire constant
COPY_PUT
XOR_PUT
OR_PUT
AND_PUT
NOT_PUT

Valoare
constant
0
1
2
3
4

Descriere
suprapune peste imaginea existent
sau exclusiv ntre imagini
sau ntre imagini
i ntre imagini
copiaz inversul imaginii

Exemplu. S se simuleze micarea unei bile pe o mas de biliard care are aplicat un
anumit model (de exemplu gen tabl de ah). Se vor folosi dou pagini grafice, una pe care se
afl modelul mesei de biliard i cealalt va fi vizual. Micarea bilei se va realiza ntr-un ciclu
care conine urmtorii pai: cu ajutorul funciilor getimage i putimage se citete modelul de pe
pagina nevizual i se afieaz peste bil, iar bila se va afia la noile coordonate.
# include <stdio.h>
# include <conio.h>
# include <graphics.h>
# include <process.h>
# include <stdlib.h>
# include <dos.h>
# define r 5
# define r1 10
# define r2 8
void ig()
{
int err,gd=VGA,gm=VGAMED;
initgraph(&gd,&gm,"");
err = graphresult();
if (err != grOk)
{
printf("Graphics error: %s\n", grapherrormsg(err));
getch();
exit(1);
}
}
void afisfundal1(int cx1,int cy1,int cx2,int cy2)
{
int i,j,x1,y1,x2,y2;
x1=cx1/10;
x2=cx2/10;
y1=cy1/10;
y2=cy2/10;
for (i=x1;i<=x2;i++)
97

for (j=y1;j<=y2;j++)
{
if ((i+j)%2) setfillstyle(1,14);
else setfillstyle(1,LIGHTRED);
if (i==x1 || i==x2 || j==y1 || j==y2) setfillstyle(1,LIGHTCYAN);
bar(i*10,j*10,i*10+10,j*10+10);
}
}
void afistaste()
{
setcolor(BLUE);
setfillstyle(1,DARKGRAY);
bar(0,getmaxy()-45,145,getmaxy());
rectangle(0,getmaxy()-45,145,getmaxy());
setcolor(15);
outtextxy(8,getmaxy()-40,"+/- Viteza");
outtextxy(8,getmaxy()-30,"ENTER Pauza");
outtextxy(8,getmaxy()-20,"SPATIU Repornire");
outtextxy(8,getmaxy()-10,"ESC Exit");
}
void golbuff() { while (kbhit()) getch(); }
void main(void)
{
char a[1000],b[1000],c;
int i,dirx,diry,dx,dy,x,y,x1,y1,pauza=10,cx1,cx2,cy1,cy2,maxx,maxy;
randomize();
dirx=random(r*2+1)-r;
diry=random(r*2+1)-r;
if (dirx==0 && diry==0)
{
dirx=1;
diry=-1;
}
dx=abs(dirx);
dy=abs(diry);
ig();
setbkcolor(15);
cleardevice();
maxx=getmaxx()/2;
maxy=getmaxy()/2;
cx1=random(maxx-50);
cx2=maxx+50+random(maxx-50);
cy1=random(maxy-50);
cy2=maxy+50+random(maxy-50);
x=(cx1+cx2)/2;
y=(cy1+cy2)/2;
setactivepage(0);
setvisualpage(1);
afisfundal1(cx1,cy1,cx2,cy2);
setactivepage(1);
98

afistaste();
afisfundal1(cx1,cy1,cx2,cy2);
setcolor(1);
setfillstyle(1,1);
c='~';
while (c!=27)
{
if (kbhit())
{
c=getch();
if (c==13) getch();
if (c=='+' && pauza>0) pauza--;
if (c=='-' && pauza<50) pauza++;
if (c==' ')
{
pauza=10;
cx1=random(maxx-50);
cx2=maxx+50+random(maxx-50);
cy1=random(maxy-50);
cy2=maxy+50+random(maxy-50);
setactivepage(0);
afisfundal1(cx1,cy1,cx2,cy2);
setactivepage(1);
cleardevice();
afistaste();
afisfundal1(cx1,cy1,cx2,cy2);
setcolor(1);
setfillstyle(1,1);
x=(cx1+cx2)/2;
y=(cy1+cy2)/2;
}
golbuff();
}
setactivepage(0);
x1=x;
y1=y;
getimage(x-r1-dx,y-r2-dy,x+r1+dx,y+r2+dy,a);
x+=dirx;
y+=diry;
if (x>cx2-r1-2*dx || x<cx1+r1+2*dx)
{
dirx=-dirx;
sound(2000);
delay(7);
nosound();
}
if (y>cy2-r2-2*dy || y<cy1+r2+2*dy)
{
diry=-diry;
sound(2000); delay(7); nosound();
}
fillellipse(x,y,r1,r2);
getimage(x1-r1-dx,y1-r2-dy,x1+r1+dx,y1+r2+dy,b);
99

putimage(x1-r1-dx,y1-r2-dy,a,0);
setactivepage(1);
putimage(x1-r1-dx,y1-r2-dy,b,0);
delay(pauza);
}
closegraph();
}

U14.9. Ferestre grafice


48. Definirea unei ferestre grafice se face cu setviewport(x1,y1,x2,y2,m);
Efectul este asemntor cu instruciunea window din modul text. Afiarea se va face n
interiorul ferestrei cu captul stnga-sus n (x1,y1) i captul stnga-jos n (x2,y2). Dac m este
diferit de 0, atunci desenele ce depesc limitele ferestrei nu vor fi afiate. Dac m este 0, atunci
nu se va ine cont de fereastra definit.
49. Curarea ferestrei grafice definite anterior cu
clearviewport();

setviewport se face cu

Exemplu. Afiarea unui cerc care nu ncape ntr-un viewport.


#include <graphics.h>
#include <stdio.h>
#include <conio.h>
int main(void)
{
int gd=DETECT,gm,eroare;
initgraph(&gd,&gm,"");
setbkcolor(15);
cleardevice();
100

eroare=graphresult();
if (eroare!=grOk)
{
printf("Graphics error: %s\n", grapherrormsg(eroare));
getch(); return 1;
}
setcolor(BLUE);
rectangle(100,50,500,400);
setcolor(RED);
setviewport(100,50,500,400,1);
circle(150,170,200);
getch(); closegraph(); return 0;
}

Rezumat
Pentru a desena sub MS-DOS n Borland C trebuie intrat n modul grafic folosind funcia
initgraph. Pentru a se reveni n modul text se apeleaz funcia closegraph(). Antetele funciilor
de lucru n modul grafic se gsesc n fiierul antet graphics.h.

Teme
1. S se rescrie jocul prezentat ntr-unul dintre exemplele de mai sus aa nct aciunea s se
desfoare n interiorul unui viewport.
2. Folosind anexa 1 a acestui curs s se deplaseze nava din jocul de mai sus folosind mouse -ul.

101

ANEXA 1 - Folosirea mouse-ului sub DOS


Mediul de programare Borland C/C++ pentru DOS nu ofer faciliti directe de utilizare a
mouse-ului. Propunem n continuare cteva funcii pentru utilizarea mouse-lui att n modul text
ct i n modul grafic.
Scriei urmtorul cod ntr-un fiier cu numele mouse.h. Includei acest fiier de fiecare
dat cnd avei nevoie s scriei programe n care se folosete mouse -ul.
# include <dos.h>
# include <stdio.h>
typedef struct graphtype
{
char screenmask[16];
char cursormask[16];
int xactive,yactive;
}graphshapetype;
# define screenmask
{ \
0xFEFF,0xFEFF,0xFEFF,0xFEFF,0xFEFF,0xFEFF,0xFEFF,0x0001,\
0xFEFF,0xFEFF,0xFEFF,0xFEFF,0xFEFF,0xFEFF,0xFEFF,0xFeFF \
};
# define cursormask
{\
0x0100,0x0100,0x0100,0x0100,0x0100,0x0100,0x0100,0xFFFE,\
0x0100,0x0100,0x0100,0x0100,0x0100,0x0100,0x0100,0x0000 \
};
# define waitdoubleclick 300;
typedef struct ppe
{
char ofs,seg;
}ptrtype;
struct REGPACK r;
void
void
void
void
void
void
void
void
void
void
void
void
void
void

clicknumber(int *buttons,int *clicks,int *x,int *y);


defgraphlocator(graphshapetype shape);
defsensitivity(int deltax,int deltay);
deftextlocator(int styleflag,char scrmask,char cursmask);
defxrange(int xmin,int xmax);
defyrange(int ymin,int ymax);
getbuttonpress(int *button,int *n,int *x,int *y);
getbuttonrelease(int *button,int *n,int *x,int *y);
getmotion(int *deltax,int *deltay);
getmouse(int *button,int *x,int *y);
hidelocator();
resetmouse(int *foundmouse,int *buttons);
setdoublespeed(int speed);
setmouse(int x,int y);
102

void showlocator();
int foundmouse();
void resetmouse(int *foundmouse,int *buttons) // activeaza mouse-ul
{
r.r_ax = 0;
intr(0x33,&r);
*buttons=r.r_bx;
*foundmouse=(! r.r_ax==0);
}
void showlocator() // face sa apara cursorul mouse-lui
{
r.r_ax=1;
intr(0x33,&r);
}
void hidelocator() // ascunde cursorul mouse-lui
{
r.r_ax=2;
intr(0x33,&r);
}
void getmouse(int *button,int *x,int *y)
// returneaza pozitia mouse-lui
{
// si combinatia de butoane apasate
r.r_ax=3;
intr(0x33,&r);
*button=r.r_bx;
*x=r.r_cx;
*y=r.r_dx;
}
void setmouse(int x,int y) // pozitioneaza mouse-ul pe ecran la coordonatele (x,y)
{
r.r_ax=4;
r.r_cx=x;
r.r_dx=y;
intr(0x33,&r);
}
void getbuttonpress(int *button,int *n,int *x,int *y)
{
r.r_ax=5;
r.r_bx=*button;
intr(0x33,&r);
*button=r.r_ax;
*n=r.r_bx;
*x=r.r_cx;
*y=r.r_dx;
}
void getbuttonrelease(int *button,int *n,int *x,int *y) // returneaza butoanele apasate
{
103

r.r_ax=6;
r.r_bx=*button;
intr(0x33,&r);
*button=r.r_ax;
*n=r.r_bx;
*x=r.r_cx;
*y=r.r_dx;
}
void clicknumber(int *buttons,int *clicks,int *x,int *y) // returneaza nr. de click-uri
{
getmouse(buttons,x,y);
if (*buttons==1)
{
delay(300);
*buttons=0;
getbuttonpress(buttons,clicks,x,y) ;
}
else *clicks=0;
}
void defxrange(int xmin,int xmax)
// defineste limitele inferioare si
{
// superioare pe orizontala ecranului
r.r_ax=7;
r.r_cx=xmin;
r.r_dx=xmax;
intr(0x33,&r);
}
void defyrange(int ymin,int ymax)
// defineste limitele inferioare si
{
// superioare pe verticala ecranului
r.r_ax=8;
r.r_cx=ymin;
r.r_dx=ymax;
intr(0x33,&r);
}
void defgraphlocator() // defineste cursorul n modul grafic
{
r.r_ax=9;
r.r_bx=1;//activ x
r.r_cx=1;//activ y
r.r_dx=0xfe;
r.r_es=0x01;
intr(0x33,&r);
}
void deftextlocator(int styleflag,char scrmask,char cursmask) // defineste cursorul
{
// n modul text
r.r_ax=10;
if (styleflag) r.r_bx=0; else r.r_bx=1;
r.r_cx=scrmask;
r.r_dx=cursmask;
104

intr(0x33,&r);
}
void getmotion(int *deltax,int *deltay)
// returneaza pasul de miscare
{
// pe orizontala si pe verticala
r.r_ax=11;
intr(0x33,&r);
*deltax=r.r_cx;
*deltay=r.r_dx;
}
void defsensitivity(int deltax,int deltay) // defineste sensibilitatea la miscare
{
// pe orizontala si pe verticala
r.r_ax=15;
r.r_cx=deltax;
r.r_dx=deltay;
intr(0x33,&r);
}
void setdoublespeed(int speed)
{
r.r_ax=19;
r.r_dx=speed;
intr(0x33,&r);
}
Ca aplicaie la utilizarea mouse-ului n modul grafic propunem desenarea de cercuri,
ptrate i elipse la apsarea butoanelor stnga, dreapta, respectiv stnga mpreun cu dreapta
(simultan):
# include <conio.h>
# include <string.h>
# include <graphics.h>
# include "mouse.h" // includere fisier cu functiile pentru mouse de mai
sus
# define r 40 // dimensiune figuri (cercurri si patrate)
void main(void)
{
char s[10];
int gd=DETECT,gm,buton,x,y,dx,dy;
initgraph(&gd,&gm,"");
showlocator(); // face sa apara cursorul mouse-lui
do
{
getmouse(&buton,&x,&y);
// returnare buton si pozitie
mouse
getmotion(&dx,&dy);
// returnare valori deplasare
mouse
if (dx || dy)
// verificare daca s-a miscat
mouse-ul
{
105

setfillstyle(SOLID_FILL,RED);
setcolor(WHITE);
bar(0,0,56,10);
sprintf(s,"%3d/%3d",x,y);
outtextxy(1,2,s); // afisare pozitie cursor mouse
}
switch (buton)
{
case 1: // click buton stanga mouse
setcolor(YELLOW);
circle(x,y,r);
break;
case 2: // click buton dreapta mouse
setcolor(LIGHTCYAN);
rectangle(x-r,y-r,x+r,y+r);
break;
case 2: // click butoane stanga+dreapta mouse
setcolor(LIGHTGREEN);
ellipse(x,y,0,360,r,2*r);
break;
}
}
while (!kbhit());
getch(); closegraph();
}

Aplicaia pe care o propunem pentru utilizarea mouse-ului n modul text este afiarea
caracterelor x i o la apsarea butoanelor stnga, respectiv dreapta:
# include <conio.h>
# include <stdio.h>
# include "mouse.h" // includere fisier cu functiile pentru mouse de mai
sus
void main(void)
{
int buton,x,y,dx,dy;
textbackground(0); clrscr();
showlocator(); // face sa apara cursorul mouse-lui
do
{
getmouse(&buton,&x,&y);
// returnare buton si pozitie
mouse
getmotion(&dx,&dy);
// returnare valori deplasare
mouse
if (dx || dy)
// verificare daca s-a miscat
mouse-ul
{
textcolor(WHITE);
textbackground(RED);
gotoxy(1,1);
cprintf("%3d/%3d",x,y); // afisare pozitie cursor
mouse
106

}
switch (buton)
{
case 1: // click buton stanga mouse
textbackground(0);
textcolor(YELLOW);
gotoxy(x/8+1,y/8+1);
cprintf("o");
break;
case 2: // click buton dreapta mouse
textbackground(0);
textcolor(LIGHTCYAN);
gotoxy(x/8+1,y/8+1);
cprintf("x");
break;
}
}
while (!kbhit()); // cand se apasa buton de la tastatura se
paraseste programul
getch();
}

Observaie: Poziia mouse-lui n modul text este dat de ctre funcia getmouse tot n puncte
(ca i n modul grafic). Rezoluia ecranului n modul text obinuit co80 este 640x200. De aceea,
pentru a afla poziia mouse-lui n coordonate text, trebuie ca la poziia n puncte mprit la 8 s
se adauge 1. Astfel, obinem coordonatele text ale cursorului mouse-lui (X,Y) = (x/8+1,y/8+1).
Evident obinem c X{1, 2,,80} i Y{1, 2,, 25}, pornind de la coordonatele n puncte
(x,y) returnate de funcia getmouse, unde x {0, 8, 16, , 632} i y{0, 8, 16, , 192}.
Scriei un program C n care se citesc coordonatele vrfurilor unui poligon. Translatai i
rotii poligonul pe ecran cu ajutorul mouse-lui.

ANEXA 2 - Urmrirea execuiei unui program. Rulare pas cu pas.


Pentru a vedea efectiv traseul de execuie i modul n care se i modific variabilele
valorile ntr-un program, putem rula pas cu pas. Acest lucru se face n Borland C/C++ cu ajutorul
butoanelor F7 sau F8, iar n Visual C++ cu F10 sau F11, combinaii de taste care au ca efect
rularea liniei curente i trecerea la linia urmtoare de execuie.
Execuia programului pn se ajunge la o anumit linie se face apsnd pe linia
respectiv butonul F4 n Borland C/C++ i respectiv Ctrl+F10 sau Ctrl+F11 n Visual C++.
n Borland C/C++ pentru a fi posibil urmrirea execuia unui program, n meniul
Options, la Debugger, trebuie selectat On n Source Debugging ! n lipsa acestei setri, dac se
ncearc execuia pas cu pas, se afieaz mesajul de atenionare WARNING: No debug info.
Run anyway?. Este bine ca la Display Swapping (n fereastra Source Debugging) s se selecteze
opiunea Always, altfel fiind posibil alterarea afirii mediului de programare. Reafiarea
mediului de programare se poate face cu Repaint desktop din meniul . Este bine de tiut c
informaiile legate de urmrirea execuiei sunt scrise n codul executabil al programului ceea ce
duce la o ncrcare inutil a memoriei cnd se lanseaz n execuie aplicaia. Aa c programul,
dup ce a fost depanat i este terminat, este indicat s fie compilat i link-editat cu debugger-ul
dezactivat.
107

Pentru ca execuia programului s se ntrerup cnd se ajunge pe o anumit linie (break),


se apas pe linia respectiv Ctrl+F8 n Borland C/C++ i F9 n Visual C++. Linia va fi marcat
(de obicei cu rou). Pentru a anula un break se apas tot Ctrl+F8, respectiv F9 pe linia
respectiv.
Execuia pas cu pas a unui program poate fi oprit apsnd Ctrl+F2 n Borland C/C++ i
Shift+F5 n Visual C++.
Dac se dorete continuarea execuiei programului fr Debbuger, se poate apsa
Ctrl+F9 n Borland C/C++ i F5 n Visual C++.
n orice moment, n Borland C/C++ de sub DOS rezultatele afiate pe ecran pot fi
vizualizate cu ajutorul combinaiei de taste Alt+F5.
n Borland C/C++ valorile pe care le iau anumite variabile sau expresii pe parcursul
execuiei programului pot fi urmrite n fereastra Watch, pe care o putem deschide din meniul
Window. Adugarea unei variabile sau a unei expresii n Watch se face apsnd Ctrl+F7, sau
Insert n fereastra Watch. Dac se apas Enter pe o expresie sau variabil din fereastra Watch,
aceasta poate fi modificat.
n Visual C++ valoarea pe care o are o variabil pe parcursul urmririi execuiei unui
program poate fi aflat mutnd cursorul pe acea variabil. Urmrirea valorii unei expresii pe
parcursul rulrii programului pas cu pas se poate face din meniul Debug folosind comanda
QuickWatch. Adugarea unei expresii ntr-o list de urmrire se face apsnd butonul
AddWatch.

108

BIBLIOGRAFIE
1. A. Deaconu, Programarea n limbajele C/C++ i aplicaii, editura Albastr, Cluj-Napoca,
2007.
2. A. Deaconu, Programare avansat n C i C++, Editura Univ. Transilvania, Braov, 2003.
3. J. Bates, T. Tompkins, Utilizare Visual C++ 6, Editura Teora, 2000.
4. Nabajyoti Barkakati, Borland C++ 4. Ghidul programatorului, Editura Teora, 1997.
5. B. Stroustrup, The C++ Programming Language, a doua ediie, Addison-Wesley Publishing
Company, Reading, MA, 1991..
6. T. Faison, Borland C++ 3.1 Object-Oriented Programming, ediia a doua, Sams Publishing,
Carmel, IN, 1992.
7. R. Lafore, Turbo C++ - Getting Started, Borland International Inc., 1990.
8. R. Lafore, Turbo C++ - User Guide, Borland International Inc., 1990.
9. R. Lafore, Turbo C++ - Programmers Guide, Borland International Inc., 1990.
10. O. Catrina, I. Cojocaru, Turbo C++, ed. Teora, 1993.
11. M. A. Ellis, B. Stroustrup, The Annotatted C++ Referense Manual, Addison-Wesley
Publishing Company, Reading, MA, 1990.
12. S. C. Dewhurst, K. T. Stark, Programming in C++, Prentice Hall, Englewood Cliffs, NJ,
1989.
13. E. Keith Gorlen, M. Sanford, P. S. Plexico, Data Abstraction and Object-OrientedProgramming in C++, J. Wiley & Sons, Chichester, West Sussex, Anglia, 1990.
14. B. S. Lippman, C++ Primer, ediia a doua, Addison-Wesley, Reading, MA, 1991.
15. C. Spircu, I. Lopatan, Programarea Orientat spre Obiecte, ed. Teora.
16. M. Mullin, Object-Oriented Program Design with Examples n C++, Addison-Wesley,
Reading, MA, 1991.
17. I. Pohl, C++ for C Programmers, The Benjamin/Cummings Publishing Company. Redwood
City, CA, 1989.
18. T. Swan, Learning C++, Sams Publishing, Carmel, IN, 1992.
19. K. Weiskamp, B. Flaming, The Complete C++ Primer, Academic Press, Inc., San Diego,
CA, 1990.
20. J. D. Smith, Reusability & Software Construction: C & C++, John Wiley & Sons, Inc., New
York, 1990.
109

21. G. Booch, Object-Oriented Design with Applications, The Benjamin/Cummings Publishing


Company. Redwood City, CA, 1991.
22. B. Meyer, Object-Oriented Software Construction, Pretice Hall International (U.K.) Ltd.
Hertfordshire, Marea Britanie, 1988.
23. L. Pinson, R. S. Wiener, Applications of Object-Oriented Programming, Addison-Wesley
Publishing Company, Reading, MA, 1990.
24. J. Rambaugh, M. Blaha, W. Premerlani, F. Eddy, W. Lorensen, Object-Oriented Modelling
and Design, Prentice Hall, Englewood-Cliffs, NJ, 1991.
25. L. A. Winblad, S. D. Ewards, D. R. King, Object-Oriented Software, Addison-Wesley
Publishing Company, Reading, MA, 1990.
26. R. Wirfs-Brock, B. Wilkerson, L. Wiener, Designing Object-Oriented Software, Prentice
Hall, Englewood Cliffs, NJ, 1990.
27. D. Claude, Programmer en Turbo C++, Eyrolles, Paris, 1991.

110