PROGRAMARE PROCEDURAL
2009 - 2010
Cuvnt nainte
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
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
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.
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.
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"
define
define
define
define
N 100
PI 3.14159
suma(x,y) x+y
alipire(a,b) (a##b)
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.
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:
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 ?
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.
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
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.
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.
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.
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.
15
Introducere
Definiiile funciilor pentru scrierea i citirea datelor n limbajului C le gsim n fiierul
antet stdio.h.
caracter (char)
ir de caractere ncheiat cu caracterul \0 (string)
16
%d
%u
%ld
%lu
%x
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
---------------------------------------------------------------
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!");
1 */
2 */
n */
n+1 */
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.
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
23
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
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.
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
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]
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]);
}
}
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
34
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
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.
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).
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.
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
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
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.
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, ®, ®);
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
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
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.
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);
}
54
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
fseek(fis,0,SEEK_END);
return ftell(fis);
}
void main(void)
{
printf("Fisierul 'autoexec.bat' are %ld octeti.\n",
flung("c:\\autoexec.bat"));
getch();
}
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).
No such file or directory (nu exist fisierul numef sau este invalid)
Permission denied (nu exist drepturi de scriere).
57
# 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;
}
# 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
/*
/*
/*
/*
/*
/*
rezervat
*/
atribut fisier */
ora creare fisier */
data creare fisier */
lungime fisier */
nume fisier
*/
{
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).
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;
}
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;
}
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).
65
void main(void)
{
int i;
for (i=0;i<10;i++) fct();
}
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.
66
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.
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();
}
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.
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.
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
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
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.
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}
int gd=DETECT,gm;
initgraph(&gd,&gm,"c:\\bc\\bgi");
Valoare
constant
0
1
2
3
4
5
6
7
8
9
10
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
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
/* ........................... */
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();
}
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
78
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)
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();
}
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
Valoare
constant
0
1
2
Descriere
Aliniere la stnga
Text centrat
Aliniere la dreapta
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();
}
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
------
-------------------------------
Observaie:
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();
}
86
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();
}
90
91
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();
}
96
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();
}
setviewport se face cu
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
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.
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
110