Aplicatii C CPP Patrut
Aplicatii C CPP Patrut
Aplicatii C CPP Patrut
APLICAII
N
C i C + +
Editura EduSoft
Bacu - 2006
Editura EduSoft
600065 Bacu, str. 9 Mai, nr. 82, sc. C, ap. 13
E-mail: [email protected], 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.
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
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
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
- 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
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
selecie
iteraie
salt
expresie
eticheta
bloc
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
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
i=0; s=0;
while (i<n) {s+=i; i++}
21
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
}
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
27
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
# 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
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>
void main()
{
int g, p;
#include <stdio.h>
void main()
Se declar cele trei variabile reale:
{
float a,b,x;
Apoi se citete 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);
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
verifica
aceasta
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;
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
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);
}
dar nu i aa:
#include <stdio.h>
void main()
{ int x=3; printf("Adresa lui x: %ld",&x); }
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));
}
printf("Dati n: ");
scanf("%d",&n);
printf("2^%d = %d\n",n,m=(m<<n));
39
#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.
#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();
}
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);
}
41
putchar('\n');
}
/* marginea de jos */
putchar(LEFT_BOT);
for (i=0; i<n; i++)
putchar(HORIZ);
putchar(RIGHT_BOT);
putchar('\n'); getch();
#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);
}
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;
}
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();
}
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();
}
#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.
47
Probleme propuse
1.
2.
3.
4.
5.
6.
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.
42.
43.
44.
45.
46.
47.
48.
49.
50.
P = (1
51.
52.
1
1
1
)
(
1
)
...(
1
).
22
32
n2
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
52
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
distana euclidian de la A la B;
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
55
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);
}
56
int c, i;
for (i=0; i < limita-1 && (c = getchar()) != EOF
&& c != '\n'; ++i)
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]
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...");
}
#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.
#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));
}
#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();
}
#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
ch;
i;
l;
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.
64
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
e = x1+x3+...+x..;
e = x0x1x2...xn;
e = x1x3x5...x..;
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];
e=(x0+y0)(x1+y1)...(xn-1+yn-1);
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.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
69
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
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:
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
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.
#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
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,
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);
}
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.
#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);
}
80
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
}
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];
{"##### ####",
"### # ####",
"###
####",
83
"
# ####",
"### # ####",
"#
##",
" ## #####",
"#### #####"};
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");
}
}
void main()
{
clrscr();
// afisam labirintul
int i,j;
84
Probleme propuse
1.
2.
3.
4.
5.
6.
7.
8.
9.
85
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
88
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
*p = valoare;
citeste1(q,'q');
92
citeste(&a,'a'); scrie(a,'a');
citeste(&b,'b'); scrie(b,'b'); printf("\n");
93
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
95
}
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();
}
97
#include
#include
#include
#include
<string.h>
<stdio.h>
<conio.h>
<stdlib.h>
}
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();
}
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
#include "mouset.h"
#include <conio.h>
Observaii:
1. S considerm funcia de baz a lui mouset.h:
a1 = regs.r_ax;
regs.r_dx;
}
a2
regs.r_bx;
a3
regs.r_cx;
a4
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();
}
103
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
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
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);
Probleme propuse
1.
2.
3.
4.
5.
6.
7.
calcularea mediilor;
111
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
112
23.
24.
25.
NULL
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
114
linia de intrare
linia de ieire
linia de manevr
40.
41.
42.
43.
44.
45.
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
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.
if (!strcmp(nume_fis,"")) return;
Se declar o variabil:
FILE *f;
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
ordonat=1;
Observaie. Valoarea
nregistrarea curent!
returnat
reprezint
octetul
curent,
size_t
fread(void
*p,
size_t
120
m,
nu
fread(&p,sizeof(struct
fread(&q,sizeof(struct persoana),1,f);
persoana),1,f);
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;
}
fseek(f,poz+lung_pers,SEEK_SET);
fclose(f);
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.
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);
}
#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.
8.
9.
10.
11.
12.
13.
14.
15.
126
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
127
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();
}
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();
Probleme propuse
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
132
14.
15.
16.
10
11
12
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
Probleme rezolvate
1.
1/f = 1/x1-1/x2,
#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
}
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);
}
2.
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 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.
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
db
db
db
db
db
db
dw
db
dw
db
db
db
;
;
;
;
;
;
;
;
;
;
;
;
;
80h '+'
81h-82h
83h
84h
85h-86h
87h
88h
89h
90h
91h-95h
96h
96h+2n
96h+3n
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>
/*
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;
#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 );
}
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);
}
}
WriteChar(cuvint[i], 0, x, y, x, y);
x += Char_Width[cuvint[i]];
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.
21.
:
Aceeai problem pentru fiecare din cele dou figuri de mai jos:
151
22.
23.
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.
153
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:
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
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.
#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.
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 .....
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
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");
}
}
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");
}
}
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");
}
}
//
//
//
//
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);
}
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);
}
172
174
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());
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]);
}
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]);
}
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]);
}
178
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]);
}
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]);
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]);
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]);
}
else
y[i]=suma_cifre(x[n-i+1]);
for (i=1; i<=n/2; i++)
printf("%d,",y[i]);
printf("%d,",x[i]);
184
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]);
186
}
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);
}
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);
}
191
192
193
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);
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);
196
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);
}
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");
}
}
201
int matrice[10][10];
/* 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);
203
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]);
}
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]);
}
205
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
209
210
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
214
215
Bibliografie
Bogdan Ptru
Herbert Schildt
K. Jamsa, L. Klauder
Liviu Negrescu
Grigore Albeanu
Dorel Lucanu
Emanuela Mateescu,
Ioan Maxim
Victor Mitrana
Doina Rancea
Dennis M. Ritchie,
Brian. W. Kernighan
Bogdan Ptru
Bogdan Ptru
Bogdan Ptru
Sorin Tudor
***
216
CUPRINS
Introducere
32
56
74
116
89
128
135
216
217
166
153
Vizitai www.edusoft.ro !
Cri i software educaional
218