Sunteți pe pagina 1din 218

Bogdan Ptru

Carmen Violeta Muraru

APLICAII
N
C i C + +

Editura EduSoft
Bacu - 2006

Copyright 2006 Editura EduSoft


Toate drepturile asupra prezentei ediii sunt rezervate Editurii EduSoft. Reproducerea
parial sau integral a coninutului, prin orice mijloc, fr acordul scris al Editurii
EduSoft este interzis i se va pedepsi conform legislaiei n vigoare.

Editura EduSoft
600065 Bacu, str. 9 Mai, nr. 82, sc. C, ap. 13
E-mail: contact@edusoft.ro, Web: www.edusoft.ro
Tel. 0234/206090, 0723 187198, 0741 638182
De aceiai autori la Editura EduSoft:

20 aplicatii in Delphi
si Visual Basic,
Bogdan Patrut,
ISBN 973-87655-3-6

Metode numerice.
Seminarii MATLAB,
Carmen Violeta Muraru,
ISBN 973-87655-4-4.

ISBN 973-8934-05-2
www.edusoft.ro
2

Introducere

Deviza acestei cri este: mai clar, mai simplu, mai multe exemple.
Cartea se dorete a fi un supliment la manualele de C/C++ existente pe
piaa romneasc a lucrrilor de informatic. Ea este o culegere de exerciii,
dar nu se limiteaz la nivelul acesta. Dup un capitol introductiv, care se
constituie ca un memento al limbajului C, fiecare capitol din urmtoarlee
cuprinde dou pri: una cu probleme rezolvate i una cu probleme propuse
spre rezolvare.
n prima parte a fiecrui capitol, cititorul este invitat s rezolve
mpreun cu autorul mai multe probleme, grupate n capitole ce urmresc, n
mare msur programa de liceu (clase de informatic). Problemele sunt
prezentate gradat i au rezolvrile ct mai scurte i, credem noi, mai clare,
fiind nsoite i de comentarii ce urmresc s pun n eviden unele aspecte
teoretice legate fie de elementele de limbaj folosite n respectivul program, fie
de algoritmul care st la baza rezolvrii problemei.
Unele dintre aceste comentarii i observaii sunt marcate cu unul din
simbolurile:
- reprezentnd observaii mai puin importante sau uor de reinut,
referitoare, de obicei, doar la subiectul tratat n respectivul exemplu;
- reprezint observaii mai importante, cu caracter de generalitate mai
mare, care se refer la elemente teoretice mai complexe i care ar fi indicat ca
cititorul s i le noteze.
Programele alese sunt foarte diferite ntre ele (algoritmi matematici,
operaii la nivel de bii, algoritmi recursivi, structuri de tip nregistrare, ordonare,
prelucrarea fiierelor, tehnici de programare, liste i arbori, bioritm, joc cu
strategie, clase de intervale), ns odat cu trecerea la un nou program se
introduc i se explic noi elemente ce in de limbajul C.
Toate aceste programe care rezolv problemele au fost scrise i rulate
pe un calculator PC, cu compilatorul Borland C++ 3.1. Astfel, majoritatea
exemplelor din lucrare, chiar dac sunt scrise n limbajul C standard (deci
neobiectual), folosesc un minim de faciliti aduse de limbajul C++, cum ar fi
comentariile cu simbolurile // i declararea variabileor simultan cu iniializarea
lor, n cadrul unor instruciuni repetitive.

Cea de a doua parte a fiecrui capitol cuprinde o serie de probleme


care se rezolv foarte asemntor celor rezolvate i au diferite grade de
dificultate, unele dintre ele au putnd fi folosite n concursuri de programare
pentru elevi i studeni. Cele opt capitole totalizeaz un numr de peste 400 de
probleme propuse.
Muli programatori nceptori consider dificil de nvat limbajul C. El
este un limbaj "greu" mai ales pentru cei care s-au obinuit s lucreze n
Pascal. Ei nu neleg adesea cum se evalueaz unele expresii sau aritmetica
pointerilor, precum i folosirea structurilor sau a fiierelor.
Prin problemele rezolvate prezentate n aceast lucrare, am dorit s
venim tocmai n ntmpinarea acelor programatori, care fac trecerea la limbajul
C, plecnd de la un alt limbaj de programare (Pascal, Basic, Fortran), fie c
acetia sunt elevi de liceu (crora cartea li se adreseaz cu precdere),
studeni, profesori de informatic sau chiar programatori experimentai, tuturor
celor care vor s ptrund cu uurin n minunata lume a puternicului limbaj
Borland C/C++.
Problemele propuse spre rezolvare vin n sprijinul elevilor i studenilor
informaticieni, dar i al profesorilor lor, care vor gsi n aceast lucrare o
bogat surs de exerciii i probleme ce pot fi rezolvate la tabl, n clas, sau
se pot constitui n teme pentru acas. De aceea am inclus un capitol special cu
probleme recapitulative.
Cu sperana c parcurgnd atent aceast carte, cititorii vor privi cu ochi
mai prietenoi limbajul C, le dorim lectur plcut i... compilare rapid i fr
erori!
Autorii

Capitolul 0. Scurt introducere n limbajul C


Limbajul C a fost dezvoltat la nceputul anilor 1970 de Ken Thompson i
Dennis Ritchie, care aveau nevoie de un limbaj simplu i portabil pentru
scrierea nucleului sistemului de operare Unix. Este implementat pe marea
majoritate a platformelor de calcul existente azi, i este cel mai popular limbaj
de programare pentru scrierea de software de sistem.
Identificatori
In C numele de variabile, constante, tipuri de date definite de utilizator, functii,
etc sunt denumite identificatori. Acetia sunt succesiuni de litere sau cifre, n
care primul caracter sa nu fie cifr.
Constantele
Sunt valori care nu se modific pe parcusrsul programului. Daca li se asociaz
un identificator, ele pot fi referite apoi pe parcursul programului cu acest
identificator
Exemplu
Const int a=10 ;
Utilizarea calificatorului const din declaraie certific faptul c valoarea
respectiv nu poate fi modificat de ctre program.
Tipuri de date: reprezint o mulime omogene de date. Tipul de date se
identific printr-un identificator, plaj de valori ataat tipului. Toate datele
dintr-un anume tip sunt reprezentate intern, n memoria calculatorului, n
acelai mod. In C tipurile de date pot fi predefinite (de baza) si definite de
utilizator (derivate). Un tip de date este caracterizat de dimensiunea zonei de
memorie alocate unui element.Dimensiunea i domeniul de valori ale acstor
tipuri de date pot varia insa de la un procesor la altul. Totui ntotdeauana un
caracter echivaleaz cu un octet.
Tipul
char,
unsigned char
short,
unsigned short
int,
unsigned int

Intervalul
[-128, 128]
[0, 255]
[-32768, 32767]
[0, 65535]
[-32768, 32767]
[0, 65535]
5

Numar de octeti
1
2
2

long,
unsigned long
float
double
long double

[-2147483648,2147483647]
[0, 429467259]
Valoarea absoluta in
[3,4*10-38, 3.4*1038]
Valoarea absoluta in
[1.7*10-308, 1.7*10308]
Valoarea absoluta in
[3.4*10-4932, 1.1*104932]

4
4
8
10

Tabel 1
Variabilele sunt caracterizate de elementele: nume, adresa de memorie, un tip
de date i valoarea. Locaia de memorie (adresa), stocheaz valoarea
variabilei la un moment dat. Prin urmare variabilele sunt date care i pot
modifica valoarea pe parcursul execuiei programului. Toate variabilele dintr-un
program trebuie declarate nainte. Iniializarea variabilei se poate face simultan
cu declararea sa. Forma general a unei declaraii este :
Tip lista _variabile ;
Dac avei mai multe variabile de acelai tip ele pot fi declarate, niruind
numelor lor separate de virgul n dreptul tipului de baz, pe aceeai linie.
Exemplu :
int a, b ;
int m=1 ;
char c ;
float x, y=5 ;
Variabilele locale
Variabilele declarate n interiorul unor funcii sunt numite variabile locale.
Aceste variabile n C, se mai numesc i variabile automate. Aceste variabile nu
vor fi recunoscute n afara blocului funciei.
Exemplu : void functie_1(void)
{
int x,y ;
x=10 ;
y=x+3 ;
}
void functie_2(void)
{
int x ;
x=-123 ;
}
6

De remarcat c variabila x, declarat n funcie_1 nu are nici o legatur cu


variabila x din funcie_2. In C avem posibilitatea s declaram variabilele nu
numai imediat dup acolada, ci i n interiorul blocului funciei.
void f (void)
{
int s ;}
Un avantaj al declararii unei variabile locale n interiorul unui bloc este ca
memoria pentru variabila va fi alocat numai dac e necesar. Variabilele locale
sunt create la fiecare inteare n blocul funciei i distruse la ieirea din el.
Observaie Limbajul C face diferena dintre dintre literele misi i cele mari.
Inserarea de comentarii
Uneori pentru o mai bun inelegere a programului, putem aduga acestuia
comentarii.
Comentariile se insereaz n program n dou moduri. Prima posibilitate este
s inserai caracterele slash //, naintea textului vostru.
// Acesta este un comentariu
A alt posibilitate este s scriei textul ntre caractere slash i asteriscuri, astfel
/* Acesta este un comentariu*/
La ntlnirea simbolurilor pentru inserarea comentariilor, compilatorul ignor
aceste mesaje, ele avnd importan doar pentru programator.
Parametrii formali
Intr-o funcie care folosete argumente trebuie declarate variabilele care
accept valorile argumentelor, variabile numite parametrii formali ai funciei

Observaie
Parametrii formali declarai trebuie s fie de acelasi tip cu argumentele folosite
la apelarea funciei. Un parametru este o valoare transmis unei functii. Cele
mai multe dintre programe transmit parametri ctre funcia printf:
printf (valoarea este %d\n, rezultat);
Exemplu
void info_angajat (int varsta, float salariu, int nr_marca).
{
// instruciunile funciei;
7

}
Variabilele vrst, salariu, nr_marca, reprezint parametrii formali ai funciei
info_angajat
Parametrii formali se aloca pe stiv ca i variabilele automatice. De aceea, ei
se consider a fi variabile locale i sunt utilizabili numai n corpul funciei n
antetul creia sunt declarati.
La apelul unei functii, se aloca pe stiva parametri formali, daca exista, li se
atribuie valorile parametrilor efectivi care le corespund. Apoi se aloc pe stiva
variabilele automatice declarate la nceputul corpului funciei respective.
La revenirea din funcie, se realizeaza curtirea stivei, adic sunt eliminate de
pe stiv (dezalocate) att variabilele automatice, ct i parametrii. In felul
acesta, la revenirea din funcie, stiva ajunge la starea dinaintea apelului.
Variabile globale
Spre deosebire de cele locale, acestea sunt recunoscute de ctre toate
componentele programului.
Observaie Dac o variabil local i una globala au acelai nume, trimiterile la
numele acelei variabile din interiorul blocului de cod n care a fost declarat
variabila local se vor referi numai la variabila local i nu vor afecta variabila
global. Zona de alocare a memoriei pentru variabilele locale este o regiune
fix de memorie, special destinat n acest scop de ctre compilatorul de C.
Variabilele globale sunt utile cnd un numar mare de funcii din programul dvoastra folosesc aceleai date. In schimb variabilele globale inutile vor ocupa
spaiu de memorie pe toat durata execuiei programului.
Expresii
Expresiile sunt formate din unul sau mai multi operanzi i operatori. Un
operand poate fi o constant, numele unei variabile, numele unei structuri,
numele unei funcii sau chiar o expresie ntre paranteze rotunde.
Prioritatea operatorilor este cea care determin ordinea de efectuare a
operaiilor. In C se definesc urmatorii operatori: aritmetici, relaionali, logici i
pe bii.
In funcie de aceasta avem urmtoarea grupare a operatorilor:
Operatorul de atribuire se folosete n interiorul oricrei expresii valide n C.
Forma general a acestui operator este:
nume_variabila=expresie
Observaie
8

Cnd variabilele de un tip sunt combinate cu variabile de alt tip se produce o


conversie de tip. Regula acestei conversii este ca valoarea membrului drept
(expresia), este convertit la tipul membrului stng.
Operatorii de incrementare i decrementare
Operatorii de incrementare ++ i decrementare sunt doi operatori utili ce n
general nu mai apar n alte limbaje de programare. Operatorul de incrementare
adaug o unitate la operand, iar cel de decrementare scade o unitate.
Exemplu :
x=x+1 este echivalent cu ++x ;
i
x=x-1 este echivalent cu x-- ;
Cei doi operatori pot precede sau urma operandului, existnd diferene ntre
cele dou forme.
Exemplu
a=2 ;
b=++a ;
stabilete valoarea lui b la 3 ;
a=2 ;
b=a++ ;
stabilete valoarea lui b la 2.
Operatorii de pointer & si *
Pointer-ul este adresa de memorie a unei variabile. Operatorul de pointer &
este un operator unar care returneaz operandului su adresa de memorie.
Exemplu
a=&num ;
unde n a se va plasa adresa variabilei num, adresa care reprezint doar
localizarea intern a variabilei i nu are legatur cu valoarei ei.
Operatorul * este complementul operatorului adresa i calculeaz valoarea
variabilei localizate la adresa ce urmeaz.
m=*a, unde a este adresa variabilei num.
Variabilele care memoreaz adrese ( pointeri ) trebuie declarate cu simbolul *
naintea numelui variabilei.
Astfel n exemplul char *ch, ch nu este o variabil caracter ci un pointer la
caracter.
Operatorul modulo
In cazul n care v intereseaz restul unei mpriri, limbajul C v ofer
operatorul modulo (rest)- %

Exemplu
# include <stdio.h>
void main (void)
{
int rest;
rest =110%3;
printf (110 mparit la 3 d restul %d\n, rest);
}
Orice program n C are urmtoarea structur:
-

directive de procesare

declaraii globale de variabile i funcii;

- definiii de funcii ;
Orice program n C poate fi mprit pe mai multe seciuni. Pentru a asocoa
anumite instruciuni unei seciuni, se includ acele instruciuni ntre acolade ({}).
Aceste acolade fac parte din sintaxa limbajului. Orice acolad deschis trebuie
s aveti i una nchis.
Prepocesarea
Inainte de a fi compilat, un program poate fi prelucrat (prepocesat). Utilizatorii
limbajului C si C++ pot folosi o serie de funcii aflate n bibliotecile standard ale
acestor limbaje. Prototipurile acestor functii se gsesc in fiiere header (.h).
Una din directivele de prepocesare este #define, folosit pentru includerea
unui fiier header poate avea una din formele :
# include specificator_de_fiier
# include <specificator_de_fisier>
Modul de ncadrare a numelui fiierului controleaz modul de cautare a
fiierului indicat : , cutarea se face mai nti n directorul curent i apoi n
cele standard pentru include i <>, cutarea se face doar n directoarele
standard.
Dac nu ai inclus intr-un program fiierul surs de care programul are nevoie,
compilatorul va afia un mesaj de eroare de forma :
Warning...Function printf should have aprototype in function main().
Limbajul C pune la dispoziia utilizatorului funcii pentru prelucrarea datelor,
grupate n biblioteci.
- stdio.h si io.h pentru citire/scriere
- conio.h pentru interfata cu consola
- graphics.h pentru interfata grafica
- ctype.h pentru prelucrarea caracterelor
10

- stdlib.h si math.h pentru prelucrari numerice


- dos.h pentru interfaa cu sistemul de operare DOS
Exemplu :
# include <stdio.h>
Directiva #define definete o macrocomand ce inseamn definirea unui
simbol care nlocuiete o poriune de cod C. In momentul preprocesarii, fiecare
apariie a numelui macrocomenzii va fi nlocuita cu definiia sa.
Exemplu :
# define nume succesiune_de_caractere
# define PI 3.14159
Ca urmare PI va fi nlocuit cu valoarea specificat mai sus, pn la sfritul
codului de program.
# define XY acesta este un test
Astfel XY se va inlocui acolo unde se intalneste cu sirul de caractere acesta
este un test . Foarte util este reprezentarea macrocomenzilor de tip funcie.
Exemplu
# define Abs (a) (a)<0 ? (a) :( a)
E interesant de observat c numele macrocomenzii poate avea argumente.
S definim macrocomenzile pentru ptrat i cub :
# define ptrat(x) ((x)* (x))
# define cub(x) ((x)*(x)*(x))
O alt categorie de directive o reprezint cele condiionale. In aceast
categorie avem : #if, #ifndef, #else, #elif si #endif ce controleaz care pri ale
fiierului surs vor fi compilate i n ce condiii.
Functii de intrare-ieire formatat
In C, funciile care pot scrie i citi date n diferite formate stabilite de programator
sunt funciile printf () i respectiv scanf ().
Funcia de scriere cu format printf ()
Funcia realizeaz afiarea datelor n consol , folosind specificatorii de format
ce indic modul n care vor fi afiate argumentele care urmeaz. Un specificator
de format ncepe cu simbolul % i este urmat de codul formatului.
Prototipul funciei este :
printf (const char *format [, lista argumente]) ;
Numrul de argumente trebuie s fie egal cu cel al specificatorilor de format.
Aceast funcie se afl n STDIO.H, biblioteca funciilor de intrare-ieire.
Funcia printf () accept o gam larg de specificatori de format:

11

cod
%d
%i
%o
%x
%u
%e
%E
%f
%g
%G
%c
%s

Format
intreg in baza 10 cu semn
intreg in baza 8,10 sau 16 cu semn
octal fara semn
hexazecimal fara semn (litere mici)
intreg fara semn
Numar real de forma iii.zzzzzz (numarul implicit de
zecimale 6)
numar real de forma i.zzzzzz (nr de zecimale
implicit 6)
nr. real ce suprima caracterele terminale ce nu
influenteaza valoarea, adica cifre de zero
caracter
sir de caractere
Tabel 2

Observaii:
Pentru a genera la ieire o valoare fr semn se folosete %u. Specificatorul de
format %f afieaz numr n virgul mobil, iar specificatorii %e si %E pentru
argumente n format double.
Exemplu
1. printf ( Acesta este un %s, test.);
afiseaza pe ecran
Acesta este un test.
2. # include <stdio.h>
void main (void)
{
int x;
for (x=1;x<10;x++)
printf (%d, x)
}
Programul afiseaz pe ecran secvena de numere:
1, 2, 3, 4, 5, 6, 7, 8, 9
3. # include <stdio.h>
void main (void)
{
int a,b;
12

..
printf (suma numerelor este %d, a+b );
}
Programul va afia suma numerelor a i b introduse de la tastatur.
Funcia printf ( ) se folosete dealtfel i pentru afiarea de mesaje.
printf ( Acesta este un test \n ) ;

Modificatori de format
Modificatorul de format se nsereaza ntre simbolul procentului i codul
formatului, specificnd limea minim a cmpului, numrul de cifre dup virgul
sau alinierea la stnga.
Specificatorul limii minime de cmp este un ntreg plasat ntre simbolul
procentului i codul formatului, indicnd numrul minim de spaii pe care se
afieaz numrul.Dac irul sau numrul este mai lung dect minimum, va fi
afiat n ntregime.
Exemplu
. # include <stdio.h>
void main (void)
{ double a ;
a=10.3456 ;
printf ( %f \n , a) ;
printf ( %10f\n ,a) ;
printf ( %012f\m ,a) ;
}
Programul va afia :
10.345600
- adaug doua zerouri pna la 6, valoarea implicit a numrului
de zecimale
10.345600 -cmpul minim pe care se tiparete numrul este de 10 spaii
00010.345600
- se adaug zerouri n faa pn se completeaz cu
dimensiunea cmpului minim
Directivele de formatare pot avea opional i alte componente :
% fanion dimensiune. specificator de precizie
Fanioane pentru functia printf(), cu exceptia lui * (pt scanf)
- : aliniaza valoarea la stanga intr-un camp de dimensiune data
+ : pune +ianintea unui numar pozitiv de tip cu semn
spatiu : pune spatiu inainte de un numar pozitiv de tip cu semn

13

Specificatorul de precizie
Acest specificator urmeaz specificatorului limii minime de cmp (cnd acesta
exist). Se reprezint printr-un ntreg precedat de un punct. Dac se aplic
numerelor reale , acesta specific numrul de zecimale cu care va fi afiat
numrul. De exemplu %9.3f afieaz un numr de cel puin 9 caractere avnd 3
cifre dup virgul.
Exemple de scriere formatat
printf ( %f\n ,1.0) ; /* 1.000000 : 6 cifre zecimale
printf ( %.2f\n ,1.009) : /*1.01 : 2 cifre zecimale
printf ( %e\n ,1.0) ; /* 1.000000+00e+00 : 6 cifre zecimale
Scriere de numere ntregi n form de tabel :
printf ( |%6d| , -12) ; /* | -12| */
printf ( |%-6d| , -12) ; /* |-12 | */
printf ( |%+6d| , -12) ; /* | +12| */
printf ( |%06d| , -12) ; /* |-00012| */
Cnd se dorete ca printf() s nceap afiarea pe o linie nou, trebuie s
includeti un caracter special, linie nou (\n), n interiorul textului pe care printf
urmeaz s-l afieze. Astfel la ntlnirea tabulatorului, printf va avansa cursorul
la linia urmatoare.
Exemplu
# include <stdio.h>
void main (void)
{
printf ( Aceasta este linia unu \n);
printf ( Aceasta este linia a doua);
}
Funcia de citire cu format scanf ()
Cu ajutorul acestei funcii se face introducerea datelor de la tastatur.
Prototipul aceste funcii este :
scanf ( const char *format [, lista_adrese_variabile])
i o gsim tot n biblioteca de funcii STDIO.H. Constantele format le gsim n
Tabelul 2 pentru diferite tipuri de date. Funcia citete o secven de argumente
de intrare, caracter cu caracter pn la terminarea irului de argumente sau
pn la apsarea tastei Enter.
De exemplu, pentru citirea unei linii de forma:
3, 4, 5
se va scrie urmatoarea secven:
int a, b, c;
scanf ("%d %d %d", &a, &b,, &c);

14

Observaii
Toate variabilele folosite pentru a primi valori cu functia scanf (), se transmit
utiliznd adresele acestora, aa cum s-a vazut i n exemplul de mai sus.
Funcii pentru citirea i afiarea caracterelor
Cele mai simple funcii pentru citirea si afiarea caracterelor la consol sunt
getchar(), care citete un caracter de la tastatur i putchar(), care scrie un
caracter pe ecran. Funcia getchar () ateapt apsarea unei taste i apoi
returneaz valoarea Ascii a acesteia. Tasta apsat se va scrie pe ecran. Forma
celor doua funcii :
int getchar (void);
int putchar (int c);
Aceste funcii se gsesc n fiierul antet STDIO.H
Urmtorul cod de program va citi i va afia caractere pn la caracterul linie
nou:
do
{ litera=getchar () ;
putchar (litera);
}
while (litera !=\n);
La funcia getchar() exist i funcii alternative, dou dintre cele mai folosite
sunt : getch() si gerche(). Prototipurile acestor funcii sunt :
int getch (void) ;
int getche (void);
i pot fi gsite n fiierul CONIO.H.
Cele dou funcii asteapt apsarea unei taste, dup care returneaz imediat.
Deosebirea e c la getch() caracterul nu apare pe ecran pe cnd la geche() el
se tiprete pe ecran.
Exemplu :
# include <stdio.h>
# include <ctype.h>
# include <conio.h>
void main (void)
{
int litera ;
do
{ litera=getche () ;
litera =toupper (litera) ;
}
while (litera !=A) ;
15

Programul de mai sus citete caractere de la tastatur utiliznd citirea direct.


Se introduc litere pn la tastarea lui A, litere ce sunt transformate in
majuscul.
Funcii
O funcie are o definiie i attea apeluri ntr-un program, cte sunt necesare.
O definiie de funcie are formatul:
1. antet
2. corp
tip nume (lista declaraiilor parametrilor formali)// antet
{declaratii de variabile locale
instruciuni terminate cu ;
}
O funcie poate folosi sau nu parametrii. Un parametru este o informaie pe
care programul o transmite funciei [K. Jamsa]. Dac nu se folosesc
parametri atunci dup numele funciei trebuie s plasai ntre paranteze
cuvntul void. Utilizarea unei funtii n program se numete defapt apel de
funcie. Orice program n C conine o funcie principal, main, n care sunt
apelate celelalte funii ale programului, dac ele exist.
Exemplu
# include <stdio.h>
void main (void)
{
lista_instruciuni urmate de ;
}
Apelul unei funcii trebuie s fie precedat de definiia sau de prototipul ei.
El poate avea acelai format ca i antetul funciei, n plus este urmat de punct
i virgul.
Prototipul unei funcii conine informaii asemntoare cu cele din antetul ei:
1. tipul valorii returnate;
2. numele functiei;
3. tipurile parametrilor.
Tip- tipul valorii returnate de funcie (implicit este ntreg). Pentru cele care nu
returneaz nimic tipul este void. Funciile care nu returneaz nimic sunt
16

echivalentul procedurilor din Pascal. Lista declaraiilor parametrilor formali,


separatai prin virgule trebuie specificai cu numele i tipul lor. Aceast list n
anumite condiii poate fi vid.
Exemplu
void f (void)
int g ()
main ()
Parametrii utilizai la apel se unesc parametri actuali sau efectivi. Transmisia
parametrilor se face prin valoare. Folosind apelul prin valoare , modificrile
parametrilor funciei vor exista doar n cadrul funciei apelate. Astfel la sfritul
execuiei funciei, valorile variabileor transmise de program funciei rmn
nemodificate.
Orice program n C conine o funcie principal ce conine instruciunile care se
execut ct i apelurile de alte funcii care apar ntr-un program.
Observaie
1. Toate funciile care returneaz valori trebuie s conin instruciunea
return.. Dac nu exist nici o instruciune return, atunci valoarea
returnat a funciei este nedefinit din punct de vedere tehnic.
2. Parametrii actuali s corespund cu cei formali prin ordine i tip
3. La apel se atribuie parametrilor formali valorile parametrilor actuali, apoi
execuia se continu cu prima instructiune a funciei apelate.

Exemplu de funcie cu return


int a_patrat ( int valoare)
{
return (valoare*valoare);
}
S scriem acum codul funciei principale n care se face apelul funciei de mai
sus pentru o anumit valoare.
# include <stdio.h>
int a_patrat ( int valoare)
{
return (valoare*valoare);
void main (void )
{
printf ( Ptratul lui 4 este %d\n , a_patrat(4)) ;
}
17

Comentariile ncep cu secvena de caractere /* i se termin cu */. Ele sunt


ignorate de compilator.
Instruciuni n C
In C instruciunile sunt grupate n cteva categorii:
-

selecie

iteraie

salt

expresie

eticheta

bloc

Instruciunile de selecie (decizie)


Valorile de adevr i fals sunt date de expresiile condiionale. In C, o valoare
de adevr nseamn orice valoare diferit de zero, inclusiv numere negative.
O valoare fals, nseamn o valoare de zero.
Avem dou instruciuni de selecie n C : if i switch. Mai exist un operator n
C care uneori poate constitui o alternativ la if.
Exemplu :
min=(a<b) ?a :b
Instruciunea if (dac)
Forma acestei instructiuni este :
if (expresie) instructiune ;
else instructiune ;
Instruciunea ramific programul n doua n urma evalurii unei expresii logice .
Componenta else este opional. Dac valoarea expresiei este adevarat se
execut instruciunea de dup if ; dac nu, se va executa intructiunea de dup
else dar niciodat amndou.
Testarea unei egaliti se realizeaz tot cu ajutorul instruciunii if, utiliznd
semnul egal dublu (==). De remarcat c un singur egal se utilizeaz doar la
instruciunea de atribuire.
if (a== 0)
instruciune
18

Observaie
Limbajul C nu opereaz cu tipul boolean, valorile de adevr fiind codificate
numeric, dup urmtoarea regul: o valoare nul este echivalent cu fals iar o
valoare nenul cu adevrat.
Exemplu
Determin minimul a doua numere:
int a,b ;
if (a<b) min=a;
else min=b;
O variant pentru instruciunea if este operatorul
ternar ?, care are
urmtoarea form general:
exp1? exp2: exp3
Valoarea unei expresii ? se determin astfel: se evalueaz exp1. Dac
aceast este adevarat, atunci se evalueaz i exp2, care devine valoarea
ntregii expresii. Pentru exp1 fals, atunci se evalueaz exp3 i valoarea ei
devine valoarea ntregii expresii.
Astfel codul :
x=3 ;
y=x>2 ? 30 :200
este echivalent cu instructiunea if :
x=3;
if (x>2) y=30;
else y=200
In cazul n care avem mai multe ci de decizie, vom folosi structuri if imbricate:
Exemplu
if (x<0) e=x*x;
else if (x= =0) e=5.0;
else e=x+4;
Se observ c in C nu e greit s punem ; naintea lui else, aa cum eram
obinuii n Pascal.
Instruciunea switch
Este o instruciune de decizie multipl i are urmtoarea sintax:
switch (expresie)
{ case const_1 : instruciune_1 ;[break ;]
case const_2 : instruciune_2 ;[break ;]
...................
case const_n : instruciune_n ;[break ;]
[default: secvena]
}
Se compar valoarea expresiei cu fiecare din valorile constantelor exprimate
n instruciunile case. Cnd se descoper o egalitate, secvena de instructiuni
19

asociat acelei instruciuni case se execut pn la instruciunea break sau


pn la sfritul instruciunii switch. Intruciunea default se execut cnd nu
se gsete nici o egalitate. Instruciunile break si default sunt facultative.
Observatii
1. Instruciunea switch spre deosebire de if , efectueaz doar teste de
egalitate, n timp ce if poate evalua orice expresie de tip relaional sau logic.
2. Instructiunea switch se folosete cu succces n cazul prelucrrii
comenzilor provenite de la tastatura, cum ar fi selecia meniurilor.
Exemplu
switch (op){
case '*' : nmulete(a, b);
break;
case '+' : adun(a, b);
break;
case '-' : scade(a, b);
break;
default : printf("eroare");}

Instruciuni de ciclare
Instruciunea for
Este o instructiune repetitiv cu numr cunoscui de pai.
Are urmtoarea form general :
for (iniializare ;condiie ; increment)
Pe lnga aceste forme mai exist i alte variaii n functie de contextul
problemei.
Iniializarea este n general o instruciune de atribuire care stabilete valoarea
de nceput a contorului ciclului. Condiia este o expresie relaional care
determin cnd se ncheie ciclul. Incrementul definete regula de modificare a
variabilei contor pe parcursul buclei.
Instruciunea for se execut atta timp ct condiie este adevarat. Cnd
aceasta devine fals programul continu cu instruciunea imediat urmtoare lui
for.
Variaiile instruciunii for rezult din ideea c nu este necesar existena
tuturor celor trei elemente ale buclei for, prezentate mai sus.
Exemplu
for (x=1 ; x !=100 ; )
scanf( %d , &x)
Se observ inexistena zonei rezervate increment . Aceasta nseamn c la
fiecare rulare a cilclului x este comparat cu 100 i atta timp ct nu gsete
20

egalitate se reia bucla. Dac se introduce ns 100 de la tastatura se ncheie


execuia buclei i programul continu cu instruciunea de citire a variabilei.
Exist situaii cnd variabila contor se iniializeaz n afara instruciunii for i
atunci initializare poate lipsi. Astfel :
Exemplu
i=0 ;
for ( ; i<100 ;i++)
Se observ n ambele cazuri ca semnul ; nu lipsete din sintaxa chiar dac
unele elemente lipsesc.
Deasemenea cu ajutorul unei variaii a ciclului for se poate exprima un ciclu
infinit astfel :
for ( ; ; )
Exemplu :
for ( ; ;)
{ ch=getchar() ;/* scrie un caracter
if (ch = =A) break ; /*se ncheie ciclul
}
Ciclul de mai sus se va executa pn cnd se va tasta un A de la tastatura.
Instruciunea break va determina ncheierea imediat a instruciunii for, n
acest caz.
Limbajul C va permite s iniializai i s incrementai mai multe variabile ntr-o
bucla for, separndu-le prin virgula.
for(i=0,j=0 ;i<=100 ;i++, j++)
Dac se folosesc variabile multiple n for, atunci vom utiliza bucle imbricate
(vezi matrici).
Instruciunea while
Este o instruciune repetitiv cu test iniial i numr necunoscut de pai.
Expresia general a instructiunii este :
while (conditie) instructiune ;
Condiie poate fi orice expresie, care dac este adevarat (valoare diferit de
zero) va determina continuarea buclei while. Cnd conditie va fi fals, execuia
programului continu cu instruciunea imediat urmtoare lui while.
Instruciunea while poate fi considerat o variaie a instructiunii for, caz n care
lipsesc elementele: iniializare i increment.
for ( ; conditie ; ) instruciune
Exemplu 1
int n,i,s;

i=0; s=0;
while (i<n) {s+=i; i++}
21

Exemplu 2 (K. Jamsa)


printf ( dorii s continuai ? (D/N) : ) ;
litera= getch () ;
litera =toupper (litera) ;
while ((litera !=D) && (litera !=N))
{
putch (7)
// emite un sunet
litera =getch() ;
litera =toupper (litera) ;
}
Instruciunea do-while
Spre deosebire de ciclurile for i while care testeaz condiia executrii la
nceput , ciclul do-while verific condiia la sfrit. Prin urmare un ciclu dowhile se execut cel puin odata. Forma generala este:
do {
instructiune;
} while (conditie);
De amintit c acoladele nu se folosesc n cazul unei singure instruciuni ci doar
cnd avem bloc de instruciuni.
Exemplu
int i,n, s ;

i=1; s=0;
do {s+=i;
i++; } while (i<=n);
Observatie
Ciclul do-while este foarte des utilizat la functii de selectie a meniurilor.
Exemplu 2 scris cu ajutorul instruciunii while, poate fi modificat cu do-while,
astfel :
Exemplu (K. Jamsa)
printf ( dorii s continuai ? (D/N) : ) ;
do
{ litera= getch () ;
litera =toupper (litera) ;
if ((litera !=D) && (litera !=N))
putch (7);
//emite un sunet
}
while ((litera !=D) && (litera !=N))
}
22

Urmtorul cod de program realizez suma numerelor pozitive introduse de la


tastatur. Programul se ncheie la introducerea primului numr negativ.
Exemplu
sum = 0.0;
scanf (%d, &x);
do {
sum += x;
scanf (%d, &x);
}
while (x > 0.0);
Instruciuni de salt
1. Instruciunea return
Este o instruciune ce nu trebuie s lipsesasc din corpul unei funcii
care returneaz o valoare, deoarece obine rezultatul funciei. Este considerat
de salt pentru c determin programul s revin la punctul n care s-a facut
apelarea funciei. Dac instruciunii return i se asociaz o valoare, acea
valoare devine valoarea funciei.
Forma general a instruciunii :
return expresie ;
unde expresie este opionala i cnd exist va deveni valoarea returnat de
funcie.
Astfel o funcie declarat void nu poate conine o instruciune return care
specific o valoare.
2. Instruciunea break
Aceast instruciune aa cum s-a vazut i mai sus , poate fi folosit n
primul rnd pentru a ncheia execuia unei instruciuni case
aflate ntr-o
instruciune switch. Dar poate fi folosit i pentru incheierea unui ciclu, prin
omiterea testului conditional al ciclului.
# include <stdio.h>
void main (void)
{
int x;
for (x=1; x<20;x++) {
printf (%d,x);
if (x= =10) break;
}
23

}
In exemplul de mai sus se scriu pe ecran numerele de la 1 la 10, i cnd s-a
tiparit 10, se iese imediat din ciclu, ignornd testul condiional x<20, datorit
instruciunii break.
3. Instruciunea continue
Spre deosebire de intruciunea break, instruciunea continue foreaz
urmtoarea iteraie a ciclului , prin omiterea oricror linii de program dintre cele
dou iteraii. Astfel n ciclul for aceast instruciune realizeaz saltul la pasul de
reiniializare. Pentru ciclurile while si do-while, realizeaz direct evaluarea
expresiei ce decide continuarea ciclului.
Exemplu
4. Instruciunea goto
Are sintaxa urmtoare:
goto eticheta;
Se realizeaz saltul necondiionat la instruciunea a crei etichet este cea
specificat n dreptul instruciunii. De reinut este faptul c nu se face salt n
afara funciei curente. Este recomandabil restrngerea utilizrii acestei
instruciuni doar atunci cnd este neaparat necesar, de exmplu pentru
optimizarea programului.
Exemplu
# include <stdio.h>
void main (void)
{
int numar=5 ;
eticheta :
printf ( %d , numar ++) ;
//afieaz numerele de la 5 la 100
if (numar <=100)
goto eticheta;
}
Tablouri i iruri
Tabloul (array) este o structur de variabile de acelasi tip. Tipul variabilelor se
numete tipul de baz al tabloului, iar numrul componentelor unui tablou
(variabile) este determinat de numrul de valori ale tipului indicelui. Pentru
declararea unui tablou trebuiesc specificate tipul de baza ct i dimensiunea
acestuia, adic numrul maxim de elemente. La declarare compilatorul de C
aloc suficient memorie pentru a putea reine toate elementele. Prima intrare
este locaia 0, iar ultimul element va aparea la o locaie cu unul mai mic dect
dimensiunea tabloului.
24

Observaie
C nu are faciliti de verificarea depirii limitelor pentru tablouri. Aa c
rmne n sarcina programatorului s se asigure de depirea limitelor acolo
unde este nevoie. Liniile respective vor fi compilate fr erori dar sunt
incorecte.
Fiecare element dintr-un tablou este dat de un indice (vector) sau doi indici
(matrici). Aceti indici sunt obligatoriu numere ntregi i indic poziia
elemntului n cadrul tabloului. Elementele tabloului sunt ordonate de aceti
indici. Tablourile pot avea una sau mai multe dimensiuni. In cadrul variabilelor
de tip tablou identificm vectorii i matricile pentru cazul tablourilor
unidimensionale, respectiv bidimensionale. Tablourile trebuiesc declarate la fel
ca orice alt variabil.
tip nume_variabil[dimensiune] */ pentru variabile tablou unidimensionale
tip nume_variabil[dimensiune][dimensiune]
*/ pentru variabile tablou
biidimensionale
Exemplu :
int a[100] ;
float lista[30] ;
float matrice [20][30]
Pentru a putea accesa un element al tabloului se specific numele tabloului
urmat de indicele elementului ntre paranteze ptrate.
Exemplu
lista [3]=30 ;
a[8] ;
a[i] ;
Pentru parcurgerea elementelor unui tablou putem utiliza o instruciune
repetitiv folosind ca variabil de ciclare indicele tabloului i. In cazul tablourilor
bidimensionale (matrici) parcurgerea elementelor se face dup doi indici
corespunztori liniilor i coloanelor, i respectiv j.
# include <stdio.h>
void main (void)
{
int lista [6]={20, 30, 40, 50, 60, 70};
int i;
printf( valorile tabloului sunt \n) ;
for (i=0; i<6;i++)
printf (lista[%d] = %d\n, i, lista[i] );
}
25

Exemplu
int vector[20] ;
int matrice[20][20] ;
Urmtorul cod de program realizeaz citirea unui vector de la tastatur:
printf( n= ); scanf (%d, &n) ;
for (i=0 ; i<n ; i++)
{ printf ( a[%d]= , i) ;
scanf ( %f , &a[i]) ; }
Citirea unei matrice ptratice de dimensiune n :
printf( n= ); scanf (%d, &n) ;
for (i=0 ; i<n ; i++)
for (j=0 ; i<n ; i++)
{ printf ( a[%d][%d]= , i,j) ;
scanf ( %f , &a[i][j]) ; }
Afiarea unui vector la consol :
for (i=0 ; i<n ;i++)
printf ( %.3f , a[i]) ;
Declararea irurilor de caractere
Un ir de caractere reprezint defapt o secven de caractere ASCII. Pentru
toate irurile citite de la tastatur, programele le atribuie automat caracterul
NULL la sfritul lor, pentru a-i marca sfritul. In C un ir de caractere
reprezint defapt un tablou de caractere care se ncheie cu caracterul nul
(zero). De reinut c irurile de caractere trebuiesc declarate cu caracter mai
lung dect cel mai lung ir pe care l pot memora. Astfel pentru a declara un
ir ce memoreaz 20 de caractere vei scrie :
char ir [21] ;
Compilatorul de C poate crea iruri capabile s stocheze 256 de caractere,
indexate de la 0 la 255.
Observaie Cnd se lucreaz cu iruri de caractere e de datoria
programatorului s se asigure de includerea caracterului NULL, pentru
reprezentarea sfritului de ir.
Constantele ir sunt liste de caractere ncadrate ntre ghilimele duble.
S observm astfel diferena dintre caracterele A i A . In primul caz este
reprezentat caracterul A prin valoarea ei Ascii, n al doilea caz este
reprezentat defapt un ir ce conine litera A dar i caracterul Null. Aceste
dou simboluri sunt stocate diferit i trebuie avut grij la diferena dintre ele.

26

C dispune n bibliotecile sale de o varietate de funcii pentru manipularea


irurilor de caractere
strcpy (s1,s2)
- copiaz s2 n s1
strcat (s1,s2)
- concateneaz s2 la sfritul lui s1
strlen (s1)
- calculeaz lungimea lui s1
strcmp (s1, s2) - returmeaz valoare 0 dac s1 i s2 sunt idntice, negativ
dac
s1<s2 i pozitiv dac s1>s2
Citirea i scrierea irurilor de caractere
S-a vazut c un ir de caractere este un tablou cu valori de tip char.
Funciile care permit citirea i scrierea irurilor de caractere sunt gets() si
puts().
Cu ajutorul functiei gets() se pot introduce caractere de la tastatur pn la
apsarea tastei ENTER. Prototipul functiei este :
char *gets (char *str) ;
i se gsete n fiierul STDIO.H
Str este un tablou de caractere care primete caracterele introduse de
utilizator.
Exemplu : se citete un ir de caractere
# include <stdio.h>
# include <string.h>
void main (void)
{
char str[80];
gets (sir);
}
Functia puts() are prototipul :
int puts (const char *str) ;
i ea i scrie argumentul pe ecran. Acioneaz ca i funcia printf (), dar este
incapabil s genereze numere sau s efectueze conversii de format, fiind
destinataexclusiv afirii irurilor de caractere. Prin urmare ruleaz mai
repede dect printf(), necesitnd mai puine resurse.
Exemplu :
puts ( asta este un test ) ;
Pentru a creea o constant de tip ir de caractere, n program trebuie plasate
caracterele ntre ghilimele.
Acesta este un sir de caractere

27

Funcii pentru iruri de caractere


In C pentru a indica sfritul unui ir de caractere se utilizeaz n mod obinuit
caracterul NULL.
Cnd se lucreaz cu iruri de caractere, pentru a determina numrul de
caractere dintr-un ir C pune la dispoziie funcia strlen, care returneaz
numarul de caractere din ir.
Prototipul functiei:
strlen (const char *sir);
i este inclus n fiierul STRING.H.
Cnd dorii s copiai coninutul unui ir n altul C v pune la dispoziie funcia
strcpy care copiaz caracterele dintr-un ir surs n altul, destinaie.
Prototipul functiei :
*strcpy (char *destinatie, const char *sursa) ;
i si este inclus n fiierul STRING.H.
Aceast funcie returneaz un pointer care indic nceputul irului destinaie.
Pentru a adauga coninutul unui ir la altul C v pune la dispoziie funcia
strcat(). Procesul de adaugare a unui sir l altul se numeste concatenare de
siruri.
Prototipul functiei :
*strcat (char *destinatie, const char *sursa) ;
i este inclus n fiierul STRING.H.
Transmiterea tablourilor ctre funcii n C se realizeaz cu ajutorul
pointerilor. Astfel, funciei i se poate transmite un pointer ctre tablou, indicnd
numele tabloului fr a fi urmat de indicele tabloului.
Exemplu
void main (void)
{
int vector [10] ;
funct_1 (vector) ;
.............
}
In aceast situaie parametrul formal al funciei poate fi declarat :
-

ca pointer

ca tablou dimensionat

ca tablou nedimensionat

28

Exemple
1. void funct_1 (int *x)
/*pointer
{..
}
2. void funct_1 (int x[10]) /*tablou dimensionat
{.
}
3. void funct_1 (int x[]) /* tablou nedimensionat
{
}
Iniializarea tablourilor
La atribuirea de valori iniiale variabilelor tablou, acestea trebuie transmise
ntre acolade ({}). In cazul irurilor de caractere valoarea iniial a variabilei se
transmite ntre ghilimele duble.
Exemple
char titlu[60]= S nvm C ;
int puncte [7]= {20, 30, 50, 88, 70, 28, 56} ;
int matrice [2][3]= {{1, 3, 5},
{6, 11, 8}} ;
Afiarea valorilor coinute n variabila matrice.
# include <stdio.h>
void main (void)
{
int linie, coloana;
float matrice [3][4]= {{1.0, 2.3, 3.4, 5.6},
{6.0, 8.7, 6.9, 4.0},
{11.0, 2.6, 7.9, 33.0}} ;
for (linie=0 ; linie <3 ; linie++)
for (coloana=0 ; coloana<4 ; coloana++)
printf ( matrice [%d][%d]= %f\n , linie,
[linie][coloana]) ;
}

coloana,

matrice

Recursivitate
Un program n C poate fi mprit n pri mai mici, numite funcii, astfel
programul va fi mai uor de manipulat i de testat. In cadrul funciei principale
a oricrui program n C, se pot apela mai multe funcii, care la randul lor pot
apela alte funcii. Limbajul C permite ca o funcie s se apeleze pe sine nsi.
29

O astfel de funcie se numete funcie recursiv, iar procesul acesta de


apelare se numete recursivitate.
Un exemplu des ntlnit este cel al calculului factorialului unui numr.
factorial (n)=n*factorial (n-1).
Urmtorul program creeaz o funcie recursiv factorial, care se va apela n
funcia principal, main.
La apelare aceast funcie primete o valoare a parametrului, care este testat
cu 1. Dac aceast valoare este 1, funcia returneaz valoarea 1, altfel
returneaz rezultatul nmulirii dintre valoare i factorialul valorii minus 1.
# include <stdio.h>
int factorial (int valoare)
{
if (valoare==1)
return 1;
else
return (valoare*factorial (valoare-1))
}
void main (void)
{
int i;
for (i=1; i<=5;i++)
printf (factorial de %d este %d\n, i, factorial (i));}

Cteva funcii matematice


Funcia abs, returneaz valoarea absolut a unei expresii de tip ntreg. Se
utilizeaz astfel:
# include <stdlib.h>
int abs (int expresie);
# include <stdlib.h>
# include <stdio.h>
void main (void)
{
printf ( valoarea absolut a lui %d este %d\n, 5, abs (5)) ;
}
Pentru ridicarea la putere limbajul C dispune de funcia pow, care returneaz
rezultatul ridicrii unei valori la o putere dat, astfel :
# include <math.h>
double pow (double val, double putere) ;
30

# include <stdio.h>
# include <math.h>
void main (void)
{
int putere;
for (putere= 2; putere<6; putere++)
printf (5 ridicat la %d e %f\n, putere, pow(5.0, putere));
}
Limbajul C ofer dou funcii pentru generarea de numere aleatoare: rand,
random, care returneaz numere ntregi aleatoare:
# include <stdlib.h>
int rand (void);
int random (int limit)
Pentru operaia de extragere a rdcinii ptrate, limbajul C v ofer funcia
sqrt.
# include <math.h>
double sqrt (double val)
Funcia lucreaz numai valori pozitice, altfel returneaz eroare.
# include <stdio.h>
# include <math.h>
void main (void)
{
double val;
for (val=0.0 ; val< 100 ;val+=10)
printf ( valoarea %f
rdcin ptrat %f\n , val, sqrt (val)) ;
}
Pentru calculul logaritmului natural se utilizeaz funcia log
# include < math.h>
double log (double val) ;

31

Capitolul 1. Elemente de baz ale limbajului C/C++


y variabile y expresii y instruciuni y apelul funciilor y
y transmiterea parametrilor prin valoare i folosind adrese y
y intrri i ieiri y ecranul n mod text y

Probleme rezolvate
1.
S se scrie un program care s calculeze numrul de picioare
dintr-o curte, n care se afl g gini, p pisici i un om.
Includem header-ul cu operaiile de intrare i ieire standard:
#include <stdio.h>

Programul este constituit dintr-o singur funcie, funcia main:

void main()
{
int g, p;

S-au declarat variabilele de intrare, care apoi se citesc cu scanf:


printf("Dati numarul de gaini: ");
scanf("%d",&g);

%d inseamn "numr intreg"

printf("Dati numarul de pisici: ");


scanf("%d",&p);

&p nseamn c valoarea lui p este preluat n funcia scanf. n


continuare, se declar i se afieaz data de ieire, numrul total de picioare.
Firete, o gina are dou picioare, o pisic patru, iar omul are i el dou:
int np=2*g+4*p+2;

Mai sus avem att o declarare, ct si un calcul al variabilei np

printf("\nNumarul total de picioare: %d",np);

"\n" de la nceputul apelului lui printf reprezint trecerea la un nou rnd.


2.

S se verifice dac un numr real x se afl n intervalul [a,b).

#include <stdio.h>
void main()
Se declar cele trei variabile reale:
{
float a,b,x;

Se citesc capetele intervalului:

printf("Dati capetele intervalului:\n");


scanf("%f %f",&a,&b);

Apoi se citete x:

printf("Dati numarul cu pricina:");


scanf("%f",&x);

Se verific dac x este n intervalul cutat: && nseamn "i"

if ((a<=x) && (x<b))

Dac da, atunci se afieaz textul: Numrul x se afl... Valoarea lui x


se afieaz pe 6 poziii, din care 3 zecimale (o poziie o ocup i punctul
zecimal)
else

printf("Numrul %6.3f se afl...",x);


32

... numrul nu se afl n intervalul [a,b)...


}

printf("Numrul %6.3f nu se afl...",x);

3.
Se dau trei numere reale a,b,c. Pot reprezenta ele lungimile
laturilor unui triunghi.
Firete a, b, c pot fi lungimile laturilor unui triunghi doar dac ele sunt
toate numere pozitive, iar suma oricror dou este mai mare dect al treilea
numr.
Vei observa cu uurin c programul nici nu pare scris in limbajul C, ci
mai degrab ntr-o combinaie de limba romna i C. i totui, programul
merge i face ce trebuie s fac. Tot secretul reuitei lui const n definiiile de
mai jos, n care relaia "&&" este inlocuit cu cuvntul "si", n loc de "if" apare
daca, iar pentru "else" folosim "altfel".
#define si &&
#define daca if
#define altfel else
#include <stdio.h>
void main()
{
float a,b,c;
printf("Dati lungimile laturilor:\n");
scanf("%f %f %f",&a,&b,&c);

Mai jos se verific condiia de triunghi:

daca ((a>=0) si (b>=0) si (c>=0) si


(a<b+c) si (b<a+c) si (c<a+b))
printf("%4.2f, %4.2f
si %4.2f formeaza triunghi.",
a,b,c);
altfel
printf("Nu formeaza triunghi.");

4.
S se scrie un program care s verifice dac trei numere reale a, b
i c pot reprezenta lungimile laturilor unui triunghi. Dac da, atunci s se
precizeze de ce tip este triunghiul: echilateral, isoscel, dreptunghic sau
oarecare.
De data aceasta, dac tot am scris programul anterior, n care verificm
dac a, b, c pot fi lungimile laturilor unui triunghi, vom rescrie funcia main()
din acel program, dndu-i numele FormeazaTriunghi n acest nou program.
Astfel, cnd n funcia main() se va ajunge la instruciunea if
FormeazaTriunghi(a,b,c)..., programul i va continua execuia cu primul
rnd din funcia sus numit. n locul lui x (primul parametru al funciei) va veni
a, adic valoarea sa, n locul lui y va veni valoarea lui b, iar in locul lui z valoarea lui c. Firete, parametrii (argumentele) funciei FormeazaTriunghi ar
putea fi numite chiar i a, b, c, (eventual n alt ordine), aceste variabile
33

neavnd nimic comun cu variabilele a,b,c din funcia main() (n afar de


nume).
Se spune c apelul funciei se face prin valoare. Comunicarea
main()-FormeazaTriunghi() este ntr-un singur sens, de la prima funcie
ctre a doua. Astfel, chiar dac, s zicem, x s-ar modifica n interiorul celei de
a doua funcie, aceasta nu ar afecta n nici un fel valoarea variabilei a, adic a
parametrului efectiv cu care main() apeleaz pe FormeazaTriunghi(). Putei

verifica

aceasta

singuri sau urmrii exemplul urmtor. Funcia


FormeazaTriunghi returneaz o valoare de adevr, adic adevrat sau fals,
lucru care se traduce in limbajul C printr-o valoare nenul, pentru adevrat,
respectiv prin valoarea 0, pentru fals. Variabilele echil, isos i drept au
valorile 1 dac triunghiul este respectiv echilateral, isoscel, dreptunghic.
Firete, un triunghi echilateral va fi i isoscel. E greu s se obin triunghiuri
dreptunghic iscoscele, deoarece e greu s se introduc (pentru scanf())
valori potrivite.
#include <stdio.h>
int FormeazaTriunghi(int x, int y, int z)
{
return ((x>=0) && (y>=0) && (z>=0) && (x<y+z)
&& (y<x+z) && (z<x+y));
}
void main()
{
float a,b,c;
printf("Dati lungimile laturilor:\n");
scanf("%f %f %f",&a,&b,&c);
if (FormeazaTriunghi(a,b,c))
{
int echil=((a==b) && (b==c));
int isos=((a==b) || (b==c) || (c==a));
int drept=((a*a==(b*b+c*c)) ||
(b*b==(a*a+c*c)) || (c*c==(a*a+b*b)));
if (echil) printf("Triunghi echilateral.\n");
if (isos) printf("Triunghi isoscel.\n");
if (drept) printf("Triunghi dreptunghic.\n");
if ((!echil) && (!isos) && (!drept))
printf("Triunghi oarecare.\n");
}
else printf("Nu formeaza triunghi.\n");
}

5.
S se scrie un program care s returneze succesorul unui numr
intreg dat.
Este vorba despre un program banal, ns vom ncerca s punem n
eviden un anumit aspect, anume o simulare a transmiterii prin valoare a
parametrilor, n cazul funciilor.
#include <stdio.h>
int succesor(int x)

34

int y=x+1;

... evident, y este succesorul lui x.


x++;

... l cretem pe x cu o unitate. Oare se va transmite n exterior valoarea nou?

return y;
}
void main()
{ int a;
printf("Dati numarul a: "); scanf("%d",&a);
printf("Deocamdata a = %d\n",a);
int b=succesor(a); printf("Succesorul b = %d\n",b);
printf("Iar acum a = %d\n (ala vechi!)\n",a);
int c=succesor(3);
printf("Succesorul lui 3 este = %d\n",c);
printf("Iar 3 tot 3 ramane, nu-i asa ?\n");
int d=succesor(a+3);
printf("In fine, succesorul lui 3+%d este = %d\n",a,d);
}
Se va observa cu usurin, c valoarea modificat a lui x nu se
transmite i lui a. Motiv pentru care putei apela funcia succesor i cu un

argument constant sau cu o expresie ca n exemplul anterior. Iat de ce e


nevoie de un nou mecanism de transmitere a parametrilor, pentru a realiza
comunicarea de la funcia apelat ctre cea apelant (de exemplu, de la
succesor la main).

Un astfel de mecanism se numete transmitere prin referin a


parametrilor i aceasta se realizeaz n felul urmtor: n loc s punem ca
argument formal n apel numele variabilei respective, vom pune simbolul "&" n
faa variabilei. Aceasta schimb semnificaia! Dac x este o variabil oarecare,
prin &x vom nelege adresa din memorie
unde se afl variabila x (indiferent pe unde ade ea acolo!). Astfel, trebuie ca i
funcia care primete pe &x ca argument s tie s lucreze cu o adres a unei
variabile de tipul lui x (practic este vorba tot despre un apel prin valoare, insa
valorile sunt adrese de memorie sau pointeri).
Un exemplu l constituie exerciiul urmtor.
6.
S se scrie un program care s returneze succesorul unui numr
ntreg dat, dar s ncrementeze cu 1 valoarea numrului iniial.
Vom ncerca sa punem n eviden un anumit aspect, anume
transmiterea prin referin a parametrilor, n cazul funciilor
#include <stdio.h>
int succesor(int *x)
{
int y=(*x)+1;

... evident, y este succesorul valorii lui x


(*x)++;

... cretem valoarea lui x cu o unitate.


35

return y;
}
void main()
{ int a;
printf("Dati numarul a: "); scanf("%d",&a);
printf("Deocamdata a = %d\n",a);
int b=succesor(&a);
printf("Succesorul b = %d\n",b);
printf("Iar acum a = %d\n (ala vechi!)\n",a);
//
printf("Succesorul lui 3 = %d",succesor(&3);
}

Funcia succesor ar fi putut arta i astfel:

int succesor(int *x)


{
return ++(*x);
}

dar nu i aa:

int succesor(int *x)


{
return (*x)++;
}

Firete, att ++m, ct i m++ reprezint incrementri ale lui m cu o unitate,


ns diferena e de finee: pe cnd n primul caz are loc nti incrementarea lui
m, apoi folosirea sa, n cel de al doilea caz are loc nti utilizarea sa (a valorii
neincrementate nc) i apoi incrementarea. Atenie deci, cci putei avea
probleme! Se va observa c valoarea lui x se transmite n exterior variabilei a.
nainte de a trece mai departe, s analizm nca puin exemplul dat.
Dac pn acum noi puteam apela funciile descrise nu doar cu variabile, ci i
cu constante sau chiar expresii (n fond cu valorile lor), de aceast dat, un
apel de genul celui pus n comentariu n finalul programului anterior
semnaleaza eroare. Nici apelul succesor(3) nu e mai bun! Dar, dac &m
nseamn adresa variabile m, acest lucru ne oblig ca n antetul funciei care o
folosete, s definim ceva de genul nume_functie(tip * mm), n care tip
este tocmai tipul lui m, mm este argumentul funciei, iar steluta * semnaleaz
faptul c mm nu este un numr ntreg, ci un pointer la un numr ntreg, adic un
indicator ctre o zon de memorie unde se afl un numr ntreg (practic, n
momentul execuiei programului, apelnd funcia cu valoarea adresei lui m (&m),
mm va conine tocmai aceast adres (ceea ce se numete c mm este un
indicator ctre m)
Oare funcia scanf() nu lucreaz la fel? Ba da, e i normal, deoarece
ea trebuie s trimit ctre exterior (adic funciei apelante) rezultatele citirilor,
deci ntotdeauna trebuie s avem grij cum folosim funcia scanf().
Fiindc printf() nu modific n nici un fel valorile afiate, e normal ca
la printf() s nu avem nevoie de &. Dect, dac dorim s obinem adresa
unei variabile, ca n exemplul urmtor:
36

#include <stdio.h>
void main()
{ int x=3; printf("Adresa lui x: %ld",&x); }

Dar un asemenea exemplu nu ne ajut cu nimic, de obicei, fiind pur


didactic...
7.
S se scrie un program care s calculeze valoarea mediei
aritmetice a dou valori reale a i b. Se vor folosi dou funcii, una care
va trimite rezultatul prin numele funciei, iar alta printr-unul din parametri.
#include <stdio.h>
float media(float x, float y)
{
return (x+y)/2;
}
void proc_media(float x, float y, float * m)
{
*m = (x+y)/2;
}
void main()
{
float a, b, m1, m2;
printf("Dati cele doua numere:\n");
scanf("%f %f",&a,&b);
m1 = media(a,b);
proc_media(a,b,&m2);
printf("Media returnata prin numele functiei: %7.3f\n",
m1);
printf("Media returnata ca si parametru
: %7.3f\n",
m2);
printf("Nici o diferenta !\n");
}

De fapt, dac prima funcie folosete return pentru a obine valoarea


medie (adic se comport ca o funcie adevarat), cea de a doua se
comport ca o procedur din limbajul Pascal, motiv pentru care nici nu
returneaz nimic (apare void ca tip al funciei), iar rezultatul se transmite prin
intermediul parametrului de tip pointer m.
Observai diferena dintre x i y, pe de o parte, i m pe de alt parte, n
antetul funciei proc_media, ct i modul n care este apelat ea!
8.
S se determine maximul i minimul a dou numere ntregi, fr a
folosi instruciunea "if".
Programul ar fi banal, firete, ns dac nu trebuie s folosim cuvntul
if, nseamn c vom utiliza interesantul operator condiional ? :.
Astfel, vom putea defini dou macrouri, cu numele minim i maxim,
dup cum urmeaz:
#define max(x,y) x > y ? x : y
#define min(x,y) x < y ? x : y
#include <stdio.h>

37

void main()
{
int x, y;
printf("Ia sa vedem care-i mai tare !\n");
printf("Da x si y:"); scanf("%d %d",&x,&y);
printf("\nCel mai tare este: %d",max(x,y));
printf("\nIar cel mai slab : %d",min(x,y));
}

Simplu, elegant i frumos, nu-i aa?


Nu v facei griji dac lucrai cu numere reale n loc de numere ntregi,
macrourile funcioneaz perfect n orice situaie!

#define max(x,y) x > y ? x : y


#include <stdio.h>
void main()
{
float x, y;
printf("Ia sa vedem care-i mai tare !\n");
printf("Da x si y:"); scanf("%f %f",&x,&y);
printf("\nCel mai tare este: %7.3f",max(x,y));
}

E simplu de neles acum cum funcioneaz operatorul ternar ?:: s


considerm c avem 3 expresii e1, e2 i e3, n care e2 i e3 trebuie s fie, n
mare fie spus, cam de acelai tip. Se evalueaz e1. Dac e1 e o valoare nenul
(adevrat), atunci rezultatul este e2, altfel e3.
9.
S se calculeze puterea a n-a a lui 2, unde n este un ntreg dat de
la tastatur.
Pentru c tot am vorbit n exemplul anterior despre unul din operatorii
speciali, pe care i are limbajul C, vom prezenta n exemplul de fa operatorul
de shiftare ("iftare", rotire, deplasare) spre stnga <<.
Fie x un numr ntreg. Prin x<<1 nelegem deplasarea spre stnga a
biilor din reprezentarea pe bii (n baza 2) a lui x, completndu-se cu 0 n
dreapta. Astfel, de exemplu, dac x=6, adic 101, atunci, deplasarea spre
stnga va duce la obinerea numrului x=12, adic 1010. De fapt, o shiftare
spre stnga cu o unitate reprezinta o nmulire a lui x cu 2. O shiftare spre
stnga cu p poziii a lui x reprezint o nmulire a lui x cu 2 de p ori.
Tot la fel, o shiftare spre dreapta ar nsemna o mprire succesiv la 2
(n care nu se ine cont de rest).
Folosind acest artificiu (al deplasrilor spre stnga), am calculat i noi
puterea lui 2, conform programului urmtor:
#include <stdio.h>
void main()
{
int n, m=1;

... aici se declara att variabila n, ct i m, care se i iniializeaz la valoarea 1


38

printf("Dati n: ");
scanf("%d",&n);
printf("2^%d = %d\n",n,m=(m<<n));

Al doilea apel al funciei printf are un element interesant: se afieaz


valoarea expresiei m=(m<<n).
Valoarea unei expresii de forma m=e, care evident este i o instruciune
de atribuire, este tocmai valoarea expresiei e. Astfel, cnd scriem m=(m<<n),
nseamn c m este shiftat spre stnga cu n poziii, deci m, inial 1, devine egal
cu puterea n a lui 2. Aceasta este i valoarea expresiei m=(m<<n), care va fi
afiat.
10.
sale.

S se determine aria unui triunghi n funcie de lungimile laturilor


Soluia pe care o prezentm n continuare nu face apel la funcia

FormeazaTriunghi, pe care am prezentat-o ntr-un exemplu anterior. De

aceast dat, presupunem utilizatorul programului bine intenionat, astfel nct


ne vom axa pe formula de calcul a ariei, cnd se cunosc lungimile a, b, c ale
celor trei laturi, formul cunoscut sub denumirea de formula lui Heron.
Elementul interesant din acest program este folosirea funciei sqrt(x), care
ne d radcina ptrat a unui numr real x, precum i a funciei getch(),
care ne returneaz valoarea tastei apsate (un caracter). Fiecare din cele
dou funcii necesit includerea n textul surs al programului a doua fiiere
.H, anume <math.h> i respectiv <conio.h>.
#include <stdio.h>
#include <math.h>
#include <conio.h>
void main()
{
float a,b,c,p,aria;
printf("Dati lungimile laturilor:\n");
scanf("%f %f %f",&a,&b,&c); p=(a+b+c)/2;
aria=sqrt(p*(p-a)*(p-b)*(p-c));
printf("Aria este: %7.3f.",aria); getch();
}

Spre deosebire de toate funciile folosite pna acum, getch() este


utilizat ntr-un alt mod. Practic, se comport ntocmai ca o procedur din
Pascal. Chiar dac ea returneaz caracterul apsat la tastatur, acesta
conteaz mai puin, important este "efectul lateral" pe care l are aceast
funcie, aici concretinzndu-se n ateptarea apsrii unei taste. Acest lucru
este foarte util, in sensul c dup fiecare rulare a programului, nu vom mai fi
nevoii s acionm combinaia de taste Alt-F5 pentru a comuta intre ecranul
cuprinznd rezultatul execuiei programului i cel al mediului de programare
Borland.
11.
S se determine rdcina ptrat a unui numar real a, fra a utiliza
funcia sqrt.

39

Aceast problem se poate soluiona pornind de la irul recurent al lui


Newton:
x0 = 1, xn = (xn-1 + a/xn-1)/2, pentru n1
De fiecare dat vom avea nevoie doar de doi termeni succesivi ai
acestui ir, fie ei xn i xn1. Vom calcula pe xn plecnd de la xn1, apoi vom
actualiza pe xn1 cu valoarea lui xn, iar procedeul continu repetitiv pn
cnd diferena dintre xn i xn1 este nesemnificativ.

#include <stdio.h>
#include <conio.h>
#include <math.h>
float radical(float a)
{ const eps=0.00001; // o constanta,
// avand valoarea egala cu precizia dorita in calculul
radicalului
float xn1=1, xn=(1+xn1)/2;
do { xn1=xn;
xn = (xn1+a/xn1)/2;
} while (fabs(xn-xn1)>eps);
// fabs(x) = |x|, unde x este numar real
return xn;
// rezultatul este ultimul termen calculat al sirului
}
void main()
{
clrscr(); // se curata ecranul
float a;
printf("Dati a:"); scanf("%f",&a);
printf("\nsqrt
(%7.3f)=%10.6f",a,sqrt(a));
// se compara cele doua functii
printf("\nradical(%7.3f)=%10.6f",a,radical(a));
printf("\nCinci zecimale exacte!");
getch();
}
Observai folosirea instruciunii repetitive do... while... , avnd

semnificaia: execut ... att timp ct ... . Este vorba despre o instruciune
repetitiv n care testul se face la sfritul ciclului.
12.

Ce va afia urmtorul program (care folosete operatorul ",") ?

#include <conio.h>
#include <stdio.h>
void main()
{
clrscr(); int x=1,y; int z = (x = 2, y=x+3);
printf("%d, %d, %d",x,y,z); getch();
}

n atribuirea z = (x=2, y=x+3) au loc urmtoarele: mai inti x


primete valoarea 2, apoi y valoarea 5, iar z tot valoarea 5. Deci se va afia
3,5,5 .
40

13.
Se citesc litere pna la intlnirea caracterului ".". S se
contorizeze numrul de vocale citite.
De data aceasta, vom folosi macroul predefinit getchar(), care
returneaz tasta apsat, de fapt el citete din intrarea standard, stdin.
#include <stdio.h>
void main()
{
char c; int nr_voc; nr_voc=0;
printf("Dati textul:\n");
while ((c = getchar()) != '.')
{
printf("%c", c);
if ((c=='a') || (c=='e') || (c=='i') ||
(c=='o') || (c=='u')) nr_voc++;
}
printf("\nTotal vocale: %d",nr_voc);
}

nlocuind '.' cu '\n', getchar() va citi pn la apsarea lui Enter.


14.
S se deseneze un dreptunghi de dimensiune mn, folosind
caracterele speciale pentru coluri.
Vom folosi macroul putchar() pentru a afia pe ecran. Colurile au
urmtoarele valori (in hexazecimal):
#include <stdio.h>
#include <conio.h>
#define LEFT_TOP 0xDA
#define RIGHT_TOP 0xBF
#define HORIZ
0xC4
#define VERT
0xB3
#define LEFT_BOT 0xC0
#define RIGHT_BOT 0xD9
void main()
{
int m, n;
char i, j;
clrscr();
printf("Dati m si n: ");
scanf("%d %d",&m,&n);
/* marginea de sus */
putchar(LEFT_TOP);
for (i=0; i<n; i++)
putchar(HORIZ);
putchar(RIGHT_TOP);
putchar('\n');
/* mijlocul */
for (i=0; i<m; i++)
{
putchar(VERT);
for (j=0; j<n; j++)
putchar(' ');
putchar(VERT);

41

putchar('\n');
}
/* marginea de jos */
putchar(LEFT_BOT);
for (i=0; i<n; i++)
putchar(HORIZ);
putchar(RIGHT_BOT);
putchar('\n'); getch();

Putei remarca utilizarea variabilelor i, j ca numere ntregi, dei ele au


fost declarate ca fiind de tip char. Trebuie precizat c C-ul poate face astfel
de conversii, iar un char ocup doar un octet (iar un int doi), i cum valorile
pentru i i j sunt mici, se poate folosi char.
15.
S se mite o liter pe ecranul text, folosind cele patru taste de
cursor.

#include <stdio.h>
#include <conio.h>
void main()
{
clrscr();
char tasta; char x=40,y=12;
gotoxy(x,y); putch('X');
do {
tasta=getch(); gotoxy(x,y); putch(' ');
switch(tasta) {
case 72: { if (y>1) y--; break; }
case 80: { if (y<24) y++; break; }
case 75: { if (x>1) x--; break; }
case 77: { if (x<80) x++; }
}
gotoxy(x,y); putch('X');
} while (tasta!=27);
}

n exemplul anterior, am folosit afiarea cu putch() (care scrie doar pe


ecran, direct n memoria video). Poziionarea cursorului se face cu funcia
gotoxy (declarat n conio.h). Ecranul are 25 de linii i 80 de coloane,
numerotate de la 1 la 25, respectiv de la 1 la 80. Noi am evitat afirile pe linia
25, deoarece o afiare n punctul de pe aceast linie i ultima coloan are ca
efect ridicarea textului cu o linie n sus, pe ecran.
Observai i utilizarea instruciunii de decizie multipl switch. n cadrul
ei am folosit instruciunea if pentru a evita ieirile din ecran, precum i
instruciunea break, care determin continuarea execuiei programului cu
instruciunea de dup switch.
Tasta acionat se citete cu getch() (dar nu se i afieaz). Ea
poate fi cursor sus (72), stnga (75), dreapta (77) sau jos (80), pentru
deplasare, respectiv Escape (27), pentru terminarea programului.
42

16.
S se simuleze micarea unei bile de sus in jos, pe coloana 40 a
ecranului. Afiarea se va repeta, de fiecare dat bila avnd o culoare
aleas la ntmplare.
Noutile aduse de acest exemplu sunt:
utilizarea fiierului <dos.h>, care conine declaraia funciei delay. Apelul
delay(p) face o pauz (n execuia programului) de p milisecunde. Astfel,
delay(500) nseamn o pauz de o jumtate de secund.
utilizarea unor funcii declarate n <stdlib.h>, pentru obinerea de
numere aleatoare (de fapt generate dup o anumit formul, ntr-un ir de
numere, pornind de la o anumit valoare iniial):
void randomize() schimb valoarea iniial a acestui ir de
valori aleatoare;
int random(int n) returneaz o valoare aleatoare ntreag, din
intervalul [0,n-1]. Astfel, pentru a obine una din cele 15 culori
(exceptnd negrul=0), am folosit textcolor(1+random(15)).
o alt noutate este folosirea lui puts pentru a afia un ir de caractere;
rspunsul la ntrebarea din finalul ciclului do-while este afiat pe ecran.
El este o liter, preluat cu getche(). Dac aceasta este n,
programul se oprete. Diferena ntre getche() i getch() este c prima
afieaz caracterul apsat (deci este cu ecou), pe cnd cea de a doua nu.

#include <stdio.h>
#include <conio.h>
#include <dos.h>
#include <stdlib.h>
void main()
{
randomize();
do {
delay(500); clrscr(); textcolor(1+random(15));
char y=1;
while (y<=25)
{
gotoxy(40,y); putch(' ');
gotoxy(40,++y); putch('o'); delay(50);
}
puts("\nMai doriti odata ? ->");
} while (getche()!='n');
}

17.
S se determine cel mai mare divizor comun i cel mai mic
multiplu comun pentru dou numere ntregi a i b.
Pentru a determina cel mai mic multiplu comun al lui a i b, trebuie ca
mai nti s determinm c = cel mai mare divizor comun al lui a i b. Dac cel
puin unul din cele dou numere (a sau b) este 0, vom considera cellalt
43

numr ca fiind c. Dac ambele numere sunt diferite de 0, atunci vom scdea
numrul mai mic din numrul mai mare, pn vom obine egalitatea numerelor
a i b. n acest moment, c=a. n fine, metoda se numeste algoritmul lui
Euclid cu scaderi, iar pentru a obine cel mai mic multiplu comun nmulim pe
a i b iniiali i mprim la c.
#include <stdio.h>
#include <conio.h>
long cmmdc(long a, long b)
{
if (!a) return b;
else if (!b) return a;
else while (a-b) // adica daca a-b != 0, adica a !=b
if (a>b) a-=b; else b-=a;
return a;
}
long cmmmc(long a, long b)
{ long c=cmmdc(a,b);
if (c) return a*b/c; else return 0;
}

Cnd ambele numere sunt 0, cmmmc nu exist, dar returnm 0.

void main()
{
long a,b,c,d;
printf("\nDati a, b: "); scanf("%ld %ld",&a,&b);
c=cmmdc(a,b);
d=cmmmc(a,b); // conversia rezultatului impartirii
// la numarul intreg d se face automat
printf("Cmmdc(%ld,%ld)=%ld\n",a,b,c);
printf("Cmmmc(%ld,%ld)=%ld\n",a,b,d); getch();
}

De subliniat faptul c o declaraie de forma long x este echivalent cu


o declaraie de forma long int (ntreg lung). "%ld" permite afiarea de
ntregi lungi.
18.
S se simuleze micarea unei bile pe o mas de biliard, fr
frecare.
Bila va fi caracterizat de patru variabile ntregi: x i y vor indica
coordonatele bilei; (1x80, 1y24);
vx i vy vor reprezenta direciile de deplasare ale bilei:
Astfel, la fiecare pas, bila se va deplasa din poziia (x,y), n poziia
(x+vx, y+vy), unde vx i vy pot lua valorile 1 sau -1. De pild, o deplasare n
direcia stnga-jos este dat de vx=-1 i vy=1.
#include <conio.h>
#include <dos.h>
void HideCursor()
{
/* sa scrieti exact asa: asm { si nu cu acolada pe randul
urmator !! */
asm {
mov ax, 0x0100
mov cx, 0x2607
44

int 0x10
}

}
void ShowCursor()
{
asm {
mov ax, 0x0100
mov cx, 0x0506
int 0x10
}
}
void main()
{
clrscr(); HideCursor();
char x=40, y=12, vx=1, vy=1;
while (!kbhit())
{
gotoxy(x,y); putch(' ');
if ((x==1) || (x==80)) vx=-vx;
if ((y==1) || (y==24)) vy=-vy;
x+=vx; y+=vy;
gotoxy(x,y); putch('o'); delay(50);
}
ShowCursor();
}

Acest exemplu are urmtoarele elemente de noutate:


functia kbhit() - returneaz 1 (adevrat) dac fu apsat o tast (tocmai
s-a apsat o tast), respectiv 0, n caz contrar;
se pot scrie n textul C secvene de program n limbaj de asamblare,
folosind declaraia asm { i }, ca n funciile HideCursor() i
ShowCursor().
cursorul plpitor din modul text se poate ascunde cu prima funcie i
reafia cu cea de a doua.
19.

S se afieze primele n numere prime.


Mai nti, vom scrie o funcie care va verifica dac un numr ntreg este
prim sau nu.
Pentru a vedea dac x este prim, se compar, mai nti, x cu 0, 1 si 2.
Dac x2, atunci se verific dac x este par sau nu. n caz c este impar, se
imparte succesiv la toate numerele impare ncepnd cu 3, pn se obine un
divizor d al lui x (caz n care numrul nu este prim) sau se ajunge la partea
ntreag a rdcinii ptrate a lui x (caz n care numrul e prim)

#include <stdio.h>
#include <conio.h>
#include <math.h>
int EstePrim(int x)
{
if ((x==0) || (x==1)) return 0;

45

else
if (!(x%2)) //adica daca x modulo 2 este zero...
if (x==2) return 1;
else return 0;
else
{ int d=1, radical=sqrt(x);
while ((d<=radical) && (x%(d+=2)));
/* adica cat timp d radical, iar x se nu imparte exact
la d (care creste cu doua unitati, incepand cu 1 (deci prima
valoare testata va fi 3)) */
return (d > radical);
}
}
void main()
{
clrscr();
int i=0, j=1, n;
printf("Dati nr. de numere: "); scanf("%d",&n);
for ( ; j<=n, getch(); i++)
if (EstePrim(i)) { printf("%d,",i); j++; }
}

Acest program poate c este cel mai ciudat dintre toate cele prezentate
pn acum. n funcia EstePrim am pus n eviden un mod interesant de a
folosi instruciunea while, care nu are dect condiie (nu i instruciune)! ns,
n cadrul condiiei se ascunde, totui, o simpl instruciune de incrementare cu
2 a valorii lui d. Astfel, instruciunea while de acolo este echivalent cu:
while ((d<=radical) && (x%d!=0)) d=d+2;
Valoarea returnat este 1, dac d>radical (adic s-a depit
valoarea maxim de test pentru eventualii divizori ai lui x, respectiv 0, n caz
contrar.
n privina programului principal (funcia main), observai modul special
de folosire a instruciunii for. Practic, iniializarea lui i la 0 este deja fcut
(cnd se declar i), apoi apare i operatorul virgul ,, care conine testul de
terminare a ciclului for, precum i un apel al lui getch() care va determina
ateptarea apsrii unei taste pentru fiecare numr (prim sau nu), pn la
sfrit.
20.

S se transforme un numr din baza 10 ntr-o baz p, 2p10.

Vom mpri succesiv pe x (numrul dat) la p, reinnd cifrele din baza p


ntr-un numr xpi, care va fi apoi rsturnat (oglindit), pentru a obine numrul
xp, vzut ca reprezentarea n baza p a lui x. Pentru a nu avea probleme n
cazul n care prima cifr a lui xpi ar fi 0, folosim o incrementare cu 1 a cifrelor
la transformarea xxpi, respectiv o decrementare la transformarea xpixp.
#include <conio.h>
#include <stdio.h>
void main()
{
46

clrscr(); int x, xpi, xp, p;


printf("Dati x in baza 10: "); scanf("%d",&x);
printf("Dati noua baza p : "); scanf("%d",&p);
for (xpi=0; x; xpi=10*xpi+x%p+1, x=x/p);
for (xp=0; xpi; xp=10*xp+(xpi-1)%10, xpi=xpi/10);
printf("Numarul in baza %d este: %d",p,xp); getch();

De remarcat, n acest exemplu, elegana folosirii operatorului , n


cadrul instruciunilor for. De pild, primul for se interpreteaz astfel:
se iniializeaz xpi cu 0;
ct timp x este diferit de 0 execut:
xpi devine 10*xpi+x%p+1;
x se mparte la p (i se face conversia la int)
21.
S se calculeze suma S = 1-2+3-4+...n, pentru un n dat de la
tastatur.
Vom folosi o variabil semn care va lua pe rnd valorile 1 i -1.
#include <conio.h>
#include <stdio.h>
void main()
{
clrscr(); int n;
printf("Dati numarul n: "); scanf("%d",&n);
for (int i=1, suma=0, semn=1; i-(n+1);
suma+=(semn*i), i++, semn=-semn);
printf("Suma dorita este: %d",suma); getch();
}

Firete, suma e foarte uor de determinat matematic. Am vrut, ns, s


punem n eviden urmtoarele aspecte:
declararea i iniializarea variabilelor i, suma i semn, n cadrul primei
expresii din instruciunea for;
folosirea condiiei i-(n+1) pentru a verifica dac in sau nu;
folosirea operatorului virgul n cadrul expresiilor ce apar in for;
inexistena unei alte instruciuni n cadrul lui for.
De remarcat puterea de care d dovad instruciunea for din limbajul
C, n comparaie, de pild, cu cea din cazul limbajului Pascal.
22.
S se deseneze n ecranul text un dreptunghi, specificat prin
coordonatele a dou coluri diagonal opuse.
Vom citi x1, y1 i respectiv x2, y2, coordonatele acestor coluri.
Folosind operatorul ternar ?: vom determina n x1, y1 minimele, iar n x2,
y2 maximele (ceea ce va nsemna c, n final, aceste coordonate vor fi ale
colurilor stnga-sus i dreapta-jos). Apoi vom folosi dou instruciuni for
pentru a desena. Caracterul va avea codul hexazecimal B0 (adic 178) i va fi
afiat cu o funcie PrintAt.
#include <conio.h>
#include <stdio.h>

47

void PrintAt(char x, char y, char c)


{
gotoxy(x,y); putch(c);
}
void main()
{
int x1,y1,x2,y2,aux,x,y;
char cc=0xB0; // numar hexazecimal = 178, in baza 10
clrscr();
printf("\nDati x1: "); scanf("%d",&x1);
printf("\nDati y1: "); scanf("%d",&y1);
printf("\nDati x2: "); scanf("%d",&x2);
printf("\nDati y2: "); scanf("%d",&y2);

Daca x1>x2, folosind variabila aux, se interschimb valorile lui x1 i x2


x1>x2 ? aux=x1, x1=x2, x2=aux: 1;

... aici, n loc de 1 ar fi putut fi orice;


Facem la fel pentru y1 i y2:

y1>y2 ? aux=y1, y1=y2, y2=aux: 1;


clrscr();
for (x=x1; x<=x2; x++)
for (y=y1; y<=y2; y++)
PrintAt(x,y,cc);
//... se face conversie de la int la char
getch();

Probleme propuse
1.
2.
3.
4.
5.

6.

Care este valoarea variabilei p dup efectuarea urmtoarelor operaii?


a) p=i=1; while (i<7) i++; p*=i;
b) p=1; i=7; while (i>1) {p*=i; i-=1;}
S se calculeze suma: S=1-13+135-...135...(2n-1).
Ce este greit n secvena de instruciuni de mai jos:
if (n<5) x=while; else i:=i+1; while (p<4) k++;
Fie a, b, c trei numere reale. Scriei o funcie care s verifice dac a, b
pot reprezenta lungimile laturilor unui dreptunghi, respectiv c s fie
diagonal n acel dreptunghi.
a) Elaborai un program care s tipreasc tabela de temperaturi
Fahrenheit i echivalenele lor n centigrade sau grade Celsius, folosind
formula: C=(5/9)*(F-32), ntre valorile extreme 0 i 300 grade
Fahrenheit.
b) Elaborai un program care s tipreasc tabela corespunztoare
Celsius-Fahrenheit.
Ce execut urmtorul program C ? Rescriei-l folosind instruciunea for.
#include <stdio.h>
void main()
{
long nc=0;
while (getchar() != EOF) ++nc;
printf("%ld\n",nc);
48

7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.

22.
23.
24.
25.
26.
27.

}
Scriei un program care s numere spaiile, tab-urile i new-line-urile
(trecerile la un nou rnd) date de la tastatur.
Scriei un program care s copieze intrarea n ieire, nlocuind fiecare ir
de unul sau mai multe spaii cu un singur spaiu.
Scriei un program care s nlocuiasc fiecare tab printr-o secven de
trei spaii.
Scriei o funcie int power(int x, int n) care ridic pe x la
puterea n.
Scriei un program care s determine cel mai mare divizor comun a dou
numere ntregi, prin algoritmul clasic al lui Euclid (cu mpriri repetate).
S se determine dac dou numere sunt prime ntre ele sau nu.
S se scrie programe pentru a deplasa o bil pe ecran, de la stnga la
dreapta i de la dreapta la stnga, pn la acionarea unei taste.
Scriei un program care s citeasc mai multe numere ntregi, pn la
ntlnirea lui zero, i s determine cel mai mic numr i cel mai mare
numr citit.
Scriei un program care s calculeze valoarea unui polinom ntr-un punct
dat. Polinomul este dat prin coeficienii si. Nu se vor utiliza tablouri!
Scriei un program care s calculeze factorialul unui numr ntreg n.
Scriei funcii care s calculeze aria unui cerc n funcie de: a) raza
cercului; b) diametrul cercului; c) lungimea cercului; d) latura triunghiului
echilateral nscris n cerc; e) latura ptratului nscris n cerc.
Aceeai problem ca i cea anterioar, dar cu citiri/afiri colorate, n
diferite poziii ale ecranului text.
S se determine perimetrul i aria unui triunghi echilateral nscris ntr-un
cerc de diametru d.
S se determine cel de al treilea unghi al unui triunghi cnd se cunosc
celelalte dou.
S se rezolve un triunghi (adic s se determine elementele sale
necunoscute (lungimi de laturi sau msuri de unghiuri)), cnd se cunosc:
a) lungimile celor trei laturi;
b) lungimea a dou laturi i msura unghiului dintre ele;
c) lungimea unei laturi i msurile unghiurilor adiacente ei
S se determine aria unui trapez cnd se cunosc lungimile bazelor i a
nlimii.
S se determine lungimea unui cerc n funcie de aria sa.
S se determine aria ptratului circumscris unui cerc, cunoscnd aria
ptratului nscris n cerc.
Catetele unui triunghi dreptunghic au lungimile a i b. S se determine
ipotenuza, perimetrul i aria sa.
O carte are n foi i r rnduri pe fiecare pagin. Cte rnduri are cartea?
Un punct material se afl la distana x0 de origine, la momentul iniial t0,
cnd ncepe s se mite rectiliniu uniform. tiind c la momentul t se
afl la distana x fa de origine, s se determine viteza v de micare a
punctului material, la momentul t.
49

28.
29.
30.
31.
32.

33.

34.
35.
36.
37.

38.

39.

40.

41.

Scriei o funcie care s transforme un unghi exprimat n radiani n


valoarea sa exprimat n grade i una care s fac transformarea
invers.
Scriei o funcie care s determine diferena dintre dou momente de
timp, date prin ore, minute i secunde.
Viteza unui automobil este de v km/h. Exprimai aceast vitez n m/s.
Un muncitor lucreaz n zile pentru a termina o lucrare. S se determine
cte zile sunt necesare pentru a termina aceeai lucrare o echip de m
muncitori.
Dou echipe de muncitori au n componena lor m1, respectiv m2
muncitori. Prima echip termin o lucrare n z1 zile, iar cea de a doua n
z2. S se determine:
a) z2 n funcie de m1, z1, m2;
b) m2 n funcie de m1, z1, z2.
ntr-o magazie sunt urmtoarele produse: fasole, cartofi i roii n
cantitile f, c, r. Un kilogram de fasole cost cf lei, unul de cartofi cc
lei. S se determine costul unui kilogram de roii, tiind c toate
legumele din magazie cost C lei.
Scriei un program care s rezolve ecuaia de gradul I ax+b=0.
Scriei un program care s rezolve ecuaia de gradul II ax2+bx+c=0,
inclusiv pentru a=0 sau cnd ecuaia admite soluii complexe, nereale.
S se determine dac un numr a este divizibil cu toate numerele b1, b2
i b3.
S se scrie un program care s citeasc dou numere reale a i b. Apoi
s pun utilizatorului o ntrebare: Ce dorii s calculm ? Media
aritmetic (1) sau geometric (2)?. Dac se va rspunde prin 1, se va
calcula i afia media aritmetic, iar pentru 2 media geometric (numai
dac numerele sunt pozitive !, iar de nu, se va afia eroare !). Dac nu
se rspunde prin 1 sau 2 se va produce un sunet n difuzor.
S se scrie un program care s citeasc trei numere reale a, b i c, apoi
s pun o ntrebare de genul: Ce dorii s calculm? Aria sau
perimetrul?. Dac se va rspunde prin aria atunci se va calcula i afia
aria, altfel perimetrul. Ce se va ntmpla dac se va rspunde prin arie ?
S se scrie un program care s citeasc un numr ntreg, iar dac acest
numr este 1 s afieze luni, dac este 2 s afieze mari, ... 7 duminic, iar dac nu este cuprins ntre 1 i 7 s afieze cuvntul eroare.
S se scrie programul folosind: a) instruciunea if; b) instruciunea
switch.
S se scrie un program care s calculeze aria unui cerc n funcie de
diametru, dac rspunsul la ntrebarea: Aria n funcie de diametru (1)
sau lungime (2)? este fie caracterul 1, fie caracterul D, sau s
calculeze aria cercului n funcie de lungime, dac rspunsul este 2 sau
L, iar dac rspunsul este diferit de aceste patru posibiliti s se
produc un sunet.
Venitul unei societi comerciale este de venit milioane lei, iar
cheltuielile sunt de chelt lei. S se precizeze dac profitul societii
50

42.

43.

44.
45.
46.

47.
48.
49.

50.

este mai mare sau nu dect o valoare constant profit_minim = 500


(milioane lei).
S se precizeze dac un triunghi cu lungimile celor trei laturi a, b i c
este sau nu isoscel. n caz afirmativ, s se produc un sunet i s se
afieze Tra-la-la n mijlocul ecranului, altfel s se rezolve ecuaia
ax2+bx+c=0, unde a i b sunt lungimile primelor dou laturi ale
triunghiului, iar c este semiperimetrul su.
S se realizeze urmtorul joc: o bil se mic pe ecran ca pe o mas de
biliard (vezi problema 2). O palet de lungime 9 (caractere), situat pe
ultima linie a ecranului, se deplaseaz stnga-dreapta cu ajutorul a dou
taste (vezi problema 3). Cnd bila lovete paleta, n difuzor se aude un
sunet mai lung, iar cnd ea lovete pereii laterali, un alt sunet, mai scurt.
Jocul se oprete cnd se apas o anumit tast de stop.
Se citesc de la tastatur caractere, pn la ntlnirea a dou caractere
care sunt identice. S se determine cte caractere sunt cifre dintre cele
citite.
De la tastatur se introduce o list de numere ntregi. Se cere s se
afieze valoarea maxim depistat n list. Dimensiunea listei este
precizat nainte de a fi introduse elementele ce o compun.
S se scrie un program care s deseneze un dreptunghi umplut cu o
anumit culoare (o cutie). Dreptunghiul se va specifica prin coordonatele
colurilor stnga-jos i lungimile laturilor, care, alturi de culoare, vor fi
introduse de la tastatur.
S se scrie un program care s deseneze pe ecran dreptunghiuri de
dimensiuni aleatoare, n poziii aleatoare i de culori aleatoare pe ecran,
pn se acioneaz o tast numeric.
S se inverseze (oglindeasc) un numr (care nu se termin cu cifra 0).
De exemplu, pentru numrul 10758 s obinem numrul 85701.
S se realizeze urmtoarea piramid a numerelor:
1
12
123
.........
1 2 3 ... n
n care numrul n este citit de la tastatur.
Folosind, pe rnd, fiecare din cele trei instruciuni repetitive, s se
calculeze valoarea urmtorului produs:

P = (1
51.

52.

1
1
1
)
(
1

)
...(
1

).
22
32
n2

S se afieze piramida de numere de mai jos:


n n-1 n-2 ... 3 2 1
.................
21
1
S se produc n difuzor un sunet cresctor, apoi descresctor i tot aa,
pn se acioneaz o tast cu o liter mare.
51

53.

54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.

S se afieze piramida de numere:


1
123
12345
...................
1 2 3 4 ... (2n-1)
S se calculeze, folosind instruciunea do, suma S=2+4+6+...+(2n),
unde n1.
S se produc n difuzor un sunet aleator, pn se acioneaz o tast.
Realizai un program care s afieze numele anotimpului corespunztor
unui numr ntreg citit de la tastatur (1..4). Scriei dou variante de
program: folosind if i folosind switch.
Scriei un program care s pun ntrebarea: n ce an s-a nscut
Eminescu ? i. dac rspunsul este corect (1850), atunci s afieze
Foarte bine, altfel un text corespunztor. Folosii instruciunea switch.
Se citete un ir de numere ntregi pna la ntlnirea numrului 0. S se
calculeze media aritmetic a numerelor din ir.
Se citesc 3 numere naturale n, p i k, apoi un ir de n numere naturale.
Cte dintre acestea, mprite la p dau restul k ?
S se calculeze produsul a dou numere naturale prin adunri repetate.
Efectuai mprirea ntreag a dou numere, fra a utiliza operatorii / i
%, ci doar scderi repetate.
Se citete un numr natural. Cte cifre conine ?
Un numr se numete palindrom dac citit invers este acelai numr.
S se verifice dac un numr este sau nu palindrom.
S se afieze toate numerele prime mai mici sau egale cu un numar m
dat.
S se afieze primele n numere prime care au suma cifrelor m.
S se afieze toate numerele de 3 cifre care, citite invers, sunt tot
numere prime.
Calculai i afiai suma: 1/(12) + 1/(23) + 1/(34) + ... +
1/(n(n+1)).
S se verifice dac un numr natural este sau nu ptrat perfect.
S se scrie un program care s rezolve cte o ecuatie de gradul II, pn
utilizatorul programului nu mai vrea acest lucru.
S se verifice dac un numr natural este sau nu cub perfect.
S se afieze toate numerele de forma a2+b3, cu 1a5 i 1b5.
S se determine toate triunghiurile diferite cu laturi numere ntregi
pozitive i perimetru p.
S se listeze toate numerele n, a cror sum a cifrelor este divizibil
prin 5.
S se transforme un numr din baza 10 n baza p<10. S se transforme
un numr din baza p<10 n baza 10.
S se transforme un numr din baza p n baza q, unde p, q 10.

52

76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.

Se citesc numere naturale pn la ntlnirea numrului 0. S se afieze


soluiile tuturor ecuaiilor de gradul I ax+b=0, unde a i b sunt toate
perechile de numere citite consecutiv, n care b este divizibil prin a.
Se citesc numere naturale pn la introducerea unui numr real. S se
calculeze suma S a tuturor numerelor citite, precum i ctul i restul
mpririi lui S la suma cifrelor lui S.
Se citesc numere naturale pn la ntlnirea numrului 12. S se afieze
toate tripletele de numere citite consecutiv, n care al treilea numr este
restul mpririi primului la al doilea.
Se citesc numere naturale pn la ntlnirea numrului 0. S se afieze
toate tripletele de numere citite consecutiv, n care al treilea numr este
media aritmetic (geometric) dintre primul i al doilea.
Se citesc numere naturale pn la ntlnirea numrului 0. S se afieze
toate perechile de numere citite consecutiv, cu proprietatea c al doilea
numr este egal cu suma cifrelor primului numr.
Se citesc numere naturale pn la ntlnirea numrului 0. S se afieze
toate perechile de numere citite consecutiv, cu proprietatea c al doilea
numr reprezint restul mpririi primului numr la suma cifrelor sale.
Se citesc numere naturale pn la ntlnirea numrului 0. S se afieze
toate perechile de numere citite consecutiv, cu proprietatea c al doilea
numr reprezint numrul de apariii ale cifrei 3 n ptratul primului.
Se citesc numere naturale pn la ntlnirea numrului 0. S se afieze
toate perechile de numere citite consecutiv, cu proprietatea c al doilea
numr reprezint ptratul numrului de apariii ale cifrei 1 n primul.
Se citesc numere naturale pn la ntlnirea numrului 0. S se afieze
toate tripletele de numere citite consecutiv, cu proprietatea c al treilea
numr este suma dintre primul i al doilea.
Se citesc numere reale pn la ntlnirea numrului 0. S se afieze
toate tripletele de numere citite consecutiv, cu proprietatea c ele pot
reprezenta laturile unui triunghi.
Se citesc numere reale pn la ntlnirea numrului 0. S se afieze
toate tripletele de numere citite consecutiv, cu proprietatea c ele pot
reprezenta laturile unui triunghi isoscel.
Se citesc numere reale pn la ntlnirea numrului 0. S se afieze
toate tripletele de numere citite consecutiv, cu proprietatea c ele pot
reprezenta laturile unui triunghi dreptunghic.
Se citesc numere reale pn la ntlnirea numrului 0. S se afieze
soluiile tututor ecuaiilor de gradul 2 ax2+bx+c=0, unde a, b i c sunt
toate tripletele de numere citite consecutiv, n care b2-4ac=0.
Se citesc numere reale pn la ntlnirea numrului 0. S se afieze
soluiile tututor ecuaiilor de gradul II ax2+bx+c=0, unde a, b i c sunt
toate tripletele de numere citite consecutiv, n care b2-4ac>0.
Se citesc numere naturale pn la ntlnirea numrului 0. S se afieze
toate perechile de numere (n1,n2) citite consecutiv, cu proprietatea c
n1>n2 i suma cifrelor lui n1 este mai mic dect suma cifrelor lui n2.
53

91.
92.
93.

94.
95.
96.
97.
98.
99.
100.

101.
102.
103.
104.

S se gseasc toate reprezentrile posibile ale numrului natural n ca


sum de numere naturale consecutive.
S se calculeze determinantul unei matrice ptratice de ordinul doi i a
unei matrice ptratice de ordinul trei.
La un concurs sportiv s-au nscris patru echipe A, B, C i D. La sfritul
tuturor probelor cele patru echipe au obinut respectiv X, Y, Z i T puncte.
S se afieze valoarea de adevr a propoziiei: Echipa A a obinut cel
mai mare punctaj.
Scriei un program care s se rezolve ecuaia de gradul III:
ax3+bx2+cx+d=0, a, b, c, d numere reale, a0, folosind metoda lui
Cardano.
Generai trei numere reale din intervalul [0,1) i apoi calculai i afiai
media lor aritmetic.
Prima defectare a unui calculator survine dup o durat de funcionare
specificat prin trei numere ntregi: h ore, m minute i s secunde. Scriei
un program care s determine durata de funcionare n secunde.
Scriei un program care s rezolve un sistem de dou ecuaii liniare cu
dou necunoscute: a1x+b1=c1, a2x+b2=c2.
Scriei un program care s determine elementele mulimii
{x|xR, cos(narccos(x))=0}.
Calculai media armonic a trei numere reale x, y i z.
Scriei funcii i apoi dezvoltai programe C pentru rezolvarea
urmtoarelor probleme:
a) Fie A(x1,x2) i B(x2,y2) dou puncte din planul euclidian. Afiai:

distana euclidian de la A la B;

coordonatele mijlocului segmentului |AB|.


b) Fie A(x1,y1), B(x2,y2) i C(x3,y3) cele trei puncte din planul
euclidian ce reprezint colurile unui triunghi ABC. S se determine:

coordonatele mijloacelor laturilor;

lungimile laturilor;

lungimile medianelor.
c) Pentru datele de la punctul anterior, s se determine coordonatele
cercului nscris n triunghi i a celui circumscris triunghiului, precum i
razele acestor cercuri.
d) S se determine coeficienii a, b i c ai dreptei ax+by+c=0, care trece
prin punctele P i Q de coordonate date.
Scriei un program care s verifice dac trei puncte din planul euclidian,
date prin coordonatele lor (x1,y1), (x2,y2) i (x3,y3) sunt sau nu
coliniare.
S se verifice dac trei drepte, date prin ecuaiile lor de forma
ax+by+c=0, sunt sau nu concurente.
S se calculeze distana de la un punct P(xp,yp) la dreapta
ax+by+c=0.
Dndu-se trei numere reale a, b i c, s se rezolve ecuaia
ax4+bx2+c=0, a0.
54

105. Scriei un program C care s studieze natura i semnul soluiilor unei


ecuaii de gradul doi.
106. Se citete un numr natural n i se cere s se afieze descompunerea
lui n factori primi.

55

Capitolul 2. Tablouri i pointeri


y iruri de caractere y tablouri y legtura pointerilor cu tablourile y
y operaii pe bii y

Probleme rezolvate
1.
S se scrie un program care s contorizeze apariiile fiecrei cifre,
a fiecrui caracter de spaiere (blanc, tab, linie nou) i a tuturor
celorlalte caractere.
#include <stdio.h>
void main()
{
int c, i, n_sp=0, n_altele=0;
int n_cifre[10];
for (i=0; i<10; n_cifre[i++]=0);
while ((c = getchar()) != EOF)
if (c >= '0' && c <= '9')
++n_cifre[c-'0'];
else if (c == ' ' || c == '\n' || c == '\t')
++n_sp;
else
++n_altele;
printf("Cifrele: ");
for (i=0; i<10; i++)
printf(" %d",n_cifre[i]);
printf("\nCaractere de spatiere: %d, alte
caractere: %d\n",n_sp,n_altele);
}

Exemplul ne permite s punem n eviden mai multe aspecte ale


limbajului:
declaraia int n_cifre[10] reprezint crearea unui tablou unidimensional
(vector, ir) de 10 numere ntregi, indexate de la 0 la 9 (unde n_cifre[c]
reprezint numrul de apariii ale cifrei c n fiierul standard de intrare (de
exemplu tastatura)); indicele poate fi orice expresie ntreag, inclusiv
variabilele ntregi ca i sau constantele ntregi;
incrementarea ++n_cifre[c-'0'] pune n eviden diferena ntre dou
caractere, adic diferena ntre codurile lor ASCII, care se transform n numar
ntreg, adic ntr-un indice cu valori ntre 0 i 9;
instruciunea for pune n eviden un mecanism de utilizare a operatorului
++ pentru indicele i; astfel, ciclul for de acolo face o iniializare a
elementelor vectorului cu 0; dac am fi scris n_cifre[++i], diferena era c,
n acest al doilea caz, mai nti se incrementa i, apoi se folosea pe post de
indice, ceea ce ar fi nsemnat c i ar fi fost folosit ca indice de la 1 la 10 i nu
de la 0 la 9, ca n cazul descris;

56

reprezentarea caracterelor de trecere la o noua linie (Enter): '\n' i de


TAB: '\t';
folosirea constantei EOF care reprezint sfritul de fiier; practic, la
rularea programului, pentru a termina ciclul while, va trebui tastat Ctrl-Z.
2. S se scrie un program care citete mai multe linii i o tiprete pe cea
mai lung.
Vom pune n eviden, cu ajutorul acestui exemplu, lucrul cu tablourile
de caractere. Schia programului este simpl:
while (mai exist o alt linie)
if (este mai lung dect linia anterioar)
salveaz-o pe ea i lungimea ei;
tiprete linia cea mai lung
Vom scrie o funcie getline care s citeasc urmtoarea linie de la
intrare (un fel de generalizare a lui getchar). getline va trebui, n cel mai
defavorabil caz, s returneze un semnal despre un eventual sfrit de fiier; ea
va returna lungimea liniei, respectiv 0, cnd se ntlnete sfritul de fiier;
zero nu este niciodat o lungime valid de linie, deoarece orice linie are cel
puin un caracter, chiar i o linie ce conine doar caracterul linie nou are
lungimea 1. Salvarea unei linii mai lungi dect linia anterioar se va face cu
funcia copy.
#include <stdio.h>
#define lung_max 1000 // lungimea maxima a unei linii
int getline(char s[], int limita)

Primul argument al funciei este un tablou de caractere (nu se


precizeaz lungimea), iar cel de al doilea un numr ntreg; comunicarea cu
main() se face astfel: maingetline : prin argumente; getlinemain : prin
rezultatul funciei getline.

int c, i;
for (i=0; i < limita-1 && (c = getchar()) != EOF
&& c != '\n'; ++i)

Att timp ct nu s-a atins limita maxim admis i nu s-a ajuns la


sfritul de fiier (deci nu s-a tastat Ctrl-Z, de pild) i nici nu s-a ajuns la o
linie nou (tastarea lui Enter), se preia n c un caracter de la intrarea standard.
s[i] = c; // acesta se pune in tabloul s, pe pozitia i
if (c == '\n')
Dac ultimul caracter introdus era '\n', acesta se adaug liniei s.
s[i++] = c;
s[i] = '\0';

La sfritul liniei se pune caracterul cu codul 0 care simbolizeaz, n


cazul tablourilor de caractere sfritul de sir: caracterul NULL.

return i;
}
void copy(char s1[], char s2[])
Copiaz n tabloul s2 coninutul tabloului s1, firete pn se ntlnete
caracterul de sfrit de ir '\0'.
57

{
}

int i=0;
while ((s2[i++] = s1[i]) != '\0');

Mai nti s2[i] primete valoarea lui s1[i], iar apoi i crete cu 1.
void main()
{
int lung, max;
// lungimea liniei curente si a celei maxime pana acum
char linie[lung_max];
// linia curenta introdusa = un vector de caractere
char linie_maxima[lung_max]; // cea mai lunga linie
max=0;
while ((lung = getline(linie,lung_max)) > 0)
if (lung > max)
{ max = lung; copy(linie,linie_maxima); }
if (max > 0)
printf("Linia maxima este: %s Ea are lungimea: %d.",
linie_maxima,max);
else printf("Nici o linie citita...");
}
Dac rulai programul, vei vedea c funcia copy lucreaz corect i ne
referim aici la faptul c valoarea primit de s2 este trimis n exterior, aa cum
se ntampla n exemplele unde vorbeam despre transmiterea parametrilor prin
referin.
Acest lucru este posibil, deoarece in C o expresie de forma:
<exp1>[exp2]

este, de fapt, definit ca un pointer:


*((exp1) + (exp2)).
Rulnd programul vei observa c mesajul Ea are lungimea ... va fi
afiat pe o linie nou, iar asta deoarece linie_maxima conine drept ultim
caracter pe '\n'. "%s" folosete pentru afiarea irurilor de caractere.

3.
S se rescrie programul de la exemplul anterior folosind declaraii
de variabile globale.
O variabil global trebuie s fie definit n afar oricrei funcii (deci
nici mcar n funcia "main"; acest lucru face s se aloce memorie real
pentru ea. Astfel de variabile pot fi accesate prin numele lor de orice funcie din
program. Ele i pstreaz valorile i dup ce funcia care le-a folosit i,
eventual, setat i-a terminat execuia.
Vom rescrie programul precedent, n care linie, linie_maxima i max
vor fi declarate variabile globale, externe oricarei funcii. Astfel, antetele,
corpurile i apelurile functiilor se vor schimba.
#include <stdio.h>
#define lung_max 1000 // lungimea maxima a unei linii
char linie[lung_max], linie_maxima[lung_max];
int getline()
58

//
//
//
//
//

int c, i;
for (i=0; i < lung_max-1 && (c = getchar())
!= EOF && c != '\n'; ++i) linie[i] = c;
acesta se pune in tabloul s, pe pozitia i
if (c == '\n')
daca ultimul caracter introdus era '\n', acesta se adauga
linie[i++] = c; // liniei s
linie[i] = '\0';
la sfarsitul liniei se pune caracterul cu codul 0,
care simbolizeaza, in cazul tablourilor de caractere,
sfarsitul de sir
return i;

}
void copy()
{
int i=0; while ((linie_maxima[i++] = linie[i]) != '\0');
}

void main()
{
int lung, max;
// lungimea liniei curente si a celei maxime pana acum
max=0;
while ((lung = getline()) > 0)
if (lung > max) // !!
{ max = lung; copy(); }
if (max > 0)
printf("Linia maxima este: %s Ea are lungimea: %d.",
linie_maxima,max);
else printf("Nici o linie citita...");
}

Observaie: dac se vor introduce mai multe linii de aceeai lungime


maxim, se va observa c programul o afieaz pe prima linie din ele. Dac
relaia notat '!!' s-ar scrie: "lung >= max", atunci s-ar afia ultima dintre
aceste linii maxime.
4.

Scriei o funcie care s returneze lungimea unui ir de caractere.


Funcia se numeste strlen; ea nu ia n considerare caracterul NULL.

#include <stdio.h>
int strlen(char s[])
/* functia este o rescriere a lui 'strlen' din fisierul
"string.h", care contine mai multe declaratii referitoare la
sirurile de caractere si prelucrarea lor */
{
int i=0; while (s[i++] != '\0');
return i-1;
}
void main()
{
char s[20];
puts("\nDati sirul: "); gets(s); int l=strlen(s);
printf("Lungimea sirului este: %d",l);
}
59

5.

Scriei o funcie care convertete un ir de caractere ntr-un ntreg.


De fapt, avem de rescris funcia atoi, definit n <stdlib.h> :

#include <stdio.h>
int atoi(char s[])
{
int i, n=0;
for (i=0; s[i] >= '0' && s[i] <= '9'; i++)
n = 10*n + s[i] - '0';
/* conversia se opreste odata cu intalnirea unui caracter ce nu
este cifra */
return n;
}
void main()
{
char s[10];
puts("\nDati sirul: "); gets(s);
printf("Numarul este: %d.",atoi(s));
}

Dupa cum am artat i n exemplul Q1, expresia s[i]-'0' reprezint


valoarea numeric a caracterului aflat n s[i], deoarece valorile caracterelor
'0', '1' etc. formeaz un ir cresctor pozitiv i contiguu.
6.
Scriei un program care citete un ir de caractere i afieaz irul
de caractere doar cu litere mici.
Vom scrie o funcie lower care va transforma n liter mic o majuscul
din setul ASCII. #include <stdio.h>

#include <conio.h>
char lower(int c)
// se foloseste conversia intre char si int !
{
if (c >= 'A' && c <= 'Z') return c+'a'-'A';
else return c;
}
void main()
{
clrscr();
char s[30], t[30];
puts("Dati sirul initial: "); gets(s);
for (int i=0; s[i]; t[i] = lower(s[i]), i++);
t[i] = NULL; // se marcheaza sfarsitul sirului t
printf("Sirul final este: \n");
printf("%s",t);
getch();
}

De observat c se putea folosi o instructiune for ca urmtoarea:


for (int i=0; i<=strlen(s); ...),
adic folosind funcia
descris ntr-un exemplu anterior.
7.

S se elimine toate apariiile caracterului spaiu dintr-un text.


60

Vom scrie o funcie mai general elimina(char s[], char c) care


va elimina toate apariiile caracterului c din irul s.

#include <stdio.h>
void elimina(char s[], char c)
{
int d=c;
// se foloseste conversia unui caracter la un intreg
int i,j;
for (i = j = 0; s[i]; i++) // o atribuire multipla: i=j=0
if (s[i] != d)
s[j++] = s[i];
// intai se foloseste j ca indice in s, apoi j=j+1
s[j] = NULL; // adica '\0'
}
void main()
{
char s[40];
puts("Dati textul: "); gets(s); elimina(s,' ');
puts("A ramas textul: "); puts(s);
}

8.
Scriei o funcie getbits(x, p, n) care s returneze (cadrat la
dreapta) cmpul de lungime n bii al lui x, care ncepe la poziia p.
Presupunem c bitul 0 este cel mai din dreapta i c n i p sunt valori
pozitive sensibile. De exemplu, getbits(x,4,3) returneaz 3 bii n poziiile 4,
3 i 2, cadrai la dreapta.
#include <stdio.h>
unsigned getbits(unsigned x, unsigned p, unsigned n)
{
return ((x >> (p+1-n)) & ~(~0 << n));
}
void main()
{
int x=13; // 00001101
printf("\nx=%d",x);
int y=getbits(x,4,3);
printf("\ny=%d",y); // 3, adica 011
}
Funcia getbits are argumente de tip unsigned, iar tipul returnat este
tot unsigned. unsigned, alturi de signed, short i long se numesc

modificatori de tip. Un astfel de modificator schimb semnificaia tipului de


baz pentru a obine un nou tip.
Fiecare dintre aceti modificatori poate fi aplicat tipului de baz int.
Modificatorii signed i unsigned pot fi aplicai i tipului char, iar long
poate fi aplicat lui double.
Cnd un tip de baz este omis din declaraie, se subnelege c este
int. Exemple:
long
x;
int este subneles
unsigned char
signed
int
unsigned long int

ch;
i;
l;

signed este implicit


nu era nevoie de int
61

Acest exemplu pune n eviden i un alt aspect al limbajului C, cum ar


fi operatorii pentru manipularea biilor, din care noi am folosit doar civa.
Operatorii pentru manipularea biilor sunt:
{I, bit cu bit
SAU inclusiv, bit cu bit
SAU exclusiv, bit cu bit
deplasare la stanga a bitilor (despre care am mai vorbit)
deplasare la dreapta a biilor
complement fa de 1 (este un operator unar)
Acestia nu se pot aplica lui float sau lui double.
Operatorul {I, bit cu bit & este folosit adesea pentru a masca
anumite mulimi de bii.
De exemplu, c = n & 0177 pune pe zero toi biii lui n, mai puin bitul
7, (cel mai tare).
Operatorul SAU, bit cu bit | este folosit pentru a pune pe 1 bii:
x = x | MASK pune pe 1, n x, biii care sunt setai pe 1 n MASK.
Trebuie s distingei cu grij operatorii pe bii & i | de conectorii
logici && i ||. De exemplu, dac x este 1 i y este 2, atunci x & y este 0,
dar x && y este 1!
Operatorul unar ~ d complementul fa de 1 al unui ntreg, adic el
convertete fiecare bit de 1 n 0 i invers.
Un exemplu de utilizare ar fi: x&~077. Aici se mascheaz ultimii 6 bii ai
lui x pe 0. De notat c x&~077 este independent de lungimea cuvntului i
deci, preferabil, de exemplu, lui x&0177700, care vede pe x ca o cantitate de
lungime 16 bii.
n funcia getbits, x este declarat unsigned pentru a ne asigura c la
shiftarea spre dreapta, biii vacani vor fi umplui cu 0 i nu cu biii de semn
(independent de implementarea de C !). ~0 este cuvntul cu toi biii pe 1. Prin
operatia ~0 << n crem o masc cu zerouri pe cei mai din dreapta n bii i 1 n
rest; complementndu-l apoi cu ~, facem o masc cu 1 pe cei mai din dreapta
n bii.
Propunem cititorului s rescrie getbits pentru a numra biii de la
stnga la dreapta. Un alt exerciiu ar putea fi scrierea unei funcii
right_rot(n,b) care s roteasc ntregul n la dreapta cu b poziii.
&
|
^
<<
>>
~

9.
Scriei o funcie bitcount(n) care s contorizeze numrul de bii
pe 1 dintr-un argument ntreg.
#include <stdio.h>
int bitcount(unsigned n)
{
for (int b=0; n; n =>> 1) // este echivalent cu n=n>>1
if (n & 01)
b++;
return b;
}
62

void main()
{
long x; printf("\nDati x: "); scanf("%ld",&x);
printf("Avem %d biti pe 1 in %ld",bitcount(x),x);
}

10.
Dndu-se o expresie (cuprinznd paranteze rotunde, operanzi
litere mici ale alfabetului latin i operatorii +, -, * i /), s se scrie n
forma polonez posfixat.
De exemplu, pentru expresia "a*(b+c)" se obine abc+*, iar pentru
expresia a*(b+c)-e/(a+d)+h se obine abc+*ead+/-h+.
Fie s expresia iniial i fp forma sa polonez. Algoritmul de rezolvare
a problemei folosete o stiv a operatorilor, notat cu st. Se citete cte un
caracter s[i] din expresie i:
a) dac el este '(', atunci se trece n stiv;
b) dac este ')' se trec n fp toi operatorii, pn la ntlnirea lui '(', care se
terge din stiv;
c) dac s[i] este un operator aritmetic, se compar prioritatea sa cu a acelui
operator aflat n vrful stivei i:
dac este mai mic, se copiaz din stiv n fp toi operatorii cu prioritate mai
mare sau egal dect acesta, apoi acest operator e trecut n stiv;
dac nu, se trece direct n stiv acest operator;
n orice alt caz, rmne c s-a citit un operand, iar acesta se trece n fp.
Programul C care rezolv problema este dat mai jos:
/* FormaPoloneza */
#include <stdio.h>
#include <string.h>
int pr(char c)
{
switch(c) {
case '(': return 0;
case '+':
case '-': return 1;
case '*':
case '/': return 2;
}
return -1;
}
void main()
{
char t[30]="", s[30]="", fp[30]="", st[30]="";
int i,sp=-1,k=-1;
printf("Expresia: "); scanf("%s",&t);
strcpy(s,"("); strcat(s,t); strcat(s,")");
for (i=0; i<=strlen(s); i++)
switch (s[i]) {
case '(': st[++sp]='('; break;
case ')': while (st[sp]!='(') fp[++k]=st[sp--];
sp--; break;
case '+': case '-': case '*':
63

case '/':
if (pr(st[sp])>=pr(s[i]))
{
while (pr(st[sp])>=pr(s[i]))
{ fp[++k]=st[sp]; sp--; }
st[++sp]=s[i];
}
else st[++sp]=s[i];
break;
default: fp[++k]=s[i];

}
printf("Forma poloneza este: %s\n",fp);
fflush(stdin); getchar();

Probleme propuse
1.
2.
3.

4.
5.
6.
7.
8.
9.
10.

11.
12.

Se citesc de la intrare mai multe linii. Scriei un program care s


tipreasc toate liniile mai scurte de 80 de caractere.
S se elimine spaiile nesemnificative (cele de dup un caracter diferit de
spaiu sau tab) din fiecare linie de intrare i, de asemenea, tergei liniile
care conin doar spaii.
Elaborai un program care s "mptureasc" liniile de intrare lungi dup
ultimul caracter diferit de spaiu care apare nainte de a n-a coloan a
intrrii, unde n este un parametru. Asigurai-v c programul
dumneavoastr lucreaz inteligent cu liniile foarte lungi, chiar dac nu e
nici un tab sau spaiu nainte de coloana respectiv.
Scriei o funcie void rightrot(unsigned n, unsigned b) care
rotete ntregul n la dreapta cu b poziii.
Scriei o funcie void invert(unsigned x, unsigned p,
unsigned n) care inverseaz cei n bii ai lui x, care ncep de la poziia
p, lsndu-i pe ceilali neschimbai.
Scriei o funcie care terge fiecare caracter din irul s1 care se
potrivete cu vreun caracter din irul s2.
Scriei o funcie lower care s converteasc literele mari n litere mici
pentru un ir de caractere, folosind o expresie condiional i nu if.
Scriei programe care s realizeze inversarea unui vector: a) n acelai
vector i fr a utiliza un vector suplimentar; b) ntr-un alt vector.
Scriei un program C care s determine simultan minimul i maximul unui
vector de numere reale.
Scriei o funcie care s expandeze notaiile scurte de tipul a-z ntr-un ir
s1 n lista echivalent i complet abc..xyz n irul s2. Sunt permise att
litere mari, mici, ct i cifre. Se vor trata i cazuri de tipul a-b-c i a-z0-9
sau -a-z.
Pentru un vector de numere reale dat, s se determine a) S1= suma
componentelor sale; b) S2 = suma ptratelor componentelor vectorului.
S se afieze doar elementele pare dintr-un vector de numere ntregi.

64

13.
14.
15.

16.
17.

18.

19.

20.
21.
22.
23.
24.

S se afieze doar elementele de pe poziii impare dintr-un vector


oarecare.
S se determine numrul elementelor negative i a celor pozitive dintr-un
vector de numere reale.
Se consider un ir de n persoane, notat cu x. S se verifice dac,
pentru o persoan p dat, exist o persoan n x cu acelai nume ca i
p. Dac nu, s se insereze pe poziia k n x noua persoan p. Discuie
dup valoarea lui k.
S se afieze toate numere prime dintr-un tablou de numere ntregi
pozitive.
Fie declaraiile: float a[20]; int n; float e. S se determine
valoarea e n fiecare din cazurile:

e = x0+x1+...+xn-1 (adic x[0]+x[1]+...+x[n-1]);

e = x1+x3+...+x..;

e = x0x1x2...xn;

e = x1x3x5...x..;

e = media aritmetic a componentelor din vector;

e = suma cuburilor componentelor negative din vector;

e = x0-x1+x2-x3+... xn-1;
Fie doi vectori de numere reale x i y, din care doar componentele
0..n-1 se folosesc. S se determine vectorul de numere reale z, astfel
nct:

z[i]=x[i]+y[i];

z[i]=x[i]-y[i];

z[i]=minimul dintre x[i] i y[i].


Fie doi vectori x i y, din care doar primele n componente se folosesc.
S se determine expresia e calculat astfel:

e=(x0+y0)(x1+y1)...(xn-1+yn-1);

e=x0y0+x1y1+...+xn-1yn-1;// produsul scalar a doi vectori

e=minim(x0,yn-1) + minim(x1,yn-2) + minim(x2,yn-3) +


... + minim(xn-1,y0);

e = x02y1+x12y2+...+xn-12y0.
Memorai n primele n componente ale unui vector x de numere ntregi
primele n numere prime.
Memorai n primele n componente ale unui vector x de numere ntregi
primele n numere prime mai mari decit 999, care citite invers sunt tot
numere prime.
Fie un vector x de numere ntregi. S se formeze un vector y de numere
ntregi, n care y[i] s fie reprezentarea n baza 2 a numrului x[i].
Fie un vector x de numere ntregi. S se formeze un vector y de numere
ntregi, n care y[i] s fie restul mparirii lui x[i] la suma cifrelor lui
x[i]. Complicai exerciiul fcnd mprirea prin scderi repetate!
Fie un vector x de numere ntregi. S se determine un numr p, care s
fie cel mai mare numr prim din cadrul vectorului. Daca nu exist, atunci
65

25.

26.

27.

28.

p s fie egal cu 0. Dac p nu este 0, atunci s se mpart (ca numere


ntregi) toate componentele lui x la suma cifrelor lui p. Complicai
exerciiul, ncercnd s determinai radicalul prin metoda lui Newton, iar
mprirea s o facei prin scderi repetate!
Realizai, folosind tablouri, o aplicaie practic referitoare la un concurs
de admitere ntr-un liceu cu un singur profil. Exist n elevi candidai, iar
numrul de locuri este m. Fiecare elev ia dou note. Primii m elevi sunt
considerai reuii dac fiecare not a lor este mai mare sau cel puin
egal cu 5. Aplicaia va permite, aadar, ordonarea elevilor dup media
obinut, dar se cere i o ordonare alfabetic, precum i implementarea
cutrii unui elev dup nume.
S presupunem, n continuare, c au avut loc ordonrile descresctoare
ale mediilor pentru dou licee unde s-au susinut concursuri de admitere.
Inspectoratul colar Jude]ean ar putea fi interesat de situaia pe
ansamblu a notelor obinute de candidaii de la ambele licee, deci
ordinea descresctoare, dup medie, a reuniunii celor dou mulimi de
candidai. O prim soluie ar fi s realizm reuniunea mulimilor de
candidai, apoi s o sortm. Dar ar fi mai bine s ne folosim de faptul c
avem deja ordonai elevii pe dou liste. De aceea, v propunem s
scriei un program care face o interclasare a celor dou liste.
S presupunem c avem informaii despre un numr de maxim 10 elevi
(numele i punctajele lor obinute la un concurs de informatic). V
propunem s realizai o histogram a rezultatelor lor. Fiecare elev va fi
trecut cu numele su i cu o bar vertical, de o anumit culoare, ce
reprezint situaia sa, adic punctajul su, dup modelul din figur:

S presupunem c avem doi vectori A (de m elemente distincte) i B (de


n elemente distincte). S realizm reuniunea i respectiv intersecia lor.

pentru reuniune, vom copia n vectorul rezultat (Reun) toate


elementele din A, dup care vom aduga acele elemente din B
care nu se gsesc i n A;

pentru intersecie, vom pune n mulimea rezultat (Inters) toate


elementele din A care se regsesc n B.
Cele dou mulimi ar putea cuprinde candidaii la un concurs de
admitere. Se poate verifica, fcnd intersecia mulimilor, dac nu cumva
66

exist un elev care s se fi nscris la concurs la ambele licee, nclcnd,


astfel, legea!
29. Determinai valoarea unui polinom ntr-un punct. Coeficienii polinomului
sunt memorai ntr-un tablou de numere reale.
30. Memornd n tablouri coeficienii a dou polinoame, determinai suma i
diferena a dou polinoame, precum i produsul lor. S se mpart dou
polinoame, obinnd n doi vectori ctul i restul mpririi.
31. Un efect grafic interesant (pentru nceputul unui program mai complex)
am putea obine prin vizualizarea micrii unor bile de diferite culori pe
ecran. Acestea s se deplaseze ca pe o mas de biliard, dar s se
supun legii reflexiei, nu i a frecrii. Vom avea astfel nevoie de 5
vectori: doi pentru coordonatele bilelor (X i Y), unul pentru culorile bilelor
(Culoare) i nc doi pentru deplasrile relative (pe orizontal i pe
vertical) ale celor n bile (dX i dY, avnd componente ce iau doar
valorile -1 i +1.). Scriei un astfel de program.
32. Scriei o funcie care transform un ir scris cu litere mici n acelai ir,
cu litere mari. Apoi scriei o funcie care face conversia invers.
33. Limba psreasc. Problema cere nlocuirea fiecrei vocale V dintr-un
ir prin grupul pVp.
34. Scriei un program care s despart o propoziie n cuvinte i s le
numere.
35. Afiarea unui ir prin litere care cad. Jocurile pe calculator, pe care le
putei realiza i dumneavoastr, cu cunotinele de pn acum, pot avea
prezentri dintre cele mai frumoase. Un efect interesant i atractiv l
reprezint cderea unor litere; ele se depun pe un rnd al ecranului,
formnd un text. Realizai un astfel de program.
36. Scrisul defilant. Pe linia 20 va apare, defilnd de la dreapta la stnga, un
mesaj. El apare din extrema dreapt a ecranului i intr n cea stng.
Procesul se repet pn se apas o tast. Scriei un program care s
realizeze acest lucru.
37. ntr-o coal sunt m clase, fiecare avnd cte n elevi. Se cere s se
determine care elev are media la nvtur cea mai mare.
38. ntr-o clas exist NrB biei i NrF fete care i iubesc, ns fiecare fat
iubete numai anumii biei. Se cere s se determine biatul pe care l
iubesc cele mai multe fete, precum i topul tuturor bieilor. Dac exist
cel puin doi biei cu punctajele egale, atunci nu exist un unic fericit i
se va afia un mesaj corespunztor.
39. Un elev din clasa I are la dispoziie n litere mici din alfabetul latin, din
care m distincte. Doamna nvtoare i cere urmtoarele lucruri: a) S
verifice dac exist litere care apar de mai multe ori i s pstreze toate
literele distincte o singur dat. b) S aeze aceste litere n ordine
alfabetic. Exemplu: n=6, a,b,a,d,c,c sunt cele 6 litere. a) litere distincte:
a,b,d,c; b) ordinea alfabetic: a,b,c,d.
40. Pentru un grup de n persoane, se definesc perechi de forma (i,j) cu
semnificaia persoana i este influenat de persoana j. Se cere s se
determine persoanele din grup care au cea mai mare influen.
67

41.

42.

43.
44.

45.

46.

47.
48.
49.
50.
51.
52.

53.
54.
55.

O matrice cu n linii i n coloane (n impar) care conine toate numerele


naturale de la 1 la n2 i n care suma elementelor de pe fiecare linie,
coloan i diagonal este aceeai, se numete ptrat magic de ordinul n.
De exemplu, un ptrat magic de ordinul 3 este:
S se scrie un program care verific - printr-o singur parcurgere - dac
o matrice cu n linii i n coloane este ptrat magic, adic o matrice
ptratic n care suma de pe fiecare linie i cea de pe fiecare coloan,
precum i sumele elementelor de pe diagonale coincid.
Se d un ir a cu n elemente numere ntregi. S se scrie un program
care determin ce element se afl pe poziia k (dat) n irul obinut din
irul a prin ordonare, fr a-l ordona pe a i fr a utiliza alte iruri.
Numerele C1 , C2 , C3 , ..., Cn reprezint valorile colesterolului a n
persoane. O persoan este considerat sntoas dac are colesterolul
ntre dou limite date a i b. Se cere s se afle numrul persoanelor
sntoase i media aritmetic a colesterolului persoanelor bolnave.
O persoan are de cumprat din m magazine n produse care au preuri
diferite. S se ntocmeasc un program care s indice pentru fiecare
produs magazinul n care acesta are preul minim. Cunoscnd cantitile
ce trebuie cumprate din fiecare produs, s se determine suma ce
urmeaz a fi cheltuit.
Se consider n aruncri cu un zar. Se cere: a) S se determine de cte
ori apare fiecare fa i la a cta aruncare. b) S se determine toate
perechile de forma (Fi, Ki), cu proprietatea c Fi+Ki este un numr par,
unde Fi reprezint numrul feei, iar Ki = numrul de apariii ale feei Fi.
Se d un numr natural N. S se verifice dac numrul obinut prin
eliminarea primei i ultimei cifre din N este ptrat perfect.
S se determine cel mai mare divizor comun a n numere.
Se d o propoziie n care cuvintele sunt separate fie prin spaiu, fie prin
caracterele punct, virgul, punct i virgul, semnul exclamrii i semnul
ntrebrii. Desprii propoziia n cuvinte.
Dintr-o matrice dat M, s se listeze valorile tuturor punctelor a i poziia
lor. M[i,j] este considerat punct a dac este minim pe linia i i
maxim pe coloana j.
S se elimine dintr-o matrice A (cu m linii i n coloane) linia l i coloana k
i s se listeze matricea rmas. (Nu se va folosi o alt matrice.).
S se bordeze o matrice A (avnd m linii i n coloane) cu linia m+1 i
coloana n+1, unde A[m+1,j] s fie suma elementelor de pe coloana j,
cu j de la 1 la n, iar A[i,n+1] s fie suma elementelor de pe linia i, cu
i de la 1 la m.
Fiind dat un vector V cu n componente elemente ntregi, s se formeze
un nou vector W, n care W[i] s conin suma (produsul) cifrelor
elementelor lui V[i].
S se genereze aleator cuvinte de lungime 4.
S se insereze ntre oricare dou elemente dintr-un vector de numere
reale media lor aritmetic.
68

56.
57.
58.

59.
60.
61.

62.

63.

64.

S se determine de cte ori se ntmpl ca ntr-un vector de numere


reale s existe un element ce reprezint produsul elementelor sale
vecine.
S se scrie n spiral numerele de la 1 la n2 ntr-o matrice ptratic cu n
linii i n coloane ncepnd: a) din centrul matricei (n impar); b) din colul
stnga-sus. Se vor considera, pe rnd, ambele sensuri de deplasare.
Se d o matrice ptratic de ordin n. Se consider c cele dou
diagonale mpart matricea n patru zone: nord, sud, est i vest
(elementele de pe diagonal nu fac parte din nici o zon).

S se calculeze suma elementelor din nord, produsul elementelor


din sud, media aritmetic a elementelor din est i numrul
elementelor nule din vest.

S se obin simetrica matricei iniiale fa de diagonala


principal.

S se obin simetrica matricei iniiale fa de diagonala


secundar.

S se obin simetrica matricei iniiale fa de o ax orizontal ce


trece prin centrul matricei.

S se obin simetrica matricei iniiale fa de o ax vertical ce


trece prin centrul matricei.
Pentru o matrice cu m linii i n coloane, cu elemente numere reale, s se
listeze toate liniile, precum i numerele sale de ordine, care conin cel
puin k elemente nule.
Scriei un program care verific dac o matrice este simetric fa de
diagonala principal sau dac are toate elementele nule.
Se dau dou iruri de numere ntregi x cu nx elemente i y cu ny
elemente, unde nx>ny. S se decid dac y este un subir al lui x,
adic dac un numr k, astfel nct: xk = y1, xk+1 = y2, ..., xk+ny1 = yny . n caz afirmativ, se va afia valoarea lui k.
Pentru dou matrice cu elemente reale, A, cu m linii i n coloane, i B, cu
n linii i p coloane, se numete produsul matricelor A i B matricea C, cu
m linii i p coloane, n care elementul C[i,j] este suma
A[i,0]B[0,j]+A[i,1]B[1,j]+...+A[i,n-1]B[n-1,j],
pentru orice i ntre 1 i m i orice j ntre 0 i p-1. S se scrie un
program care citete dou matrice A i B i calculeaz i afieaz
produsul lor, C.
Fie dat un vector x=(x0, x1, ..., xn-1). S se modifice vectorul
astfel nct, n final, s avem:

x=(x1, x2, ..., xn-1, x0);

x=(xn-1, x0, ..., xn-2);

x=(x1, x0, x3, x2, ...., xn-1, xn-2) (n - par).


S se transforme un numr din baza 10 n baza 2, memornd numrul
rezultat: a) ntr-un vector; b) ntr-un ir de caractere.

69

65.
66.

67.

68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.

80.

S se realizeze deplasarea unei ferestre pe ecran, folosind tastele de


cursor i, de asemenea, redimensionarea sa, la apsarea altor dou
taste (de pild Home i End).
S se realizeze un joc de tip puzzle (perspico), n care juctorul
dispune de o matrice cu 44 csue. n acestea sunt puse, pe rnd, nite
ptrele cu numerele 1, 2, ..., 15, ultima csu fiind liber. Se amestec
aceste numere, prin deplasarea csuei libere sus, jos, stnga sau
dreapta. Simulai amestecarea ptrelelor i dai posibilitatea
utilizatorului s refac matricea, cu ajutorul tastelor de cursor.
Generalizare pentru nn csue..
Numerele de la 1 la n sunt aezate n ordine cresctoare pe
circumferina unui cerc, astfel nct n ajunge lng 1. ncepnd cu
numrul s, se elimin din cerc, numerele din k n k, dup fiecare
eliminare, cercul strngndu-se. Care va fi numrul ce va rmne?
Aceeai problem ca cea anterioar, dar numerele nu se elimin, ci se
marcheaz, pn unul din ele va fi marcat de dou ori. Cte numere au
rmas nemarcate?
Fie A o matrice cu m linii i n coloane, cu elemente reale. S se
determine linia l i coloana k pe care suma elementelor este maxim.
Fie A o matrice cu m linii i n coloane, cu numere reale i un vector V cu
n componente reale. S se determine dac acest vector apare ca linie n
matricea A i, n caz afirmativ, s se afieze numrul acestei linii.
S se determine toate soluiile de tip short int ale ecuaiei 7x-4y=3.
Fie V un vector cu elemente de tip Char. S se construiasc un vector W,
astfel nct W[i] = numrul de apariii ale lui V[i] n vectorul V.
Se d un vector de numere ntregi pozitive. S se determine cea mai
lung subsecven de elemente consecutive prine, ale cror oglindite
sunt tot numere prime.
Se d un vector de numere ntregi. Se cere s se afieze subsecvena
palindromic de lungime maxim. (Elementele subsecvenei sunt
elemente consecutive n vector.)
Pentru un numr ntreg n s se determine toate permutrile irului 1, 2,
.., n. Aceeai problem pentru un ir de numere x1, x2, ..., xn.
O instituie cuprinznd n persoane trebuie s trimit ntr-o inspecie o
echip format din m persoane. Cte echipe se pot forma i care sunt
acestea?
ntr-un raft ncap m cri din cele n de aceeai grosime, de care se
dispune. Care sunt toate posibilitile de a aranja crile pe raft?
S se scrie un program care s determine produsul cartezian al n
mulimi, fiecare cu un numr finit pi de elemente.
S considerm c avem o mulime de m biei i o mulime de n fete. Ne
punem problema de a cupla bieii cu fetele n toate modurile posibile,
pentru a dansa fiecare din cele p dansuri, la o petrecere. Scriei un
program pentru soluionarea acestei probleme.
Scriei un program care s genereze toate submulimile unei mulimi cu n
elemente.
70

81.

82.
83.

84.

85.

86.

87.

88.

89.

Cu ajutorul unui rucsac de greutate maxim admisibil GG trebuie s se


transporte o serie de obiecte din n disponibile, avnd greutile G1, G2, ...,
Gn, aceste obiecte fiind de utilitile C1, C2, ..., Cn. Dac pentru orice
obiect i putem s lum doar o parte xi[0,1] din el, atunci spunem c
avem problema continu a rucsacului, iar dac obiectul poate fi luat doar
n ntregime sau nu, spunem c avem problema discret a rucsacului.
Scriei programe C care s rezolve ambele probleme.
Pe o tabl de ah cu nn ptrate, s se aeze n dame care s nu se
atace ntre ele.
Pe o tabl de ah cu nn ptrate, s se aeze n piese care s nu se
atace ntre ele i astfel nct piesele s fie cte una pe fiecare coloan a
tablei de ah. Piesele mut sub forma: a) unui cal; b) unui nebun; c) unei
ture; d) ca un cal i un nebun mpreun; e) ca un cal i o tur mpreun.
Se d un ir (un vector) de n numere ntregi. Se cere s se determine cel
mai lung subir cresctor al acestuia. De exemplu, pentru vectorul
V=(4,1,8,5,8) de lungime n=5, rspunsul este: 4,8,8. Se va folosi
metoda programrii dinamice.
Unor elevi li se cere s pun n<200 cuvinte formate doar din litere mici
ntr-o ordine fireasc. De exemplu: platon kant marx stalin havel (ordine
cronologic). Fiecare elev i d profesorului o succesiune de cuvinte pe
care o consider corect. Problema pe care trebuie s o rezolve
profesorul este de a puncta fiecare elev cu o not ntre 1 i n,
reprezentnd numrul de cuvinte plasate ntr-o succesiune corect.
Pentru exemplul anterior, avem urmtoarele secvene date de elevi i
notele obinute:

marx stalin kant platon havel


3

havel marx stalin kant platon


2

havel stalin marx kant platon


1
Ajutai-l pe profesor !
Problema platourilor. Fie un tablou a: array[0..n-1] cu elemente de
tip ntreg cu proprietatea a[0]a[1]...a[n-1]. Un platou este o
subsecven maximal de elemente consecutive n tablou care conine
aceeai valoare. Lungimea unui platou este numrul de elemente ce
compun tabloul. Se cere s se determine lungimea p a celui mai lung
platou.
S se scrie un program care s determine pentru un vector a numrul
platourilor (vezi problema anterioar). Definim noiunea de pant ca fiind
o secven de elemente consecutive din a astfel nct a[i]=a[i-1]+1.
S se determine panta de lungime maxim.
Numere pitagoreice. S se determine, pentru un numr ntreg n dat,
toate tripletele de numere pitagoreice (a,b,c) (deci c2=a2+b2) astfel nct
1a,bn).
Problema steagului naional olandez. Se consider n pioni de trei culori
(rou, alb i albastru), aranjai n linie. S se rearanjeze, prin

71

90.
91.
92.
93.
94.

95.
96.
97.
98.
99.
100.
101.
102.

103.

interschimbri, aceti pioni, astfel nct nti s avem pionii roii, apoi cei
albi, apoi cei albatri. Pionii se pot interschimba doi cte doi.
S se scrie un program care s caute binar un element ntr-un vector. Se
va folosi metoda iterativ divide et impera.
La un concurs sunt prezentate 5 melodii A, B, C, D, E. S se afle toate
posibilitile de a le prezenta, tiind c melodia B va fi interpretat
naintea melodiei A.
S se aeze 2n-2 nebuni pe o tabl de ah cu n2 ptrate astfel nct nici
o pereche de nebuni s nu se amenine.
S se aeze pe o tabl de ah cu n2 ptrate ct mai multe dame care s
nu se atace ntre ele.
Pe produsul cartezian NN se definete operaia: (a,b)(b,c)=(a,c),
pentru orice a, b i cN, despre care tim c:

este asociativ: ((a,b)(b,c))(c,d)=(a,b)((b,c)(c,d));

efectuarea ei necesit exact abc secunde.


Fiind date x1, x2, ..., xn N, n3, care este timpul minim i cel maxim n
care se poate efectua produsul (x1,x2)(x2,x3)...(xn-1,xn)? De exemplu,
pentru produsul (7,1)(1,9)(9,3) avem rezultatul (7,3), care se poate
obine cel puin n 48 secunde i cel mult n 4 minute i 12 secunde.
Fie s o permutare a mulimii {1,2, .., n}. S se scrie un program care s
afieze cel mai mic numr nenul k pentru care sk=e, unde e este
permutarea identic.
Fie s o permutare a mulimii {1,2, ..., n}. S se determine numrul de
inversiuni i signatura permutrii s.
S se determine coeficienii polinomului P(X)=Xn+a1Xn-1+..+an, dac
se cunosc toate rdcinile sale.
Scriei un program C care s afieze toate numerele ntregi de n cifre,
egale cu de k ori produsul cifrelor lor (kN).
Scriei un program C care s afieze toate numerele ntregi de n cifre,
egale cu suma ptratelor cifrelor lor.
S se determine toate numerele de n cifre care adunate cu oglinditul lor
dau un ptrat perfect.
Scriei un program care, folosind un numr minim de interschimbri, s
rearanjeze toate componentele unui vector de numere reale, astfel nct
mai nti s avem elementele negative, iar apoi cele pozitive.
S se genereze primele 100 numere din mulimea M={1,3,4,...},
definit astfel:
a) 1M;
b) dac xM, atunci i 2x+1 i 3x+1 M (regula se poate aplica de un
numr finit de ori);
c) nici un alt element nu mai poate fi din M.
Cum putem decide dac un numr natural x este sau nu n M, fr a
genera elementele lui M mai mici sau egale cu x?
Scriei un program C care, pentru dou numere ntregi, cu n cifre,
memorate sub forma unor vectori, s determine suma, produsul lor,
72

104.
105.
106.
107.
108.
109.

110.

111.
112.
113.
114.
115.
116.

precum i ctul i restul mpririi primului laq al doilea, memornd


rezultatele tot vectorial.
Pentru o matrice real ptratic de dimensiune nn s afieze liniile
cresctor dup: a) primul element al liniei; b) suma elementelor liniei; c)
elementul minim al liniei.
Pentru o matrice real ptratic de dimensiune nn s se utilizeze
proprietile determinanilor pentru a-i calcula determinantul.
Generai toate matricele cu 6 linii i 6 coloane, cu elemente din mulimea
{-1,1}, astfel nct pe fiecare linie i coloan s fie un numr impar de
-1.
Se consider n puncte n plan, date prin coordonate carteziene. S se
determine n care din aceste puncte putem alege centrul cercului de raz
minim ce conine cele n puncte date.
Se citesc n numere reale a0, a1, ..., an-1. S se calculeze coeficienii
polinomului fn(x)=(x-a1)(x-a2)...(x-an).
Un profesor dispune de n culegeri de probleme, care conin, respectiv p1,
p2, ..., pn probleme. El vrea s gseasc acel set de culegeri care
totalizeaz un numr de probleme ce poate fi mprit exact la numrul n
de elevi ai si.
Se d un rucsac cu greutatea maxim admisibil G. Se cere s se
transport cu el acele obiecte, din n disponibile, astfel nct suma
utilitilor obiectelor luate n rucsac s fie ct mai apropiat (n valoare
absolut) de o valoare dat. Obiectele au utilitile u1, ..., un i greutile
g1. ..., gn. Se vor considera dou cazuri: a) obiectele nu pot fi secionate
(se pun ntregi); b) obiectele pot fi secionate.
S se genereze i s se afieze att n baza 2, ct i n baza 10, toate
numerele ale cror reprezentri au a cifre de 1 i b cifre (semnificative)
de 0.
Pentru o mulime finit M cu n elemente se d o lege de compoziie sub
forma unei matrice cu nn csue. Se cere s se verifice dac aceast
lege de compoziie determin pe M o structur de grup abelian.
Scriei un program care genereaz aleator matrice de dimensiuni
corespunztoare, cu elemente reale i calculeaz produsul lor.
Scriei un program care, dndu-i-se un numr n cifre tiprete acel
numr n cuvinte. De exemplu, pentru numrul 152365 se obine "o sut
cinci zeci i dou de mii trei sute aizeci i cinci".
Scriei un program care s transcrie cu cifre romane un numr scris cu
cifre arabe.
S se scrie un program care s opereze asupra unei matrice ptratice M,
de numere ntregi cuprinse ntre 0 i 255, n felul urmtor. Se alege un
numr p la intmplare ntre 1 i lungimea curent a matricei (n). Se
adaug la vectorul V, iniial vid, elementul de la intersecia liniei p cu
coloana p, dup care se elimin din matrice att linia p, ct i coloana p.
Procedeul continu, pn cnd matricea se "golete" definitiv. Cte
elemente va conine vectorul V n final?
73

Capitolul 3. Recursivitate
y funcii recursive y operaii n vectori y divide et impera y turnurile din Hanoi y
y sortare prin interclasare y cutare binar y problema damelor y
y backtracking recursiv y problema labirintului y

Probleme rezolvate
1.

Se consider urmtoarele declaraii i convenii:

typedef int vector[20];


x este, de obicei, un vector (ir de elemente), n = lungimea sa
(n1), iar k i e numere ntregi.

Se cere s se scrie funcii recursive pentru a determina, pentru un


vector x de lungime n, urmtoarele mrimi:
a. suma componentelor;
b. produsul componentelor;
c. numrul componentelor negative;
d. produsul componentelor pozitive;
e. suma elementelor pare din vector;
f. produsul elementelor de pe poziii impare;
g. suma elementelor pare de pe poziii divizibile prin k;
h. suma ptratelor componentelor cu cubul mai mic dect k;
j. suma numerelor prime din vector;
k. cel mai mare divizor comun al componentelor;
l. existena elementului e in vector;
m. prezena elementului e pe o poziie impar din vector;
n. numrul componentelor pozitive pare;
o. numrul componentelor impare din intervalul [-2, 3);
p. de cte ori o component este media aritmetic ntreag a
componentelor vecine; presupunem c exist cel puin 3 componente n
vector;
q. de cte ori o component este egal cu produsul
componentelor vecine; presupunem c exist cel puin 3 componente n
vector;
r. media aritmetic a componentelor.
Vom rezolva doar cteva din punctele problemei, scriind funcii
corespunztoare i apelndu-le din main.

#include <stdio.h>
#include <conio.h>
typedef int vector[20];
// a. suma componentelor;
int Suma(vector x, int n)
{
if (n==-1) return 0;
else return (x[n]+Suma(x,n-1));
74

}
// b. produsul componentelor;
int Produs(vector x, int n)
{
if (n==-1) return 1;
else return (x[n]*Produs(x,n-1));
}
// c. numarul componentelor negative;
int NumarNegative(vector x, int n)
{
if (!n) return (x[n]<0);
else return (x[n]<0) + NumarNegative(x,n-1);
}
// d. produsul componentelor pozitive;
int ProdusPozitive(vector x, int n)
{
if (!n) return (x[n]>0 ? x[n] : 1);
else return (x[n]>0 ? x[n] : 1)*ProdusPozitive(x,n-1);
}
// r. media aritmetica a elementelor;
float MediaElementelor(vector x, int m, int n)
/* n este dimensiunea reala a vectorului, iar m este elementul
ultim considerat, adica cel dupa care are loc inductia */
{
return (float)x[m]/n + (m ? MediaElementelor(x,m-1,n) : 0);
/* conversie la float ! */
}
void main()
{
vector x; int n;
printf("\n\nDati n: "); scanf("%d",&n);
for (int i=0; i<n; i++)
{
printf("Dati x[%d]: ",i); scanf("%d",&x[i]);
}
// se apeleaza functia pentru ultimul element al vectorului
printf("Suma: %d\n", Suma(x,n-1));
printf("Produsul: %d\n", Produs(x,n-1));
printf("Numar negative: %d\n", NumarNegative(x,n-1));
printf("Produs pozitive: %d\n", ProdusPozitive(x,n-1));
printf("Media aritmetica: %6.2f\n",
MediaElementelor(x,n-1,n));
getch();
}

2.
Problema "turnurilor din Hanoi": se dau trei turnuri numerotate cu
1, 2 i 3. Pe turnul 1 se afl n discuri, de diametre 1, 2, 3, ..., n (de sus n
jos). Acestea trebuie mutate pe turnul 2, folosind eventual turnul 3, n ct
mai multe mutri. O mutare const n luarea unui disc din vrful unui turn
75

i aezarea sa n vrful altui turn, cu condiia ca diametrul discului pe


care se aaz s fie mai mare dect al discului in cauz.
Problema se rezolv prin metoda divide et impera, folosind
recursivitatea. Astfel, pentru a muta n discuri de la un turn p la un turn q, n
condiiile impuse, va trebui s mutm (recursiv) primele n-1 turnuri de la p la r
(turnul auxiliar), apoi discul al n-lea se va muta direct de la p la q, urmnd ca,
n final, celelalte n-1 discuri s se aduc (recursiv) de la r la q. Algoritmul de
baz este descris n funcia hanoi (vezi programul).
n continuare prezentm o variant cu grafic i animaie (n mod text)
pentru aceast problem, n care numrul de discuri este constant, egal cu 8.
#include <stdio.h>
#include <dos.h> // pentru pauzele date de 'delay'
#include <conio.h>
#include <stdlib.h>
// declaratii globale
// virf[i] reprezinta linia de afisare al discului din varful
// turnului (tijei) a i+1 -a
int virf[3];
// pauza intre doua miscari din timpul animatiei
int pauza=35;
Aceast funcie afieaz un caracter c, ns testeaz i dac s-a

apasat o tast sau nu. n caz afirmativ se iese forat din program, printr-un apel
al funciei exit (declarat n <stdlib.h>.

void punecar(char c)
{
if (kbhit()) exit(1); else putch(c);
}
/* determina coloana unde se afla turnul 'tija' */
int col_tija(int tija)
{
return (7*tija+9+17*(tija-1));
}
void muta_dreapta(int disc, int tija1, int tija2)
{
int i,k;
for (i=col_tija(tija1)-disc; i<col_tija(tija2)-disc;i++)
{
delay(pauza); gotoxy(i,3);
for (k=0;k<2*disc+1;k++) punecar(' ');
gotoxy(i+1,3);
for (k=0;k<2*disc+1;k++) punecar('');
}
}
void muta_stinga(int disc, int tija1, int tija2)
{
int i,k;
for (i=col_tija(tija1)-disc; i>col_tija(tija2)-disc;i--)
{
delay(pauza); gotoxy(i,3);
for (k=0;k<2*disc+1;k++) punecar(' ');
76

gotoxy(i-1,3);
for (k=0;k<2*disc+1;k++) punecar('');

}
}
void coboara(int disc, int tija)
{
int i,k;
for (i=3;i<virf[tija-1]-1;i++)
{
delay(pauza); gotoxy(col_tija(tija)-disc,i);
for (k=0;k<2*disc+1;k++) punecar(' ');
gotoxy(col_tija(tija)-disc,i+1);
for (k=0;k<2*disc+1;k++) punecar('');
}
virf[tija-1]--;
}
void ridica(int disc, int tija)
{
int i,k;
for (i=virf[tija-1];i>3;i--)
{
delay(pauza); gotoxy(col_tija(tija)-disc,i);
for (k=0;k<2*disc+1;k++) punecar(' ');
gotoxy(col_tija(tija)-disc,i-1);
for (k=0;k<2*disc+1;k++) punecar('');
}
virf[tija-1]++;
}
Aceast funcie mut discul din vrful turnului tija1 n vrful lui tija2,

apelnd funciile de mai nainte:


- l ridic pe tija1;
- l mut de la tija1 la tija2;
- l coboar pe tija2:

void muta(int disc,int tija1,int tija2)


{
ridica(disc,tija1);
if (tija1 < tija2) muta_dreapta(disc,tija1,tija2);
else muta_stinga(disc,tija1,tija2);
coboara(disc,tija2);
}

Procedura recursiv ce implementeaz algoritmul descris este:

void hanoi(int n,int tija1,int tija2,int tija3)


{
if (n == 1)
muta(1,tija1,tija2);
else
{
hanoi(n-1,tija1,tija3,tija2);
muta(n,tija1,tija2);
hanoi(n-1,tija3,tija2,tija1);
}
}
void initializari(void)
{
77

int k,disc;
virf[0]=13;
virf[1]=virf[2]=22;
clrscr();
for (disc=1;disc<=9;disc++)
{
gotoxy(col_tija(1)-disc,virf[0]+disc-1);
for (k=0;k<2*disc+1;k++)
punecar('');
}

}
void main(void)
{
clrscr(); initializari(); gotoxy(32,1);
puts("~Turnurile din Hanoi~");
hanoi(8,1,2,3); getch();
}

3.
S se scrie un program care ordoneaz un ir de numere prin
metoda sortrii prin interclasare.

#include <stdio.h>
#include <conio.h>
typedef int vector[20];
void Citeste(vector x, int *n)
{
int p;
printf("Dati nr. de elemente: "); scanf("%d",&p);
*n=p;
for (int i=0; i<p; i++)
{
printf("Dati x[%d]=",i);
scanf("%d",&x[i]);
}
}
void Afiseaza(vector x, int n)
{
printf("Elementele lui x sunt: ");
for (int i=0; i<n; i++)
printf("%d,",x[i]);
printf("%c.\n\n",8);
}

Urmtoarea funcie interclaseaz cele dou pri ale unui vector a,


situate ntre inceput i mijloc, pe de o parte, i mijloc+1 i sfarsit, pe de
alta, unde mijloc este (inceput+sfarsit)/2. (Vezi i exemplul Q13.)
void Interclasare(vector a, int inceput,
int mijloc, int sfarsit)
{
int i, j, k; vector c;
i = inceput; j = mijloc+1; k = 0;
while (i<=mijloc && j<=sfarsit)
if (a[i]<a[j]) c[k++]=a[i++];
else c[k++]=a[j++];
78

while (i<=mijloc) c[k++]=a[i++];


while (j<=sfarsit) c[k++]=a[j++];
for (i=0; i<k; i++) a[i+inceput]=c[i];

Ordonarea se realizeaz recursiv astfel: dac irul conine doar un


element, nseamn c el este deja ordonat; n caz contrar, el se mparte n
dou subiruri, care se ordoneaz la fel (recursiv) i apoi se interclaseaz.

void SortarePrinInterclasare(vector a, int start, int stop)


// start si stop sint capetele intre care se face sortarea
{
int mij=(start+stop)/2;
if (start<stop)
{
SortarePrinInterclasare(a, start, mij);
SortarePrinInterclasare(a, mij+1, stop);
Interclasare(a, start, mij, stop);
}
}
void main()
{
int i, n; vector a;
clrscr(); Citeste(a,&n); Afiseaza(a,n);
SortarePrinInterclasare(a,0,n-1);
Afiseaza(a,n);
getch();
}

4.
S se scrie un program care caut existena unui element ntr-un
ir x = (x1, x2, ..., xn) ordonat cresctor. Se va folosi metoda
cutrii binare.

Vom aplica, din nou, metoda divide et impera astfel:


se compar elementul cutat cu elementul din mijlocul sirului;
daca ele coincid, nseamn c elementul exist n ir i procesul se
ntrerupe;
dac primul este mai mic dect al doilea, nu are sens o cutare dincolo de
elementul din mijloc, ci doar n fa, deci n stnga;
dac, ns, elementul cutat este mai mare dect cel din mijloc, cutarea
se va face doar n partea din dreapta elementului din mijloc.
Acest algoritm este implementat in funcia recursiv CautareBinara.

#include <stdio.h>
#include <conio.h>
typedef int vector[20];
void Citeste(vector x, int *n)
{
int p;
printf("Dati nr. de elemente: "); scanf("%d",&p);
*n=p;
for (int i=0; i<p; i++)
{
printf("Dati x[%d]=",i+1);
79

// consideram indexarea de la 1 la n !
scanf("%d",&x[i]);
}

}
void Afiseaza(vector x, int n)
{
printf("Elementele lui x sunt: ");
for (int i=0; i<n; i++)
printf("%d,",x[i]);
printf("%c.\n\n",8);
}

n continuare avem aplicarea metodei divide et impera n varianta


recursiv; sugerm cititorului s scrie i o variant iterativ a acestei funcii.
int CautareBinara(vector a, int elem, int inceput, int sfarsit)
{
if (inceput<=sfarsit)
{
int mijloc=(inceput+sfarsit)/2;
if (elem==a[mijloc])
return mijloc+1; // atentie la indici !
else
if (elem<a[mijloc])
return
CautareBinara(a, elem, inceput, mijloc-1);
else
return
CautareBinara(a, elem, mijloc+1, sfarsit);
}
else return 0;
}
void main()
{
int n,p,e; vector a;
clrscr(); Citeste(a,&n); Afiseaza(a,n);
printf("Dati numarul cautat: "); scanf("%d",&e);
printf("\n");
if (p=CautareBinara(a,e,0,n-1))
printf("%d exista pe pozitia %d in sir !",e,p);
else
printf("%d nu exista in sir !",e);
getch();
}
Funcia CautareBinara returneaz poziia p pe care se afl elementul

cutat n cadrul vectorului dat, respectiv 0, n caz c nu exist. De remarcat c


p este un indice care este cu o unitate mai mare dect indicele real, innd

cont c n C lucrm cu vectori indexai ncepnd cu 0 i nu cu 1.


5.
S se scrie un program care caut existena unui element ntr-un
ir x = (x1, x2, ..., xn) ordonat cresctor. Se va folosi metoda
cutrii prin interpolare.

80

Cutarea prin interpolare este o ameliorare a metodei cutrii binare,


care se bazeaz pe strategia adoptat de o persoan cnd caut un cuvnt
ntr-un dicionar. Astfel, dac cuvntul cutat ncepe cu litera C, deschidem
dicionarul undeva mai la nceput, iar cnd cuvntul ncepe cu litera V,
deschidem dicionarul mai pe la sfrit. Dac e este valoarea cutat n
vectorul a[ic..sf], atunci partiionm spaiul de cutare pe poziia
m=ic+(e-a[ic])*(sf-ic)/(a[sf]-a[ic]). Aceast partiionare permite
o estimare mai bun n cazul n care elementele lui a sunt numere distribuite
uniform.
/* Cautare prin interpolare */
#include <stdio.h>
#include <conio.h>
typedef int vector[20];
void Citeste(vector x, int *n)
{
int p;
printf("Dati nr. de elemente: "); scanf("%d",&p);
*n=p;
for (int i=0; i<p; i++)
{
printf("Dati x[%d]=",i+1);
// consideram indexarea de la 1 la n !
scanf("%d",&x[i]);
}
}
void Afiseaza(vector x, int n)
{
printf("Elementele lui x sunt: ");
for (int i=0; i<n; i++)
printf("%d,",x[i]);
printf("%c.\n\n",8);
}
int CautInterp(vector a, int e, int ic, int sf)
{
if (ic<=sf)
{
int m; m=ic+(e-a[ic])*(sf-ic)/(a[sf]-a[ic]);
if (e==a[m])
return m+1; // atentie la indici !
else
if (e<a[m])
return CautInterp(a, e, ic, m-1);
else
return CautInterp(a, e, m+1, sf);
}
else return 0;
}
void main()
{
int n,p,e; vector a;
clrscr(); Citeste(a,&n); Afiseaza(a,n);
printf("Dati numarul cautat: "); scanf("%d",&e);
printf("\n");
81

if (p=CautInterp(a,e,0,n-1))
printf("%d exista pe pozitia %d in sir !",e,p);
else printf("%d nu exista in sir !",e);
getch();

6.
"Problema celor 8 regine". S se aseze n dame pe o tabl de ah
cu nn csue, astfel nct damele s nu se atace ntre ele. O dam atac
toate cmpurile de pe aceeai linie, coloan i de pe diagonalele pe care
se afl.
Vom rezolva problema damelor prin metoda back-tracking
recursiv. Astfel, s facem o analiz preliminar a problemei. n primul rnd,
observm c nu putem aeza doua dame pe o aceeai coloan, deoarece ele
s-ar ataca reciproc pe vertical.
Prin urmare, vom pune fiecare dam pe o alt coloan. Aadar, vom
aeza damele n ordinea coloanelor, dama numarul k fiind pus pe coloana a
k-a. Firete, ea trebuie aezat astfel nct s nu atace damele deja aezate.
Procednd astfel, ne asigurm c nu le va ataca nici pe cele ce vor fi aezate
dup ea. Aezarea damei a k-a se face la intersecia dintre coloana a k-a i o
linie, s zicem x[k], cuprins ntre 1 i n.
n continuare, s observm c x[k] trebuie s fie diferit de x[i],
pentru orice 1<=i<k, ceea ce nseamn evitarea atacului pe orizontal. Pentru
a evita atacul pe diagonal ntre dama k i o dam i dinaintea sa, s
observm c aceasta nseamn c diferena coloanelor s fie diferit de cea a
liniilor celor dou dame, deci abs(x[k]-x[i]) != k-i.
Toate aceste elemente se regsesc n funcia PotContinua care
returneaz 1 n momentul n care aezarea damei k corespunde restriciilor,
deci se poate trece la aezarea damei k+1. Apelul recursiv din cadrul funciei
Dama realizeaz tocmai acest lucru.
n cazul n care nu se poate trece la dama k+1, iar toate valorile pentru
x[k] au fost ncercate (1<=x[k]<=n), funcia Dama eueaz i se revine la
dama anterioar. (ntr-o variant recursiv s-ar scrie k-- .)
n funcia main se pleac de la dama 1.
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
const max=11;
typedef int vector[max]; // vom folosi indicii incepand cu 1
int NrSol; // variabila globala reprezentand numarul de solutii
void Scrie(int n, vector x)
{
int i; NrSol++;
printf("Solutia nr: %d:\n",NrSol);
for (i=1; i<= n; i++)
printf("Dama de pe coloana %d e pe linia %d.\n",i,x[i]);
printf("\n"); getch();
}
int PotContinua(vector x, int k)
82

for (int atac=0, i=1; i<k && !atac;


atac=(x[i]==x[k] || abs(x[i]-x[k])==k-i), i++);
return !atac;

}
void Dama(vector x, int k, int n)
{
int l=1;
// l reprezinta linia pe care se incearca asezarea damei k
while (l<=n)
{
x[k]=l;
if (PotContinua(x,k))
if (k==n) Scrie(n,x); else Dama(x,k+1,n);
l++;
}
}
void main()
{
vector AsezareDame; int NrDame;
clrscr(); printf("Problema Damelor\n\n");
NrSol=0;
printf("Dati numarul de dame: ");
scanf("%d",&NrDame);
Dama(AsezareDame,1,NrDame);
}

7.
"Problema labirintului". Se d un labirint memorat sub forma unei
matrice de caractere, unde zidurile sunt reprezentate de caracterul '#', iar
prin spaii locurile de trecere. Un oricel, aflat n poziia (i_initial,
j_initial) trebuie s ajung la o bucic de cacaval, din poziia
(j_initial, j_final). El poate s se mite ortogonal, n csuele libere
alturate. S se determine toate drumurile pe care le poate face oricelul
sau s se afieze 'imposibil', cnd nu exist nici un drum.
Aceasta este o problem clasic rezolvabil prin metoda back-tracking
recursiv, n plan. Lungimea drumului oricelului poate varia, de la o soluie la
alta. Drumul oricelului este memorat n matricea Traseu, cu semnficaia
Traseu[i][j]=pas dac oricelul trece la pasul pas prin csua de pe linia i
i coloana j, respectiv 0, dac nu trece pe acolo.
#include <stdio.h>
#include <conio.h>
const m=8; const n=10;
typedef int sir[4];
typedef char matrice[m][n];

n continuare, tablourile Labirint, oriz i vert sunt declarate i


iniializate ca variabile globale.
matrice Labirint=

{"##### ####",
"### # ####",
"###
####",
83

"
# ####",
"### # ####",
"#
##",
" ## #####",
"#### #####"};

Urmtoarele tablouri indic direciile de deplasare: stnga, jos, sus i


dreapta:
sir
oriz={-1,0,1, 0};
sir vert={ 0,1,0,-1};

Matricea care va memora traseul oricelului este:

matrice Traseu;
int i,j,i_initial,j_initial,i_final,j_final;
void Scrie()
{
int i,j;
for (i=0; i<m; i++)
{
for (j=0; j<n; j++)
if (Traseu[i][j]==0)
if (Labirint[i][j]==' ')
printf("%2c",' '); // 2 spatii
else printf("[]"); // "zid"
else
printf("%2d",Traseu[i][j]);
printf("\n");
}
printf("\n");
}

Procedura recursiv de determinare a drumului ctre cacaval, plecnd


din punctul de coordonate (i,j), unde ne aflm la pasul pas:

void Drum(int i, int j, int pas) */


{
int i_nou, j_nou, varianta;

Se ncearc oricare din cele 4 direcii (adic variante):

for (varianta=0; varianta<=3; varianta++)


{
i_nou=i+oriz[varianta];
j_nou=j+vert[varianta];
if (0<=i_nou && i_nou<m && 0<=j_nou && j_nou<n)
if (Labirint[i_nou][j_nou]==' '
&& Traseu[i_nou][j_nou]==0)
{
Traseu[i_nou][j_nou]=pas;
if (i_nou==i_final && j_nou==j_final) Scrie();
else Drum(i_nou,j_nou,pas+1);
Traseu[i_nou][j_nou]=0;
}
}

}
void main()
{
clrscr();
// afisam labirintul
int i,j;

84

for (i=0; i<m; i++)


{
for (j=0; j<n; j++)
if (Labirint[i][j]==' ')
printf("%2c",' '); // 2 spatii
else
printf("[]"); // "zid"
printf("\n");
}
printf("\n");
// initializam matricea traseului
for (i=0; i<m; i++)
for (j=0; j<n; j++)
Traseu[i][j]=0;
// citim coordonatele soricelului si a cascavalului
printf("Dati pozitia initiala: ");
scanf("%d%d",&i_initial,&j_initial);
i_initial--; j_initial--; // indicii sunt de la 0 !
printf("Dati pozitia finala: ");
scanf("%d%d",&i_final,&j_final);
i_final--; j_final--;
// pornim la drum !
Traseu[i_initial][j_initial]=1; printf("Solutii:\n");
Drum(i_initial,j_initial,2); getch();
}

Probleme propuse
1.
2.
3.
4.
5.
6.
7.
8.

9.

S se calculeze suma S(n)=1+3+5+...+(2n-1), folosind o funcie


recursiv.
S
se
calculeze
produsele
P1(n)=147...(3n-2)
i
P2(n)=246...(2n), folosind funcii recursive.
S se scrie o funcie recursiv care s returneze inversul unui ir de
caractere.
Scriei o funcie recursiv itoa pentru a converti un ntreg ntr-un ir de
caractere.
Folosind recursivitatea, s se verifice dac un vector conine cel puin un
numr negativ n primele n poziii.
S se afieze coninutul unui vector, folosind o funcie recursiv.
S se inverseze un vector. Se va folosi recursivitatea.
Evaluator de expresii algebrice. V propune s realizai un program care
s citeasc expresia oricrei funcii i s o poat tabela, adic,
dndu-i-se un numr de puncte dintr-un interval, s afieze valorile
funciei n fiecare din acele puncte. Expresia funciei va fi memorat
ntr-un ir de caractere. Ea va putea conine operaii i funcii elementare
(adunare, scdere, nmulire, mprire, ridicare la putere, exp, ln, abs,
radical, sin i cos)). Pentru a putea utiliza inclusiv funcii cu acolad,
vom folosi o convenie din limbajul BASIC.
Astfel, s considerm urmtoarele dou funcii:

85

10.

11.
12.
13.
14.
15.
16.

17.

18.

x cos(1 / x), dac\ x 0


f ( x) =
dac\ x = 0.
0,
i
x2 ,
dac\ x 0
f ( x) =
x sin( x 2), altfel
Prima funcie va fi dat sub forma: (x#0)*(x*cos(1/x))+(x=0)*0;
iar a doua sub forma: (x>0)*(x^2)+(x<0)*(x-sin(x*2)). Deci se
vor folosi simbolurile < (mai mic sau egal), > (mai mare sau egal), =
(egal) i # (diferit), precum i convenia din limbajul BASIC, anume c
expresiile relaionale se evalueaz la 1, dac sunt adevrate, respectiv
la 0, dac sunt false.
Scriei o funcie care s verifice dac un ir de caractere este sau nu
palindrom, adic coincide cu rsturnatul (oglinditul) su.
Rescriei funciile de lucru cu iruri de caractere, care se gsesc n
<STRING.H>.
S se defineasc un tip de date pentru numere naturale foarte mari i s
se scrie proceduri care s adune i s scad astfel de numere.
Elaborai o funcie care s determine diferena ntre dou momente de
timp date prin or, minute i secunde.
Scriei un program care s tabeleze o funcie, definit n textul
programului, adic s afieze valorile funciei n n puncte dintr-un interval
dat [a,b].
mbuntii programul AdmitereLiceu (din seciunea 3 a acestei lecii)
pentru a avea posibilitatea de a terge, insera un elev sau modifica
datele despre un elev. De asemenea, programul s permit listarea
tuturor elevilor care au mediile cuprinse ntre dou valori date.
Ce afieaz programul de mai jos:
#include <stdio.h>
int x;
int F(int x) { x=x+1; return x*x; }
voi main()
{ x=2; printf("x=%d F(x)=%d x=%d",x,F(x),x));}
Rezolv problema mutrii a n discuri de pe turnul p pe turnul q, n
problema Turnurilor din Hanoi, urmtoarea procedur? Este ea o
procedur definit consistent din punct de vedere al recursivitii?
void Hanoi2(int n,p,q)
{ int r=6-p-q;
if (n==1) printf("%d-%d",p,q);
else { printf("%d-%d",p,r);
Hanoi2(n-1,p,r); printf("%d-%d",r,q); }
}
Semnificaia funciei este: pentru a muta n discuri de la turnul p la turnul
q se mut discul de deasupra de pe turnul p pe turnul r, apoi se mut,
recursiv, cele n-1 discuri de pe turnul p pe turnul auxiliar r, dup care se
aduce discul de pe q pe r.
86

19.
20.

21.

22.
23.
24.
25.

26.
27.
28.
29.
30.

31.

32.

Scriei o funcie iterativ care s calculeze, cu ajutorul unei stive proprii,


suma S=1+2+3+...+n, respectiv produsul P=135...(2n-1).
Scriei funcii recursive pentru a determina: a) cel mai mare divizor
comun a dou numere ntregi a i b; b) coeficientul binomial Cnk, din
dezvoltarea binomului lui Newton; c) produsul scalar a doi vectori cu cte
n componente reale.
Scriei o funcie recursiv pentru a aeza n piese pe o tabl de ah nn,
cte una pe fiecare coloan, astfel nct piesele s nu se atace. Fiecare
pies atac precum: a) un nebun; b) o tur; c) un cai; d) un cal i un
nebun simultan; e) un nebun i o tur simultan; f) un cal i o tur
simultan.
Scriei o funcie recursiv care s genereze permutrile unei mulimi cu n
elemente.
S se genereze recursiv submulimile cu k elemente ale unei mulimi cu
n elemente.
S se genereze un ir de lungime n format numai din literele a, b i c,
astfel nct s nu existe dou subiruri alturate identice.
O matrice dreptunghiular cu m linii i n coloane reprezint o imagine
fotografic (alb/negru) a unui obiect. Elementele matricei sunt valorile
binare 0 i 1. Valoarea 0 corespunde fondului, iar valoarea 1 prezenei
obiectului. S se determine numrul de componente ale obiectului,
considernd c dou puncte pot fi vecine att ortogonal, ct i diagonal.
S se parcurg, cu un cal, o tabl de ah cu n linii i n coloane, n aa fel
nct prin fiecare csu s se treac exact o singur dat.
S se aeze 2n-2 nebuni pe o tabl de ah cu n2 ptrate astfel nct nici
o pereche de nebuni s nu se amenine.
S se aeze pe o tabl de ah cu n2 ptrate ct mai multe dame care s
nu se atace ntre ele.
Scriei o funcie recursiv i una iterativ pentru a cuta un cuvnt ntr-un
vector de cuvinte, care sunt puse n ordine alfabetic.
Se d o bucat dreptunghiular de tabl cu lungimea L i limea H,
avnd N guri, de coordonate numere ntregi. S se decupeze din ea o
bucat de arie maxim care nu prezint guri. Sunt permise doar tieturi
verticale i orizontale. Se va utiliza metoda divide et impera.
Un ran primete o bucat dreptunghiular de pmnt pe care dorete
s planteze o livad. Pentru aceasta, el va mpri bucata de pmnt n
mn ptrate, avnd dimensiunile egale, iar n fiecare ptrat va planta un
singur pom din cele patru soiuri pe care le are la dispoziie. S se afieze
toate variantele de a alctui livada respectnd urmtoarele condiii: a) nu
trebuie s existe doi pomi de acelai soi n dou csue nvecinate
ortogonal sau diagonal; b) fiecare pom va fi nconjurat de cel puin un
pom din toate celelalte trei soiuri. Observaie: ranul are la dispoziie
suficieni pomi de fiecare soi.
Un teren muntos are forma unei matrice cu mn zone, fiecare zon
avnd o nlime. Un alpinist pleac dintr-o anumit zon i trebuie s
ajung ntr-o zon maxim n altitudine. Dintr-o zon, alpinistul se poate
87

33.

34.

35.

36.

deplasa diagonal sau ortogonal, ntr-una din zonele (csuele) alturate,


doar urcnd sau mergnd la acelai nivel. Poate el ajunge ntr-unul din
vrfuri? Dac da, artai toate soluiile problemei.
Attila i regele. Un cal i un rege se afl pe o tabl de ah. Unele
cmpuri sunt arse, poziiile lor fiind cunoscute. Calul nu poate clca pe
cmpuri arse, iar orice micare a calului arde cmpul pe care se duce.
S se afle dac exist o succesiune de mutri permise (cu restriciile de
mai sus) prin care calul s ajung la rege i s revin la poziia iniial.
Poziia iniial a calului, precum i poziia regelui sunt considerate
nearse.
Care din urmtoarele funcii C evalueaz n factorial?
int fact(int n) { if (n<=1) return 1; else return
(n*fact(n-1)); }
int fact(int n) { if (n==1) return 1; else { n--;
return (n+1)*fact(n); }
Pete de culoare. Se consider o matrice de dimensiunea 3040 ale
crei elemente sunt numere naturale cuprinse ntre 1 i 9, reprezentnd
diferite culori. Se definete mulimea conex a unui element ca fiind
mulimea elementelor matricei n care se poate ajunge din elementul
respectiv prin deplasri succesive pe linie sau coloan, cu pstrarea
culorii. S se determine culoarea i numrul de elemente al mulimii
conexe cu numrul maxim de elemente. Dac exist mai multe soluii, se
va preciza una dintre ele.
Scriei n limbajul C funcia recursiv a lui Ackermann, n care
A(m,n)=n+1, dac m=0, A(m,n)=A(m-1,1), dac n=0 i
A(m,n)=A(m-1,A(m,n-1)), n alte cazuri.

88

Capitolul 4. Structuri i tipuri definite de programator


y structuri y accesarea cmpurilor y variabile pointeri y variabile referin y
y pointeri la structuri y reuniuni y liste y arbori y
y sortare rapid y programarea mouse-ului n mod text y

Probleme rezolvate
1.
S se defineasc un tip de date pentru reprezentarea numerelor
complexe i s se scrie funcii pentru diferite operaii cu astfel de
numere.
De remarcat c n <complex.h> sunt declarate toate elementele
necesare lucrului cu numerele complexe, dar noi vom scrie propriile funcii.
Astfel, de pild, vom folosi functia sqrt din <math.h> pentru a determina
modulul unui numr complex.
#include <math.h>
#include <stdio.h>
#include <conio.h>
#include <alloc.h>
typedef struct {
double re, im;
} complex;
void scrie(complex z, char nume)
{
printf("Numarul complex %c este: (%7.3lf,%7.3lf)\n",
nume,z.re,z.im);
}
void citeste(complex *pz, char nume)
{
double a, b;
printf("Dati %c.re: ",nume); scanf("%lf",&a);
printf("Dati %c.im: ",nume); scanf("%lf",&b);
/* doua modalitati de a referi campurile variabilei dinamice
indicate de pz */
(*pz).re=a; pz->im=b;
}
void citeste1(complex & z, char nume)
{
double a,b;
printf("Dati %c.re: ",nume); scanf("%lf",&a);
printf("Dati %c.im: ",nume); scanf("%lf",&b);
z.re=a; z.im=b;
}
double modul(complex z)
{
return sqrt(z.re*z.re+z.im*z.im);
}
complex suma(complex z1, complex z2)
{
89

complex z;
z.re=z1.re+z2.re; z.im=z1.im+z2.im;
return z;

}
complex produs(complex z1, complex z2)
{
complex z;
z.re=z1.re*z2.re-z1.im*z2.im;
z.im=z1.re*z2.im+z1.im*z2.re;
return z;
}
complex *suma1(complex z1, complex z2)
{
complex z, *pz;
pz=(complex *)malloc(sizeof(complex));
z.re=z1.re+z2.re; z.im=z1.im+z2.im;
*pz=z;
return pz;
}
complex *suma2(complex z1, complex z2)
{
complex *pz;
pz=(complex *)malloc(sizeof(complex));
pz->re = z1.re + z2.re;
pz->im = z1.im + z2.im;
return pz;
}
complex *suma3(complex *pz1, complex *pz2)
{
complex *pz;
pz=(complex *)malloc(sizeof(complex));
pz->re = pz1->re+pz2->re; pz->im = pz1->im + pz2->im;
return pz;
}
void main()
{
clrscr(); complex q; citeste1(q,'q');
printf("Modulului lui q: |q|=%lf.\n",modul(q));
complex a,b,c,*pa,*pb,*pc;
citeste(&a,'a'); scrie(a,'a');
citeste(&b,'b'); scrie(b,'b'); printf("\n");
c=suma(a,b); scrie(c,'S');
c=produs(a,b); scrie(c,'P');
pc=suma1(a,b); scrie(*pc,'S');
free(pc);
pc=suma2(a,b); scrie(*pc,'S'); free(pc);
pa=(complex *)malloc(sizeof(a));
*pa=a; pb=&b;
pc=suma3(pa,pb); scrie(*pc,'S');
free(pc); free(pa);
getch();
}

90

Exemplul de fa, dei simplu, n esena sa, ne permite prezentarea


unor elemente ale limbajului foarte importante, referitoare la definirea tipurilor,
structuri, pointeri, variabile dinamice, variabile referin.
Mai nti, s observm c am definit un nou tip de date, numit complex,
ca fiind o nregistrare (vezi record din Pascal!) cu dou cmpuri. Modul de
referire a cmpurilor se vede n funciile scrie, modul, sum i produs.
n limbajul C putem avea att variabile definite n zona de memorie a
programului, ct i variabile dinamice, generate prin program i alocate n
timpul execuiei programului. Acestea, ns, trebuie indicate (pointate) de ctre
nite variabile pointeri, definite n program.
Un pointer pv ctre o variabila v de tipul tip se definete prin tip *pv.
Aceasta simbolizeaz faptul c pv va conine adresa de memorie a unei
variabile anonime, generate dinamic. Zona n care se pastreaz variabilele
dinamice se numeste heap (grmad). Pentru a obine o variabil acolo,
trebuie ca acesteia s i se aloce memorie corespunztoare mrimii n octei
cerute de tipul sau. De acest lucru se ocup funcia malloc, care se gsete
att n <stdlib.h>, ct i n <alloc.h>, unde se gsesc i alte funcii
asemntoare. Dup ce a fost folosit, variabila anonim dinamic poate fi
abandonat, folosind funcia free.
Fiecrei variabile dinamice i se pune n coresponden cel puin un
pointer, care s o refere. Dac p este un pointer ctre un tip de date tip,
atunci crearea unei variabile dinamice de tip t, care s fie indicat de p se
poate face prin:
tip *p;
p = (tip *)malloc(sizeof(tip));

n acest moment, putem s iniializm variabila dinamic prin:

*p = valoare;

Observm cum am apelat funcia malloc:


se face o conversie ctre un pointer la tip, cci malloc returneaz un
pointer la void (un pointer general);
argumentul lui malloc este numrul de octei necesari variabilei dinamice;
acesta poate fi dat de funcia sizeof, care poate fi aplicat att numelui tipului,
ct i unei variabile oarecare de acel tip:
tip v, *p;
p = (tip *)malloc(sizeof(v));

De pild, pentru o variabil de tip complex, mrimea este de 16 octei,


deoarece fiecare din cei doi double ai structurii este de 8 octei.
Dupa ce variabila dinamic indicat de p a fost folosit, zona de
memorie din heap ocupat de ea poate fi eliberat prin: free(p);
S considerm, acum, c p este un pointer ctre o structur ca n cazul
programului anterior (vezi funciile citeste i suma2). Pentru a ne referi la
cmpul camp al variabilei dinamice indicate de p va trebui s scriem fie
(*p).camp1, fie p->camp .
91

O extensie binevenit n urma trecerii de la C la C++ a fost


introducerea variabilelor referin, definite cu ajutorul lui &.
Asfel, dac avem declaraiile: tip v, *pv, putem scrie pv=&v, prin
aceasta nelegnd c pv va pointa (indica) ctre zona de memorie a
variabilei v, adic pv va primi valoarea adresei de memorie a variabilei v (care,
firete, are deja alocat memorie, n partea static a programului). (Acest lucru
se ntlnete n funcia main, n cazul lui pb i b.)
Un apel free(pv) este lipsit de sens, deoarece variabila pv nu indic
n heap.
Noutatea adus de C++ const i n aceea c argumentele funciilor
pot fi variabile referin, ceea ce nseamn un plus de flexibilitate n privina
apelurilor. A se vedea n acest sens funcia citeste1.
n continuare s lum pe rnd altele din funciile programului anterior i
s le analizm:
a.
Funcia suma1 primete ca argumente dou numere complexe i
returneaz un pointer ctre un numr complex. Rezultatul se pastreaz, pe
parcursul funciei n doua locuri: att n variabila local z, ct i n variabila
dinamica *pz, indicat de pointerul pz, creia i se aloc memorie chiar n
corpul funciei.
O variant greit a lui suma1 este cea n care ar lipsi alocarea de
memorie i am face alocare n cadrul lui main() pentru pc. O alt variant
greit a lui suma1 este:
complex *suma1(complex z1, complex z2)
{
complex z, *pz;
pz=(complex *)malloc(sizeof(complex));
z.re=z1.re+z2.re; z.im=z1.im+z2.im;
*pz=z; return pz;
}
Eroarea const n faptul c atribuirea *pz=z se face nainte ca z s

primeasc vreo valoare.


b.
Funcia suma2 lucreaz ntocmai ca i funcia suma1, dar se renun la
variabila z, lucrul cu pointerul pz fiind mai eficient din punct de vedere a
memoriei ocupate (a se compara, de pild cu funcia suma).
c.
Ct privete funcia suma3, aceasta, spre deosebire de toate celelalte,
are drept argumente pointeri la compleci, de fapt, variabile dinamice.
d.
Funcia principal apeleaz toate funciile definite, dup o anumit
logic, astfel:
void main()
{
clrscr(); complex q;

Se citete valoarea numrului complex q, apelul fiind prin referin!

citeste1(q,'q');

92

Se afieaz modului lui q ca double.

printf("Modulului lui q: |q|=%lf.\n",modul(q));


Se definesc numerele complexe a, b, c i trei pointeri la complex; pa,
pb, pc.
complex a,b,c,*pa,*pb,*pc;
Se citesc valorile lui a i b i se afieaz. Apelul este tot prin referin,

ns se trimit ca argumente adresele variabilelor!

citeste(&a,'a'); scrie(a,'a');
citeste(&b,'b'); scrie(b,'b'); printf("\n");

Se calculeaz i se afieaz suma i produsul a+b, a*b, folosind


funciile
simple, fr pointeri:

c=suma(a,b); scrie(c,'S'); c=produs(a,b); scrie(c,'P');


Se apeleaz funcia suma1 pentru a calcula, prin pointeri, a+b i se
afieaz valoarea variabilei dinamice *pc ce pstreaz rezultatul:
pc=suma1(a,b); scrie(*pc,'S'); Apoi aceast variabil dispare (memoria
s-a alocat n cadrul lui suma1):
free(pc);
Se procedeaz la fel folosind functia suma2
pc=suma2(a,b);
scrie(*pc,'S'); free(pc);
Se
aloc
memorie
pentru
pa:
pa=(complex *)malloc(sizeof(a));
Se copiaz valoarea complexului a n heap, n zona referit de pa:
*pa=a;
n pointerul pb se depune valoarea adresei variabilei b:
pb=&b;
Se calculeaz, folosind suma3, suma acelorai numere complexe i se

afieaz. Se va observa c n toate cele patru cazuri valoarea sumei este


aceeasi.
pc=suma3(pa,pb); scrie(*pc,'S');

Se elibereaz memoria alocat variabilelor dinamice indicate de pc i


pa:

free(pc); free(pa); getch(); }


Lucrul cu pointeri ofer
foarte multe posibiliti de lucru programatorilor experimenti, mai ales cnd
se dorete crearea de structuri de date nlnuite (definite recursiv), precum
listele i arborii.
Exist i avantaje legate de memorie. Astfel, daca o structura de tip
complex ocup 16 octei, un pointer ctre o astfel de structur ocupa doar 4
octei, restul de 16 fiind n heap. De fapt, orice pointer ocup doar 4 octei,
fiindc reprezint o adres de memorie.

Programatorul trebuie s fie foarte atent la utilizarea pointerilor, mai ales


la alocarea de memorie pentru variabilele dinamice pe care le indic, deoarece
acetia creeaz multe probleme.
De pild, dac n funcia main nu se aloc memorie pentru pc puteau
apare diverse probleme, pe cnd lipsa apelului lui free(pc) ar fi pstrat n
memorie gunoaie.

93

Astfel de cazuri i, de asemenea, altele, precum o asignare prost


conceput poate genera mesajul null pointer assignment chiar i dup
terminarea programului!
2.
Se d o list de persoane i punctajele obinute de acestea la un
concurs. S se ordoneze descresctor persoanele n funcie de punctaj i
s se afieze lista ordonat.
Pentru a memora datele a 10 persoane dintr-un ir i a dou persoane
oarecare p i q putem scrie ceva de genul:
typedef struct {
char nume[20];
int punctaj;
} persoana;
persoana x[10], p, q;

deci definind un nou tip de date, persoana, i declarnd un tablou


unidimensional cu 10 persoane (al cror nume nu depaeste 30 de caractere.).
O alt posibilitate este definirea direct a unei variabile x[10] cu
acelai neles ca mai sus, precum i a variabilelor p i q este:
struct persoana {
char nume[20];
int punctaj;
} x[10], p;

Nu, nu l-am uitat pe q, ci doar am vrut s precizm ca el putea fi


declarat att alturi de x[10] i p, dar poate fi declarat ulterior prin:
struct persoana q;

Cele doua feluri de a declara variabile de tip nregistrare sunt


echivalente. Pentru a accesa elementele unei structuri, se foloeste selectorul
. De exemplu, prin p.punctaj=10 se acord nota 10 lui p, iar prin
strcpy(x[0].nume,'Ionescu') se denumete primul concurent Ionescu.
Observaie: nu e nevoie ca s declarm neaparat nite structuri ntre }
i ;. De pild, n exemplul de mai jos, vectorul de persoane este local funciei
main, chiar dac declaraia de struct este global.
#include <string.h>
#include <stdio.h>
#include <conio.h>
#define max 20
struct persoana {
char nume[max]; int punctaj;
};
int Citeste(struct persoana p[])
{
int i,n;
printf("Dati numarul de persoane: "); scanf("%d",&n);
for (i=0; i<n; i++)
{
fflush(stdin); // !! se poate folosi si flushall() !!
printf("Dati numele persoanei nr. %d: ",i+1);
94

gets(p[i].nume); p[i].nume[max]='\0';
printf("Dati punctajul lui %s: ",p[i].nume);
scanf("%d",&p[i].punctaj); fflush(stdin);
}
return n;

}
void Schimba(struct persoana *a, struct persoana *b)
{
struct persoana aux; aux = *a; *a = *b; *b = aux;
}
int Ordoneaza(struct persoana p[], int n)
{
int i, j, ord=1;
for (i=0; i<n-1 && ord; i++)
if (p[i].punctaj<p[i+1].punctaj) ord = 0;
if (!ord)
{
for (i=0; i<n-1; i++)
for (j=i+1; j<n; j++)
if (p[i].punctaj<p[j].punctaj) Schimba(&p[i],&p[j]);
}
return (!ord);
}
void Afiseaza(struct persoana *x, int n)
{
int i;
for (i=0; i<n; i++)
printf("%d. %20s -> %4d.\n",i+1,x[i].nume,x[i].punctaj);
}
void main()
{
struct persoana x[max]; // sirul persoanelor
int n; // numarul de persoane
clrscr();
printf("Ordonare persoane dupa punctaj\n\n");
if ((n = Citeste(x)) == 0) printf("\nNu exista persoane.");
else
{
if (Ordoneaza(x,n)) printf("\nAm ordonat persoanele.\n");
else printf("\nPersoanele erau deja ordonate.\n");
Afiseaza(x,n);
}
getch();
}
Funcia Citeste returneaz numrul de persoane citite. n mod similar,
funcia Ordoneaza returneaz 1 dac irul persoanelor era neordonat i a fost

ordonat, respectiv 0 dac el era ordonat de la bun nceput.


Observaie!! De remarcat c dac dup ce s-a citit un numr urmeaz
s se citeasc un ir de caractere e bine s se goleasc buffer-ul. Altfel
compilatorul interpreteaz caracterul <Enter> apsat dup introducerea
numrului ca fiind irul de caractere ce se dorete a fi citit.

95

Prin fflush(f) se golete fiierul (stream-ul) f. Deci, prin


fflush(stdin) golim buffer-ul intrrii standard, care n cazul de faa este
tastatur. Se poate folosi i flushall(), care golete toate bufferele asociate
stream-urilor de intrare.
Observatie. n conformitate cu cele spuse n exemplul anterior, apropo
de funcia citeste1, i aici putem s nlocuim funcia Schimba cu funcia de
mai jos:

void Schimba1(struct persoana &a, struct persoana &b)


{
struct persoana aux; aux = a; a = b; b = aux;
}
Fireste, apelul Schimba(&p[i],&p[j]) va trebui nlocuit, n acest caz,
cu Schimba1(p[i],p[j]).

Propunem cititorului s rescrie procedura de ordonare aplicnd


algoritmul quick-sort de sortare rapid.
3.
Se d o list de persoane i punctajele obinute de acestea la un
concurs. S se ordoneze descresctor persoanele n funcie de punctaj i
s se afieze lista ordonat.
Vom proced c n exemplul precedent, dar de data aceasta vom apela
la funcia qsort (definit n <stdlib.h> i n <search.h> care implementeaz
algoritmul de sortare quick sort.
#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#define max 20
struct persoana {
char nume[max];
int punctaj;
};
int Citeste(struct persoana p[])
{
int i,n;
printf("Dati numarul de persoane: "); scanf("%d",&n);
for (i=0; i<n; i++)
{
fflush(stdin); // !! se poate folosi si flushall() !!
printf("Dati numele persoanei nr. %d: ",i+1);
gets(p[i].nume); p[i].nume[max]='\0';
printf("Dati punctajul lui %s: ",p[i].nume);
scanf("%d",&p[i].punctaj);
fflush(stdin);
}
return n;
}
void Schimba(struct persoana *a, struct persoana *b)
{
96

struct persoana aux;


aux = *a; *a = *b; *b = aux;

}
int CompararePersoane(const void *a, const void *b)
{
struct persoana *pa, *pb;
pa=(struct persoana *)a; pb=(struct persoana *)b;
return (pa->punctaj < pb->punctaj);
}
void Ordoneaza(struct persoana p[], int n)
{
qsort((void *) p, n, sizeof(struct persoana),
CompararePersoane);
}
void Afiseaza(struct persoana *x, int n)
{
int i;
for (i=0; i<n; i++)
printf("%d. %20s -> %4d.\n",i+1,x[i].nume,x[i].punctaj);
}
void main()
{
struct persoana x[max]; // sirul persoanelor
int n; // numarul de persoane
clrscr();
printf("Ordonare persoane dupa punctaj\n\n");
if ((n = Citeste(x)) == 0) printf("\nNu exista persoane.");
else
{
Ordoneaza(x,n);
Afiseaza(x,n);
}
getch();
}

Exemplul ne pune n eviden, apropo de utilizarea functiei qsort,


urmtoarele:
posibilitatea de a defini parametri constani (ca n antetul funciei
CompararePersoane);
posibilitatea de a face conversie ntre pointeri, ca n cazul:
pa=(struct persoana *)a; din funcia CompararePersoane sau
qsort((void *) p, ...) din funcia Ordoneaza;
posibilitatea de a folosi numele unei funcii pe post de argument n alt
funcie, ca n cazul apelului lui qsort din funcia Ordoneaza.
4.
Se d o list de persoane i punctajele obinute de acestea la un
concurs. S se ordoneze descrescator persoanele n funcie de punctaj i
s se afieze lista ordonat.

97

Vom proceda ca n exemplul precedent, dar vom lucra cu un tablou de


pointeri la structuri, n locul unui tablou de structuri. Aceasta prezint dou
avantaje principale:
se face economie de spaiu din zona programului;
daca am estimat gresit numarul maxim de persoane, alegandu-l mult mai
mare decat cel real, necesar, penalizarea este mai mica, proportional cu
spatiul ocupat de o adresa (4 octeti) si nu de valoarea unei structuri de tip
persoana (care este max+2 octeti);
exista facilitatea de a defini structuri generice de date.

#include
#include
#include
#include

<string.h>
<stdio.h>
<conio.h>
<stdlib.h>

#define maxp 100


#define maxn 20
struct persoana {
char nume[maxn];
int punctaj;
};
typedef persoana *ppers;
typedef ppers multime_pers[maxp];
int Citeste(multime_pers p)
{
int i,n; struct persoana op;
char numele[maxn]; int punctajul;
printf("Dati numarul de persoane: "); scanf("%d",&n);
for (i=0; i<n; i++)
{
fflush(stdin); // !! se poate folosi si flushall() !!
printf("Dati numele persoanei nr. %d: ",i+1);
gets(numele); numele[maxn]='\0';
printf("Dati punctajul lui %s: ",numele);
scanf("%d",&punctajul);
strcpy(op.nume,numele); op.punctaj=punctajul;
p[i]=(ppers)malloc(sizeof(struct persoana));
*p[i]=op; fflush(stdin);
}
return n;
}
void Schimba(ppers a, ppers b)
{
struct persoana aux;
aux = *a; *a = *b; *b = aux;
}
int Ordoneaza(multime_pers p, int n)
{
int i, j, ord=1;
for (i=0; i<n-1 && ord; i++)
if (p[i]->punctaj<p[i+1]->punctaj) ord = 0;
if (!ord)
{
98

for (i=0; i<n-1; i++)


for (j=i+1; j<n; j++)
if (p[i]->punctaj<p[j]->punctaj)
Schimba(p[i],p[j]);
}
return (!ord);

}
void Afiseaza(multime_pers p, int n)
{
int i;
for (i=0; i<n; i++)
{
printf("%d. %20s -> %4d.\n",i+1,p[i]->nume,p[i]->punctaj);
free(p[i]);
}
}
void main()
{
multime_pers x; // sirul pointerilor catre persoane
int n; // numarul de persoane
clrscr();
printf("Ordonare persoane dupa punctaj\n\n");
if ((n = Citeste(x)) == 0) printf("\nNu exista persoane.");
else
{
if (Ordoneaza(x,n)) printf("\nAm ordonat persoanele.\n");
else printf("\nPersoanele erau deja ordonate.\n");
Afiseaza(x,n);
}
getch();
}

Observaie: Alocarea memoriei pentru irul de variabile dinamice de tip


nregistrare se face n procedura Citeste, iar eliberarea memoriei ocupate n
funcia Afiseaza.
5.
Scriei un program care s deseneze dreptunghiuri n modul text,
folosind mouse-ul. Se apas butonul din stnga i se marcheaz un col,
apoi se mic mouse-ul i se d drumul la buton n momentul n care s-a
fixat cel de-al doilea col (colurile sunt diagonal opuse).
Firete, n primul rnd, trebuie s dispunem de funcii pentru lucrul cu
mouse-ul. Acestea sunt scrise n fiierul mouset.h:

void MOUSE(int &a1, int &a2, int &a3, int &a4)


{
struct REGPACK regs;
regs.r_ax = a1; regs.r_bx = a2;
regs.r_cx = a3; regs.r_dx = a4;
intr(0x33, &regs);
a1 = regs.r_ax; a2 = regs.r_bx; a3 = regs.r_cx; a4 = regs.r_dx;
}
99

void MouseInit(void)
{
int a=1,b,c,d; MOUSE(a,b,c,d);
}
void MouseHide(void)
{
int a=2,b,c,d; MOUSE(a,b,c,d);
}
void MouseShow(void)
{
int a=1,b,d,c; MOUSE(a,b,c,d);
}
void MouseTData(int& but, int& x, int& y)
{
int a=3, b, c, d; MOUSE(a,b,c,d);
but=b; x=c/8+1; y=d/8+1;
}
void MouseTMove(int x, int y)
{
int a=4, b, c=8*x-1, d=8*y-1; MOUSE(a,b,c,d);
}
MouseInit() va iniiliaza mouse-ul. MouseShow() l afieaz pe ecran
MouseHide() l ascunde, MouseTData(b,x,y) preia n variabilele ntregi b, x
i y datele despre mouse n mod text: b = butonul de mouse apsat

b=0 nseamn c nici un buton nu s-a apsat;


b=1 butonul din stnga, b=2 butonul din dreapta, b=3 ambele butoane;
x, y = coloana, respectiv linia unde se afl mouse-ul;
MouseTMove(x,y) mut cursorul de mouse n csua de pe coloana x
i linia y. De remarcat apelul lui MouseData(b,x,y) prin referin.
n continuare, s scriem programul principal:

#include "mouset.h"
#include <conio.h>

#include <dos.h> /* aceasta nu neaparat, caci deja e inclusa in


"mouset.h" */
// deseneaza un chenar de la (x1,y1) la (x2,y2) de caracterul c
void Dreptunghi(int x1, int y1, int x2, int y2, char c)
{
int aux,x,y;
if (x1>x2) { aux = x1; x1 = x2; x2 = aux; }
if (y1>y2) { aux = y1; y1 = y2; y2 = aux; }
for (x=x1; x<=x2; x++)
{
gotoxy(x,y1); putch(c);
gotoxy(x,y2); putch(c);
}
for (y=y1; y<=y2; y++)
{
gotoxy(x1,y); putch(c);
gotoxy(x2,y); putch(c);
}
}
100

// deseneaza un dreptunghi umplut de la (x1,y1) la (x2,y2)


void DreptunghiPlin(int x1, int y1, int x2, int y2)
{
int aux,x,y;
if (x1>x2) { aux = x1; x1 = x2; x2 = aux; }
if (y1>y2) { aux = y1; y1 = y2; y2 = aux; }
for (x=x1; x<=x2; x++)
for (y=y1; y<=y2; y++)
{
gotoxy(x,y);
putch(219);
}
}
void main()
{
int b,x,y,px,py;
clrscr();
// se initializeaza si afiseaza mouse-ul in centrul ecranului
MouseInit();
MouseShow();
// se determina primul punct de coordonate (px,py)
do {
MouseTData(b,px,py);
} while (b!=1);
/* pentru a nu avea neaplaceri in afisarea dreptunghiurilor
partiale, se ascunde mouse-ul */
MouseHide();
do {
MouseTData(b,x,y);
/* x,y sunt coordonatele provizorii
ale celui de al doilea punct */
Dreptunghi(px,py,x,y,178);
MouseShow(); delay(50); MouseHide();
Dreptunghi(px,py,x,y,32);
/* intai se deseneaza dreptunghiul, apoi se afiseaza
putin mouse-ul, apoi se sterge dreptunghiul */
} while (b==1); // pana se apasa butonul de mouse
DreptunghiPlin(px,py,x,y);
// se deseneaza dreptunghiul plin final
MouseShow; getch();
}

Observaii:
1. S considerm funcia de baz a lui mouset.h:

void MOUSE(int &a1, int &a2, int &a3, int &a4)


{
struct REGPACK regs;
regs.r_ax = a1; regs.r_bx = a2; regs.r_cx = a3; regs.r_dx =
a4;
intr(0x33, &regs);
101

a1 = regs.r_ax;
regs.r_dx;
}

a2

regs.r_bx;

a3

regs.r_cx;

a4

Aceast funcie folosete structura predefinit n <dos.h> cu numele


REGPACK. Practic, se pot accesa regitrii interni ai calculatorului. Funcia de mai
sus folosete intreruperea DOS 33 (hexazecimal) care gestioneaz mouse-ul.
Structura REGPACK conine mai multe cmpuri ce reprezint valorile
pasate sau returnate de un apel al funciei intr (care se afl tot n <dos.h>)
i care permite apelul de intreruperi DOS pentru procesorul 8086:
struct REGPACK {
unsigned r_ax,
unsigned r_bp,
unsigned r_ds,
};
nrudit cu intr sunt

r_bx, r_cx, r_dx;


r_si, r_di;
r_es, r_flags;

int86 i int86x, acestea lucrnd cu reuniuni REGS

2. Propunem utilizatorului s utilizeze mouse-ul n propriile aplicaii ce


lucreaza n mod text.
6.
S se exemplifice folosirea reuniunilor (union) pentru citirea i
afiarea datelor despre mai multe persoane de ambele sexe.
Vom folosi o structur pentru a memora numele, vrsta i sexul unei
persoane, indiferent dac aceasta este femeie sau brbat. Dar, n functie de
sex, persoan respectiv va avea un so (dac e femeie), respectiv o soie
(dac e brbat). O nregistrare de tip union va fi folosit, aadar, pentru a
memora partenerul unei persoane oarecare.
O nregistrare union este similar cu o nregistrare de tip struct, cu
excepia faptului c union va permite s definii variabile (cmpuri) care s-i
mpart acelai spaiu de memorare.
De exemplu, fie declaraia
union int_or_long {
int
i;
long
l;
} n;

Borland C++ va aloca destul spaiu de memorare n variabila n pentru a


memora cel mai mare element dintr-un union. Spre deosebire de struct,
variabilele n.i i n.l ocup aceeai locaie de memorie. Astfel, scriind ntr-una
din ele, i cealalt va fi afectat.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
union partener {
char sotie[20];
char sot[20];
};

102

struct persoana {
char nume[20];
char sex;
int varsta;
union partener p;
};
void Citeste(int nr_p, struct persoana *x)
{
int vs; char sx;
printf("Se citesc datele persoanei a %d-a:\n",nr_p);
fflush(stdin);
printf("Dati numele: ");
gets(x->nume);
printf("Dati varsta: ");
scanf("%d",&vs);
x->varsta=vs; fflush(stdin);
printf("Dati sexul: "); scanf("%c",&sx);
x->sex=sx; fflush(stdin);
if (x->sex=='F' || x->sex=='f')
{
printf("Dati numele sotului: "); gets(x->p.sot);
}
else
{
printf("Dati numele sotiei: "); gets(x->p.sotie);
}
}
void Scrie(int nr_p, struct persoana x)
{
if (wherey()==20) { printf("\nApasati o tasta...\n"); getch();
}
printf("Datele persoanei a %d-a:\n",nr_p);
printf("Numele: %s.\n",x.nume);
printf("Varsta: %d.\n",x.varsta);
printf("Sexul: %c.\n",x.sex);
if (x.sex=='F' || x.sex=='f')
printf("Numele sotului: %s.\n",x.p.sot);
else
printf("Numele sotiei: %s.\n",x.p.sotie);
}
void main()
{
clrscr();
struct persoana om[20]; int i,n;
printf("Dati numarul de persoane: "); scanf("%d",&n);
for (i=0; i<n; i++) Citeste(i+1,&om[i]);
for (i=0; i<n; i++) Scrie(i+1,om[i]);
getch();
}

Observaie. n funcia de afiare, apare linia:

if (wherey()==20) { printf("\nApasati o tasta...\n"); getch();

103

n acest fel se ateapt apsarea unei taste n momentul n care


afiarea a adus cursorul pe linia 20. Funcia wherex() lucreaz la fel ca i
wherey(), dar pentru coloane. Ambele sunt definite n <conio.h>.
7.
S se scrie o structur de date eficien pentru lucrul cu listele
dublu nlnuite. S se proiecteze o aplicaie simpl care s prelucreze o
list dublu nlnuit.
Ne propunem s realizm o structura de list dublu nlnuit de
numere ntregi (de fapt date de tipul tip).
Lista este definit printr-o nregistrare care conine:
un ntreg reprezentnd lungimea listei (cea utilizat efectiv);
un pointer ctre elementul curent al listei;
un pointer ctre santinela inceput a listei i unul ctre santinela sfarsit a
listei: acestea sunt dou celule exterioare listei, care faciliteaz lucrul cu
lista.
O celul a listei este o nregistrare cu urmtoarea structur:
o informaie de tipul tip;
un pointer ctre celula anterioar din lista;
un pointer ctre celula urmtoare din lista.
Funciile ce vor fi implementate sunt cele de iniializare a listei,
adugare, inserare i tergere a unei liste, de deplasare n cadrul listei, de
testare daca lista este vida i de afiare.
Unele funcii returneaz 1 sau 0 i anume. Se returneaz 1, cnd
funcia face ceva anume, deci reuete, respectiv 0, n alte cazuri (nu are sens
operaia sau nu este posibil alocarea de memorie etc.).

Acest fel de a scrie aplicaii se numete stilul defensiv de


programare.
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
typedef int tip; // tipul elementelor din lista
#define format_afis1 "%d "
#define format_afis2 "%d"
#define format_cit "%d"
// o celula a listei
struct celula {
tip info;
struct celula *prec;
struct celula *urm;
};
typedef celula * pcelula; // pentru inlantuiri
// o structura de lista
typedef struct {
int lung;
pcelula inceput;
104

pcelula curent;
pcelula sfarsit;

} lista;
int Init(lista *pl)
// initializeaza lista, creand santinelele si facand legaturile
{
pl->lung=0;
pl->inceput = (pcelula) malloc(sizeof(celula));
if (!pl->inceput) return 0;
pl->sfarsit = (pcelula) malloc(sizeof(celula));
if (!pl->sfarsit) return 0;
pl->inceput->prec = NULL;
pl->inceput->urm = pl->sfarsit;
pl->sfarsit->prec = pl->inceput;
pl->curent=pl->sfarsit;
pl->inceput->info = -1;
pl->sfarsit->info = -1;
return 1;
}
int EsteVida(lista l)
// testeaza daca lista contine macar un element
{
return (l.lung==0);
}
int Insereaza(lista *pl, tip el)
/* insereaza un element in fata celui curent; elementul inserat
devine curent */
{
pcelula p, a, b;
p=(pcelula) malloc(sizeof(celula));
if (!p) return 0;
p->info = el;
a=pl->curent->prec; b=pl->curent;
a->urm=p; p->prec=a; p->urm=b; b->prec=p;
pl->lung++; pl->curent=p;
return 1;
}
int Sterge(lista *pl)
/* sterge elementul curent din lista; elementul curent va fi
succesorul
celui sters */
{
pcelula p, a, b;
if (!pl->lung) return 0;
else
{
a=pl->curent->prec; b=pl->curent->urm;
p=pl->curent;
free(p);
a->urm=b; b->prec=a;
pl->lung--;
pl->curent=b;
if ((b==pl->sfarsit) && (!EsteVida(*pl)))
pl->curent=pl->curent->prec;
return 1;
105

}
}
void Distruge(lista *pl)
// elibereaza zonele de memorie ocupata de o lista
{
while (!EsteVida(*pl)) Sterge(pl);
}
int Inainte(lista *pl)
/* inainteaza pe p->curent cu o pozitie, cel mult pina la
precedentul lui p->sfirsit, daca lista nu e vida, respectiv
p->sfirsit, daca lista e vida */
{
if (EsteVida(*pl) || (pl->curent->urm==pl->sfarsit)) return 0;
else
{ pl->curent=pl->curent->urm; return 1; }
}
int Inapoi(lista *pl)
/* aduce pl->curent inapoi cu o pozitie, cel mult pina la
succesorul lui pl->inceput */
{
if (pl->curent!=pl->inceput->urm)
{ pl->curent=pl->curent->prec; return 1; }
else return 0;
}
int Adauga(lista *pl, tip el)
// adauga un element dupa ultimul element al listei
{
while (Inainte(pl));
if (!EsteVida(*pl)) pl->curent=pl->curent->urm;
return Insereaza(pl,el);
}
void Afiseaza(lista l)
// afiseaza continutul listei
{
pcelula p;
if (EsteVida(l))
{ printf("Lista vida...\n"); return; }
p=l.inceput->urm;
printf("Lista este:\n");
while (p!=l.sfarsit)
{
if (l.curent!=p)
printf(format_afis1,p->info);
else
{
printf("["); printf(format_afis2,p->info);
printf("] ");
}
p=p->urm;
}
printf("\n");
}

106

Funcia principal main() care exploateaz structura de list i


operaiile definite mai sus este prezentat n continuare. Ieirea se realizeaz
cu tasta o.

void main()
{
lista o_lista;
Init(&o_lista); Afiseaza(o_lista);
tip un_element;
char tasta;
do
{
printf("[A]daugare, [S]tergere, [I]nserare,");
printf(" Ina[p]oi, I[n]ainte, [O]prire\n");
tasta=getche(); printf("\n");
switch(tasta) {
case 'a': {
printf("Dati elementul: ");
scanf(format_cit,&un_element);
Adauga(&o_lista, un_element);
} break;
case 'i': {
printf("Dati elementul: ");
scanf(format_cit,&un_element);
Insereaza(&o_lista, un_element);
} break;
case 's': Sterge(&o_lista); break;
case 'p': Inapoi(&o_lista); break;
case 'n': Inainte(&o_lista);
}
Afiseaza(o_lista);
} while (tasta !='o');
Distruge(&o_lista);
}

Observaie.

afar

de

funciile

precizate,

exist

funcia

DistrugeLista. Ea este apelat n finalul programului, pentru a dealoca

memoria ocupat de list n timpul programului. Funcionarea ei este simpl:


ct timp lista nu s-a golit, s se tearg cte un element din ea; s-ar fi putut
scrie i astfel: ct timp se mai pot terge elemente din list, s se tearg.
Adic:
void Distruge(lista *pl)
// elibereaza zonele de memorie ocupata de o lista
{
while (Sterge(pl));
}

Atenie la apelurile funciilor! Observai c la cele care modific


coninutul listei n vreun fel sau altul, s-au folosit pointeri drept parametri, iar n
rest parametrii erau elemente simple de tip list.

107

8.
S se scrie o structur de date eficient pentru lucrul cu arborii
binari (coninnd n noduri numere ntregi). S se proiecteze o aplicaie
simpl care s prelucreze arborii binari
Arborii binari care i vom putea construi cu funciile din acest exemplu
se bucur de o anumit proprietate. Fiecare nod conine un element care este
mai mare dect elementul din oricare nod al subarborelui stng (daca exist) i
mai mic sau egal cu orice element din subarborele drept (dac exist). Pentru
a creea astfel de arbori, e de ajuns s scriem o funcie de adugare a unui nou
element ntr-un arbore binar, funcie recursiv care s ndeplineasc
urmtoarele condiii:
dac arborele este NULL, atunci se creeaz un nod n care se pune acest
element;
dac arborele nu este NULL, atunci:
dac elementul din rdcin este > elementul nou sosit, acesta se
adaug n subarborele din stng;
dac nu, el se adaug n subarborele din dreapta.
Adugrile sunt, firete, recursive.
Dup ce vom creea funcia de adugare a unui element n arbore, vom
scrie i trei funcii care s afieze n preordine, inordine i postordine un astfel
de arbore. Se observ imediat c afiarea n inordine a arborelui creeat cu
nite elemente oarecare va duce la o afiare ordonat cresctor a acestor
elemente.
Observaie: Cele trei feluri de a parcurge un arbore sunt toate
recursive. Afiarea n preordine a unui arbore a nseamn afiarea informaiei
din rdcin (R), apoi a subarborelui stng (S), apoi a celui drept (D). Afiarea
n postordine nseamn ordinea S D R, iar n inordine: S R D. n fine, exemplul
conine i o funcie ce verific dac exist sau nu un element ntr-un arbore.
Aceste fiind spuse, s trecem la atac!

#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
typedef int tip; // tipul elementelor din nodurile arborelui
#define format_afis "%d "
#define format_cit "%d"
// un nod al arborelui
struct nod {
tip info;
struct nod *st;
struct nod *dr;
};
// un arbore binar e definit ca un pointer catre o inregistrare
de tip nod
typedef nod * arbore;
int EsteNul(arbore pa)
// testeaza daca arborele a este NULL
{
108

return (pa==NULL);
}
void Init(arbore *pa)
// initializeaza arborele, adica il face NULL
{
if (!EsteNul(*pa)) *pa=NULL;
}
int Adauga(arbore *pa, tip el)
// adauga un element el in arborele a
{
if (EsteNul(*pa))
{
*pa=(arbore)malloc(sizeof(nod));
if (!*pa) return 0;
(*pa)->info = el;
(*pa)->st = NULL; (*pa)->dr = NULL;
return 1;
}
else
if (el < (*pa)->info)
return Adauga(&(*pa)->st, el);
else
return Adauga(&(*pa)->dr, el);
}
int Exista(arbore a, tip el)
// verifica existenta elementului el in arborele a
{
if (!EsteNul(a)) // se poate scrie simplu if (a) !!
{
if (a->info==el) return 1;
else
if (el<a->info) return Exista(a->st, el);
else return Exista(a->dr, el);
}
else return 0;
}
void Preordine(arbore a)
{
if (!EsteNul(a))
{
printf(format_afis,a->info);
Preordine(a->st); Preordine(a->dr);
}
}
void Postordine(arbore a)
{
if (!EsteNul(a))
{
Postordine(a->st); Postordine(a->dr);
printf(format_afis,a->info);
}
}
void Inordine(arbore a)
{
if (!EsteNul(a))
109

Inordine(a->st);
printf(format_afis,a->info);
Inordine(a->dr);

Funcia principal main() care exploateaz structur de lista i


operaiile definite mai sus este prezentat n continuare. Ieirea se realizeaz
cu tasta o.
void main()
{
arbore un_arbore;
Init(&un_arbore);
tip un_element;
char tasta;
do
{
printf("\n[A]daugare, [P]reordine, [I]nordine, ");
printf("Po[s]tordine, [O]prire, [C]autare\n");
tasta=getche(); printf("\n");
switch(tasta) {
case 'a': {
printf("Dati elementul: ");
scanf(format_cit, &un_element);
Adauga(&un_arbore, un_element);
} break;
case 'i': Inordine(un_arbore); break;
case 's': Postordine(un_arbore); break;
case 'p': Preordine(un_arbore);
case 'c': {
printf("Dati elementul: ");
scanf(format_cit, &un_element);
if (Exista(un_arbore, un_element))
printf("Elementul exista.\n");
else
printf("Elementul nu exista.\n");
}
}
} while (tasta !='o');
}

Propunem cititorului care cunoate elemente de grafic s realizeze o


procedur recursiv ce s afieze arborele creat prin apeluri succesive ale lui
Adauga.

Probleme propuse
1.

Scriei declaraii de tip sau structuri pentru a specifica: a) timpul, n ore,


minute i secunde; b) data curent sub forma: zi/luna/an; c) adresa unei
persoane sub forma: ora/strada/nr/scara/etaj/apartament/judet/cod; d)
un numr complex: parte real / parte imaginar sau modul / argument;
110

2.

3.

4.
5.

6.

7.

e) un ir cu maxim 20 de puncte n spaiul euclidian, date prin


coordonate carteziene.
Scriei declaraii de tip sau structuri pentru a specifica: a) un numr
raional sub forma numrtor / numitor; b) un articol din fiierul unei
biblioteci sub forma: cot / autor/ titlu / an apariie / numr pagini / ISBN;
c) factura telefonic sub form: antet / numr factur / numr de telefon /
valoare abonament / chirie terminal / diverse / cost impuls / numr de
impulsuri / total sum de plat.
S se scrie un program pentru admiterea la un liceu care s permit:

iniializarea bazei de date (a vectorului de nregistrri de tip elev);

adugarea unui elev n baza de date;

nlocuirea unui elev cu alt elev;

inserarea unui elev pe o anumit poziie n baza de date;

eliminarea unui elev de pe o anumit poziie din baza de date;

eliminarea din baza de date a unui elev avnd un anumit nume;

cutarea unui elev dup nume;

calcularea mediilor;

listarea alfabetic a elevilor;

listarea elevilor n ordinea descresctoare a mediilor;

listarea tuturor elevilor cu medii peste o valoare dat;

amestecarea elevilor din baza de date;

eliminarea ultimului elev din baza de date.


S se realizeze deplasarea unei ferestre pe ecranul text, folosind mouseul i, de asemenea, redimensionarea sa, precum n mediul Borland C++.
S se scrie un program care s administreze un parc de automobile.
Informaiile relative la un automobil sunt: numrul de locuri, puterea (n
cai putere), marca, numrul de nmatriculare, tipul de carburant (benzin
sau motorin), natura (berlin, break sau coupe). Programul s permit
intrarea unei maini, ieirea unei maini, nlocuirea unei maini cu alta de
acelai model (avnd alt numr de nmatriculare).
Scriei un program care s citeasc temperaturile msurate din or n
or, precum i cantitile zilnice de precipitaii dintr-o lun a anului. Apoi
programul s permit afiarea temperaturii maxime (mpreun cu ziua i
ora asociat), temperatura minim (cu ziua i ora asociat), lista zilelor,
ordonat descresctor n funcie de cantitatea de precipitaii, media
precipitaiilor zilnice din respectiva lun a anului. Eventual s se
realizeze histograme la diferite date statistice.
Pentru un numr complex z i un numr natural n1, scriei
funcii/programe pentru a evalua urmtoarele funcii complexe:
exp(z)=1+z/1!+z2/2!+...+zn/n!;
sin(z)=z-z3/3!+z5/5!-...+(-1)nz2n+1/(2n+1)!;
cos(z)=1-z2/2!+z4/4!-...+(-1)nz2n/(2n)!;
ln(1+z)=z-z2/2+z3/3-...+(-1)nzn/n, dac |z|<1;
arctg(z)=z-z3/3+z5/5-...+(-1)nz2n+1/(2n+1), dac |z|<1.

111

8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.

20.
21.

22.

Scriei declaraii pentru notaiile unui numr complex n coordonate


polare i n coordonate carteziene, apoi funcii care s realizeze
conversia ntre o notaie i alta.
Scriei un program C care s rezolve o ecuaie de gradul II cu coeficieni
compleci.
Fiind date dou fracii p i q, s se afieze forma ireductibil a fraciilor
p+q, p-q, p/q, pq, punnd n eviden numrtorul i numitorul
acestora.
S se determine printr-un program de cte ori o persoan nscut n
anul A>19000, luna L, ziua Z, avnd vrsta V i-a aniversat ziua de
natere n aceeai zi a sptmnii cu cea n care s-a nscut.
S se verifice dac un numr p dat este "deosebi" sau nu. Spunem c p
este "deosebit" dac exist q astfel nct p=q+s(q), n care s(q) este
suma cifrelor lui q.
S se elimine dintr-o list de numere ntregi (creat dinamic) acele
numere care mprite la 13 dau un rest divizibil prin 3.
S se creeze o list a unor numere ntregi, citite de la tastatur. Apoi s
se creeze i afieze lista rstrurnatelor (oglinditelor) acestor numere.
S se elimine dintr-o list de numere reale acele numere care au partea
zecimal egal cu zero.
S se elimine dintr-o list de numere ntregi acele numere care sunt
pare.
Se d o list de numere ntregi creat dinamic. S se creeze dinamic
dou liste, una cuprinznd numerele prime, iar alta cuprinznd numerele
care nu sunt prime, dar sunt impare.
Se citesc n numere de la tastatur. S se creeze o list circular a lor.
a) S se rezolve problema damelor, memornd soluiile ntr-o list
dinamic.
b) S se genereze permutrile unei mulimi de elemente, memorate
ntr-o list creat dinamic.
Implementai algoritmii "quick-sort" (sortare rapid) i "merge-sort"
(sortare prin interclasare), pe baza tehnicii "divide et impera" i realizai
programe n care s-i folosii.
Coliere de mrgele. Se consider n casete, fiecare coninnd un numr
precizat de mrgele bicolore (combinaii de rou, galben, albastru, verde,
maro), culorile fiind cunoscute. Mrgelele din fiecare caset sunt
identice. S se scrie un program interactiv pentru generarea tuturor
colierelor circulare distincte de lungime maxim, cu condiia ca mrgelele
alturate s vin n contact cu aceeai culoare. Se consider colier un
irag de minimum dou mrgele.
Masa rotund. Un numr de 2n+1 persoane particip la discuii la o
mas rotund, care dureaz n zile. S se gseasc variantele de
aezare la mas astfel nct o persoan s nu aib n dou zile diferite
acelai vecin.

112

23.
24.
25.

Pentru o expresie aritmetic coninnd paranteze, operatorii +.-. / i * i


operanzi numerici, s se determine valoarea sa. (Se vor folosi dou
stive, una a operanzilor, iar alta a operatorilor).
Se cere s se scrie un program care s deriveze (formal) o expresie. Se
va folosi faptul c orice expresie aritmetic poate fi memorat sub forma
unui arbore binar.
Se consider un arbore oarecare i se cere memorarea sa sub forma
unui arbore binar, folosind legturi de tip fiu-frate. Un exemplu este dat n
figura urmtoare. Observm c putem lega rdcina 1 de nodul 2, iar
apoi, nodul 2 poate fi legat de primul fiu al su (21) i de urmtorul fiu al
rdcinii, deci 3, despre care se spune c este un frate a lui 2.
Procednd astfel pentru toate nodurile din arbore, vom obine un arbore
binar, cu dou legturi: cea din stnga este ctre primul fiu, iar cea din
dreapta ctre primul frate din dreapta al acestui fiu.

Astfel, arborele din figura anterioar se va memora n arborele binar de


mai jos:

NULL

26.
27.

Se citesc numere ntregi de la tastatur, pn la ntlnirea numrului 0.


Se cere s se creeze dou liste dublu nlnuite, una a numerelor
negative, iar alta a numerelor pozitive prime.
Se d o list dublu nlnuit de numere ntregi pozitive. S se creeze o
list dublu nlnuit care s conin doar numerele pare, apoi s se
concateneze cele dou liste.
113

28.
29.

30.
31.
32.
33.
34.
35.
36.

37.
38.
39.

Se dau doi arbori binari. Se cere s se nlocuiasc fiecare nod al primului


cu cel de al doilea arbore.
Se d un arbore oarecare, informaiile din noduri fiind iruri de caractere.
S se construiasc o list dublu nlnuit care s conin toate irurile
din nodurile arborilor, care au lungimile pare, apoi s se ordoneze
aceast list.
Scriei o funcie care verific dac elementele unei liste simplu nlnuite
cuprinznd date de tip char sunt sau nu ordonate.
Scriei o funcie care s calculeze suma elementelor pozitive dintr_o list
cuprinznd doar numere reale. Scriei o funcie care s determine
lungimea listei.
ntr-o list circular dublu nlnuit s se nlocuiasc fiecare apariie a
unui caracter care este vocal cu cea mai apropiat consoan din cadrul
listei. Aceeai problem n cazul unei liste circulare simplu nlnuite.
ntr-o list circular simplu nlnuit s se nlocuiasc fiecare apariie a
unui caracter care este vocal cu cea mai apropiat consoan din
alfabet. Aceeai problem cnd lista este o coad (necircular).
Scriei funcii/programe pentru a calcula suma, diferena, produsul i
pentru a efectua mprirea cu ct i rest a dou polinoame, ale cror
coeficieni (reali) sunt memorai n liste create dinamic.
Implementai structuri de date eficiente pentru a memora arbori oarecare.
Scriei apoi funcii care s parcurg un arbore oarecare n lime i,
respectiv, n nlime.
Fie Fk al k-lea termen din irul lui Fibonacci. Un arbore Fibonacci de
ordin k are Fk-1-1 vrfuri interne (notate cu 1, 2, ..., Fk+1-1) i Fk+1
frunze (notate cu 0, -1, -2, ... -(Fk+1+1)) i se construiete dup cum
urmeaz:
pentru k=0 i k=1 arborele este [1].;
pentru k2, rdcina este notat cu Fk, subarborele stng este arbore
Fibonacci de ordin k-1, iar subarborele drept este arbore Fibonacci de
ordin k-2, n care valorile vrfurilor sunt mrite cu Fk.
a) S se scrie o funcie (recursiv) pentru a construi un arbore Fibonacci
de ordin n.
b) S se parcurg arborele creat n ordine, listnd doar informaia din
nodurile interne.
Fiind dat un arbore de sortare, scriei o funcie recursiv pentru a terge
un nod astfel ca dup tergere, arborele rmas s fie n continuare
arbore de sortare.
Se citesc ntregii pozitivi n i m, ambii mai mici dect 100. Se cere s se
afieze reprezentarea ca fracie zecimal a numrului r=m/n. Eventuala
perioad se va afia ntre paranteze.
ntr-un triaj exist o linie de cale ferat pentru manevre ca n figura de
mai jos. Pe linia de intrare sunt n vagoane, numerotate de la 1 la n.
Deplasrile sunt permise doar conform sensurilor sgeilor din figur.

114

linia de intrare

linia de ieire

linia de manevr

40.

41.

42.

43.
44.
45.

a) Cunoscndu-se ordinea vagoanelor la intrare i ordinea dorit pe linia


de ieire, se cere s se stabileasc dac problema are soluie, iar n caz
afirmativ s se afieze manevrele necesare pentru a deplasa vagoanele
de pe linia de intrare pe cea de ieire;
b) Aceeai problem, dar se consider c pe linia de intrare deplasarea
este permis n ambele sensuri;
c) n aceleai condiii ca la (a), s se stabileasc toate posibilitile de a
deplasa vagoanele de pe linia de intrare pe cea de ieire.
d) n aceleai condiii ca la (b), s se stabileasc toate posibilitile de a
deplasa vagoanele de pe linia de intrare pe cea de ieire.
Sortare topologic. Se citete un set de relaii de forma x<y, cu
semnificaia c n definirea unui termen y se folosete termenul x,
dintr-un dicionar. Se cere s se afieze toi termenii din dicionar ntr-o
anumit ordine astfel nct s nu se defineasc la un moment dat un
termen care necesit cunoaterea unui alt termen definit mai trziu n
cadrul dicionarului.
Se citesc relaii despre mai multe mulimi, de forma A in B, A nd B i
A dj B, cu semnificaiile: mulimea A este inclus n mulimea B,
mulimile A i B nu sunt disjuncte, respectiv mulimile A i B sunt
disjuncte. S se verifice dac un astfel de set de relaii este sau nu
consistent, n sensul c nu exist o contradicie ntre relaii. n caz de
consisten, s se elimine relaiile redundante. (De exemplu, pentru seul
de relaii: X in Y, Y in Z i X dj Z avem contradicie.
n bile colorate n cel mult k culori, sunt etichetate cu numere ntre 1 i n.
Bilele se afl pe o andrea vertical. Se cere s se mute pe alte k
andrele, pe fiecare andrea punnd bilele de aceeai culoare. Fiecare
andrea are un capt blocat (de o gmlie), iar cellal este liber i permite
intrarea bilelor.
Se dau dou liste alocate dinamic, fiecare cuprinznd cuvinte ordonate
alfabetic. Se cere s se realizeze lista tuturor cuvintelor n ordine
alfabetic.
Determinai o structur de date eficient pentru memorarea matricelor
rare (care au dimensiuni mari i foarte multe elemente de zero). Realizai
adunarea i nmulirea a dou astfel de matrice.
Se consider un arbore care cuprinde strmoii unei persoane, al crei
nume figureaz n rdcinile arborelui. Nodul care figureaz n stnga
cuprinde numele tatlui, iar cel din dreapta numele mamei. Fiind dat
numele unei persoane oarecare din familie s se afieze numele
bunicilor, dac acetia figureaz n arbore.
115

Capitolul 5. Exploatarea fiierelor


y moduri de deschidere a fiierelor y citiri i scrieri din/n fiiere y
y poziionarea n cadrul fiierului y numrarea articolelor y
y sortarea componentelor dintr-un fiier cu structuri y
y utilizarea argumentelor din linia de comand y

Probleme rezolvate
1.
Mai multe persoane au participat la un concurs i au obinut
puncte. S se realizeze o aplicaie care s permit stocarea datelor
persoanelor ntr-o baz de date (un fiier cu structuri), s poat adaug
noi persoane, s caute i s modifice punctajul unei persoane i s
ordoneze persoanele descrescator dup punctaj.
Vom folosi funciile standard ale limbajului C pentru lucrul cu fiiere,
care sunt declarate n <stdio.h>. De remarcat c funciile fopen, fread,
fwrite etc. la care ne referim pot prelucra orice gen de fiiere, att fiiere text,
ct i fiiere binare sau fiiere avnd anumite structuri de acelasi tip, una dup
alta, cum e cazul bazelor de date din exemplul nostru. ns, trebuie avut mare
grij la modul de folosire a acestor funcii, deoarece ele pot crea mari probleme
programatorului amator, sau cel obinuit cu procedurile i funciile similare din
Pascal!
#include <stdio.h>
#include <conio.h>
#include <string.h>
struct persoana {
char nume[20];
int punctaj;
};
void Citeste(struct persoana *p)
{
fflush(stdin);
printf("Dati numele: ");
gets((*p).nume);
printf("Dati punctajul lui %s: ",(*p).nume);
scanf("%d",&(*p).punctaj);
fflush(stdin);
}
void Schimba(struct persoana *a, struct persoana *b)
{
struct persoana aux;
aux = *a; *a = *b; *b = aux;
}
void Adauga(char nume_fis[13])
{
/* Se compara numele fisierului cu sirul vid.
In caz ca numele fisierului este vid, nu se executa nimic. */
if (!strcmp(nume_fis,"")) return;
FILE *f;
struct persoana p;
116

/* se deschide fisierul f pentru "a"daugare la sfarsit, in mod


"b"inar */
if ((f = fopen(nume_fis,"ab")) == NULL)
{
printf("\nNu se poate deschide fisierul %s.\n",nume_fis);
return;
}
Citeste(&p);
fwrite(&p, sizeof(p), 1, f);
fclose(f);
}
void CautaSiModifica(char nume_fis[13])
{
/* Se compara numele fisierului cu sirul vid.
In caz ca numele fisierului este vid, nu se executa nimic. */
if (!strcmp(nume_fis,"")) return;
FILE *f;
struct persoana p, q;
// se deschide f pentru actualizare ("r+") in mod "b"inar
if ((f = fopen(nume_fis,"r+b")) == NULL)
{
printf("\nNu se poate deschide fisierul %s.\n",nume_fis);
return;
}
Citeste(&p);
int gasit=0; long poz;
while (!feof(f) && (!gasit))
{
poz=ftell(f);
fread(&q,sizeof(struct persoana),1,f);
if (!strcmp(p.nume,q.nume))
{
gasit=1; fseek(f,poz,SEEK_SET);
fwrite(&p,sizeof(p),1,f);
}
}
fclose(f);
if (!gasit) printf("\nPersoana inexistenta.\n");
else
printf("\Persoana avea punctajul: %d si acum are: %d.\n",
q.punctaj,p.punctaj);
}
long FileSize(FILE *f)
// returneaza numarul de octeti ale unui fisier oarecare f !!
{
long poz_curenta, lungime;
poz_curenta = ftell(f); fseek(f, 0L, SEEK_END);
lungime = ftell(f); fseek(f, poz_curenta, SEEK_SET);
return lungime;
}
void Listeaza(char nume_fis[13])
{
/* Se compara numele fisierului cu sirul vid.
117

In caz ca numele fisierului este vid, nu se executa nimic. */


if (!strcmp(nume_fis,"")) return;
struct persoana p;
FILE *f;
if ((f = fopen(nume_fis,"rb")) == NULL)
{
printf("\nNu se poate deschide fisierul.\n");
return;
}
long i=0;
while (!feof(f))
{
fread(&p,sizeof(struct persoana),1,f);
if (!feof(f)) // atentie !!
printf("%ld. %s -> %d\n",++i,p.nume,p.punctaj);
if (wherex()==20)
{
printf("\nApasati o tasta pentru continuare...\n");
getch(); clrscr();
}
}
printf("\nIn total: %ld persoane.\n",
FileSize(f)/sizeof(struct persoana));
fclose(f);
}
void Sorteaza(char nume_fis[13])
/* sorteaza inregistrarile din baza de date curenta,
punctaj */
{
if (!strcmp(nume_fis,"")) return;
struct persoana p, q;
FILE *f;
if ((f = fopen(nume_fis,"r+b")) == NULL)
{
printf("\nNu se poate deschide fisierul.\n");
return;
}
size_t lung_pers = sizeof(struct persoana); // 22 octeti
long lungime_fisier=FileSize(f)/lung_pers;
long poz, i;
int ordonat;
do {
ordonat=1; rewind(f);
for (i=1; i<=lungime_fisier-1; i++)
{
poz=ftell(f);
fread(&p,sizeof(struct persoana),1,f);
fread(&q,sizeof(struct persoana),1,f);
if (p.punctaj<q.punctaj)
{
fseek(f,poz,SEEK_SET);
fwrite(&q,sizeof(q),1,f);
fwrite(&p,sizeof(p),1,f);
118

dupa

ordonat=0;
}
fseek(f,poz+lung_pers,SEEK_SET);

}
} while (!ordonat);
fclose(f);

}
void main(void)
{
FILE *f; char nf[13]; char c;
struct persoana p;
strcpy(nf,"");
do {
clrscr();
printf("\nAGENDA TELEFONICA -> %s\n\n",nf);
printf("\n[D]enumire fisier, [A]daugare, [S]orteaza");
printf("\n[C]autare/modificare, [L]istare, [O]prire\n");
c=getche(); printf("\n");
switch(c) {
case 'd': printf("Dati numele agendei: ");
gets(nf); break;
case 'a': Adauga(nf); getch(); break;
case 'c': CautaSiModifica(nf); getch(); break;
case 'l': Listeaza(nf); getch(); break;
case 's': Sorteaza(nf); Listeaza(nf); getch();
}
} while (c!='o');
}
Pentru a nelege mai bine funciile de lucru cu fiiere n limbajul C/C++,

vom coment mai jos funcia care ordoneaz descresctor o baz de date,
dup punctaj.
Metoda folosit este sortarea prin bule (bubble-sort), care poate fi
descris foarte simplu astfel:
repeta
{
ordonat=adevarat;
parcurge sirul elementelor, de la primul la penultimul si
daca elementul curent < elementul de pe pozitia urmatoare atunci
{
interschimba cele doua elemente;
ordonat=fals;
}
}
pana cand ordonat=adevarat.

Funcia ncepe cu linia:

if (!strcmp(nume_fis,"")) return;

care face o verificare asupra numelui fiierului corespunztor bazei de date


curente. Astfel, se folosete funcia strcmp(s1,s2) care returneaz:
0 dac cele dou fiiere sunt identice;
< 0, dac primul ir e mai mic (alfabetic) dect al doilea;
> 0, dac cel de al doilea e mai mic dect primul.
119

Apoi se declar dou variabile p i q, ce vor fi folosite n sortarea bazei


de date.
struct persoana p, q;

Se declar o variabil:

FILE *f;

care se asociaz fiierului extern cu numele nume_fis.


Se ncearc deschiderea fiierului asociat lui f, prin funcia fopen, n
modul binar, pentru citiri i scrieri (r+b).
Dac operaia nu reuete, se afieaz un mesaj de eroare:
if ((f = fopen(nume_fis,"r+b")) == NULL)
{
printf("\nNu se poate deschide fisierul.\n"); return;
Altfel, se determin mrimea unei nregistrri din baza de date:
}
size_t lung_pers = sizeof(struct persoana); // 22 octeti i

numrul de astfel de nregistrri, adic numrul de persoane.

long lungime_fisier=FileSize(f)/lung_pers;
S-a folosit o funcie proprie, FileSize(f) care d numrul de octei ai
unui fiier binar oarecare f, dar care trebuie s fie deschis. Vom comenta i

aceast funcie, mai trziu.


Variabila poz va reine poziia elementului curent (al i-lea) din fiier,
adic octetul la care ncepe el n fiier.
long poz, i;
Variabila ordonat indic dac la o anumit parcurgere a
bazei de date a avut loc o interschimbare (0) sau nu (1).
int ordonat;
ntr-un ciclu corespunztor metodei de sortare
descrise...
do {

ordonat=1;

... ne intoarcem la nceputul fiierului f cu rewind(f):


rewind(f); Parcurgem baza de date pentru fiecare pereche (p,q) de
structuri din ea:
for (i=1; i<=lungime_fisier-1; i++)
{

Vedem unde ne aflm n fiier, nainte de a citi cele doua nregistrri:


poz=ftell(f);

Observaie. Valoarea
nregistrarea curent!

returnat

reprezint

octetul

curent,

Citim cele dou nregistrri, folosind fread, care are sintaxa:

size_t

fread(void

*p,

size_t

size_t n, FILE *f);


Aceast funcie citete un numr specificat prin n de itemi de mrimi
egale (m) dintr-un fiier dat f, rezultatul depunndu-se ntr-un bloc de la adresa
memorat n p. Numrul total de octei citii este nm.

120

m,

nu

Observaie.Valoarea returnat este numrul de itemi citii (nu octei!), iar


n caz de eroare sau sfrit de fiier returneaz, de obicei 0.

fread(&p,sizeof(struct
fread(&q,sizeof(struct persoana),1,f);

persoana),1,f);

Apoi comparm punctajele celor dou nregistrri:

if (p.punctaj<q.punctaj)
{
n caz c cea de a doua (q=succesoarea lui p) este cu punctaj mai bun,
folosind fseek i fwrite le inversm:
fseek(f,poz,SEEK_SET);
fwrite(&q,sizeof(q),1,f);
fwrite(&p,sizeof(p),1,f);
ordonat=0;
}

Trecem la urmtoarea nregistrare:

fseek(f,poz+lung_pers,SEEK_SET);

Procesul se repet pn n momentul n care ordonat i


pstreaz valoarea 1. } while (!ordonat);
... dup care se nchide fiierul
}

fclose(f);

Funcia de poziionare n cadrul fiierului este fseek, dar ea lucreaz


}
la nivel de octei! Sintaxa sa este: int fseek(FILE *f, long l, int
unde). Aici f este fiierul, l este diferena n octei ntre poziia unde i noua
poziie. Pentru fiierele deschise ca fiiere text, l ar putea fi 0 sau o valoare
returnat de ftell.
n sfrit, noutatea adus fa de Pascal este parametrul unde, care
poate avea una din valorile:
SEEK_SET = 0, semnificnd c se pleac de la nceputul fiierului,
SEEK_CUR = 1, semnificnd o distan de la poziia curent n fiier,
SEEK_END = 2, semnificnd de la sfritul fiierului
Dac funcia reuete (deci indicatorul n fiier s-a mutat cu succes),
fseek returneaz 0, n caz de eec fseek returneaz un ntreg diferit de zero,
eventual un cod de eroare, n cazul n care, de pild, fiierul nu ar fi fost
deschis.
n continuare, ne ocupm de funcia FileSize. Ea returneaz numrul
de octei al unui fiier oarecare f, deschis:

long FileSize(FILE *f)


{
long poz_curenta, lungime;
// memoram locul unde ne aflam
poz_curenta = ftell(f);
// ne ducem la sfarsitul fisierului
fseek(f, 0L, SEEK_END); // 0L semnifica numarul 0 vazut ca
long int !
// locul unde ne aflam acum este chiar lungimea fisierului
121

lungime = ftell(f);
// ne intoarcem de unde am plecat
fseek(f, poz_curenta, SEEK_SET);
return lungime;
}

2.
Scriei un program care s afieze toi parametrii din linia de
comand i variabilele de mediu.

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
void main(int nr_de_p, char *param[], char *var_mediu[])
{
int i;
clrscr();
for(i=0; i<nr_de_p; i++)
printf("Parametrul[%d] = %s\n",i,param[i]);
for(i=0; env[i] != NULL ; i++)
printf("Variabila de mediu[%d] = %s\n",i,var_mediu[i]);
}

Ce face acest program? Este primul program n care funcia main are i
parametri. Acetia sunt:
- nr_p = un numr ntreg reprezentnd numrul de parametri din linia de
comand, adic lungimea vectorului param;
- param = un vector de iruri de caractere, n care:
param[0] = numele programului pornit (cu toat calea sa);
param[1] = primul argument al programului pornit (dac exist);
param[2] = al doilea argument al programului pornit (dac exist);
...;
- env[0] ... env[...] = variabile de mediu, nelegnd prin aceasta
diferite date, precum:
- directorul fiierelor temporare;
- directorul de boot-are (ncarcare a sistemului de operare);
- fiierul interpretor de comenzi (COMMAND.COM);
- cile de cutare (stabilite cu PATH);
- alte variabile stabilite cu SET;
- prompterul sistemului;
- ultima linie de comand dat din sistemul de operare.
Toate aceste informaii pot fi folosite n programe ce lucreaz cu fiiere,
ca n exemplul urmtor, sau n diverse programe profesionale. Succes!
3.

Implementai comanda copy din MS-DOS.

Vom folosi facilitile descrise n exemplul anterior. Astfel, denumind


acest fiier my_copy.cpp, se va creea, n urma compilrii, executabilul
my_copy.exe care se va putea apela cu:
122

my_copy <fisier_sursa> <fisier_destinatie>


ns, daca lipsesc
unul sau ambii parametri, funcia AnalizaParametri va cere parametrii lips.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#define BUFLNG
1000 //lungimea buffer-ului folosit la copiere
#define FTMP
"my_copy.tmp" //fisier de lucru temporar
char sursa[13], dest[13];
void AnalizaParametri(int nr_p, char *param[])
{
strcpy(sursa,param[1]);
strcpy(dest,param[2]);
switch (nr_p)
{
case 1: printf("\nFisier sursa: "); gets(sursa);
case 2: printf("\nFisier destinatie:"); gets(dest);
case 3: strcpy(sursa,sursa); strcpy(dest,dest); break;
default: printf("\nPrea multi parametri.\n");
exit(1);
}
}
void Copiere(FILE *f1, FILE *f2)
{
char c,*buf_cit;
int nb_cit, nb_scr;
if ((f1= fopen(from,"rb"))== NULL )
{
printf("\nFisier de intrare eronat.\n");
exit(1);
}
if ((f2 = fopen(dest,"rb"))!= NULL)
{
printf("\nFisier destinatie existent.);
printf( Suprascriem [d/n]? ");
c = getche();
if (c=='N' || c=='n') strcpy(dest,FTMP);
}
if ((f2 = fopen(to,"wb"))== NULL)
{
printf("\n\aEroare creare fisier destinatie.\n");
exit(1);
}
if ((buf_cit = (char *)malloc(BUFLNG))== NULL)
{
printf("\n\aMemorie insuficienta.\n");
exit(1);
}
while ((nb_cit=fread(buf_cit,1,BUFLNG,f1)) !=0 &&
(nb_scr=fwrite(buf_cit,1,nb_cit,f2)) == nbcit);
fclose(f1); fclose(f2);
printf("\nCopiere");
if (nb_cit != nb_scr) printf("\a in");
printf("completa.\n");
}
123

void main(int argc,char *argv[])


{
FILE *pfrom,*pto;
AnalizaParametri(argc,argv); Copiere(pfrom,pto);
}

Observaii.
1. Mesajul afiat poate fi i copiere incomplet. De ce? Lsm n
seama cititorului s schimbe programul pentru a funciona n orice caz.
2. Afiarea lui \a nseamn producerea unui sunet n difuzor.
4.
Scriei un program care s afieze un fier text astfel: dac fiierul
conine texte ntre acolade { i }, acelea s fie afiate n alb deschis,
iar restul textului n alb nchis. De asemenea, se cere ca literele s fie
afiate cu incetinitorul".
Vom deschide un fiier n mod binar, pentru a nu avea neplceri
cauzate de caracterul Enter i citind caracter cu caracter, l vom analiza i l
vom afia. Excepiile sunt date de cele dou caractere speciale, care vor
controla culorile.
#include <stdio.h>
#include <conio.h>
#include <dos.h>
#define pauza 20
void main(void)
{
FILE *fis;
char nume_fis[13];
char linie[255];
char c;
textcolor(7); textbackground(0); clrscr();
printf("Dati numele fisierului: "); gets(nume_fis);
if ((fis = fopen(nume_fis, "rb")) == NULL)
{
printf("Nu se poate deschide fisierul.\n");
return;
}
while (!feof(fis))
{
c=fgetc(fis); // fgetc preia un caracter dintr-un fisier
if (c=='{') textcolor(15);
else
if (c=='}') textcolor(7);
else
if (c==9) { putch(' '); putch(' '); putch(' '); }
else { putch(c); delay(pauza); }
}
fclose(fis);
}

Observaie. Afiarea pe ecran a caracterului citit se face cu putch, care


ine cont de culori. De asemenea, se observ c TAB (caracterul cu codul
124

ASCII egal cu 9) este nlocuit cu trei spaii. Propunem cititorului perfecionarea


programului, folosind eventual fiiere text.
5.

Scriei un program care s fac o copie unui fiier text dat.

#include <stdio.h>
void main(void)
{
FILE *in, *out; char sursa[13], dest[13];
fflush(stdin);
printf("Dati sursa: "); scanf("%s",&sursa); fflush(stdin);
printf("Dati destinatia: "); scanf("%s",&dest);
if ((in = fopen(sursa, "rt")) == NULL)
{
printf("Nu se poate deschide fisierul sursa.\n");
return;
}
if ((out = fopen(dest, "wt")) == NULL)
{
printf("Nu se poate crea fisierul destinatie.\n");
return;
}
// se copiaza caracterele din "in" in "out"
while (!feof(in))
fputc(fgetc(in), out);
fclose(in); fclose(out);
}

Probleme propuse
1.
2.
3.

4.
5.
6.
7.

S se scrie un program C care afieaz coninutul directorului curent.


Scriei un program care s elimine toate comentariile dintr-un program C.
Nu uitai s manevrai adecvat irurile dintre ghilimele i constantele de
caractere!
Scriei un program care citete de la tastatur cte trei numere reale,
apoi le scrie ntr-un fiier text 'IN.TXT'. Apoi, citind aceste trei numere,
reprezentnd laturile unui triunghi, scrie n fiierul text OUT.TXT tipul
triunghiului format.
Scriei un program C care concateneaz dou fiiere text ntr-unul singur
(primul dintre ele):
Scriei un program pentru a verifica un program C din punct de vedere al
erorilor de sintax rudimentare, ca de exemplu: paranteze neperechi. Nu
uitai ghilimelele, att cele simple, ct i cele duble i comentariile.
S se scrie un program care sorteaz un fiier text n el nsui; fiierul
conine cel mult 100 de linii.
S se realizeze o aplicaie complex care s gestioneze mai multe seturi
de date referitoare la elevii participani la un concurs (de admitere, de
exemplu). Programul va realiza urmtoarele:

selectarea numelui fiierului de lucru (nf), adic a bazei


de date;
125

8.

9.

10.
11.
12.

13.
14.
15.

adugarea unui elev n baza de date, precum i


tergerea unui elev din baza de date (tergerera se va
face n funcie de numele elevului sau de poziia sa n
cadrul fiierului);

cutarea unui elev n fiier;

ordonarea alfabetic a elevilor din baza de date, precum


i ordonarea descresctoare dup medii a elevilor din
baza de date;

listarea coninutului fiierului (la un moment dat);


Toate aceste operaii vor fi realizate cu ajutorul unor proceduri,
selectabile dintr-un meniu. Activarea unei opiuni din meniu se va face cu
ajutorul tatstelor de sgei sus i jos. Selectarea propriu-zis a ei se va
realiza acionnd tasta Enter. Programul se va termina cnd se va
alege ultima opiune sau se va aciona tasta Escape (n meniu). Ca
variant propunem utilizarea mouse-ului.
Fie un fiier creat prin apeluri succesive ale procedurii de adugarea
unui elev din programul realizat la problema anterioar. Scriei un
program separat care s afieze coninutul fiierului ntr-un fiier text.
Adugai, apoi, acest program, programului de la problema anterioar,
sub forma unei noi opiuni/funcii.
Un fiier text conine cel puin 100000 linii de forma:
nume prenume nota1 nota2
Fiecare linie cuprinde informaii referitoare la un elev care d un anumit
examenul. Se cere s se creeze un fiier cu tip, al elevilor care obin cel
puin media 5. Fiecare articol al fiIerului creat va conine numele i
prenumele elevului, precum i media.
n condiiile problemelor anterioare, se cere crearea unui fiier al elevilor
neadmii (cu medii sub 5).
Se d un fiier text cu foarte multe linii. Se cere s se ordoneze.
Se consider un fiier F cuprinznd datele mai multor elevi (nume,
punctaj). Se cere s se creeze trei fiiere text G1, G2 i G3, fiecare
cuprinznd cte o treime din elevii lui F, dup ce F a fost ordonat dup
punctaj. Liniile acestor fiIere vor conine numele i punctajele elevilor.
Primul fiier va cuprinde prima treime de elevi, fiierul G2 va cuprinde
urmtoarea treime din elevi, iar G3 va conine elevii rmai.
Aceeai problem ca mai nainte, dar fr a ordona mai nti fiierul F. n
plus, se cere s se ordoneze fiierele G1 i G2, apoi s se interclaseze
fiierele G1 i G2 rezultnd un fiier G.
Scriei un program cuprinznd diferite funcii de prelucrare a fiierelor
cuprinznd numere ntregi: ordonare, cutare, adugare sau tergere de
articole etc.. Realizai n funcia main diferite apeluri ale acestor funcii.
S se scrie un program care s realizeze un pian electronic. Fiecrei
taste i se va ataa o not muzical. Tastele funcionale (F1..F12) vor fi
folosite pentru diferite operaii speciale: salvarea melodiei curente ntr-un
fiier, restaurarea i cntarea unei melodii dintr-un fiier etc.

126

16.
17.
18.
19.
20.
21.

22.

23.
24.

25.
26.
27.

S se scrie un program care tiprete distribuia frecvenei lungimii


cuvintelor aflate ntr-un fiier text. Cuvintele sunt separate prin spaii.
S se scrie un program care compar, linie cu linie, coninutul a dou
fiiere text, afind numrul de ordine al celor neidentice.
Se dau dou iruri de caractere S i T i un fiier text F. S se scrie
funcia care copiaz tot coninutul lui F ntr-un alt fiier text G, ns
nlocuiete fiecare apariie a irului S cu irul T.
S se concateneze dou fiiere oarecare ntr-un al treilea fiier. Numele
celor trei fiiere se vor citi din linia de comand a programului.
Se consider un fiier cu informaii despre locul naterii unor persoane.
S se determine pentru fiecare localitate, numrul de persoane nscute
n localitatea respectiv.
Se consider un fiier cu tip cuprinznd mai multe numere reale,
memorate pe 10 poziii caracter, din care 3 zecimale. S se scrie ntr-un
fiier text, cte 10 pe linie, acele numere care sunt i ntregi i sunt i
prime.
S se realizeze un program pentru o agend telefonic care s permit
gestionarea unor persoane, a adreselor lor i a numerelor lor de telefon.
Operaiile care vor fi realizate sunt: adugare persoan, eliminare
persoan, cutare numar de telefon a unei persoane, cutarea unei
persoane a crui numr de telefon se cunoate, modificare numr de
telefon persoan, ordonare alfabetic, listarea persoanelor ntr-un fiier
text.
S se scrie un program cu fiiere care s permit administrarea unui top
al preferinelor dumneavoast muzicale.
Scriei un program pentru evidena mprumuturilor de cri la o bibliotec.
Programul va permite editarea unui raport lunar ce va cuprinde: data
raportului; numrul de mprumuturi; numrul de cri mprumutate;
numrul de cri napoiate; numrul de cri pierdute; mprumuturile
restante.
S se afieze coninutul unui fiier text ntr-o fereastr ecran astfel nct
textul s fie aliniat: a) la stnga; b) la dreapta; c) pe mijloc.
Aceeai problem ca cea anterioar, dar alinierea textului s se fac "din
stnga n dreapta", n sensul c se vor pune spaii suplimentare ntre
cuvinte, pentru ca textul s fie aliniat n ambele pri.
S se scrie un program cu o interfa ct mai prietenoas, care s
realizeze evidena aprovizionrilor/vnzrilor efectuate ntr-un magazin.

127

Capitolul 6. Algoritmi de teoria grafurilor


y arbori oarecare y parcurgereri n lime i adncime y
y arbori pariali de cost minim y

Probleme rezolvate
1.
S se defineasc o structur adecvat pentru memorarea arborilor
oarecare. S se scrie funcii care s parcurg astfel de arbori n lime i
n adncime.
Vom defini un nod al arborelui ca fiind o structur caracterizat de o
informaie (aici un numr ntreg) i un numr de fii, care vor fi pointeri ctre alte
structuri de acelai fel.
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
typedef int tip; // tipul elementelor din nodurile arborelui
// un nod al arborelui
struct nod {
tip info; // informatia din nod
int nf; // numarul de fii
struct nod *fiu[20]; // fii = pointeri la alte noduri
};
typedef nod * arb;
int Creeaza(arb *pa, int nr, int parinte)
{
tip el;
*pa=(arb)malloc(sizeof(nod));
if (!*pa) return 0;
printf("Dati info pt. fiul %d al lui %d: ",nr,parinte);
scanf("%d",&el); (*pa)->info = el;
if (el)
{
printf("Dati nr. de fii pt. %d: ",el);
scanf("%d",&(*pa)->nf);
for (int i=0; i<(*pa)->nf; i++)
Creeaza(&(*pa)->fiu[i], i+1, el);
}
return 1;
}
void Adancime(arb a)
{
if (a)
{
printf("%d,",a->info);
for (int i=0; i<a->nf; i++) Adancime(a->fiu[i]);
}
}
void Latime(arb a, int e_radacina)
{
if (a)
128

{
int i;
if (e_radacina) printf("%d,",a->info);
for (i=0; i<a->nf; i++) printf("%d,",a->fiu[i]->info);
for (i=0; i<a->nf; i++) Latime(a->fiu[i],0);
}

}
void main()
{
arb p; clrscr(); printf("\nCrearea arborelui:\n");
if (!Creeaza(&p,0,0))
{
printf("Memorie insuficienta!"); return;
}
printf("\nParcurgerea in adincime:\n"); Adancime(p);
printf("\nParcurgerea in latime:\n"); Latime(p,1);
getch();
}

Creearea arborelui se realizeaz astfel: se cere informaia nodului


curent, apoi numrul de fii ai acestuia, iar dup aceasta se apeleaz acceai
procedur recursiv. Parcurgerea n lime i cea n lrgime sunt ambele
proceduri recursive.
La parcurgerea n lime se exploreaz mai nti rdcina, apoi
recursiv, fiecare fiu al ei. Parcurgerea n lime nseamn parcurgerea
rdcinii, apoi a fiilor acesteia, apoi a fiilor fiilor .a.m.d. pe toate nivelele.
2.
Pentru construirea unei reele interne de comunicaie ntre seciile
unei ntreprinderi s-a ntocmit un proiect n care au fost trecute toate
legturile ce se pot realiza ntre seciile ntreprinderii. n vederea
definitivrii proiectului i ntocmirii necesarului de materiale etc., se cere
s se determine un sistem de legturi ce trebuie construit, astfel nct
orice secie s fie racordat la aceast reea de comunicaie, iar
cheltuielile de construcie s fie minime.
Problema e una clasic de teoria grafurilor i se reduce la determinarea
unui arbore parial de cost minim al unui graf cu n noduri, dat prin matricea
costurilor C, unde C[i][j]= (infinit,o valoare foarte mare), cnd i i j nu
sunt noduri vecine n graf. Problema se poate rezolva fie cu algoritmul lui Prim,
fie cu cel al lui Kruskal.
n algoritmul lui Prim se folosete un vector Vecin. n fiecare pas al
algoritmului, Vecin[i]=0 dac i este n arborele parial deja construit,
respectiv Vecin[i]=k, k fiind vrful cu proprietatea c (i,k) este muchia de
cost minim printre toate muchiile cu o extremitate i, n afara arborelui, i o alta
n arborele deja construit. Astfel, se folosete metoda greedy.
#include <stdio.h>
#include <conio.h>
#define max 10
#define infinit 1000;

129

void main()
{
// nodurile sunt numerotate de la 1 la n !
int C[1+max][1+max];
int n,i,j,k,pas, Cost=0, min;
int Vecin[1+max];
clrscr(); printf("Algoritmul lui Prim\n");
printf("Dati n: "); scanf("%d",&n);
for (i=1; i<=n-1; i++)
{
for (j=i+1; j<=n; j++)
{
printf("C[%d,%d]=",i,j); scanf("%d",&C[i][j]);
if (C[i][j]==0) C[i][j]=infinit;
C[j][i]=C[i][j];
}
C[i][i]=0;
}
for (i=1; i<=n; i++) Vecin[i]=1; Vecin[1]=0;
for (pas=2; pas<=n; pas++)
{
min=infinit;
for (i=1; i<=n; i++)
if (Vecin[i]!=0)
if (C[i][Vecin[i]]<min)
{
min=C[i][Vecin[i]];
k=i;
}
printf("%d--%d\n",k,Vecin[k]);
Cost=Cost+C[k][Vecin[k]];
Vecin[k]=0;
for (i=1; i<=n; i++)
if (Vecin[i]!=0)
if (C[i][Vecin[i]]>C[i][k]) Vecin[i]=k;
}
printf("Cost = %d",Cost);
getch();
}

3.
S se determine arborele parial de cost minim al unui graf cu n
varfuri dat prin muchiile si costurile ataate lor, folosind algoritmul lui
Kruskal.
n implementarea algoritmului lui Kruskal se foloseste tot metoda
greedy. Mai nti se alege muchia de cost minim, apoi se adaug, n mod
repetat (de n-1 ori) muchia de cost minim printre cele nealese nc i cu
proprietatea c adugarea ei nu duce la formarea unui ciclu n arborele deja
creat.
Pentru a soluiona problema apariiei unui eventual ciclu prin
adugarea unei muchii, pentru fiecare nod vom memora nodul su tat, adic
130

rdcina arborelui din care face parte respectivul nod, folosind un vector Tata.
Se va pleca cu n arbori, fiecare format din cte un nod, care este i rdcina
sa: Tata[i]=-1 la nceput, dar pe parcurs:
Tata[i]=-numrul de noduri din arborele respectiv.
n momentul n care o muchie i=(u,v) devine candidat (muchiile se
iau n ordinea cresctoare a costurilor sale, de la citirea lor!), se verific crui
arbore aparin u i v, fie acetia arb1 i arb2. Dac arb1 i arb2 sunt identici,
nseamn c se formeaz ciclu, dar dac nu, se adaug aceast muchie i
apoi se reunesc cei doi arbori, legndu-l pe cel mai mic la cel mai mare.
#include <stdio.h>
#include <conio.h>
#define max 10
#define infinit 1000;
int Muchie[max+1][3]; int m,n,i,Cost=0;
int arb1, arb2; int Tata[max+1];
int Componenta(int v)
{
while (Tata[v]>0) v=Tata[v];
return v;
}
void Reuneste(int a, int b)
{
int suma=Tata[a]+Tata[b];
if (Tata[a]<Tata[b])
{
Tata[a]=suma; Tata[b]=a;
}
else
{
Tata[b]=suma; Tata[a]=b;
}
}
void main()
{
clrscr(); printf("Algoritmul lui Kruskal\n");
printf("Dati nr. de noduri: "); scanf("%d",&n);
printf("Dati nr. de muchii: "); scanf("%d",&m);
printf("Dati muchiile in ordine crescatoare a costurilor\n");
for (i=1; i<=m; i++)
{
printf("Muchia nr. %d:\n",i);
printf("prima extremitate ="); scanf("%d",&Muchie[i][1]);
printf("a doua extermitate="); scanf("%d",&Muchie[i][2]);
printf("costul muchiei
="); scanf("%d",&Muchie[i][0]);
}
for (i=1; i<=n; i++) Tata[i]=-1;
Tata[1]=0;
for (i=1; i<=m; i++)
{
arb1=Componenta(Muchie[i][1]);
arb2=Componenta(Muchie[i][2]);
if (arb1!=arb2)
{
131

Reuneste(arb1,arb2);
Cost+=Muchie[i][0];
printf("%d--%d\n",Muchie[i][1],Muchie[i][2]);

}
}
printf("Cost=%d\n",Cost); getch();

Propunem cititorului s mbunteasc programul astfel nct s


permit introducerea muchiilor n orice ordine.

Probleme propuse
1.
2.
3.
4.

5.
6.
7.
8.
9.
10.
11.
12.
13.

Scriei proceduri iterative pentru parcurgerea grafurilor a) n lime, b) n


adncime.
Scriei o procedur recursiv pentru parcurgerea unui graf orientat n
adncime.
Dndu-se n numere pozitive d1, d2, ..., dn, astfel nct suma lor este
2n-2, s se construiasc un arbore cu n noduri, ale cror grade sunt
aceste n numere.
Secven grafic. Spunem c o secven de numere d1, d2, ..., dn, este
secven graafic dac exist un graf cu n noduri pentru care d1, d2, ...,
dn s fie gradele nodurilor sale. Dndu-se o secven de n numere, se
cere s se determine dac ea este o secven grafic sau nu.
Se d un graf prin matricea sa de adiacen. S se verifice dac este
sau nu conex.
Realizai colorarea unui graf cu n noduri folosind m culori, astfel nct
dou vrfuri vecine s aibe culori diferite.
S se afieze componentele conexe ale unui graf neorientat, dat prin
matricea sa de adiacen.
Pentru un grup de n persoane s se determine celebritatea, adic acea
persoan care este cunoscut de toat lumea, dar nu cunoate pe
nimeni (dac exist).
Se consider un graf neorientat. S se verifice dac el are sau nu un
circuit de lungime a) 3; b) 4.
S se verifice dac un graf orientat aciclic conine sau nu un drum
hamiltonian. Putei gsi un algoritm liniar?
S se gseasc, folosind un algoritm liniar, dac exist, un circuit ntr-un
graf conex care conine dou noduri date a i b, dar nu conine nodul c.
Scriei un program care s determine (dac exist) un nod al unui graf
conex prin dispariia cruia graful rmne conex. Se consider c o dat
cu dispariia nodului respectiv, dispar i arcele incidente lui.
Implementai algoritmul lui Prim pentru determinarea arborelui parial de
cost minim ntr-un graf, considernd graful dat sub forma listei muchiilor,
n ordinea descresctoare a costurilor acestora.

132

14.

15.
16.

Bariere. Un oricel se afl situat ntr-un nod al unei reele dreptughiulare


de dimensiune mn, avnd forma i numerotarea nodurilor conform
figurii (n care m=4, n=3):
Fiecare nod v al reelei are exact o barier pe o muchie vw,
1

10

11

12

care blocheaz trecerea oricelului de la v la w, dar i de la w la v.


(Pentru exemplul din figura anterioar, n nodul 2 avem o barier ctre
nodul 6, care mpiedic trecerea oricelului de la nodul 2 la nodul 6, dar
i de la nodul 6 la nodul 2.). oricelul trebuie s ajung la o bucic de
cacaval, situat ntr-un alt nod al reelei, parcurgnd reeaua pe drumul
de cost minim, respectnd urmtoarele reguli:
a) oricelul, aflat n nodul v, poate trece la nodul w, dac nu exist
nici o barier pe muchia vw; aceast trecere l cost 1$.
b) oricelul poate schimba poziia barierei din nodul curent, ceea ce
l cost tot 1$. Pentru exemplul din figura anterioar, oricelul
(presupus a fi iniial n nodul 2) poate ajunge n nodul 7, n mai multe
moduri, de exemplu: a) mut bariera din 2 (aeznd-o ctre nodul 1),
se deplaseaz apoi n nodul 6, apoi n 7 (costul: 3$); b) mut bariera
din 2 (aeznd-o ctre nodul 1), se deplaseaz apoi n nodul 6, apoi
n nodul 10, unde pune bariera ctre nodul 9, apoi se duce n 11,
pune bariera de aici ctre nodul 10 i, n sfrit, se deplaseaz n
nodul 7 (costul: 7$). Se cere s se determine un astfel de drum de
cost minim al oricelului ctre cascaval.
Scriei un algoritm liniar pentru a determina numrul celor mai scurte
drumuri (nu neaprat disjuncte) ntre dou vrfuri x i y dintr-un graf
orientat.
Se d o schem a transportului n comun dintr-un ora, care conine
staiile 1, 2, ..., n. Exist m linii ntre aceste staii i se tie c ntre oricare
dou staii exist legtur, eventual cu schimbarea mijlocului de
transport. Trebuie s determinai dac exist cel puin o linie direct prin
blocarea creia legtura (direct sau indirect) ntre cel puin dou staii
se ntrerupe. Dac astfel de linii exist, s se propun nfiinarea unui
numr ct mai mic de linii directe ntre staiile existente, astfel nct prin
blocarea unei singure linii directe, oricare ar fi aceasta, circulaia ntre
133

17.

18.
19.
20.

oricare dou staii s fie posibil; se alege soluia pentru care suma
ocolurilor pe traseele variant (msurate n numr de linii directe) s fie
ct mai mic.
Fie n persoane P1, ..., Pn, care doresc fiecare s transmit propria brf
celorlalte persoane. Numim "instruciune" o pereche (i,j) avnd
urmtorul efect: persoana Pi transmite persoanei Pj propria sa brf, dar
i eventualele brfe primite anterior prin instruciuni de la alte persoane.
Din pcate, anumite perechi de persoane, citite de la tastatur, se
dumnesc i nu comunic ntre ele. S se determine, dac este posibil,
o secven de instruciuni prin care fiecare persoan s cunoasc brfele
tuturor celorlalte persoane.
Scriei un program C care s implementeze algoritmul de ordonare cu
ansambluri (heap-sort).
a) Scriei o funcie de tergere a unui arbore binar
b) Scriei o funcie de duplicare a unui arbore binar.
Scriei o funcie iterativ de parcurgere n postordine a unui arbore binar.

134

Capitolul 7. Grafic n C/C++


y utilizarea mouse-ului n mod grafic y joc cu strategie ctigtoare y
y bioritmul y utilizarea fonturilor y

Probleme rezolvate
1.

Formarea imaginilor n lentilele convergente.


Ne propunem s realizm un program didactic pentru orele de fizic
(optic), care s evidenieze formarea imaginilor n lentilele convergente, n
oricare din cele dou cazuri: cnd obiectul se afl ntre lentil i distana
focal, respectiv dup distana focal. Modul de utilizare a programului este
simplu: se fixeaza mai inti abscisa lentilei (lentila), apoi se mic mouse-ul
pn se stabilete nalimea dorit a lentilei. Mouse-ul este cobort apoi forat
pe ax i se stabileste focarul din stnga al lentilei (abscisa sa este focar =
distana focal).
n sfrit se stabilete i abscisa obiectului i nlimea sa: (obiect, h1).
Se determin apoi distana x2 a imaginii fa de lentil, folosind legea lentilelor:

1/f = 1/x1-1/x2,

unde f este distana focal,


x1 este distana obiectului fa de lentil,
iar x2 este distana imaginii fa de lentil (chiar dac aceasta este real

(negativ) sau imaginar (pozitiv).


Pe masur ce se stabilete nlimea lentilei (h1), programul reprezint
grafic i imaginea format.

#include <graphics.h>
#include <dos.h>
#include <stdlib.h>
#include "mouse.h"
void OpenGraph()
{
int gd=0, gm; initgraph(&gd,&gm,"c:\\bc\\bgi");
}
int lentila, hl; int focar, f;
int obiect, x1, x2; int h1, h2;
void StabilesteLentila()
{
int b,x,y;
do {
MouseData(b,x,y); MouseMove(x,240);
} while (b!=1);
lentila=x;
delay(500); MouseHide(); setwritemode(1);
do {
MouseData(b,x,y); MouseMove(lentila,y);
hl=240-y; //
line(lentila,240-hl,lentila,240+hl);
135

MouseShow(); delay(50); MouseHide();


line(lentila,240-hl,lentila,240+hl);
} while (b!=1);
setwritemode(0);
line(x,240-hl,x,240+hl); line(x,240-hl,x-4,240-hl+4);
line(x,240-hl,x+4,240-hl+4); line(x,240+hl,x-4,240+hl-4);
line(x,240+hl,x+4,240+hl-4); MouseShow();

}
void StabilesteFocar()
{
int b,x,y;
do {
MouseData(b,x,y); MouseMove(x,240);
} while (b!=1);
focar=x; f=abs(lentila-focar); focar=lentila-f;
MouseHide(); circle(focar,240,2); circle(lentila+f,240,2);
MouseShow();
}
void StabilesteObiect()
{
int b,x,y;
do {
MouseData(b,x,y); MouseMove(x,240);
} while (b!=1);
obiect=x; x1=abs(lentila-obiect);
obiect=lentila-x1; delay(500);
MouseHide(); setwritemode(1);
do {
MouseData(b,x,y); MouseMove(obiect,y);
setcolor(14); line(obiect,240,obiect,y);
h1 = -y+240; x2 = f*x1/(x1-f);
h2 = h1*x2/x1; setcolor(13);
line(obiect,240-h1,lentila,240-h1);
line(lentila,240-h1,lentila+x2,240+h2);
line(obiect,240-h1,lentila+x2,240+h2);
setcolor(10);
line(lentila+x2,240+h2,lentila+x2,240);
MouseShow(); delay(50); MouseHide();
setcolor(14); line(obiect,240,obiect,y);
setcolor(13);
line(obiect,240-h1,lentila,240-h1);
line(lentila,240-h1,lentila+x2,240+h2);
line(obiect,240-h1,lentila+x2,240+h2);
setcolor(10);
line(lentila+x2,240+h2,lentila+x2,240);
} while (b!=1);
h1=-y+240; setwritemode(0);
line(obiect,240,obiect,240-h1); MouseShow();
}
void DeseneazaImaginea()
{
x2 = f*x1/(x1-f); h2 = h1*x2/x1;
MouseHide(); setcolor(13);
line(obiect,240-h1,lentila,240-h1);
line(lentila,240-h1,lentila+x2,240+h2);
136

line(obiect,240-h1,lentila+x2,240+h2);
setcolor(10); line(lentila+x2,240+h2,lentila+x2,240);
MouseShow();

}
void main()
{
int b,x,y;
OpenGraph(); MouseInit(); setcolor(11);
do {
sound(300); delay(100); nosound();
MouseHide();
cleardevice(); setcolor(15);
line(0,240,639,240); MouseShow(); delay(500);
StabilesteLentila(); delay(500);
StabilesteFocar(); delay(500);
StabilesteObiect(); DeseneazaImaginea();
sound(300); delay(100); nosound();
do { MouseData(b,x,y); } while (b==0);
if (b==2) { closegraph(); exit(1); }
} while (1);
}

Programul foloseste fiierul mouse.h pentru lucrul cu mouse-ul n


modul grafic. Acest fiier este descris n continuare. Observai asemnrile i
deosebirile fa de fiierul mouset.h descris ntr-un capitol anterior i care se
referea la utilizarea mouse-ului n modul text.
#include <dos.h>
void MOUSE(int &a1, int &a2, int &a3, int &a4)
{struct REGPACK regs;
regs.r_ax = a1; regs.r_bx = a2; regs.r_cx = a3; regs.r_dx = a4;
intr(0x33, &regs); a1 = regs.r_ax; a2 = regs.r_bx;
a3 = regs.r_cx; a4 = regs.r_dx;
}
void MouseInit(void)
{
int a=1,b,c,d; MOUSE(a,b,c,d);
}
void MouseHide(void)
{
int a,b,c,d; a=2; MOUSE(a,b,c,d);
}
void MouseShow(void)
{
int a=1,b,d,c; MOUSE(a,b,c,d);
}
void MouseData(int& but, int& x, int& y)
{
int a=3, b, c, d; MOUSE(a,b,c,d);
but=b; x=c; y=d;
}
void MouseMove(int x, int y)
{
int a=4, b, c=x, d=y; MOUSE(a,b,c,d);
137

2.

Un joc cu strategie ctigtoare

Jocul ptratelor alunectoare, pe care vi-l prezentm n continuare,


poate constitui o problem interesant de programare pentru orice elev.
Pe o tabl cu nn ptrele (n ntreg impar) sunt aezate, alternativ,
piese galbene i roii, lsnd ptrelul din mijlocul tablei neocupat (v. fig. A).
Cei doi juctori mut, alternativ, ortogonal, cte o pies proprie alturat
spaiului liber, n spaiul liber. Pierde juctorul care nu mai poate muta (deci
spaiul liber este nconjurat numai de piese ale adversarului, eventual i de
marginea tablei).

Figura A
Se poate arta uor c al doilea juctor are o strategie sigur de ctig.
Astfel, s acoperim tabla de joc cu dominouri (dreptunghiuri formate din dou
ptrele elementare), lsnd csua din mijloc neacoperit (v. fig. B). Vom
observa c primul juctor, dup prima mutare, va ocupa centrul i va elibera
unul din capetele unui domino.
Astfel, cel de al doilea juctor va putea s mute piesa din cellalt capt
al dominoului. Deci, n orice moment, cel de al doilea juctor poate muta.
Partida nu se poate termina remiz, deci primul juctor va pierde.
O metod general de aranjare a dominourilor, pe o tabl oarecare
nn, cu n impar, este prezentat n figura C: dominourile se aaz n spiral,
pornind din colul stnga-sus i ajungnd n centrul tablei.
Aceast aranjare a dominourilor pe tabl va determina un vector Opus,
cu semnificaia: Opus[i]=j dac ptrelul i este liber, atunci juctorul al
doilea va muta piesa din ptrelul j.
Ptrelele sunt numerotate de sus n jos, de la stnga la dreapta.
Astfel, csua de pe linia i i coloana j va avea numrul (n-1)*i+j. De
observat c i Opus[j]=i.
138

Figura B

Figura C
Programul urmtor implementeaz aceast strategie de joc pentru
calculator, care este ntotdeauna al doilea juctor i va ctiga ntotdeauna.
/* JoculPatratelorAlunecatoare */
#include <stdio.h>
#include <conio.h>
#include <graphics.h>
#include <stdlib.h>
#include <dos.h>
typedef unsigned char byte;
typedef unsigned int word;
byte Leg[26]={0,6,7,8,5,4,1,2,3,10,9,12,11,
0,15,14,21,22,19,18,25,16,17,24,23,20};
byte spatiu=0, lat=60, x0=110, y0=50;
byte is, js, Tabla[7][7];
void OpenGraph()
{
int gd=DETECT,gm; initgraph(&gd,&gm,"c:\\bc\\bgi");
}
byte CasutaLibera()
{
return (5*(is-1)+js);
139

}
void InitTabla()
{
byte i,j; is=3; js=3;
for (i=1; i<=5; i++)
for (j=1; j<=5; j++)
if ((i+j) % 2 != 0) Tabla[i][j]=LIGHTRED;
else Tabla[i][j]=YELLOW;
Tabla[is][js]=spatiu;
for (i=0; i<=6; i++)
{
Tabla[0][i]=YELLOW; Tabla[6][i]=YELLOW;
Tabla[i][0]=YELLOW; Tabla[i][6]=YELLOW;
}
}
void DesPiesa(int i, int j)
{
if ((i!=is) || (j!=js))
{
setcolor(WHITE);
rectangle(x0+lat*i, y0+lat*j, x0+lat*i+lat, y0+lat*j+lat);
setfillstyle(SOLID_FILL,Tabla[i][j]);
fillellipse(x0+lat*i+lat/2, y0+lat*j+lat/2,lat/4, lat/4);
}
else
{
setfillstyle(SOLID_FILL,BLACK);
bar(x0+lat*i, y0+lat*j, x0+lat*i+lat, y0+lat*j+lat);
setcolor(WHITE);
rectangle(x0+lat*i,y0+lat*j, x0+lat*i+lat, y0+lat*j+lat);
}
}
void DesTabla()
{
byte i,j; setfillstyle(SOLID_FILL,MAGENTA);
bar(x0+lat+4,y0+lat+4,x0+lat*6+4,y0+lat*6+4);
for (i=1; i<=5; i++)
for (j=1; j<=5; j++)
{
setfillstyle(SOLID_FILL,0);
bar(x0+lat*i,y0+lat*j,x0+lat*i+lat,y0+lat*j+lat);
DesPiesa(i,j);
}
}
void MutaCalc()
{
byte isv,jsv,cas; isv=is; jsv=js;
cas=Leg[CasutaLibera()];
is=(cas-1)/5+1; js=(cas-1)%5+1;
Tabla[is][js]=spatiu; DesPiesa(is,js);
Tabla[isv][jsv]=YELLOW; DesPiesa(isv,jsv);
}
void MutaOm()
{
140

int tasta, mut;


do {
tasta=getch(); if (tasta==0) tasta=getch();
mut=0;
switch (tasta) {
case 75: if (is<5)
if (Tabla[is+1][js]==LIGHTRED)
{
is++; mut=1;
Tabla[is][js]=spatiu; DesPiesa(is,js);
Tabla[is-1][js]=LIGHTRED; DesPiesa(is-1,js);
}
break;
case 77: if (is>1)
if (Tabla[is-1][js]==LIGHTRED)
{
is--; mut=1;
Tabla[is][js]=spatiu; DesPiesa(is,js);
Tabla[is+1][js]=LIGHTRED; DesPiesa(is+1,js);
}
break;
case 80: if (js>1)
if (Tabla[is][js-1]==LIGHTRED)
{
js--; mut=1;
Tabla[is][js]=spatiu; DesPiesa(is,js);
Tabla[is][js+1]=LIGHTRED; DesPiesa(is,js+1);
}
break;
case 72: if (js<5)
if (Tabla[is][js+1]==LIGHTRED)
{
js++; mut=1;
Tabla[is][js]=spatiu; DesPiesa(is,js);
Tabla[is][js-1]=LIGHTRED; DesPiesa(is,js-1);
}
break;
case 27: {
closegraph();
printf("Ati abandonat...");
exit(1);
}
}
if (!mut)
{ sound(200); delay(50); nosound();
}
} while (!mut);

}
int EsteGata()
{
return ((Tabla[is-1][js]==YELLOW) && (Tabla[is+1][js]==YELLOW)
&&(Tabla[is][js-1]==YELLOW) && Tabla[is][js+1]==YELLOW));
}
void Sunet()
{
141

byte i;
for (i=1; i<=25; i++) { sound(300+20*i); delay(30); }
nosound();

}
void main()
{
OpenGraph(); setbkcolor(BLUE); setfillstyle(9,LIGHTGREEN);
bar(30,65,getmaxx()-30,getmaxy()-30);
settextstyle(DEFAULT_FONT,HORIZ_DIR,4);
settextjustify(CENTER_TEXT,CENTER_TEXT);
setcolor(CYAN); outtextxy(320,35,"ALUNECATOARELE");
InitTabla(); DesTabla();
do {
MutaOm(); delay(200); MutaCalc();
} while (!EsteGata());
Sunet(); getch(); closegraph();
printf("Iarasi ati pierdut ...");
}

3.

Trasarea grafic a bioritmului unei persoane

Specialiti din diferite domenii ale tiinelor care au ca obiect de studiu


omul, printre care i medicina, au ajuns la concluzia c puterea fizic, psihic
i intelectual a oricrei persoane evolueaz funcional sub forma unor
sinusoide, ale cror perioade sunt de 23, 28 i 33 de zile, iar nceputul
sinusoidelor depind de data naterii; pentru o persoana nscut pe 1 ianuarie
n anul 1, se consider c bioritmul su pornete cu cele trei curbe de la 0
(medie), n sens cresctor.
Pornind de la ideile de mai sus, prezentm n continuare un simplu
program de trasare grafic a bioritmului pentru o anumit persoan.
Programul, scris n Borland C (dar se poate adapta uor n orice versiune de
C, care are o interfa grafic pentru programare), cere utilizatorului s
introduc data sa de natere, numele su, precum i data de referin.
Bioritmul va fi trasat pe o perioad de 32 de zile, ncepnd cu data de referin
stabilit.
// program bioritm
#include <stdio.h>
#include <conio.h>
#include <graphics.h>
#include <math.h>
#include <stdlib.h>
#include <dos.h>
#define pi 3.1415926
void OpenGraph()
{
int gd=0, gm; initgraph(&gd,&gm,"C:\\BC\\BGI");
}
int NrZile(int d, int m, int y)
{
int n;
const int nn[12]={0,31,59,90,120,151,181,212,243,273,304,334};
n=nn[m-1]; n=n+365*y+y/4 + d + 1; n=n-y/100 + y/400;
142

if (!((y%4!=0)||(y%400==0)||(y%100==0)||(m>2))) n--;
return n;
}
void Inputt(char *sir, int *nr)
{
printf("%s",sir); scanf("%d",nr);
}
void main()
{
int p[3] = {23,28,33}; int q[3];
int m1,d1,y1,m2,d2,y2,i,n,nz,se,sen; float ur,sr;
char nume[40];
clrscr(); fflush(stdin);
printf("* BIORITM *\n\n");
printf("Dati numele : ");
gets(nume);
printf("Data nasterii:\n");
Inputt("ziua : ",&d1);
Inputt("luna : ",&m1);
Inputt("anul : ",&y1);
printf("Data de referinta :\n");
Inputt("ziua : ",&d2);
Inputt("luna : ",&m2);
Inputt("anul : ",&y2);
nz=NrZile(d1,m1,y1); nz=NrZile(d2,m2,y2)-nz;
OpenGraph();
outtextxy(100,20,"Bioritm pentru: "); outtextxy(250,20,nume);
for (i=0; i<3; i++)
{
setcolor(9+i); line(10,405+18*i,100,405+18*i);
if (i==0) outtextxy(100,400+18*i,"fizic");
else if (i==1) outtextxy(100,400+18*i,"psihic");
else outtextxy(100,400+18*i,"intelect");
q[i]=nz % p[i]; ur=2*pi*q[i]/p[i];
sr=sin(ur); se=(sr+1)*80;
for (n=nz; n<=nz+31; n++)
{
q[i] = n % p[i]; ur = 2*pi*q[i]/p[i];
sr=sin(ur); sen=(sr+1)*160;
line(24*(n-nz-1),480-(100+se),24*(n-nz),480-(100+sen));
se=sen; delay(30);
}
}
setcolor(7); char nr_zi[2];
for (i=0; i<=31; i++)
{
itoa(i, nr_zi, 10); line(20*i,50,20*i,390);
outtextxy(20*i+2,55,nr_zi); delay(30);
}
line(getmaxx(),50,getmaxx(),390); setcolor(15);
line(0,220,getmaxx(),220); rectangle(0,50,getmaxx(),390);
getch();
closegraph();
}
143

Funcia NrZile determin numrul de zile scurse de la 1 ianuarie anul 1,


pn la o anumit dat. Astfel se poate determina numrul de zile ntre data de
natere a persoanei i data de referin.
Dup cum am spus, programul poate fi rescris n orice alt
implementare de C i pe orice alt tip de calculator, ns de fiecare dat trebuie
s se in cont de rezoluia ecranului i de orientarea axei Oy. n cazul nostru,
s-a utilizat Borland C++, rezoluia a fost de 640480 pixeli, iar orientarea axei
Oy a fost de sus n jos. Dei calculatorul nu greete, e posibil ca oamenii de
tiin care au inventat bioritmul s fi greit de la bun nceput, aa nct
ramne la latitudinea dumneavoastr dac vei lua n considerare rezultatele
furnizate de acest program sau nu, tratnd programul ca un simplu
amuzament.
4.

Folosirea fiierelor CHR ale firmei Borland International

Formatul fonturilor CHR


Programatorul de grafic dornic s realizeze un afiaj pe oblic,
folosind seturile de caractere (fonturile) din fiierele CHR va trebui s
cunoasc, nainte de toate, ideea care st la baza acestor fonturi, precum i
formatul fiierelor corespunztoare.
Fonturile din fiierele CHR (numite i ncondeiate (stroke fonts, n
englez)) definesc caracterele ca o secven de linii (trsturi), n opoziie cu
fonturile de tip bitmap, care definesc caracterele ca o matrice de puncte.
Avantajul fonturilor ncondeiate este acela c ele pot fi scalate la mrimi
arbitrare i s-i menin rezoluia lor. Fonturile de tip bitmap sunt fcute
pentru o anumit mrime a punctului i nu pot fi scalate prea bine. De
exemplu, dac avei un font de tip bitmap pentru o matrice de 72 puncte pe
inch (DPI) i mrim de patru ori n nlime i n lime punctele pentru a utiliza
o imprimant laser cu 300 DPI, atunci pot aprea margini prea mari (largi) n
fontul 72 DPI.
Pe de alt parte, fonturile de tip stroke, nu sunt convertite n puncte,
pn cnd rezoluia perifericului de ieire nu este cunoscut. Astfel, dac vrei
s scriei cu fonturi de tip stroke pe o imprimant laser cu 300 DPI, punctele
care traseaz liniile caracterelor vor fi tiprite la 300 DPI.
Acestea, fiind spuse, s trecem la prezentarea structurii unui fiier de
tip CHR, exemplificnd pe fiierul TRIP.CHR, care este acelai pentru toate
mediile de programare Borland.
; offset 0h este un header specific firmei Borland:
HeaderSize
de ex. 080h
DataSize
de ex. (mrimea fiierului) ; lungimea fi. CHR
descr
de ex. "Triplex font"
; descriere
fname
de ex. "TRIP"
; numele fiierului
MajorVersion de ex. 1
; versiunea fontului
MinorVersion de ex. 0
; subversiunea
db
'PK',8,8
144

db
db
db
db
db
db
dw
db
dw
db
db
db

'BGI ',descr,' V'


MajorVersion+'0'
(MinorVersion / 10)+'0',(MinorVersion mod 10)+'0'
' - 19 October 1987',0DH,0AH
'Copyright (c) 1987 Borland International', 0dh,0ah
; (c)
0,1ah
; null & ctrl-Z = end
HeaderSize
; mrimea header-ului
fname
; numele fontului
DataSize
; mrimea fi. font
MajorVersion,MinorVersion
; numrul de versiune
1,0
; nre. de versiune min.
(HeaderSize - $) DUP (0)
; tampon
La offset-ul 80h ncep datele pentru fiier, dup cum urmeaz:

;
;
;
;
;
;
;
;
;
;
;
;
;

80h '+'
81h-82h
83h
84h
85h-86h
87h
88h
89h
90h
91h-95h
96h
96h+2n
96h+3n

indicatoare pentru tipul fiierului stroke


numrul de caractere n fiierul font (n)
nedefinit
valoarea ASCII a primului caracter din fiier
offset pt. definiiile stroke (8+3n)
scan flag (normal 0)
distana de la origine la vrful literei mari
distana de la origine la linia de baz
distana de la origine la cea mai cobort linie
nedefinit
offset-uri pentru definiii individuale de caractere
tabela grosimilor (un word pentru fiecare caracter)
startul definiiilor caracter

Definiiile individuale de caractere consist dintr-un numr variabil de


cuvinte (word) (16 bits), descriind operaia necesar n desenarea caracterului.
Fiecare word consist dintr-o perche de coordonate (x,y) i dou coduri de
operaii pe doi bii. Cuvintele sunt codificate dup cum urmeaz:
Byte 1
Byte 2

7 6 5 4 3 2 1 0 bit #
op1 <coord. X pe 7 biti cu semn>
7 6 5 4 3 2 1 0 bit #
op2 <coord. Y pe 7 biti cu semn>

Codurile de operaii sunt:


op1=0 op2=0 Sfritul definiiei de caracter.
op1=1 op2=0 Mut pointerul grafic n punctul de coordonate (x,y).
op1=1 op2=1 Traseaz o linie de la punctul curent la punctul de
coordonate (x,y).
145

/*

Descrierea n limbajul C a structurii unui font CHR este dat mai jos:
FONT.H - informaiile din header-ul unui fiier de fonturi CHR
Copyright (c) 1988,1989 Borland International

*/

#define Prefix_Size
0x80
#define Major_Version
1
#define Minor_Version
0
#define SIGNATURE +
enum OP_CODES {
END_OF_CHAR = 0, DO_SCAN
= 1, MOVE = 2, DRAW = 3
};
typedef struct {
char sig;
/* SIGNATURE byte */
int nrchrs;
/* numarul de caractere in fisier */
char mystery;
/* nedefinit inca */
char first;
/* primul caracter din fisier */
int cdefs;
/* offset la definitiile de caractere */
char scan_flag; /* True daca setul de caractere este scanabil
*/
char org_to_cap;/* inaltimea de la origine la vrful literei
mari */
char org_to_base;/* inaltimea de la origine la linia de baza
*/
char org_to_dec; /* inaltimea de la origine la linia
inferioara */
char fntname[4]; /* patru caractere pentru numele fontului */
char unused;
/* nedefinit inca */
} HEADER;
typedef struct {
char opcode;
/* Byte pentru codul de operatie */
int x;
/* Offset relativ pe directia x */
int y;
/* Offset relativ pe directia y */
} STROKE;
typedef struct {
unsigned int header_size; /* Versiunea 2.0 a formatului de
header */
unsigned char font_name[4]; /* Numele intern al fontului */
unsigned int font_size; /* Marimea in bytes a fisierului */
unsigned char font_major, font_minor; /* Info. de versiune a
driverului */
unsigned char min_major, min_minor; /* Informatii de revizie
pentru BGI */
} FHEADER;

Rutine speciale de afiare. Pornind de la informaiile prezentate


anterior, se pot dezvolta proceduri de ncrcare a fonturilor i de afiaj n orice
direcie.
// Program pentru afisari speciale
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <graphics.h>
146

#include <conio.h>
#include <math.h>
#include <string.h>
#include "font.h"
FILE *ffile;
char
*Font;
char
Prefix[Prefix_Size];
HEADER
Header;
int
Offset[256];
char
Char_Width[256];
int POZX = 25, POZY = 25, i;
int decode( unsigned int *iptr, int *x, int *y );
/*
Aceasta functie decodifica formatul fisierului,
punind-o intr-o structura interna mai convenabila
*/
int unpack( char *buf, int index, STROKE **neww )
{
unsigned int *pb;
STROKE *po;
int
num_ops = 0;
int
jx, jy, opcode, i, opc;
pb = (unsigned int *)(buf + index);
while( FOREVER ){
num_ops += 1;
opcode = decode( pb++, &jx, &jy );
if( opcode == END_OF_CHAR ) break;
}
po = (*neww = (STROKE*)calloc( num_ops, sizeof(STROKE) ));
if( !po )exit(100)
}
pb = (unsigned int *)(buf + index);
for( i=0 ; i<num_ops ; ++i ){
opc = decode(pb++, &po->x, &po->y);
po->opcode = opc; po++;
}
return( num_ops );
}

Funcia urmtoare decodific un singur cuvnt din fiier punndu-l


ntr-o structur intern mai convenabil, de tip stroke:

int decode( unsigned int *iptr, int *x, int *y )


{
struct DECODE {
signed
int xoff : 7;
unsigned int flag1 : 1;
signed
int yoff : 7;
unsigned int flag2 : 1;
} cword;
cword = *(struct DECODE *)iptr;
*x = cword.xoff;
*y = cword.yoff;
return( (cword.flag1 << 1) + cword.flag2 );
}
Pentru afiarea unui caracter litera, la poziia de coordonate (x1,y1)
fa de punctul (x0,y0), rotit sub unghiul alfa se poate folosi funcia:

147

void WriteChar(char litera, float alfa, int x0, int y0, int xl,
int yl)
{
STROKE *sptr;
int j, i = litera;
int xx, yy, xxr, yyr;
int Caracter = unpack( Font, Offset[i], &sptr );
y0 = getmaxy() - y0; yl = getmaxy() - yl;
for( j=0 ; j<Caracter ; ++j, ++sptr ){
xx = xl+sptr->x; yy = yl+sptr->y;
xxr = (xx-x0)*cos(alfa) - (yy-y0)*sin(alfa) + x0;
yyr = (xx-x0)*sin(alfa) + (yy-y0)*cos(alfa) + y0;
if (sptr->opcode == 2) moveto(xxr, getmaxy()-yyr);
if (sptr->opcode == 3) lineto(xxr, getmaxy()-yyr);
}
}
Apelnd de mai multe ori funcia WriteChar obinem funcia urmtoare,
ce permite afiarea unui ir de caractere cuvint sub unghiul alfa, n punctul
de coordonate (x1,y1), rotit fa de punctul de coordonate (x0,y0):
void WriteStr(char * cuvint, float alfa, int x0, int y0, int xl,
int yl)
{
POZX = xl; POZY = yl;
for (int i=0; i < strlen(cuvint); i++)
{
WriteChar(cuvint[i], alfa, x0, y0, POZX, POZY);
POZX += Char_Width[cuvint[i]] * cos(alfa);
POZY -= Char_Width[cuvint[i]] * sin(alfa);
x0
+= Char_Width[cuvint[i]] * cos(alfa);
y0
-= Char_Width[cuvint[i]] * sin(alfa);
}
}

Funcia de mai jos scrie un ir de caractere pe un cerc de raz i


coordonate ale centrului date:
void CircleStr(char * cuvint, int x0, int y0, int raza)
{
float alfa; int l = strlen(cuvint); int xx, yy;
y0 = getmaxy() - y0;
for (int i=0; i<l; i++)
{
alfa = -2*M_PI*i/l;
xx = x0+raza * cos(alfa);
yy = getmaxy()-y0+raza * sin(alfa);
WriteChar(cuvint[i], M_PI/2-alfa, xx, yy, xx, yy);
}
}

Se pot scrie cuvinte sub forma unei sinusoide, folosind funcia:

void SinWrite(char * cuvint, int x, int y, int raza)


{
float alfa; int l = strlen(cuvint);
for (int i=0; i<l; i++)
{
alfa = -4*M_PI*i/l;
y = y + raza * sin(alfa);
148

WriteChar(cuvint[i], 0, x, y, x, y);
x += Char_Width[cuvint[i]];

Iat un exemplu de utilizare a funciilor descrise mai sus:

void main()
{
long length, current;
char *cptr;
STROKE *sptr;
ffile = fopen( "scri.chr", "rb" );
if( NULL == ffile ){
exit( 1 );
}
fread(Prefix, Prefix_Size, 1, ffile);
cptr = Prefix;
while( 0x1a != *cptr ) ++cptr;
*cptr = '\0';
fread(&Header, sizeof(HEADER), 1, ffile);
fread( &Offset[Header.first], Header.nchrs,
sizeof(int), ffile );
fread( &Char_Width[Header.first], Header.nchrs,
sizeof(char), ffile );
current = ftell( ffile );
fseek( ffile, 0, SEEK_END );
length = ftell( ffile );
fseek( ffile, current, SEEK_SET );
Font = (char *) malloc( (int) length );
if( NULL == Font )
{
fprintf( stderr, "Memorie insuficienta.\n\n" );
exit( 1 );
}
fread( Font, (int)length, 1 , ffile );
fclose(ffile);
int gd,gm;
gd = 0; initgraph(&gd,&gm,"c:\\bc\\bgi");
rectangle(0,0,getmaxx(),getmaxy());
for (i=-3; i<3; i++)
{
setcolor(i);
if (!i) setcolor(CYAN);
WriteStr("
Try the",-M_PI*i/3,320,200,320,200);
}
setcolor(WHITE);
CircleStr("HICS ! * BEST GRAP",320,200,80);
setcolor(LIGHTCYAN);
SinWrite("Author Bogdan Patrut, tel. 034/123175",10,470,10);
getch(); closegraph();
}

Probleme propuse

149

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.

12.
13.
14.
15.
16.

17.
18.
19.

Scriei un program (care utilizeaz mouse-ul) pentru simularea grafic a


formrii imaginilor n lentilele divergente.
Scriei un program (care utilizeaz mouse-ul) pentru simularea grafic a
formrii imaginilor n oglinzile convergente.
Scriei un program (care utilizeaz mouse-ul) pentru simularea grafic a
formrii imaginilor n oglinzile divergente.
Realizai o implementare a jocului ptratelor alunectoare n care
numrul (impar) n de ptrate ale tablei s fie dat de la tastatur,
genernd, astfel, aezarea imaginar a pieselor de domino n spiral.
Scriei un program care s deseneze n dreptunghiuri concentrice, n
mijlocul ecranului.

Scrii o procedura care s deseneze un poligon regulat cu n laturi.

Scriei o procedur care s deseneze o stea cu n coluri, folosind dou


poligoane regulate cu n laturi, imaginare, concentrice i de "raze"
inegale.
Scriei un program care s rezolve ecuaia de gradul II. Intrrile i ieirile
se vor face n mod grafic.
Scriei funcii pentru introducerea, respectiv afiarea de date numerice i
alfanumerice n mod grafic.
Rescriei aplicaiile complexe din capitulul 5, astfel nct intrarile i ieirile
de la/pe ecran s se realizeze n mod grafic.
Dintr-un fiier cu tip se citesc numele unor elevi, precum i notele
acestora la 14 discipline. S se realizeze un program n modul grafic,
care s permit urmtoarele reprezentri grafice:

pentru fiecare elev, histograma notelor sale;

pentru toi elevii, histograma mediilor lor.


Scriei un program care s reprezinte grafic, pe tot ecranul, funcia
sin(x), pentru x variind ntre - i .
Realizai un program care s permit reprezentarea bioritmului a dou
persoane n dou zone de ecran, care s poat fi redimensionate i
mutate cu ajutorul mouse-ului.
Aceeai problem ca mai nainte, cu posibilitatea de a folosi tastatura n
loc de mouse.
Realizai un program / o funcie pentru reprezentarea grafic a unei
funcii.
Scriei un interpretor pentru expresii de funcii, care s recunoasc
simbolul x, numere, operatorii +, -, * i / i funciile elementare sin,
cos, ln, exp, sqrt etc.. Astfel, dac o expresie este corect, s
reprezinte grafic funcia respectiv pe un interval real precizat.
S se realizeze un program care s reprezinte grafic patru funcii n patru
zone diferite ale ecranului.
Aceeai problem ca i la problema anterioar, dar cele patru zone s
poat fi mutate cu ajutorul mouse-ului.
Realizai un program de desenare de tip PaintBrush. Se vor scrie
proceduri pentru selectarea de culori, pentru trasarea de elipse, linii i
dreptunghiuri. De asemenea, se vor scrie proceduri pentru salvarea i
150

restaurarea imaginilor. Desenarea figurilor geometrice, precum i


accesarea opiunilor din meniu se va realiza folosind mouse-ul.
20.

Realizai funcii recursive pentru a desena urmtoarea figur "recursiv"

21.

:
Aceeai problem pentru fiecare din cele dou figuri de mai jos:

151

22.

Folosind mouse-ul i funcii recursive, realizai un program care, prin


acionarea celor dou butoane de mouse s amplaseze diferite figuri
recursive pe ecran, ca n figura urmtoare:

23.

Scriei o funcie recursiv care s umple o zon de ecran mrginit de o


anumit curb colorat.
Scriei un program care s traseze un cerc, folosind ecuaiile sale
parametrice.
Scriei un algoritm pentru trasarea unui cerc, care s utilizeze doar
adunri i scderi.
Aceeai problem pentru trasarea unei elipse.
Scriei un algoritm pentru trasarea unui segment de dreapt ntre dou
puncte ale cror coordonate ecran se cunosc.
Realizai jocul "turnurilor din hanoi" cu animaie n mod grafic.
Realizai o implementare grafic a problemei damelor.
Realizai o implementare grafic a problemei colorrii grafurilor.

24.
25.
26.
27.
28.
29.
30.

152

Capitolul 8.
Programare orientat pe obiecte n Borland C++
y definirea claselor y constructori i destructori y metode y
y funcii virtuale (pure) y motenire y

Probleme rezolvate
1.

Un joc de animaie, orientat pe obiecte

Orientat obiect, programul pe care l prezentm i l comentm n


continuare realizeaz o animaie a unor obiecte grafice de diferite tipuri i
forme. Este vorba despre un joc n care trebuie s prindei mai muli fluturi
(numrul lor este introdus de la tastatur, la nceputul jocului), cu ajutorul unui
omule care are ntr-o mn o plas de prins fluturi. Totul se desfoar ntr-un
cadru natural, reprezentat de un soare care strlucete i doi nori care se
deplaseaz pe cer. Fluturii zboar aleator, iar omul care i prinde este deplasat
de ctre juctor. Exist dou variante ale jocului, una n care deplasarea se
face cu ajutorul tastelor de cursor i alta n care deplasarea se realizeaz cu
ajutorul mouse-ului.
Ideea de baz n realizarea programului este relativ simpl. Se
definete o clas abstract Obiect, din care apoi se deriveaz clasele
corespunztoare tuturor obiectelor grafice care apar pe ecran. Clasa abstract
este caracterizat de dou cmpuri care reprezint coordonatele obiectului,
plus nc dou reprezentnd deplasrile pe orizontal i pe vertical. De
asemenea exist trei metode pure, implementate la nivelul claselor derivate,
concrete: una pentru deplasarea unui obiect, care apeleaz altele dou: una
care terge obiectul (din poziia veche) i alta care l redeseneaz (n poziia
nou).
O imagine din timpul desfurrii acestui joc i listingul comentat al
programului v vor documenta mai bine n legtur cu algoritmii i bazele de
date folosite.
// Program C++ pentru prezentarea animatiei unor obiecte grafice
// de tipuri (clase) diferite, derivate dintr-o clasa abstracta
// si cu rescrierea metodelor virtuale pure.
#include <iostream.h>
#include <graphics.h>
#include <stdlib.h>
#include <conio.h>
// definirea clasei abstracte Obiect
class Obiect {
// x si y = coordonatele obiectului
// dx si dy = deplasarile (-1,0,1)

153

// aceste 4 cimpuri vor fi recunoscute de urmasi (clasele


derivate)
protected:
int x, y, dx, dy;
// metode publice
public:
// constructori
Obiect() { };
Obiect(int x0, int y0);
// metode de desenare, mutare si stergere a obiectelor
// sint pure si virtuale, deci vor fi definite in cadrul
claselor derivate
virtual void Deseneaza()=0;
virtual void Muta()=0;
virtual void Sterge()=0;
};
// clasa Soare este derivata din clasa Obiect, in mod public
class Soare: public Obiect {
private:
// un soare se poate afla in doua ipostaze,
// in functie de cum sint dispuse razele
int ipostaza;
public:
// constructorul clasei Soare va primi coordonatele initiale
// precum si ipostaza initiala a soarelui
Soare(int x0, int y0, int ipostaza0);
// cele trei metode vor fi redefinite
void Deseneaza();
void Muta();
void Sterge();
};
// derivare similara si in cazul clasei Nor
class Nor: public Obiect {
public:
Nor(int x0, int y0);
void Deseneaza();
void Muta();
void Sterge();
};
// ... si in cazul clasei Fluture
class Fluture: public Obiect {
public:
// un fluture poate fi vizibil (cind zboara)
// sau invizibil, dupa ce a fost capturat
int vizibil;
Fluture(); // constructorul, fara parametri
int GetX(); // functie ce returneaza coordonata x a
fluturelui
int GetY(); // returneaza coordonata y
void Deseneaza();
void Muta();
void Sterge();
} F[10]; // am declarat un vector F de maxim 10 fluturi
int NrInitFluturi;
154

// numarul initial de fluturi, care va fi dat de la tastatura


int NrFluturi;
// numarul curent de fluturi,
// care scade de fiecare data cind se prinde un fluture
// clasa Om, derivata public din clasa Obiect
class Om: public Obiect {
public:
Om(int x0, int y0);
int GetPX(); // coordonata x a paletei de prins fluturi
int GetPY(); // coordonata y a paletei
void Deseneaza();
void Muta();
void Sterge();
};
// clasa abstracta Obiect: definire constructor
Obiect::Obiect(int x0, int y0)
{ x=x0; y=y0; }
// clasa Soare: definire metode
// constructorul
Soare::Soare(int x0, int y0, int ipostaza0)
{
x=x0; y=y0;
ipostaza=ipostaza0;
}
// functia de desenare
void Soare::Deseneaza()
{
circle(x,y,20); // un cerc de raza 20 pixeli
// daca se afla in ipostaza 1, atunci se deseneaza
// 4 raze, verticale si orizontale
if (ipostaza==1)
{
line(x-40,y,x-20,y);
line(x+20,y,x+40,y);
line(x,y-40,x,y-20);
line(x,y+20,x,y+40);
}
else // altfel, in ipostaza 2, se deseneaza raze oblice
{
line(x-14,y-14,x-34,y-34);
line(x-14,y+14,x-34,y+34);
line(x+14,y-14,x+34,y-34);
line(x+14,y+14,x+34,y+34);
}
}
// stergerea soarelui - este, de fapt, o redesenare cu negru
void Soare::Sterge()
{
setcolor(BLACK);
Deseneaza();
setcolor(WHITE);
}
// functia de mutare a soarelui;
155

// nu este o mutare propriu-zisa, ci doar o reafisare in noua


ipostaza
void Soare::Muta()
{
Sterge();
ipostaza=3-ipostaza; // schimbarea ipostazei 1 <-> 2
Deseneaza();
}
// constructorul clasei Nor; deplasarea initiala este spre
stinga
Nor::Nor(int x0, int y0)
{ x=x0; y=y0; dx=-1; }
// desenarea unui nor = o elipsa cu centrul in (x,y)
void Nor::Deseneaza()
{
ellipse(x,y,0,360,70,30);
}
// functia de stergere a unui obiect din clasa Nor
void Nor::Sterge()
{
setcolor(BLACK); Deseneaza(); setcolor(WHITE);
}
// functia de mutare a unui obiect din clasa Nor
// daca obiectul ajunge cu centrul (x,y) in capete,
// se schimba sensul deplasarii pe orizontala
void Nor::Muta()
{
Sterge();
x += 10*dx;
if (x < 0) { x = 0; dx = -dx; }
if (x > getmaxx()) { x = getmaxx(); dx = -dx; }
Deseneaza();
}
// constructorul clasei Fluture initializeaza automat x si y,
// intr-o zona dreptunghiulara a ecranului;
// dx si dy se initializeaza cu una din valorile -1,0 si 1
// la inceput fluturele este vizibil
Fluture::Fluture()
{
x = 300 + random(200); y = 300 + random(100);
dx = random(3)-1; dy = random(3)-1; vizibil = 1;
}
// metoda de desenare a unui obiect din clasa Fluture
void Fluture::Deseneaza()
{
// aripa din stinga
line(x,y,x-5,y-5); line(x,y,x-5,y+5);
line(x-5,y-5,x-5,y+5);
// aripa din dreapta
line(x,y,x+5,y-5); line(x,y,x+5,y+5);
line(x+5,y-5,x+5,y+5);
// corpul
line(x,y-10,x,y+7);
// capul
circle(x,y-10,2);
// antenele
156

line(x,y-10,x-3,y-13); line(x,y-10,x+3,y-13);
}
// metoda de stergere a unui Fluture
void Fluture::Sterge()
{
setcolor(BLACK); Deseneaza(); setcolor(WHITE);
}
// mutarea unui Fluture se realizeaza doar daca el este vizibil
void Fluture::Muta()
{
if (vizibil)
{
Sterge();
// se genereaza noile deplasari
dx = random(3)-1; dy = random(3)-1;
// se actualizeaza coordonatele x si y
x += 10*dx; y += 10*dy;
// fluturele nu poate depasi o anumita zona dreptunghiulara
if (x < 0) x = 0;
if (y < 180) y = 180;
if (x > getmaxx()) x = getmaxx();
if (y > 380) y = 380;
Deseneaza();
}
}
// urmeaza functiile care returneaza coordonatele unui Fluture
int Fluture::GetX()
{ return x; }
int Fluture::GetY()
{ return y; }
// clasa Om: definire metode
// constructor
Om::Om(int x0, int y0)
{ x=x0; y=y0; }
// functie de desenare
void Om::Deseneaza()
{
circle(x,y,10); // cap
line(x,y+10,x,y+40); line(x-20,y+15,x+20,y+15);
line(x+20,y+15,x+20,y-15);
circle(x+20,y-25,10); // paleta
line(x,y+40,x-10,y+80); line(x,y+40,x+10,y+80);
}
// functiile care returneaza coordonatele paletei omului
int Om::GetPX()
{ return x+20; }
int Om::GetPY()
{ return y-25; }
// stergerea unui om, in vederea mutarii sale in alta parte
void Om::Sterge()
{
setcolor(BLACK); Deseneaza(); setcolor(WHITE);
}
// functie care stabileste daca fluturele F este prins
// de paleta omului
int PrindeFluture(Om O, Fluture F)
157

int eps = 7;
// precizia de prindere in paleta a fluturelui
return ((abs(F.GetX()-O.GetPX()) < eps) &&
(abs(F.GetY()-O.GetPY()) < eps) && (F.vizibil == 1));

}
// metoda care muta un obiect din clasa Om
void Om::Muta()
{
int tasta; // codul tastei apasata
int i;
// i = indice de fluture in vectorul F
int gasit;
// gasit = 1 daca s-a prins fluturele F[i] in paleta
dx = 0; dy = 0; // valori de deplasare a omului implicit 0
if (kbhit()) // daca se apasa o tasta
{ tasta = getch(); // se citeste codul ei
if (tasta == 0) tasta = getch();
// daca acesta este 0,
// atunci se mai citeste o data codul; acest lucru se
// foloseste pentru codurile tastelor de cursor
switch(tasta)
// se modifica dx si dy, in functie de tasta
{ case 72: dy = -1; break; // cursor sus
case 80: dy = +1; break; // cursor jos
case 75: dx = -1; break; // cursor stinga
case 77: dx = +1; break; // cursor dreapta
}
Sterge(); // se sterge omul din pozitia veche
x += 10*dx; // se actualizeaza coordonatele sale
y += 10*dy;
i = 0; gasit = 0; // se cauta secvential primul
// fluture F[i], prins in paleta
while ((i < NrInitFluturi) && (! gasit))
{
if (PrindeFluture(*this,F[i]))
// daca s-a prins F[i] in paleta, atunci...
{ F[i].Sterge(); // se sterge
F[i].vizibil = 0; // devine invizibil
gasit = 1;//se va termina ciclul while
NrFluturi--;//nr de fluturi scade cu 1
}
else i++;//daca nu, trecem la alt fluture
}
Deseneaza(); // se deseneaza omul in noua pozitie
}
}
// programul principal
void main()
{
cout << "Dati numarul de fluturi : ";
// se afiseaza acest text
cin >> NrInitFluturi; // si se citeste aceasta variabila
// s-au folosit obiectele standard cout si cin din iostream.h
/* precum si operatorii << si >>, redefiniti pentru aceste
obiecte */
NrFluturi = NrInitFluturi; // initializarea nr. de fluturi
int i, gm, gd = DETECT; // initializarea grafica
158

initgraph(&gd,&gm,"c:\\borlandc\\bgi");
line(0,200,getmaxx(),200); // linia orizontului
for (i=0; i<1000; i++) // cimpia
putpixel(random(getmaxx()),200+random(getmaxy()-200),15);
Nor N1(100,50); N1.Deseneaza(); // cei doi nori
Nor N2(400,80); N2.Deseneaza();
Soare S(550,60,1); S.Deseneaza(); // soarele
Om O(200,300); O.Deseneaza(); // omul
for (i=0; i<NrInitFluturi; i++) // fluturii
F[i].Deseneaza();
// urmeaza jocul propriu-zis:
do
{
N1.Muta();
// mutarea celor doi nori
N2.Muta();
S.Muta(); // rotirea soarelui
O.Muta(); // mutarea omului, cu taste
line(0,200,getmaxx(),200);
// redesenarea orizontului
for (i=0; i<NrInitFluturi; i++)
F[i].Muta(); //se muta toti fluturii, pe rind
if (kbhit())//se forta terminarea jocului
{ if (getch() == char(27)) // daca se apasa
{ closegraph(); exit(1); } // Escape
}
}
while (NrFluturi > 0);
// jocul se termina cind se termina fluturii
closegraph(); // se iese din modul grafic

2.
Se tie c n calculator, orice numr real este reprezentat printr-un
numr raional, deoarece nu se pot reprezenta dect un numr finit de
zecimale ale oricrui numr. Prin urmare, fiecare numr raional
corespunde mai multor valori reale, dintr-un anumit interval care
reprezint o vecintate pentru un numr raional. Acestea considerente
ne conduc la ideea realizrii unei clase interval i a operaiilor necesare
operrii cu ele, ca n exemplul urmtor:

// * Implementarea clasei INTERVAL si redefinirea operatorilor


//
+ , - , * si / pentru aceasta clasa *
#include <iostream.h>
#include <conio.h>
class interval
{
public :
float inf; float sup;
interval(float a, float b) { inf=a, sup=b;};
friend interval operator+(interval, interval);
friend interval operator-(interval, interval);
friend interval operator*(interval, interval);
159

friend interval operator/(interval, interval);


};
interval operator+(interval interv_1, interval interv_2)
{
return interval(interv_1.inf+interv_2.inf,
interv_1.sup+interv_2.sup);
}
interval operator-(interval interv_1, interval interv_2)
{
return interval(interv_1.inf-interv_2.sup,
interv_1.sup-interv_2.inf);
}
interval operator*(interval interv_1, interval interv_2)
{
float p[4], min , max;
p[0] = interv_1.inf * interv_2.inf;
p[1] = interv_1.inf * interv_2.sup;
p[2] = interv_1.sup * interv_2.inf;
p[3] = interv_1.sup * interv_2.sup;
min = p[0]; max = min;
for (int i=0; i<=3; i++)
{ if (p[i] < min) min = p[i];
if (p[i] > max) max = p[i];
}
return interval (min, max);
}
interval operator/(interval interv_1, interval interv_2)
{
float p[4], min , max;
//
* Eroare : impartire prin zero ! *
if (interv_2.inf <= 0 && interv_2.sup >=0)
{ return interval(0, 0) ;}
else
{
p[0] = interv_1.inf / interv_2.inf;
p[1] = interv_1.inf / interv_2.sup;
p[2] = interv_1.sup / interv_2.inf;
p[3] = interv_1.sup / interv_2.sup;
min = p[0]; max = min;
for (int i=0; i<=3; i++)
{ if (p[i] < min) min = p[i];
if (p[i] > max) max = p[i];
}
return interval (min, max);
}
}
void main(void)
{
float a, b, c, d;
char op;
clrscr();
cout<<" Dati intervalul 1 ! \n";
cout<<" - inf : ";
cin>>a;
160

cout<<" - sup : ";


cin>>b;
interval interv_1(a,b);
cout<<" Dati intervalul 2 ! \n";
cout<<" - inf : ";
cin>>c;
cout<<" - sup : ";
cin>>d;
interval interv_2(c,d);
interval int_sum = interv_1 + interv_2;
interval int_dif = interv_1 - interv_2;
interval int_prd = interv_1 * interv_2;
interval int_cit = interv_1 / interv_2;
cout<<" Suma : [ "<<int_sum.inf<<" , "<<int_sum.sup<<" ] \n";
cout<<" Diferenta : [ "<<int_dif.inf<<" , "<<
int_dif.sup<<" ] \n";
cout<<" Produsul : [ "<<int_prd.inf<<" , "<<
int_prd.sup<<" ] \n";
cout<<" Citul : [ "<<int_cit.inf<<" , "<<int_cit.sup<<" ] \n";
getch();

3.
S se defineasc mai multe clase, derivate dintr-o clas abstract
i s creeze o list eterogen, cuprinznd obiecte de diferite clase.
Un exemplu este dat n programul urmtor. iruri de caracter, numere,
maini i persoane se afl mpreun n lista eterogen p, pentru care metoda
vizualizeaza se comport diferit de la un caz la altul. Iniializarea datelor
obiectelor din lista eterogen se face cu ajutorul metodei set. Programul pune
n eviden i utilizarea funciilor cu argumente implicite.
/* LISTA ETEROGENA */
#include <iostream.h>
#include <string.h>
#include <conio.h>
class ORICE {
*
public :
virtual void vizualizeaza(void)=0;

// * CLASA ABSTRACTA
// * VIRTUALIZARE SI
//
FUNCTIE PURA *

};
class NR_REAL : public ORICE {
// * MOSTENIRE *
float valoare;
public :
// * INITIALIZARE FOLOSIND
NR_REAL(float a) { valoare = a; }
//
UN CONSTRUCTOR *
void vizualizeaza(void) // * REDEFINIRE METODA *
{
cout<<"NR_REAL cu valoarea = "<<valoare<<"\n";
}
// * TIPARIRE CU "COUT"
};
class NR_INTREG : public ORICE {
int valoare;
public :
NR_INTREG(int a) { valoare = a; }
void vizualizeaza(void)
{
cout<<"NR_INTREG cu valoarea = "<<valoare<<"\n";
}

161

};
class SIR : public ORICE {
char* continut;
public :
SIR(char* a)
{ continut=new char[10]; // * ALOCARE DINAMICA DE MEMORIE *
strcpy(continut,a); }
void vizualizeaza(void)
{
cout<<"SIR avind continutul = "<<continut<<"\n";
}
};
class PUNCT : public ORICE {
int x,y;
public :
PUNCT(int a, int b) { x = a; y = b; }
void vizualizeaza(void)
{
cout<<"PUNCT cu abscisa = "<<x<<" si ordonata = "<<y<<"\n";
}
};
class MASINA : public ORICE {
char* marca;
char* tara;
int viteza;
public : // * INITIALIZARE PRIN METODA *
void denumeste(char* m="Dacia 1300",
char* t="Romania", int v=170)
{ marca = new char[10];
strcpy(marca,m); tara = new char[10];
strcpy(tara,t); viteza=v ;}
void vizualizeaza(void)
{
cout<<"MASINA cu marca "<<marca<<
" produsa in "<<tara<<
", cu viteza maxima = "<<viteza<<" km/h\n";
}
};
class PERSOANA : public ORICE {
protected :
char* nume;
char* prenume;
char sex;
int virsta;
public : // * FUNCTIE CU PARAMETRI IMPLICITI *
void denumeste(char* p="Bogdan",char* n="Patrut",
char sx='M',int v=28)
{ nume = new char[15];
strcpy(nume,n); prenume = new char[20];
strcpy(prenume,p); sex = sx; virsta = v; }
void vizualizeaza(void)
{
cout<<"PERSOANA numita = "<<prenume<<" "<<nume<<
" de sex "<<sex<<" si avind "<<virsta<<" ani\n";
}
};
// * FOLOSIREA OPERATORULUI DE DOMENIU "::" *
class LISTA_ETEROGENA {
// * CREAREA UNEI LISTE ETEROGENE DE
ORICE* pB;
//
OBIECTE , TOATE DERIVATE DINTR-O
public :
//
CLASA ABSTRACTA "ORICE" *
void set(ORICE* p) { pB = p; }
void vizualizeaza(void)

162

{ pB->vizualizeaza(); }
};
void main(void)
{
SIR s("abcdef"); NR_REAL r1(-3.5), r2(0.001);
NR_INTREG k(10); PUNCT pct(50,75);
MASINA m[2]; PERSOANA pers;
LISTA_ETEROGENA p[7];
m[0].denumeste("Oltcit");
m[1].denumeste("Mercedes","Germania");
pers.denumeste();
p[0].set(&s); p[1].set(&r1); p[2].set(&m[0]);
p[3].set(&k); p[4].set(&r2); p[5].set(&pct);
p[6].set(&pers);
clrscr();
cout<<"
* LISTA ETEROGENA * \n\n";
for (int i=0;i<7;i++)
// * FOLOSIREA MECANISMULUI
{ cout<<" "<<(i+1)<<" : "; //
"LATE BINDING" PENTRU
p[i].vizualizeaza();
// FOLOSIREA METODEI IN FUNCTIE
};
//
DE INSTANTA *
getch();
}

*
1
2
3
4
5
6
7

Rezultatul programului este afiarea urmtoarelor:

LISTA ETEROGENA *
: SIR avind continutul = abcdef
: NR_REAL cu valoarea = -3.5
: MASINA cu marca Oltcit produsa in Romania, cu viteza maxima = 170 km/h
: NR_INTREG cu valoarea = 10
: NR_REAL cu valoarea = 0.001
: PUNCT cu abscisa = 50 si ordonata = 75
: PERSOANA numita = Bogdan Patrut de sex M si avind 28 ani

Probleme propuse
1.

Ce afieaz urmtorul program, cnd se rspunde: a) cu f; b) cu n.

#include <stdio.h>
struct fairy_tale
{
virtual void act1() {
printf("Printesa intilneste broscoiul\n");act2();
}
void act2() {
printf("Printesa saruta broscoiul\n");act3();
}
virtual void act3() {
printf("Broscoiul se transforma in print\n");act4();
}
virtual void act4() {
printf("Si au trait multi ani fericiti\n");act5();
}
void act5() {
printf("Sfirsit\n");
}
};
struct unhappy_tale:fairy_tale
{
void act3() {
printf("Broscoiul ramine broscoi\n");act4();
}
void act4() {
printf("Printesa fuge ingrozita\n");act5();
}

163

void act5() {
printf("Sfirsit nu prea fericit\n");
}

};
main()
{
char c;
fairy_tale* tale;
printf("Care poveste doriti ? ([f]ericita/[n]efericita)");
scanf("%c",&c);
if (c=='f') tale = new fairy_tale;
else tale = new unhappy_tale;
tale->act1();
delete tale;
}

2.
3.
4.
5.
6.
7.

8.
9.
10.

Scriei o clas C++ pentru liste dublu nlnuite i realizai operaiile de


adugare, inserare, cutare i stergere de elemente ca metode ale
acestei clase.
Scriei o clas C++ pentru stive i implementai operaiile push i pop (de
introducere, extragere a elementelor din stiv. Folosii template pentru
a crea stive cu orice gen de coninut sau folosii ideea de list eterogen.
Implementai structura de arbore binar de cutare i principalele operaii
ce se execut cu astfel de arbori.
Implementai o clas pentru numere mari i realizai operaii aritmetice cu
astfel de numere.
Definii o clas i scriei principalele metode pentru a opera cu numere
complexe: a) sub form algebric; b) sub form trigonometric.
Implementai o clas pentru lucrul cu triunghiuri (cu lungimile laturilor
cunoscute). Se vor crea metode pentru calculul ariei, perimetrului, razei
cercului circumscris sau nscris n triunghi, mediane, unghiuri, dar i
pentru testarea dac dou triunghiuri sunt congruente sau asemenea.
Implementai obiectual structura de tablou unidimensional de numere
ntregi i operaii cu astfel de obiecte: a) citire; b) afiare; c) inversare;
d) suma / produsul elementelor; e) ordonare cresctoare etc.
Aceeai problem ca i mai nainte, dar pentru orice gen de tablouri. Se
vor folosi posibilitile oferite de template!
O matrice cu dimensiuni mari i numrul de elemente nule foarte mare
se numete matrice rar. Se cere s se dea o metod general de
memorare a matricelor rare, precum i o implementare n limbajul C++ a
unor astfel de structuri de date, sub forma unei clase numit matrice.
De asemenea, se cere s se implementeze i metode de calcul cu
matrice rare, care s beneficieze de proporia mare de elemente nule.
De fapt, se va face memorarea doar a elementelor nenule i, de
asemenea, se vor executa operaii doar ntre aceste elemente ale
matricelor, ceea ce va reprezenta economisirea i de spaiu de memorie,
dar i de timp de calcul. Pentru a exemplifica un mod de memorare a
matricelor rare, s considerm matricea urmtoare, n care n loc de
elementul Aij, vom nota doar ij:
0 0 0 0 0
A= 0 0 23 0 25

Locaia 1 2 3 4 5 6
VALA 23 25 31 32 35 ... (valorile elementelor)
ICOL
3 5 1 2 5 ... (indicele pe coloan[)
164

31 32 0 0 35

11.

12.
13.

14.

15.

IPEL

1 1 3 6 .....

(pt. a identifica linia)

Memorarea matricei A se face conform schemei de dreapta sus, n care


IPEL(i) furnizeaz adresa n zona VALA i ICOL a primului element
nenul din linia i a matricei A; IPEL(i+1)-IPEL(i)=numrul de
elemente nenule din linia i; IPEL conine m+1 elemente (pentru cele m
linii ale lui A), iar IPEL(m+1)=NZ+1, n care NZ = numrul de elemente
nenule ale matricei A. Dac linia j din A este nul, atunci
IPEL(j)=IPEL(j+1).
Realizai o implementare a unei clase fereastra, care s permit
gestionarea mai multor ferestre pe ecranul grafic. Se vor implementa
operaii de redimensionare i mutare a ferestrei, nchidere, minimizare,
restaurare, maximizare, precum i metode pentru lucrul cu bare de rulare
orizontale sau verticale ("scroll bars"), ajutor ("help") etc.
Realizai o aplicaie orientat obiect pentru gestionarea datelor
referitoare la elevii dintr-o clas de liceu (nume, prenume, data naterii,
domiciliu, note la toate disciplinele etc.).
Definii o clas Graf pentru a lucra cu grafuri neorientate. Se vor
implementa metode pentru desenarea grafului, colorarea vrfurilor sale,
determinarea componentelor conexe, a circuitelor hamiltoniene etc. Se
cere, de asemenea, ca aplicaia s lucreze n mod grafic.
Definii o clas Functie pentru a lucra cu funcii reale. Se vor
implementa metode pentru tabelarea funciei, reprezentarea graficului ei,
determinarea minimului i maximului pe un interval dat, determinarea
aproximativ a rdcinilor, calculul formal al derivatei, calculul derivatei
ntr-un anumit punct, calculul integralei numerice pe un anumit domeniu.
Aplicaia va rula n mod grafic.
Realizai o aplicaie orientat obiect care s reprezinte un joc de tip
"Invadatorii": din partea de sus a ecranului grafic, mai multe iruri de
nave dumane se apropie de sol. Aici se afl nava proprie, deplasabil
stnga dreapta, cu ajutorul creia se pot nimici navele adverse (prin
tragerea unui glon). Jocul este ctigat dac navele adverse sunt
nimicite nainte de a ajunge la sol. Altfel, jocul este pierdut.

165

Capitolul 9.
Probleme recapitulative
y instruciuni de control y tipuri de date simple y vectori y
y matrice y funcii recursive y structuri y fiiere y

1. Probleme cu instruciuni de control i tipuri de date simple


1. S se afieze toate modurile n care se poate descompune un numr natural
n ca sum de numere naturale consecutive.
2. S se descompun n factori primi un numr natural n.
3. Se citete numrul natural n de la tastatur. S se afieze triunghiul de
numere:
1
12
123
..........
1 2 3 .... n
Rezolvare:
#include <stdio.h>
void main()
{
int n,i,j;
scanf("%d",&n);
for (i=1; i<=n; i++)
{
for (j=1; j<=i; j++)
printf("%2d",j);
printf("\n");
}
}

4. Se citete numrul natural n de la tastatur. S se afieze triunghiul de


numere:
1
13
135
..........
1 3 5 .... 2n-1
166

Rezolvare:
#include <stdio.h>
void main()
{
int n,i,j;
scanf("%d",&n);
for (i=1; i<=n; i++)
{
for (j=1; j<=i; j++)
printf("%2d",2*j-1);
printf("\n");
}
}

5. Se citete numrul natural n de la tastatur. S se afieze triunghiul de


numere:
1 2 3 .... n
..........
123
12
1
Rezolvare:
#include <stdio.h>
void main()
{
int n,i,j;
scanf("%d",&n);
for (i=n; i>=1; i--)
{
for (j=1; j<=i; j++)
printf("%2d",j);
printf("\n");
}
}

6. Se citete numrul natural n de la tastatur. S se afieze triunghiul de


numere:
1
1 2
1 2 3
1 2 3 4
..................
1 2 .................. n
167

Rezolvare:

#include <stdio.h>
void main()
{
int n,i,j;
scanf("%d",&n);
for (i=1; i<=n; i++)
{
for (j=1; j<=n-i; j++)
printf(" ");
for (j=1; j<=i; j++)
printf("%4d",j);
printf("\n");
}
}

7. Se citete numrul natural n de la tastatur. S se afieze triunghiul de


numere:
n n-1 ........... 3 2 1
n n-1 ........... 2 1
............
n n-1
n
Rezolvare:
#include <stdio.h>
void main()
{
int n,i,j;
scanf("%d",&n);
for (i=n; i>=1; i--)
{
for (j=n; j>=n-i+1; j--)
printf("%2d",j);
printf("\n");
}
}

8. Se citete numrul natural n de la tastatur. S se afieze triunghiul de


numere:
n n-1 ...... 3 2 1
n-1 n-2 ...... 2 1
n-2 n-3 ...... 1
...............
3 2 1
2 1
1
168

Rezolvare:
#include <stdio.h>
void main()
{
int n,i,j;
scanf("%d",&n);
for (i=n; i>=1; i--)
{
for (j=i; j>=1; j--)
printf("%2d",j);
printf("\n");
}
}

9. Se citete numrul natural n de la tastatur. S se calculeze, folosind toate


instruciunile repetitive cunoscute, expresiile:
a) S = 1 + 2 + 3 + ... + n; b) P = 1 2 3 ... n;
c) S = 13 + 23 + 33 + ... + n3; d) P = 12 22 ... n2;
e) S = 1 - 2 + 3 - 4 + .... n; f) S = 12 + 23 + 34 + ... + n(n+1);
g) S = 1 + 1/2 + 3 + 1/4 + ... (n termeni); h) P = 1 3 5 ... (2n-1);
i) S = 1 + 32 + 5 + 72 + ... (n termeni); j) S = 1 - 4 + 7 -10 + ... (n termeni);
k) S = 12 - 1/2 + 32 - 1/4 + ... (n termeni); l) P = 1 4 7 10 ... (n factori).
Rezolvare:
#include <stdio.h>
void main()
{
int i,n,semn;
long int suma, produs;
float suma_r;
printf("\nDati n:");
scanf("%d",&n);
printf("\nRezultate:\n");
// punctul a
for (suma=0, i=1; i<=n; i++)
suma+=i;
printf("a) %ld\n",suma);
// punctul b
for (produs=1, i=1; i<=n; i++)
produs+=i;
printf("b) %ld\n",produs);
// punctul c
for (suma=0, i=1; i<=n; i++)
suma+=i*i*i;
printf("c) %ld\n",suma);
// punctul d
169

//

//

//

//

for (produs=1, i=1; i<=n; i++)


produs+=i*i;
printf("d) %ld\n",produs);
punctul e
for (suma=0, semn=1, i=1; i<=n; i++, semn=-semn)
suma+=semn*i;
printf("e) %ld\n",suma);
punctul f
for (suma=0, i=1; i<=n; i++)
suma+=i*(i+1);
printf("f) %ld\n",suma);
punctul g
for (suma_r=0, i=1; i<=n; i++)
if (i % 2 == 1)
suma_r=suma_r+i;
else
suma_r=suma_r+(float)1/i;
printf("g) %0.2f\n",suma_r);
punctul h
for (produs=1, i=1; i<=n; i++)
produs*=(2*i-1);
printf("h) %ld",produs);

10. Se citete numrul natural n de la tastatur. S se calculeze, folosind toate


instruciunile repetitive cunoscute, expresiile:
a) S = 1 + 12 + 123 + .... 12...n;
b) S = 1 - 13 + 135 - 1357+ ... (n termeni)
c) S = 12 - 1/(12) + 32 - 1/(1234) + 52 - 1/(123456) + .... (n termeni)
d) S = 12 - 142 + 1472 - 147102 + ... (n termeni)
Rezolvare:
#include <stdio.h>
void main()
{
int i,n,semn;
long int suma, produs;
float suma_r;
printf("\nDati n:");
scanf("%d",&n);
printf("\nRezultate:\n");
// punctul a
for (suma=0, produs=1, i=1; i<=n; i++)
{ produs*=i; suma+=produs; }
printf("a) %ld\n",suma);
// punctul b
for (suma=0, produs=1, semn=1, i=1; i<=n; i++, semn=-semn)
{
produs*=(2*i-1);
170

suma+=semn*produs;
}
printf("b) %ld\n",suma);
// punctul c
for (suma_r=0, produs=1, i=1; i<=n; i++)
{
produs*=i;
if (i % 2 == 1)
suma_r = suma_r + i*i;
else
suma_r = suma_r - (float)1/produs;
}
printf("c) %0.2f",suma_r);
}

11. Se citete numrul natural n de la tastaur. S se determine suma primelor


n numere prime.
Rezolvare:
#include <stdio.h>
#include <math.h>
long int prim(long int m)
{
for (long int i=2; i<=sqrt(m); i++)
if (m%i==0) return 0;
return 1;
}
void main()
{
long int n, suma, a, i;
scanf("%ld",&n);
for (suma=2, a=3, i=1; i<n; a+=2)
if (prim(a))
{ suma+=a; i++; }
printf("%ld",suma);
}

12. Se citete numrul natural n de la tastatur. S se determine al n-lea


termen din irul lui Fibonacci i suma primilor n termeni din acest ir. }irul lui
Fibonacci este definit astfel: primii doi termeni sunt 1, iar oricare alt termen se
calculeaz ca fiind suma celor doi termeni imediat anteriori: 1, 1, 2, 3, 5, 8, 13,
21, 34, 55 etc.
Rezolvare:
#include <stdio.h>

171

void main()
{
long int t1, t2, t3, i, n, suma;
printf("\nDati n:"); scanf("%ld",&n);
t1=0; t2=1; t3=1;
if (n==1) suma=1; else suma=2;
for (i=2; i<n; i++)
{
t1=t2; t2=t3; t3=t1+t2;
suma+=t3;
}
printf("Termenul=%ld, suma=%ld", t3, suma);
}

13. Pentru un numr n natural citit de la tastatur s se determine suma


divizorilor si pozitivi.
Rezolvare:
#include <stdio.h>
void main()
{
long int n, i, suma;
scanf("%ld", &n);
for (i=1, suma=0; i<=n; i++)
if (n % i == 0)
suma+=i;
printf("%ld",suma);
}

14. Pentru un numr n natural citit de la tastatur s se determine suma


divizorilor si pozitivi, care sunt numere impare.
Rezolvare:
#include <stdio.h>
void main()
{
long int n, i, suma;
scanf("%ld", &n);
for (i=1, suma=0; i<=n; i++)
if ((n % i == 0) & (i % 2 == 1))
suma+=i;
printf("%ld",suma);
}

15. Pentru un numr n natural citit de la tastatur s se determine suma


divizorilor si pozitivi, care sunt numere prime.

172

16. Pentru un numr n natural citit de la tastatur s se calculeze suma


numerelor prime mai mici dect n.
17. Pentru un numr n natural citit de la tastatur s se calculeze suma
ptratelor perfecte mai mici dect n.
Rezolvare:
#include <stdio.h>
#include <math.h>
void main()
{
long int n, suma, a;
printf("\nDati n:");
scanf("%ld",&n);
for (suma=0, a=1; a<=n; a++)
if (sqrt(a)==(long int)sqrt(a))
suma = suma + a;
printf("Suma este:%ld",suma);
}

18. Pentru un numr n natural citit de la tastatur s se calculeze suma


cuburilor perfecte mai mici dect n.
19. Pentru un ir de n numere naturale citite de la tastatur determinai cte
din ele sunt cte impare, cte prime i cte cuburi perfecte.
Rezolvare:
#include <stdio.h>
#include <math.h>
long int este_prim(long int m)
{
for (long int i=2; i<=sqrt(m); i++)
if (m%i==0) return 0;
return 1;
}
int este_cub_perfect(long double m)
{
for (long int i=1; i<=m; i++)
if (i*i*i==m) return 1;
return 0;
}
void main()
{
int n, ncub, nprime, nimp, i;
long int a;
173

printf("\nDati n:"); scanf("%d",&n);


nimp=0; ncub=0; nprime=0;
for (i=0; i<n; i++)
{
printf("Dati un numar:");
scanf("%ld",&a);
if (a % 2 == 1) nimp++;
if (este_cub_perfect(a)) ncub++;
if (este_prim(a)) nprime++;
}
printf("Numarul elementelor impare
= %d\n", nimp);
printf("Numarul elementelor prime
= %d\n", nprime);
printf("Numarul elementelor cuburi
= %d\n", ncub);

20. Pentru un ir de n numere citite de la tastatur determinai numrul cel mai


mare din ir, cel mai mic numr negativ din ir.
Rezolvare:
#include <stdio.h>
long int suma_cifre(long int m)
{
long int s=0;
while (m!=0)
{ s += m % 10; m/=10; }
return s;
}
void main()
{
int i, n;
float a, max, min_neg;
printf("\nDati n:"); scanf("%d",&n);
printf("\nDati un numar: "); scanf("%f",&a);
max=a;
min_neg=a;
for (i=1; i<n; i++)
{
printf("\nDati un numar: ");
scanf("%f",&a);
if (a>max) max=a;
if ((a<min_neg) && (a<0)) min_neg=a;
}
printf("\nMaximul este: %0.2f",max);
if (min_neg<0)
printf("\nMinimul negativ este: %0.2f",min_neg);
else
printf("\nNu exista un numar negativ in sir");
}

174

21. Pentru un ir de n numere citite de la tastatur, care nu sunt divizibile prin


10, determinai numrul a crui oglindit este cel mai mic.
22. Pentru un ir de n numere citite de la tastatur, determinai cte din ele
sunt identice cu oglinditele lor i cte au suma cifrelor un ptrat perfect.
23. S se simuleze micarea unei bile de sus n jos, pe coloana C a ecranului.
Rezolvare:
#include <stdio.h>
#include <conio.h>
#include <dos.h>
void main()
{
int c,i;
clrscr();
printf("Dati coloana: "); scanf("%d",&c);
clrscr();
for (i=2; i<=24; i++)
{
gotoxy(c,i-1); printf(" ");
gotoxy(c,i); printf("O");
delay(100);
}
}

24. S se simuleze micarea unei bile de jos n sus, pe coloana C a ecranului.


25. S se simuleze micarea unei bile de la stnga la dreapta i apoi de la
dreapta la stnga, n mod repetat, pe linia L a ecranului, pn la acionarea
unei taste.
26. S se simuleze pe ecran micarea a dou bile de la stnga la dreapta i
invers i de sus n jos i invers, simultan, pn la acionarea unei taste.
27. S se simuleze pe ecran micarea unei bile pe diagonal, sub unghiul de
45 de grade, care s se comporte ca pe o mas de biliard, pn la acionarea
unei taste.
Rezolvare:
#include <stdio.h>
#include <conio.h>
#include <dos.h>
void main()
{
175

int x,y,dx,dy;
clrscr();
dx=1; dy=1; x=40; y=12;
do {
gotoxy(x,y); printf(" ");
if ((x==1) || (x==80)) dx=-dx;
if ((y==1) || (y==24)) dy=-dy;
x+=dx; y+=dy;
gotoxy(x,y); printf("O");
gotoxy(1,1);
delay(50);
} while (!kbhit());

2. Probleme cu vectori (tablouri unidimensionale)


1. Se citesc numere ntregi de la tastatur, pn la ntlnirea unui numr
negativ. S se memoreze toate numerele pare citite, ntr-un vector x.
Rezolvare:
#include <stdio.h>.

void main()
{
int a,n=0;
int x[100];
do {
scanf("%d",&a);
if ((a>=0) && (a%2 == 1)) x[n++]=a;
} while (a>=0);
for (int i=0; i<n; i++)
printf("%d,",x[i]);
}

2. Se citesc numere ntregi de la tastatur, pn la ntlnirea unui numr prim.


S se memoreze ntr-un vector sumele cifrelor tuturor numerelor citite.
Rezolvare:
#include <stdio.h>
#include <math.h>
int prim(int m)
{
for (int i=2; i<=sqrt(m); i++)
if (m%i==0) return 0;
return 1;
}
int suma_cifre(int m)
{
int s=0;
176

while (m!=0)
{ s += m % 10; m/=10; }
return s;

void main()
{
int a,n=0;
int x[100];
do {
scanf("%d",&a);
if (!prim(a)) x[n++]=suma_cifre(a);
} while (!prim(a));
for (int i=0; i<n; i++)
printf("%d,",x[i]);
}

3. S se elimine dintr-un vector x de numere ntregi elementul de pe poziia p.


Rezolvare:
#include <stdio.h>
void main()
{
int x[100],n,i,p;
scanf("%d",&n);
for (i=0; i<n; i++) scanf("%d",&x[i]);
scanf("%d",&p);
for (i=p; i<n-1; i++) x[i]=x[i+1];
n--;
for (i=0; i<n; i++) printf("%d,",x[i]);
}

4. S se elimine dintr-un vector x de numere ntregi toate elementele negative.


Rezolvare:
#include <stdio.h>
void main()
{
int x[100],n,i,j;
scanf("%d",&n);
for (i=0; i<n; i++) scanf("%d",&x[i]);
for (i=0; i<n; )
if (x[i]<0)
{
for (j=i; j<n-1; j++) x[j]=x[j+1];
n--;
}
else i++;
for (i=0; i<n; i++) printf("%d,",x[i]);
177

5. S se elimine dintr-un vector x de numere ntregi toate elementele de pe


poziii divizibile prin 3.
6. S se insereze, pe poziia p, un element a n vectorul x.

Rezolvare:
#include <stdio.h>
void main()
{
int x[100],n,i,p,a;
scanf("%d",&n);
for (i=0; i<n; i++) scanf("%d",&x[i]);
scanf("%d",&p);
scanf("%d",&a);
for (i=n; i>p; i--) x[i]=x[i-1];
x[p]=a;
n++;
for (i=0; i<n; i++) printf("%d,",x[i]);
}

7. S se insereze, ntre oricare dou elemente dintr-un vector x de numere


ntregi, suma lor.
Rezolvare:
#include <stdio.h>
void main()
{
int x[100], y[200],n,i,j,a;
scanf("%d",&n);
for (i=0; i<n; i++) scanf("%d",&x[i]);
for (i=0; i<n; i++)
{
y[2*i]=x[i];
y[2*i+1]=x[i]+x[i+1];
}
for (i=0; i<2*n-1; i++)
{
x[i]=y[i];
printf("%d,",x[i]);
}
}

178

8. S se insereze, dup fiecare element par dintr-un vector x de numere ntregi


suma cifrelor impare ale acelui element.
9. S se insereze, dup fiecare element negativ dintr-un vector x de numere
ntregi ptratul elementului respectiv.
10. S se nlocuiasc fiecare element negativ i impar dintr-un vector x de
numere ntregi cu modulul acelui element.

Rezolvare:
#include <stdio.h>
#include <math.h>
void main()
{
int x[100], y[200],n,i,j,a;
scanf("%d",&n);
for (i=0; i<n; i++) scanf("%d",&x[i]);
for (i=0; i<n; i++)
if ((x[i]<0) && (x[i] % 2 == -1)) x[i]=abs(x[i]);
for (i=0; i<n; i++) printf("%d,",x[i]);
}

11. S se nlocuiasc fiecare element prim dintr-un vector x de numere ntregi


cu suma cifrelor acelui element.
12. S se nlocuiasc fiecare element a crui sum a cifrelor este numr prim,
dintr-un vector x de numere ntregi, cu inversul acelui element.
13. Se consider un vector de numere ntregi x. Se cere s se determine un
vector y cu acelai numr de componente ntregi, astfel nct elementele lui y
s fie suma cifrelor elementelor din x.
Rezolvare:
#include <stdio.h>
int suma_cifre(int m)
{
int s=0;
while (m!=0)
{ s += m % 10; m/=10; }
return s;
}
void main()
179

int i,j,n,aux;
int x[100], y[100];
scanf("%d",&n);
for (i=0; i<n; i++)
scanf("%d",&x[i]);
for (i=0; i<n; i++)
y[i]=suma_cifre(x[i]);
for (i=0; i<n; i++)
printf("%d,",y[i]);

14. Se consider un vector de numere ntregi x. Se cere s se determine un


vector y cu acelai numr de componente ntregi, astfel nct elementele lui y
modulele elementelor lui x, pentru elementele prime, respectiv ptratele
elementelor lui x, pentru elementele care nu sunt prime.
Rezolvare:
#include <stdio.h>
#include <math.h>
int prim(int m)
{
for (int i=2; i<=sqrt(m); i++)
if (m%i==0) return 0;
return 1;
}
void main()
{
int i,j,n,aux;
int x[100], y[100];
scanf("%d",&n);
for (i=0; i<n; i++)
scanf("%d",&x[i]);
for (i=0; i<n; i++)
if (prim(x[i]))
y[i]=2*x[i];
else
y[i]=x[i]*x[i];
for (i=0; i<n; i++)
printf("%d,",y[i]);
}

15. Se consider un vector de numere ntregi x. Se cere s se determine un


vector y cu acelai numr de componente ntregi, astfel nct elementele lui y
s fie cuburile sumelor cifrelor impare ale elementelor lui x.
16. Se consider un vector de numere ntregi x. Se cere s se determine un
vector y cu acelai numr de componente ntregi, astfel nct elementele lui y
180

s fie suma dintre produsele cifrelor impare i suma cifrelor pare ale
elementelor din x.
Rezolvare:
#include <stdio.h>
int suma_cifre_pare(int m)
{
int s=0, uc;
while (m!=0)
{
uc = m % 10;
if (uc % 2 == 0) s += uc;
m/=10;
}
return s;
}
int produs_cifre_impare(int m)
{
int p=1, uc;
while (m!=0)
{
uc = m % 10;
if (uc % 2 == 1) p *= uc;
m/=10;
}
return p;
}
void main()
{
int i,n;
int x[100], y[100];
scanf("%d",&n);
for (i=0; i<n; i++)
scanf("%d",&x[i]);
for (i=0; i<n; i++)

y[i]=(suma_cifre_pare(x[i])+produs_cifre_impare(x[i]));
for (i=0; i<n; i++)
printf("%d,",y[i]);

17. Se consider un vector de numere ntregi x. Se cere s se determine un


vector y cu acelai numr de componente ntregi, astfel nct elementele lui y
s fie suma dintre elementele lui x i suma cifrelor acestora.
18. Se consider un vector de numere ntregi x, de lungime n, n fiind par. Se
cere s se determine un vector y, de lungime n/2, n care y1 = x1 + xn, y2 = x2 +
xn-1 .a.m.d.
181

Rezolvare:
#include <stdio.h>
void main()
{
int i,n;
int x[100], y[100];
scanf("%d",&n);
for (i=1; i<=n; i++)
scanf("%d",&x[i]);
for (i=1; i<=n/2; i++)
y[i]=x[i]+x[n-i+1];
for (i=1; i<=n/2; i++)
printf("%d,",y[i]);
}

19. Se consider un vector de numere ntregi x, de lungime n, n fiind par. Se


cere s se determine un vector y, de lungime n/2, n care y1 = min(x1,xn), y2 =
min(x2,xn-1) .a.m.d.
20. Se consider un vector de numere ntregi x, de lungime n, n fiind par. Se
cere s se determine un vector y, de lungime n/2, n care y1 = max(x12,sn), y2 =
max(x22,sn-1) .a.m.d., unde si = suma cifrelor pare ale lui xi2-1.
21. Se consider un vector de numere ntregi x, de lungime n, n fiind par. Se
cere s se determine un vector y, de lungime n/2, n care y1 = max(x12,sn), y2 =
max(x22,sn-1) .a.m.d., unde si = suma cifrelor prime ale lui xi.
Rezolvare:
#include <stdio.h>
int suma_cifre(int m)
{
int s=0;
while (m!=0)
{ s += m % 10; m/=10; }
return s;
}
void main()
{
int i,n;
int x[100], y[100];
scanf("%d",&n);
for (i=1; i<=n; i++)
scanf("%d",&x[i]);
for (i=1; i<=n/2; i++)
if (x[i]*x[i]>suma_cifre(x[n-i+1]))
y[i]=x[i]*x[i];
182

else

y[i]=suma_cifre(x[n-i+1]);
for (i=1; i<=n/2; i++)
printf("%d,",y[i]);

22. Se consider un vector de numere ntregi x, de lungime n, n fiind par. Se


cere s se determine un vector y, de lungime n/2, n care y1 = cmmdc(x12,xn),
y2 = cmmdc(x22,xn-1) .a.m.d.
23. Se consider doi vectori de numere ntregi x i y, de lungime n. Se cere s
se determine un vector z, de lungime n, n care z1 = cmmdc(x1, s12), z2 =
cmmdc(x2, s22) .a.m.d., n care si este suma cifrelor pare ale lui yi.
Rezolvare:
#include <stdio.h>
int suma_cifre_pare(int m)
{
int s=0, uc;
while (m!=0)
{
uc = m % 10;
if (uc % 2 == 0) s += uc;
m/=10;
}
return s;
}
int cmmdc(int a, int b)
{
if ((a==0) || (b==0)) return 0;
if (a>b) return cmmdc(a-b,b);
if (a<b) return cmmdc(a,b-a);
return a;
}
void main()
{
int i,n;
int x[100],y[100],z[100];
scanf("%d",&n);
for (i=1; i<=n; i++)
scanf("%d",&x[i]);
for (i=1; i<=n; i++)
scanf("%d",&y[i]);
for (i=1; i<=n; i++)
x[i]=cmmdc(x[i],
suma_cifre_pare(y[i])*suma_cifre_pare(y[i]));
for (i=1; i<=n; i++)
183

printf("%d,",x[i]);

24. Se consider doi vectori de numere ntregi x i y, de lungime n. Se cere s


se determine un vector z, de lungime n, n care z1 = cmmdc(x12, s12), z2 =
cmmdc(x22, s22) .a.m.d., n care si este suma cifrelor lui min(xi, yi2-1).
25. Se consider doi vectori de numere ntregi x i y, de lungime n. Se cere s
se determine un vector z, de lungime n, n care z1 = max(x12, s1), z2 = max(x22,
s2) .a.m.d., n care si este suma cifrelor impare a celui mai mare divizor
comun pentru xi i yn+1-i.
26. Se consider doi vectori de numere ntregi x i y, de lungime n. Se cere s
se determine un vector z, de lungime n, n care z1 = min(s12, t13), z2 = max(s22,
t23), z3 = min(s32, t33), z4 = max(s42,t43) .a.m.d., n care si este suma cifrelor
pare alui lui xi+yi, iar ti este produsul cifrelor divizibile prin 3 ale lui xi.
27. Se consider doi vectori de numere ntregi x i y, de lungime n. Se cere s
se determine un vector z, de lungime n, n care z1 = s1+t1, z2 = s2+t2, z3 = s3+t3,
z4 = s4+t4 .a.m.d., n care si este suma cifrelor impare alui lui xi-yi, iar ti este
produsul cifrelor divizibile prin 3 ale lui si.
28. S se memoreze n componentele unui vector primele n numere naturale
prime.
Rezolvare:
#include <stdio.h>
#include <math.h>
int prim(int m)
{
for (int i=2; i<=sqrt(m); i++)
if (m%i==0) return 0;
return 1;
}
void main()
{
int x[100], n, i, a;
scanf("%d",&n);
// Un for interesant!
for (i=0, a=2; i<n; a++)
if (prim(a)) x[i++]=a;
for (i=0; i<n; i++)
printf("%d,",x[i]);
}

184

29. S se determine componentele unui vector x astfel nct xi = 12...i.


Rezolvare:
#include <stdio.h>
void main()
{
int n, i, x[100];
scanf("%d",&n);
x[1]=1;
for (i=2; i<=n; i++)
x[i]=x[i-1]*i;
for (i=1; i<=n; i++)
printf("%d,",x[i]);
}

30. S se determine componentele unui vector x astfel nct xi = 12+22+...+i2.


31. S se memoreze n componentele unui vector primele n numere naturale
prime, care citite invers sunt tot numere prime.
Rezolvare:
#include <stdio.h>
#include <math.h>
long int prim(int m)
{
for (long int i=2; i<=sqrt(m); i++)
if (m%i==0) return 0;
return 1;
}
long int oglindit(int a)
{
int b=0;
while (a)
{
b=b*10+a%10;
a/=10;
}
return b;
}
void main()
{
long int n, i, a, x[100];
185

scanf("%ld",&n);
x[0]=2;
for (i=0, a=3; i<n; a+=2)
if (prim(a) && prim(oglindit(a)))
x[++i]=a;
for (i=0; i<n; i++)
printf("%d,",x[i]);

32. S se memoreze n componentele unui vector primele n numere naturale


prime a cror sum a cifrelor este tot numr prim.
Rezolvare:
#include <stdio.h>
#include <math.h>
long int prim(long int m)
{
for (long int i=2; i<=sqrt(m); i++)
if (m%i==0) return 0;
return 1;
}
long int suma_cifre(long int m)
{
long int s=0;
while (m!=0)
{ s += m % 10; m/=10; }
return s;
}
void main()
{
long int n, i, a, x[100];
scanf("%ld",&n);
x[0]=2;
for (i=0, a=3; i<n; a+=2)
if (prim(a) && prim(suma_cifre(a)))
x[++i]=a;
for (i=0; i<n; i++)
printf("%d,",x[i]);
}

33. S se elimine dintr-un vector x de numere naturale toate numerele prime a


cror sum a cifrelor este numr prim.
Rezolvare:
#include <stdio.h>
#include <math.h>

186

long int prim(long int m)


{
for (long int i=2; i<=sqrt(m); i++)
if (m%i==0) return 0;
return 1;
}
long int suma_cifre(long int m)
{
long int s=0;
while (m!=0)
{ s += m % 10; m/=10; }
return s;
}
void main()
{
long int x[100],n,i,j;
scanf("%ld",&n);
for (i=0; i<n; i++)
scanf("%ld",&x[i]);
for (i=0; i<n; )
if (prim(x[i]) && prim(suma_cifre(x[i])))
{
for (j=i; j<n-1; j++) x[j]=x[j+1];
n--;
}
else i++;
for (i=0; i<n; i++) printf("%ld,",x[i]);
}

34. S se elimine dintr-un vector x de numere naturale toate numerele prime


care au produsul cifrelor divizibil prin 3.
35. Se consider un vector x cu n componente ntregi. S se calculeze S = x1s1
+ x2s2 + x3s3 + ... + x4s4, unde si = suma cifrelor divizibile prin 3 ale lui xi.
Rezolvare:
#include <stdio.h>
#include <math.h>
long int suma_cifre_div3(long int m)
{
long int s=0; int cifra;
while (m!=0)
{
cifra = m % 10;
if (cifra % 3 == 0)
s += cifra;
m/=10;
}
return s;
187

}
void main()
{
long int x[100],n,i,suma;
scanf("%ld",&n);
for (i=0; i<n; i++)
scanf("%ld",&x[i]);
for (i=0, suma=0; i<n ; i++)
suma += x[i]*suma_cifre_div3(x[i]);
printf("%ld",suma);
}

36. Se consider un vector x cu n componente ntregi. S se calculeze S =


1x12 + 2x22 + 3x32 + ... +nxn2.
Rezolvare:
#include <stdio.h>
#include <math.h>
void main()
{
long int x[100],n,i,suma;
scanf("%ld",&n);
for (i=1; i<=n; i++)
scanf("%ld",&x[i]);
for (i=1, suma=0; i<=n ; i++)
suma += i*x[i]*x[i];
printf("%ld",suma);
}

37. Se consider un vector x cu n componente reale. S se determine n


vectorul y, de lungime n, prile ntregi ale componentelor din x.
38. Se consider un vector x cu n componente reale. S se determine n
vectorul y, de lungime n, prile fracionare ale componentelor din x.
39. Se consider un vector x cu n componente reale. S se memoreze n
vectorul y acele elemente din x care sunt i numere ntregi.
Rezolvare:
#include <stdio.h>
void main()
{
float x[100];
int y[100];
int n,i,j;
scanf("%d",&n);
188

for (i=0; i<n; i++) scanf("%f",&x[i]);


for (i=0, j=0; i<n; i++)
if (x[i]==(int)(x[i]))
y[j++]=x[i];
for (i=0; i<j; i++)
printf("%d,",y[i]);

40. Se consider un vector x cu n componente ntregi. S se memoreze n


vectorul y acele elemente din x care sunt ptrate perfecte.
Rezolvare:
#include <stdio.h>
#include <math.h>
void main()
{
int x[100], y[100];
int n,i,j;
scanf("%d",&n);
for (i=0; i<n; i++) scanf("%d",&x[i]);
for (i=0, j=0; i<n; i++)
if (sqrt(x[i])==(int)(sqrt(x[i])))
y[j++]=x[i];
for (i=0; i<j; i++)
printf("%d,",y[i]);
}

3. Probleme cu tipul caracter i iruri de caractere


1. Se consider un vector x cu n componente caractere. S se determine n
vectorul y, de lungime n, codurile ASCII ale componentelor din x.
2. Se consider un vector x cu n componente naturale, din intervalul 65..90. S
se determine n vectorul y, de lungime n, caracterele avnd codurile ASCII
egale cu componentele din x.
3. Se citesc n iruri de caractere. S se determine cte din acestea ncep cu
litera 'h', cte se termin cu o vocal, cte au lungimea mai mare dect 4, cte
au lungimea un ptrat perfect i cte conin un numr impar de consoane.
Rezolvare:
#include <stdio.h>
#include <string.h>
#include <math.h>
189

void main()
{
char s[20]; int i,n;
printf("Dati n: ");
scanf("%d",&n);
int nh=0, nvoc=0, n4=0, npp=0, nimpc=0;
int cons,j;
char c, t[2];
for (i=1; i<=n; i++)
{
printf("Dati sirul nr. %d:",i);
scanf("%s",&s);
if (s[0]=='h') nh++;
c=s[strlen(s)-1];
if ((c=='a') || (c=='e') ||
(c=='i') || (c=='o') || (c=='u'))
nvoc++;
if (strlen(s)>4) n4++;
if ((int)sqrt(strlen(s))==sqrt(strlen(s)))
npp++;
cons=0;
for (j=0; j<strlen(s); j++)
{
c=s[j]; t[0]=c; t[1]='\0';
if (!strstr("aeiou",t)) cons++;
}
if (cons%2==1) nimpc++;
}
printf("Nr. de siruri ce incep cu 'h': %d\n",nh);
printf("Nr. de siruri ce se termina cu o vocala: %d\n",
nvoc);
printf("Nr. de siruri ce au lungimea > 4: %d\n",n4);
printf("Nr. de siruri cu lungimea patrat perfect: %d\n",
npp);
printf("Nr. de siruri cu un nr. impar de consoane: %d\n",
nimpc);
}

4. Se citesc n iruri de caractere. S se determine cte din acestea ncep i se


termin cu aceeai liter, cte au cel puin dou vocale, cte sunt cifre i cte
sunt cifre impare.
5. Se citesc n iruri de caractere. S se memoreze ntr-un vector de iruri de
caractere.
6. Se citesc n iruri de caractere. S se memoreze ntr-un vector de iruri de
caractere acele iruri care ncep i se termin cu o vocal.
7. Se citesc n iruri de caractere. S se memoreze ntr-un vector de iruri de
caractere acele iruri care au lungimea un numr prim.
190

8. Se citesc n iruri de caractere. S se memoreze ntr-un vector de iruri de


caractere oglinditele irurilor citite.
9. Se citesc n iruri de caractere. S se memoreze ntr-un vector de caractere
primele litere ale irurilor citite.
Rezolvare:
#include <stdio.h>
#include <string.h>
#include <math.h>
void main()
{
char s[20], x[20];
int i,n;
printf("Dati n: ");
scanf("%d",&n);
int nh=0, nvoc=0, n4=0, npp=0, nimpc=0;
int cons,j;
char c, t[2];
for (i=1; i<=n; i++)
{
printf("Dati sirul nr. %d:",i);
scanf("%s",&s);
x[i]=s[0];
printf(" -> %c\n",x[i]);
}
}

10. Se citesc n iruri de caractere. S se memoreze ntr-un vector de


caractere, pentru fiecare ir n parte, prima consoan depistat n ir, iar dac
nu este s se memoreze simbolul dolarului.
11. Se citesc n iruri de caractere. S se memoreze aceste iruri ntr-un vector
de iruri de caractere, n ordine invers.
12. Se citesc n iruri de caractere, care au lungimile cel puin 2. Pentru fiecare
ir s se elimine primul i ultimul caracter, iar ceea ce rmne s se memoreze
ntr-un vector de iruri de caractere.
13. Se d un vector x de n iruri de caractere. S se elimine din vector
elementele care au mai puin de trei vocale.
14. Se d un vector x de n iruri de caractere. S se elimine din vector
elementele care au sunt identice cu oglinditele lor.

191

15. Se d un vector x de n iruri de caractere. S se creeze un vector y de


numere ntregi n care s se pstreze lungimile elementelor din x.
Rezolvare:
#include <stdio.h>
#include <string.h>
#include <math.h>
void main()
{
char x[20][20];
int y[20];
int i,n;
printf("Dati n: ");
scanf("%d",&n);
int nh=0, nvoc=0, n4=0, npp=0, nimpc=0;
int cons,j;
char c, t[2];
for (i=0; i<n; i++)
{
printf("Dati sirul nr. %d:",i);
scanf("%s",&x[i]);
}
for (i=0; i<n; i++)
{
y[i]=strlen(x[i]);
printf("%d,",y[i]);
}
}

16. Se d un vector x de n iruri de caractere. S se creeze un vector y de


numere ntregi n care s se pstreze numrul de consoane depistate n
elementele din x.
17. Se d un vector x de n iruri de caractere. S se creeze un vector y de
numere ntregi n care s se pstreze numrul de vocale depistate n
elementele din x, care au cel puin dou consoane.
18. Se consider un ir de caractere, reprezentnd o propoziie. S se
despart n cuvinte, acestea memorndu-se ntr-un vector.
19. Se consider un ir de caractere, reprezentnd o propoziie. S se
memoreze ntr-un vector cuvintele care conin mcar dou vocale.
20. Se consider un ir de caractere, reprezentnd o propoziie. S se afieze
cuvintele identice cu oglinditele lor.

192

21. Se consider un ir de caractere, reprezentnd o propoziie. S se


precizeze care sunt cuvintele ce apar n propoziie i de cte ori apare fiecare
cuvnt n propoziie.
22. Se consider un ir de caractere, reprezentnd o propoziie. S se
rearanjeze cuvintele n ir astfel nct ele s fie n ordine alfabetic.
23. Se d un ir de caractere. S se transforme toate literele mari n litere mici,
iar toate literele mici n litere mari, restul caracterelor rmnnd neschimbate.
24. Se d un ir de caractere. S se nlocuiasc fiecare vocal cu vocala
imediat urmtoare n alfabet.
25. Se d un ir de caractere. S se nlocuiasc fiecare vocal cu litera imediat
urmtoare n alfabet.
26. Se d un ir de caractere. S se nlocuiasc fiecare apariie multipl
consecutiv a unui caracter cu o singur apariie a acelui caracter i numrul
de apariii. De exemplu, dac irul dat este "BBAMEEEZZB", atunci se va
obine irul "B2AME3Z2B".
27. Se d un ir de caractere. S se determine un cel mai lung subir care este
identic cu oglinditul su.
28. Se d un ir de caractere. S se memoreze coninutul su ntr-un vector de
caractere, apoi s se ordoneze invers alfabetic acest ir.
29. Se d un ir de caractere. S se calculeze numrul de apariii a unei
consoane ntre dou vocale.
30. Se d un ir de caractere. S se afieze toate prefixele acestuia. De
exemplu, pentru irul "ABCDE" se vor afia irurile "A", "AB", "ABC", "ABCD" i
"ABCDE".
31. Se d un ir de caractere. S se afieze toate sufixele acestuia. De
exemplu, pentru irul "ABCDE" se vor afia irurile "E", "DE", "CDE", "BCDE" i
"ABCDE".
32. Se d un ir de caractere de lungime par. S se afieze toate infixele
acestuia, centrate n mijlocul irului. De exemplu, pentru irul "ABCDE" se vor
afia irurile "C", "BCD" i "ABCDE".

193

4. Probleme cu matrice (tablouri bidimensionale)


1. Se consider o matrice A de numere ntregi. S se determine cel mai mic
element, cel mai mare element par, cel mai mic numr prim i cel mai mare
ptrat perfect din A.
Rezolvare:
#include <stdio.h>
#include <math.h>
#include <values.h>
int esteprim(int n)
{
int d;
if (n<2) return 0;
if (n==2) return 1;
if (n%2==0) return 0;
for (d=3; d<=sqrt(n); d++)
if (n%d==0) return 0;
return 1;
}
int estepatratperfect(int n)
{
if (n<0) return 0;
float q=sqrt(n);
if (q==(int)q) return 1;
else return 0;
}
void main()
{
int a[10][10];
int m,n,i,j;
int min,maxpar,minprim,maxpp;
printf("Dati m,n:"); scanf("%d%d",&m,&n);
for (i=0; i<m; i++)
for (j=0; j<n; j++)
{
printf("Dati a[%d,%d]:",i,j);
scanf("%d",&a[i][j]);
}
min=a[0][0];
maxpar=-MAXINT;
minprim=MAXINT;
maxpp=0;
for (i=0; i<m; i++)
for (j=0; j<n; j++)
{
if (a[i][j]<min) min=a[i][j];
if ((a[i][j]>maxpar) && (a[i][j]%2==0))
maxpar=a[i][j];
194

if (esteprim(a[i][j]) &&
(a[i][j]<minprim))
minprim=a[i][j];
if (estepatratperfect(a[i][j]) &&
(a[i][j]>maxpp))
maxpp=a[i][j];

printf("min
printf("max
printf("min
printf("max

}
= %d\n",min);
par = %d\n",maxpar);
prim = %d\n",minprim);
patrat perfect = %d\n",maxpp);

2. Se consider o matrice A de numere ntregi. S se determine suma


componentelor
pare,
produsul
componentelor
negative,
numrul
componentelor prime i numrul componentelor care sunt divizibile prin 5.
Rezolvare:
#include <stdio.h>
#include <math.h>
int esteprim(int n)
{
int d;
if (n<2) return 0;
if (n==2) return 1;
if (n%2==0) return 0;
for (d=3; d<=sqrt(n); d++)
if (n%d==0) return 0;
return 1;
}
void main()
{
int a[10][10];
int m,n,i,j;
int sumapoz,prodneg,nrprime,ndiv5;
printf("Dati m,n:"); scanf("%d%d",&m,&n);
for (i=0; i<m; i++)
for (j=0; j<n; j++)
{
printf("Dati a[%d,%d]:",i,j);
scanf("%d",&a[i][j]);
}
sumapoz=0; prodneg=1;
nrprime=0; ndiv5=0;
for (i=0; i<m; i++)
for (j=0; j<n; j++)
{
if (a[i][j]>0) sumapoz+=a[i][j];
if (a[i][j]<0) prodneg*=a[i][j];
if (esteprim(a[i][j])) nrprime++;
195

if (a[i][j]%5==0) ndiv5++;
}
printf("Suma pozitivelor: %d\n",sumapoz);
printf("Produsul negativelor: %d\n",prodneg);
printf("Numarul numerelor prime: %d\n",nrprime);
printf("Numarul celor divizibile cu 5: %d\n",ndiv5);

3. Se consider o matrice A de numere ntregi. S se determine cte coloane


conin doar numere pozitive, cte coloane conin cel puin un numr divizibil
prin numrul de linii i cte coloane conin mcar dou numere pare.
Rezolvare:
#include <stdio.h>
void main()
{
int a[10][10];
int m,n,i,j;
int colpoz,coldiv,colpare;
printf("Dati m,n:"); scanf("%d%d",&m,&n);
for (i=0; i<m; i++)
for (j=0; j<n; j++)
{
printf("Dati a[%d,%d]:",i,j);
scanf("%d",&a[i][j]);
}
colpoz=0; coldiv=0; colpare=0;
int doar_pozitive, diviz, npare;
for (j=0; j<n; j++)
{
doar_pozitive=1; diviz=0; npare=0;
for (i=0; i<m; i++)
{
if (a[i][j]<=0) doar_pozitive=0;
if (a[i][j] % m == 0) diviz=1;
if (a[i][j] % 2 == 0) npare++;
}
if (doar_pozitive) colpoz++;
if (diviz) coldiv++;
if (npare>=2) colpare++;
}
printf("Exista %d coloane doar cu elemente pozitive\n",
colpoz);
printf("Exista %d col. cu macar un nr. diviz. prin m\n",
coldiv);
printf("Exista %d col. cu macar doua elemente pare\n",
colpare);
}

196

4. Se consider o matrice A de numere ntregi. S se determine cte elemente


au cel puin o cifr de 2, cte au un numr par de cifre impare, cte elemente
negative au mai mult de dou cifre i cte elemente pozitive au mai mult de
dou cifre de 3 sau 5.
5. Se consider o matrice A de numere ntregi. S se determine cte linii
conin cel puin dou numere prime, cte linii conin cel puin un numr avnd
mai mult de dou cifre de 4 i cte linii au suma elementelor par.
6. Se consider o matrice A de numere ntregi. S se determine cte linii au
suma elementelor egal cu ptratul numrului de coloane i cte coloane au
produsul elementelor egal cu ptratul diferenei dintre coloane i linii.
7. Se consider o matrice A de numere ntregi. S se determine cte elemente
sunt identice cu elementul maxim din matrice i cte cu elementul minim din
matrice.
8. Se consider o matrice A de numere ntregi. S se determine cte elemente
pare sunt situate pe linii cu numr de ordin impar i cte linii conin elemente
care au un numr par de cifre impare.
9. Se consider o matrice A de numere ntregi. S se elimine din matrice
coloana C i linia L.
Rezolvare:
#include <stdio.h>
void main()
{
int a[10][10];
int m,n,i,j,C,L;
printf("Dati m,n:"); scanf("%d%d",&m,&n);
for (i=0; i<m; i++)
for (j=0; j<n; j++)
{
printf("Dati a[%d,%d]:",i,j);
scanf("%d",&a[i][j]);
}
for (i=0; i<m; i++)
{
for (j=0; j<n; j++)
printf("%3d",a[i][j]);
printf("\n");
}
printf("Dati numarul coloanei si al liniei\n");
printf("C="); scanf("%d",&C);
printf("L="); scanf("%d",&L);
197

for (i=L; i<m-1; i++)


for (j=0; j<n; j++)
a[i][j]=a[i+1][j];
m--;
for (j=C; j<n-1; j++)
for (i=0; i<m; i++)
a[i][j]=a[i][j+1];
n--;
for (i=0; i<m; i++)
{
for (j=0; j<n; j++)
printf("%3d",a[i][j]);
printf("\n");
}

10. Se consider o matrice A de numere ntregi. S se introduc naintea liniei


L o linie cu elementele 1, 2, ... n, unde n este numrul de coloane ale lui A.
Rezolvare:
#include <stdio.h>
void main()
{
int a[10][10];
int m,n,i,j,L;
printf("Dati m,n:"); scanf("%d%d",&m,&n);
for (i=0; i<m; i++)
for (j=0; j<n; j++)
{
printf("Dati a[%d,%d]:",i,j);
scanf("%d",&a[i][j]);
}
for (i=0; i<m; i++)
{
for (j=0; j<n; j++)
printf("%3d",a[i][j]);
printf("\n");
}
printf("Dati numarul liniei\n");
printf("L="); scanf("%d",&L);
for (i=m; i>L; i--)
for (j=0; j<n; j++)
a[i][j]=a[i-1][j];
m++;
for (j=0; j<n; j++)
a[L][j]=j+1;
for (i=0; i<m; i++)
{
for (j=0; j<n; j++)
printf("%3d",a[i][j]);
printf("\n");
}
198

11. Se consider o matrice A de numere ntregi. S se introduc naintea


coloanei C o coloan cu elementele m, m-1, ..., 3, 2, 1, unde m este numrul
de linii ale lui A.
12. Se consider o matrice ptratic A de numere ntregi. S se determine
dac suma elementelor de sub diagonala principal este numr prim.
13. Se consider o matrice ptratic A de numere ntregi. S se determine cel
mai mare divizor comun i cel mai mic multiplu comun dintre suma elementelor
de sub diagonala principal i produsul elementelor de pe diagonala
secundar.
14. Se consider o matrice A de numere reale. S se adauge la matricea A o
coloan care s conin sumele elementelor de pe linii.
15. Se consider o matrice A de numere reale. S se adauge la matricea A o
linie care s conin sumele elementelor pare i negative de pe coloane.
16. Se consider o matrice A de numere reale. S se elimine din A liniile care
conin elemente negative mai mic dect -5.
17. Se consider o matrice A de numere reale. S se elimine din A coloanele
care conin cel puin un element nul.
18. Se consider o matrice A de numere reale. S se elimine din A liniile care
conin cel puin trei numere ntregi.
19. Se consider o matrice A de caractere. S se determine cte din
caracterele lui A sunt vocale.
20. Se consider o matrice A de caractere. S se determine cte din
caracterele lui A sunt cifre.
Rezolvare:
#include <stdio.h>
void main()
{
char a[10][10];
int ncifre;
199

int m,n,i,j;
printf("Dati m,n:"); scanf("%d%d",&m,&n);
for (i=0; i<m; i++)
for (j=0; j<n; j++)
{
printf("Dati a[%d,%d]:",i,j);
scanf("%1s",&a[i][j]);
}
ncifre=0;
for (i=0; i<m; i++)
for (j=0; j<n; j++)
if ((a[i][j]>='0') && (a[i][j]<='9'))
ncifre++;
printf("Numarul de cifre depistate in matrice:
%d",ncifre);
}

21. Se consider o matrice A de iruri de caractere. S se determine cte


elemente ncep cu o vocal i cte ncep cu o consoan.
22. Se consider o matrice A de iruri de caractere. S se determine cte
elemente ncep i se termin cu aceeai liter.
23. Se consider o matrice A de iruri de caractere. S se nlocuiasc fiecare
apariie a unui ir palindrom (adic identic cu oglinditul su) cu irul din colul
dreapta-sus al lui A.
24. Se consider o matrice A de iruri de caractere. S se elimine din A toate
liniile i apoi toate coloanele care conin mai puin de 4 iruri de lungime par.
25. Se consider o matrice A de iruri de caractere. S se creeze o matrice B
de numere ntregi, care s conin lungimile irurilor de caractere din A.
26. Se consider o matrice A de caractere. S se formeze i s se afieze irul
reprezentnd concatenarea elementelor de pe diagonala secundar.
27. Se consider o matrice A de caractere. S se formeze i s se afieze irul
reprezentnd concatenarea tuturor vocalelor ntlnite n matrice, la o
parcurgere pe vertical i de sus n jos a sa.
28. Se consider o matrice A de iruri de caractere. S se formeze o matrice B
de iruri de caractere care s conin oglinditele elementelor din A.
29. Se consider o matrice A de iruri de caractere. S se formeze o matrice A
de iruri de caractere care s conin irurile din A, dup ce s-au eliminat
200

primul i ultimul caracter din A (se presupune c elementele din A au cel puin
dou caractere).
30. Se consider o matrice ptratic A de iruri de caractere. S se obin
transpusa acestei matrice i s se afieze ambele matrici.
Rezolvare:
#include <stdio.h>
void main()
{
char a[10][10];
int n,i,j;
printf("Dati n:"); scanf("%d",&n);
for (i=0; i<n; i++)
for (j=0; j<n; j++)
{
printf("Dati a[%d,%d]:",i,j);
scanf("%1s",&a[i][j]);
}
printf("Matricea initiala:\n");
for (i=0; i<n; i++)
{
for (j=0; j<n; j++)
printf("%3c",a[i][j]);
printf("\n");
}
int aux;
for (i=0; i<n; i++)
for (j=0; j<i; j++)
{
aux=a[i][j];
a[i][j]=a[j][i];
a[j][i]=aux;
}
printf("Matricea finala:\n");
for (i=0; i<n; i++)
{
for (j=0; j<n; j++)
printf("%3c",a[i][j]);
printf("\n");
}
}

31. Se consider o matrice ptratic A de iruri de caractere, de dimensiuni


pare. Se mparte matricea n patru zone ptratice identice. S se determine
dac un anumit ir de caractere se gsete n prima zon, nu se gsete n a
doua, iar oglinditul su se gsete ntr-una din celelalte dou zone.

201

32. Se consider o matrice ptratic A de numere ntregi, de dimensiuni pare.


Se mparte matricea n patru zone ptratice identice. S se determine dac
suma elementelor din prima zon este numr par, dac produsul elementelor
din zona a doua este mai mic dect maximul dintre suma elementelor pozitive
din zona a treia i numrul de elemente impare negative din zona a patra.
33. Se consider o matrice A de numere reale, de dimensiuni m, n i o matrice
B de numere reale, de dimensiuni n, p. Se cere s se determine matricea C de
dimensiuni m, p, care s reprezinte produsul lui A cu B.
Rezolvare:
#include <stdio.h>
typedef

int matrice[10][10];

void citeste_matricea(char nume, matrice a,


int * nlinii, int * ncoloane)
{
int i,j;
printf("Dati numarul de linii ale matricei %c: ",nume);
scanf("%d",nlinii);
printf("Dati numarul de coloane ale matricei %c: ",nume);
scanf("%d",ncoloane);
for (i=0; i<*nlinii; i++)
for (j=0; j<*ncoloane; j++)
{
printf("Dati %c[%d,%d]: ",nume,i,j);
scanf("%d",&a[i][j]);
}
}
void scrie_matricea(char nume, matrice a, int nl, int nc)
{
printf("Matricea %c este:\n",nume);
int i,j;
for (i=0; i<nl; i++)
{
for (j=0; j<nc; j++)
printf("%3d",a[i][j]);
printf("\n");
}
}
void main()
{
int m,n,p,i,j,k;
matrice a,b,c;
citeste_matricea('a',a,&m,&n);
scrie_matricea('a',a,m,n);
citeste_matricea('b',b,&n,&p);
scrie_matricea('b',b,n,p);
202

/* inmultirea matricilor */
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];
}
scrie_matricea('c',c,m,p);

34. Se consider dou matrice de numere reale i se cere s se determine


suma i diferena acestora.
35. Se consider dou matrice de numere reale. S se determine o matrice n
care fiecare element este minimul dintre elementele corespunztoare din cele
dou matrice.
36. Se consider o matrice de numere reale. S se formeze dou matrice de
numere reale, n prima memorndu-se prile ntregi, iar n a doua prile
fracionare ale elementelor corespunztoare din matricea dat.
37. Se consider o matrice ptratic de numere reale. S se formeze dou
matrice de numere reale, n prima pstrndu-se ptratele elementelor
corespunztoare din matricea dat, iar n a doua suma dinte matricea dat i
transpusa matricei ptratelor.
38. S se memoreze ntr-o matrice cu m linii i n coloane primele mn numere
prime, care citite invers sunt tot numere prime. Memorarea se va face de la
stnga la dreapta i de sus n jos.
39. Se citesc nn elemente i se cere s se aeze ntr-o matrice ptratic A cu
n linii i n coloane, n spiral, n sensul acelor de ceasornic, pornind din colul
stnga sus ctre centru.
40. Se citesc nn elemente i se cere s se aeze ntr-o matrice ptratic A cu
n linii i n coloane, n spiral, n sensul invers acelor de ceasornic, pornind din
colul stnga sus ctre centru.
41. Se citesc nn elemente i se cere s se aeze ntr-o matrice ptratic A cu
n linii i n coloane, n spiral, n sensul acelor de ceasornic, pornind din centru
ctre margine.

203

42. Se citesc nn elemente i se cere s se aeze ntr-o matrice ptratic A cu


n linii i n coloane, n spiral, n sensul invers acelor de ceasornic, pornind din
centru ctre margine.
43. Se citesc nn elemente i se cere s se aeze ntr-o matrice ptratic A cu
n linii i n coloane, de la stnga la dreapta, pe liniile impare de sus n jos, iar
pe cele pare de jos n sus.

5. Probleme de ordonare
1. S se rearanjeze elementele unui vector x de numere ntregi, astfel nct
elementele pare s fie naintea celor impare, dar ordinea s se pstreze att la
cele pare, ct i la cele pare.
2. S se rearanjeze elementele unui vector x de numere ntregi, astfel nct
elementele pare s i pstreze ordinea, iar cele impare s fie n ordine
cresctoare.
3. S se rearanjeze elementele unui vector x de numere ntregi, astfel nct ele
s fie n ordinea descresctoare a sumelor cifrelor lor.
Rezolvare:
#include <stdio.h>
void main()
{
int x[100],n,i,j,a,aux;
scanf("%d",&n);
for (i=0; i<n; i++) scanf("%d",&x[i]);
for (i=0; i<n-1; i++)
for (j=i+1; j<n; j++)
if ((x[i] % 2 == 1) && (x[j] % 2 == 1) &&
(x[i] > x[j]))
{ aux = x[i]; x[i] = x[j] ; x[j] = aux; }
for (i=0; i<n; i++) printf("%d,",x[i]);
}

4. S se rearanjeze elementele unui vector x de numere ntregi, astfel nct


elementele prime s fie pe aceleai poziii, iar celelalte elemente s fie n
ordinea cresctoare a produsului cifrelor lor.
5. S se rearanjeze elementele unui vector x de numere ntregi, astfel nct
elementele a cror sum a cifrelor sunt numere prime s fie naintea celorlalte
elemente, n ordine cresctoare.
204

Rezolvare:
#include <stdio.h>
#include <math.h>
int prim(int m)
{
for (int i=2; i<=sqrt(m); i++)
if (m%i==0) return 0;
return 1;
}
int suma_cifre(int m)
{
int s=0;
while (m!=0)
{ s += m % 10; m/=10; }
return s;
}
void main()
{
int i,j,n,p,q,aux;
int x[100], y[100];
scanf("%d",&n);
for (i=0; i<n; i++)
scanf("%d",&x[i]);
p=0; q=n-1;
for (i=0; i<n; i++)
if (prim(suma_cifre(x[i])))
y[p++]=x[i];
else
/* Obs. elementele cu suma cifrelor neprima apar
in ordine inversa */
y[q--]=x[i];
for (i=0; i<p-1; i++)
for (j=i+1; j<p; j++)
if (y[j]<y[i])
{ aux=y[i]; y[i]=y[j]; y[j]=aux; }
for (i=0; i<n; i++)
x[i]=y[i];
for (i=0; i<n; i++)
printf("%d,",x[i]);
}

6. S se rearanjeze elementele unui vector x de numere ntregi, astfel nct


elementele pare s fie naintea celor impare, n ordine cresctoare, iar
elementele impare s fie n ordine descresctoare.
Rezolvare:
#include <stdio.h>

205

void schimba(int* a, int* b)


{
int aux = *a;
*a = *b;
*b = aux;
}
void main()
{
int aa=20; int bb=30;
schimba(&aa,&bb);
printf("%d,%d",aa,bb);
int i,j,n,p,q,aux;
int x[100];
scanf("%d",&n);
for (i=0; i<n; i++)
scanf("%d",&x[i]);
for (i=0; i<n-1; i++)
for (j=i+1; j<n; j++)
if ((x[i]%2==0) && (x[j]%2==0) && (x[i]>x[j]))
schimba(&x[i],&x[j]);
else
if ((x[i]%2==1) && (x[j]%2==1) && (x[i]<x[j]))
schimba(&x[i],&x[j]);
else
if ((x[i]%2==1) && (x[j]%2==0))
schimba(&x[i],&x[j]);
for (i=0; i<n; i++)
printf("%d,",x[i]);
}

7. S se rearanjeze elementele unui vector x de numere ntregi, astfel nct


elementele prime s fie naintea celorlalte, n ordine descresctoare, iar
elementele rmase s fie n ordinea cresctoare a produsului cifrelor impare
ale lor.
8. S se rearanjeze elementele unui vector x de numere ntregi, astfel nct
elementele pozitive s fie naintea celor negative, acestea din urm fiind puse
n ordine descresctoare a numrului lor de cifre.
9. Se consider o matrice A de numere reale. S se rearanjeze coloanele n
ordinea cresctoare a numrului de elemente nule pe care le conin.
Rezolvare:
#include <stdio.h>
void main()
{
int a[10][10], nnule[10];
int m,n,i,j;
206

printf("Dati m,n:"); scanf("%d%d",&m,&n);


for (i=0; i<m; i++)
for (j=0; j<n; j++)
{
printf("Dati a[%d,%d]:",i,j);
scanf("%d",&a[i][j]);
}
printf("Matricea initiala:\n");
for (i=0; i<m; i++)
{
for (j=0; j<n; j++)
printf("%3d",a[i][j]);
printf("\n");
}
for (j=0; j<n; j++)
{
nnule[j]=0;
for (i=0; i<m; i++)
if (a[i][j]==0) nnule[j]++;
}
int k, aux;
for (j=0; j<n-1; j++)
for (k=j+1; k<n; k++)
if (nnule[k]<nnule[j])
for (i=0; i<m; i++)
{ aux=a[i][j];
a[i][j]=a[i][k];
a[i][k]=aux; }
printf("Matricea finala:\n");
for (i=0; i<m; i++)
{
for (j=0; j<n; j++)
printf("%3d",a[i][j]);
printf("\n");
}

10. Se consider o matrice A de numere reale. S se rearanjeze coloanele n


ordinea cresctoare a numrului de elemente cu suma cifrelor divizibil prin 3.
11. Se consider o matrice A de numere reale. S se rearanjeze liniile n
ordinea descresctoare a numrului de elemente identice cu elementul cel mai
mic din matrice.
12. Se consider o matrice A de numere reale. S se rearanjeze liniile n
ordinea descresctoare a numrului de elemente pozitive impare pe care le
conin.
13. Se consider o matrice A de numere reale. S se rearanjeze elementele
matricii astfel nct ele s fie dispuse n ordine cresctoare de la stnga la
dreapta i de sus n jos.
207

14. Se consider o matrice A de iruri de caractere. S se formeze o matrice B


de iruri de caractere n care se regsesc elementele din A aezate n ordine
alfabetic, de la stnga la dreapta i de sus n jos.
15. Se consider o matrice A de iruri de caractere. S se formeze o matrice B
de iruri de caractere n care se regsesc elementele din B aezate n ordine
invers a lungimilor lor, de la stnga la dreapta i de sus n jos.

6. Probleme cu structuri
1. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, nota1, nota2 i media de tip real. Presupunnd cunoscute notele,
se cere s se calculeze mediile i s se ordoneze elevii descresctor dup
medii.
2. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, nota1, nota2 i media de tip real. Presupunnd cunoscute notele,
se cere s se calculeze mediile i s se ordoneze elevii n ordinea alfabetic a
numelor. Pentru nume identice, se vor ordona alfabetic dup prenume.
3. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, nota1, nota2 i media de tip real. Presupunnd cunoscute
prenumele elevilor, s se determine sexul fiecrui elev dup regula: dac
prenumele se termin n "a", atunci sexul este feminin, cu excepia numelor
precum "Mihnea", "Luca", "Horia", "Mircea", iar dac prenumele nu se termin
n "a", atunci sexul este masculin, cu excepia numelor precum "Carmen",
"Alice", ""Beatrice".
4. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, nota1, nota2 i media de tip real. Presupunnd cunoscute mediile
s se ordoneze elevii descresctor dup medii, iar pentru medii egale, alfabetic
dup nume i prenume.
5. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, nota1, nota2 i media de tip real. Presupunnd c se cunoate
sexul fiecrui elev, s se listeze mai nti fetele n ordinea invers alfabetic a
prenumelor, apoi bieii n ordinea alfabetic a numelor.
208

6. Se consider o structur pentru stocarea datelor despre n elevi, avnd


cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, media de tip real i admis de tip logic (sau ntreg). Presupunnd
cunoscute mediile s se modifice cmpul admis astfel nct doar primii m elevi
s fie considerai admii.
7. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, media de tip real i admis de tip logic (sau ntreg). Presupunnd
cunoscute mediile s se modifice cmpul admis astfel nct doar elevii avnd
medii peste o valoare citit de la tastatur s fie considerai admii.
8. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, media de tip real i admis de tip logic (sau ntreg). S se modifice
cmpurile admis astfel nct s fie considerai admii toi bieii cu medii peste
8 i toate fetele cu medii peste 7.
9. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, media de tip real i admis de tip logic (sau ntreg). S se modifice
cmpurile admis astfel nct s fie considerai admii toi elevii a cror nume
ncepe cu o consoan, iar media este peste 8.
10. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, media de tip real i admis de tip logic (sau ntreg). S se modifice
cmpurile admis astfel nct s fie considerai admii doar prima jumtate
dintre elevi, dup o aranjare alfabetic a lor (dup nume i prenume).
11. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, media de tip real i admis de tip logic (sau ntreg). S se elimine
din lista elevilor elevii neadmii i elevii care au numele mai mare de 8
caractere.
12. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, media de tip real i admis de tip logic (sau ntreg). S se elimine
din lista elevilor fetele.

209

13. Se consider o structur pentru stocarea datelor despre n elevi, avnd


cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, media de tip real i admis de tip logic (sau ntreg). S se elimine
din lista elevilor bieii avnd prenumele din trei litere.
14. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, media de tip real i admis de tip logic (sau ntreg). S se obin o
list a fetelor i una a bieilor, apoi s se afieze cele dou liste pe dou
coloane paralele, pe ecran.
15. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, media de tip real i admis de tip logic (sau ntreg). S se elimine
din lista elevilor bieii care sunt cuprini, n list, ntre dou fete.
16. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, media de tip real i admis de tip logic (sau ntreg). S se elimine
din lista elevilor fetele peste 18 ani i s se calculeze media de vrst a fetelor
rmase.
17. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, media de tip real i admis de tip logic (sau ntreg). S se elimine
din lista elevilor bieii cuprini ntre dou fete avnd peste 18 ani i s se
calculeze media de vrst a elevilor rmai.
18. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, media de tip real i admis de tip logic (sau ntreg). S se insereze
n list, ntre oricare dou persoane, o nou persoan avnd numele persoanei
dinainte i prenumele persoanei de dup, iar media egal cu a unei persoane
aleas la ntmplare din list.
19. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, media de tip real i admis de tip logic (sau ntreg). S se insereze
n list, dup fiecare persoan, o nou persoan care s aib prenumele
"Ionescu" i prenumele persoanei dinainte, dac aceasta este o fat, respectiv
"Popescu" i prenumele persoanei dinainte, dac aceasta este un biat.

210

20. Se consider o structur pentru stocarea datelor despre n elevi, avnd


cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, media de tip real i admis de tip logic (sau ntreg). S se
interschimbe prenumele elevilor astfel: al primului cu al ultimului, celui de al
doilea cu al penultimului .a.m.d..
21. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, media de tip real i admis de tip logic (sau ntreg). S se insereze
n list, ntre oricare dou persoane, o nou persoan avnd un numr de ani
ales la ntmplare ntre 15 i 20, precum i prenumele persoanei dinainte i
numele "Popescu", apoi s se determine media de vrst a tuturor persoanelor
din lista modificat.
22. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, media de tip real i admis de tip logic (sau ntreg). S se adauge
listei o persoan a crei date s fie alese la ntmplare din datele celorlalte
persoane din list (de exemplu numele de la o persoan, prenumele de la alta,
vrsta de la alta .a.m.d.). S se verifice dac numele noii persoane este
compatibil cu sexul ei. Se va ine cont de ultima liter din prenume i de faptul
c "Horia", "Mircea", "Mihnea" sau "Luca" sunt nume de biei, pe cnd "Alice",
"Beatrice" sau "Carmen" nume de fete.
23. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, media de tip real i admis de tip logic (sau ntreg). S se
determine media de vrst a fetelor i numrul bieilor cu medii mai mari
dect 8.
24. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, media de tip real i admis de tip logic (sau ntreg). S se
determine media de vrst a bieilor a cror prenume ncepe cu o liter din
prima jumtate a alfabetului, precum i numele celor mai tinere fete.
25. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, media de tip real i admis de tip logic (sau ntreg). S se
determine cte fete se numesc "Laura", "Alina" sau "Mihaela" i cte din
acestea au lng ele un biat mai mare de 16 ani.
211

26. Se consider o structur pentru stocarea datelor despre n elevi, avnd


cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, media de tip real i admis de tip logic (sau ntreg). S se
determine care valoarea mediei mediilor tuturor elevilor, apoi s se nlocuiasc
toate mediile mai mici dect valoarea rezultat cu aceasta.

7. Probleme cu fiiere
1. S se copieze coninutul unui fiier text n alt fiier text.
2. S se afieze coninutului unui fiier text pe ecran.
3. S se afieze, pagin cu pagin, coninutul unui fiier text, pe ecran.
Trecerea la urmtoarea pagin se va realiza apsnd o tast.
4. Se d un fiier text. S se creeze un alt fiier text care s conin toate liniile
din primul fiier, care au cel puin dou cuvinte (cuvintele se consider
separate de spaii sau unul din simbolurile ".", ",", ";").
5. Se d un fiier text. S se creeze un alt fiier text care s conin toate liniile
din primul fiier, mai puin cele de lungime par care ncep cu o vocal.
6. Se d un fiier text. S se creeze un alt fiier text care s conin toate liniile
din primul fiier, mai puin cele care conin un numr impar de consoane.
7. Se d un fiier text. S se elimine din el toate liniile de ordin impar.
8. Se d un fiier text. S se elimine din el toate liniile de ordin par, care conin
un numr impar de vocale.
9. Se d un fiier text. S se elimine din el toate liniile care conin un numr
impar de litere "A" i care ncep cu litera "B".
10. Se dau dou fiiere text. S se verifice dac cele dou fiiere au coninuturi
identice.
11. Se d un fiier text, cu maxim 100 de linii. S se ordoneze alfabetic liniile n
acest fiier.
12. Se d un fiier text. Se cere s se nlocuiasc fiecare linie cu oglindita sa.

212

13. Se d un fiier text, coninnd numere, separate prin spaii. Se cere s se


determine dac exist linii care s conin numere prime n ele, iar dac da,
cte.
14. Se consider un fiier text care conine m linii, pe fiecare linie cte n
numere ntregi. S se citeasc acestea ntr-o matrice A cu m linii i n coloane,
apoi s se afieze matricea A pe ecran.
15. Se dau dou fiiere text. S se alipeasc cele dou fiiere ntr-un al treilea.
16. Se consider o matrice A de numere ntregi, citit de la tastatur. S se
scrie coninutul matricei i al transpusei matricei ntr-un fiier text.
17. Se d un numr n natural. S se scrie ntr-un fiier text urmtorul triunghi
de numere:
1
12
123
..........
1 2 3 ... n
18. Se d un fiier text cu maxim 100 linii. S se creeze un alt fiier text care
s conin liniile din fiierul iniial, dispuse n ordine invers.
19. Se d un fiier text. S se preia liniile acestui fiier ntr-un vector de iruri
de caractere, apoi s se ordoneze vectorul, alfabetic i s se adauge n fiierul
text dat.
20. S se nlocuiasc fiecare apariie a unui ir de caractere S ntr-un fiier text
cu alt ir T.
21. S se elimine dintr-un fiier text toate apariiile unui ir de caractere S.
22. Se consider o structur pentru stocarea datelor despre n elevi, avnd
cmpurile: nume i prenume de tip ir de caractere, sex de tip caracter, vrst
de tip ntreg, media de tip real i admis de tip logic (sau ntreg). S se scrie un
program care s execute operaii de tergere, adugare, modificare i
consultare a datelor despre aceti elevi. De asemenea, se cere ca lista de
elevi s poat fi salvat ntr-un fiier text i preluat de acolo.
23. S se numere de cte ori apare un ir S, mrginit de spaii sau
nceput/sfrit de rnd, n cadrul unui fiier text.
213

24. Se d un fiier text. S se nlocuiasc fiecare apariie a unui ir care


ncepe cu liter mare i este mrginit cu spaii sau nceput/sfrit de rnd cu
oglinditul irului respectiv.

8. Probleme cu funcii recursive


1. S se scrie o funcie recursiv care s caute (secvenial) un element
a ntr-un vector x cu n componente.
2. S se scrie o funcie recursiv care s caute binar un element a ntrun vector x, ntre indicii s i d.
3. S se scrie o funcie recursiv care s determine suma elementelor
unui vector x de n numere ntregi.
4. S se scrie o funcie recursiv care s determine produsul
elementelor pare dintr-un vector x de n numere ntregi.
5. S se scrie o funcie recursiv care s determine suma elementelor
negative dintr-un vector x de n numere ntregi.
6. S se scrie o funcie recursiv care s determine suma ptratelor
elementelor de pe poziii impare dintr-un vector x de n numere ntregi.
7. S se scrie o funcie recursiv care s verifice dac ntr-un vector x
de n numere ntregi exist mcar un element prim.
8. S se scrie o funcie recursiv care s verifice dac ntr-un vector x
de n numere ntregi exist mcar un element pozitiv divizibil prin 3.
9. S se scrie o funcie recursiv care s verifice dac ntr-un vector x
de n numere ntregi exist mcar un element cu suma cifrelor divizibil
prin 3.
10. S se scrie o funcie recursiv pentru a determina suma elementelor
negative impare dintr-un vector x de n numerentregi.
11. S se scrie o funcie recursiv pentru a determina cel mai mare
divizor comun al elementelor dintr-un vector x cu n numere ntregi
pozitive.

214

12. S se scrie o funcie recursiv care s determine cel mai mare


element dintr-un vector.
13. S se scrie o funcie recursiv pentru a determina cel mai mic
element negativ impar dintr-un vector de numere ntregi.
14. S se scrie o funcie recursiv pentru a determina cel mai mic
element n valoare absolut dintr-un vector de numere ntregi.
15. S se scrie o funcie recursiv pentru a determina dac exist un
element negativ cu suma cifrelor pozitive impar ntr-un vector de
numere ntregi.

215

Bibliografie
Bogdan Ptru
Herbert Schildt
K. Jamsa, L. Klauder
Liviu Negrescu
Grigore Albeanu

- Aplicaii n C i C++, Editura Teora, Bucureti,


1998-2004
- C - manual complet, Editura Teora, Bucureti, 2002
- Totul despre C si C++, manual fundamental de
programare in C si C++, Editura Teora, Bucurei,
2003
- Introducere n limbajul C, Editura Mictoinformatica,
Cluj-Napoca
- Programarea n Pascal i Turbo Pascal. Culegere
de probleme, Editura Tehnic, Bucureti, 1994

Valeriu Iorga, Eugenia


Kalisz, Cristian pu

- Concursuri de programare. Probleme i soluii,


Editura Teora, Bucureti, 1997

Dorel Lucanu

- Proiectarea algoritmilor. Tehnici elementare,


Editura Universitii "Al. I. Cuza" Iai, 1993

Emanuela Mateescu,
Ioan Maxim

- Arbori, Editura ara Fagilor, Suceava, 1996

Victor Mitrana

- Provocarea algoritmilor. Probleme pentru


concursurile de informatic, Editura Agni, Bucureti,
1994

Doina Rancea

- Limbajul Turbo Pascal, Editura Libris, Cluj, 1994

Dennis M. Ritchie,
Brian. W. Kernighan

- The C Programming Language, Prentice-Hall, Inc.,


Eaglewood Cliffs, New Jersey, 1978

Bogdan Ptru

- nvai limbajul Pascal n 12 lecii, Editura Teora,


Bucureti 1997

Bogdan Ptru

- Aplicaii n Visual Basic, Editura Teora, Bucureti,


1998-2004

Bogdan Ptru

- Aplicaii n Delphi, Editura Teora, Bucureti, 20012004


- Tehnici de programare, Editura Teora, Bucureti,
1994
- Colecia Gazeta de matematic, 1996-1997,
Editura Libris, Cluj

Sorin Tudor
***

216

CUPRINS

Introducere

Capitolul 0. Scurt introducere n limbajul C

Capitolul 1. Elemente de baz ale limbajului C/C++


Capitolul 2. Tablouri i pointeri
Capitolul 3. Recursivitate

32

56

74

Capitolul 4. Structuri i tipuri definite de programator


Capitolul 5. Exploatarea fiierelor

116

Capitolul 6. Algoritmi de teoria grafurilor


Capitolul 7. Grafic n C/C++

89

128

135

Capitolul 8. Programare orientat pe obiecte n Borland C++


Capitolul 9. Probleme recapitulative
Bibliografie

216

217

166

153

Vizitai www.edusoft.ro !
Cri i software educaional

218

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