Professional Documents
Culture Documents
PROGRAMAREA CALCULATOARELOR
2006
Ministerul Educaţiei şi Cercetării
Proiectul pentru Învăţământul Rural
TEHNOLOGIA INFORMAŢIEI
Programarea calculatoarelor
2006
© 2006 Ministerul Educaţiei şi Cercetării
Proiectul pentru Învăţământul Rural
ISBN 10 973-0-04555-0;
ISBN 13 978-973-0-04555-0.
Cuprins
CUPRINS
ANEXE
BIBLIOGRAFIE............................................................................................................... 201
INTRODUCERE
Obiectivele modulului
După studiul modulului Programarea calculatoarelor, veţi reuşi să:
Temă de reflecţie
Atenţie!
Temă de reflecţie
Spaţiu
pentru
răspuns
Atenţie!
Sarcină de lucru
Atenţie!
Temă de reflecţie
Atenţie!
Cuprins Pagina
Un algoritm este compus din unul sau mai mulţi paşi, un pas reprezentând
efectuarea unei singure operaţii din şirul celor care alcătuiesc algoritmul.
Exemplul 1.1
Tabelul 1.1
Acest algoritm se foloseşte pentru obţinerea celui mai mare divizor comun
a două numere naturale. Notăm cele două numere naturale a şi b.
Algoritmul constă din efectuarea unui şir de împărţiri întregi până când se
obţine un rest nul. Pentru fiecare împărţire care se efectuează, împărţitorul
este restul împărţirii precedente, iar deîmpărţitul este împărţitorul din
împărţirea precedentă. Împărţitorul din ultima împărţire efectuată constituie
cel mai mare divizor comun al celor două numere.
Pasul Operaţia
78: 30 = 2 rest 18 împărţire
18=0 ? nu verificare
30: 18 =1 rest 12 împărţire
12 = 0 ? nu verificare
18: 12 = 1 rest 6 împărţire
6=0 ? nu verificare
12: 6 =2 rest 0 împărţire
0=0 ? da verificare
Tabelul 1.2
Adevărat / Fals
4. Aplicând algoritmul lui Euclid pentru numerele 84 şi 20, vor fi efectuate 2 împărţiri. A/F
5. Algoritmul lui Euclid nu se poate aplica dacă primul număr este mai mic decât al doilea.
A/F
naturale, mai puţin zero (N* x N*). Această propietate este cunoscută şi
sub numele de universalitate.
Exemplul 1.2
Un dreptunghi are baza de 2,75 şi înălţimea de 1,4 unităţi. Care sunt aria
şi perimetrul dreptunghiului?
Remarcăm că persoana care rezolvă această problemă trebuie să aibă o serie de cunoştinţe: ce este un
dreptunghi, ce sunt baza şi înălţimea dreptunghiului, care sunt formulele de calcul pentru aria şi perimetrul
dreptunghiului, care sunt unităţile de măsură şi relaţiile dintre ele. Pe baza acestor cunoştinţe, persoana
respectivă deduce că:
- 2,75 şi 1,4 sunt de fapt măsurile bazei şi respectiv înălţimii dreptunghiului, exprimate în unităţi dimensionale
de lungime;
- aria se poate calcula aplicând formula arie = baza * înălţime (unde '*' este operatorul de înmulţire);
- perimetrul se poate calcula cu formula perimetru = (baza +înălţime)*2;
Dacă am dori ca şi calculatorul să rezolve această problemă la fel cum o face omul, ar trebui să aibă
aceleaşi cunoştinţe, ceea ce se încearcă acum să se realizeze în cadrul sistemelor de inteligenţă artificială
prin sisteme de programe adecvate acestui scop. Calculatorul în sine este însă o simplă "maşină", care
poate executa fidel, rapid şi bine nişte comenzi, dar nu înţelege ceea ce face.
Întreaga responsabilitate a rezolvării problemei revine celui care întocmeşte "programul", care trebuie să
stabilească succesiunea de instructiuni (comenzi) pe care trebuie să le execute calculatorul pentru a rezolva
problema. Să vedem deci cum am putea concepe o succesiune de instrucţiuni, a cărei executare de către
sistem (fie acesta un om sau o maşină) să conducă de la ce "se dă" la ce "se cere" în problema de mai sus,
fără a fi necesar ca sistemul să cunoască problema sau, cu atât mai mult, să o înţeleagă.
Vom considera că sistemul care rezolvă problema primeşte pe un anumit "suport de intrare" (de exemplu pe
o hârtie, în cazul omului, sau de la tastatură, în cazul calculatorului) două numere reale, despre care noi ştim
că sunt baza şi înălţimea unui dreptunghi, dar el nu ştie. Numim aceste numere date de intrare, deoarece ele
sunt introduse de noi în sistem. Vom considera, de asemenea, că rezultatele obţinute vor trebui scrise de
sistem pe un alt suport, care poate fi citit de către om (de exemplu pe o hârtie sau pe un ecran), şi le vom
numi date de ieşire, deoarece ele sunt transmise de sistem către exteriorul său. Pentru a "rezolva problema",
sistemul trebuie să preia datele de intrare (fără să cunoască semnificaţia lor în problemă), să verifice dacă
sunt valabile şi să le înregistreze în memorie. Asupra lor trebuie să aplice apoi nişte operaţii de calcul, pe
baza cărora să obţină rezultatele cerute. Aceste rezultate vor fi şi ele înregistrate în memorie, atunci când
sunt obţinute. În fine, rezultatele trebuie transmise în exterior sub forma de date de ieşire.
Iată succesiunea de instrucţiuni care trebuie executate de către sistem pentru a rezolva problema dată:
Se observă imediat că, pentru a executa aceste instrucţiuni, sistemul nu trebuie să cunoască problema, ci
doar să "ştie" modul în care se realizează fiecare operaţie cuprinsă în ele: citire de pe suportul de intrare,
scriere pe suportul de ieşire, comparaţie, memorare (înregistrare în memorie), înmulţire, adunare, oprirea
execuţiei. Remarcăm, de asemenea, că în aceste instructiuni se operează cu nişte numere sau texte care nu
au pentru sistem nici o altă semnificaţie. Astfel de "materiale supuse prelucrarii" care nu au pentru sistem
nici o altă semnificaţie se numesc date, iar ansamblul tuturor instrucţiunilor (comenzilor) care trebuie
executate astfel încât, pornind de la datele de intrare, să se obţină datele de ieşire, se numeste algoritm.
Dacă algoritmul se execută de către un calculator, fiecare dată (de intrare, de ieşire sau rezultat intermediar)
este înregistrată în memoria internă a acestuia la o anumită adresă care este un număr. În consecinţă,
instrucţiunea 1, de exemplu, ar fi trebuit scrisă astfel:
La fel ar fi trebuit să procedăm şi cu celelalte date, fie ele de intrare, de ieşire sau auxiliare. Evident că,
pentru om, o astfel de notaţie este foarte incomodă. Din această cauză, în algoritmi şi în programe se
preferă să se folosească pentru indicarea locului în care se găsesc datele în memorie nişte nume simbolice,
numite variabile. Conversia acestor nume de variabile în adrese de memorie este una din sarcinile care revin
compilatorului, atunci când generează programul binar. Este deci bine să reţinem că, din punctul de vedere
al compilatorului, variabilele sunt nume date adreselor de memorie la care sunt plasate anumite date.
1. Citeşte b;
2. Citeşte i;
3. Dacă b<=0
atunci Scrie "datele de intrare sunt greşite"; Stop;
4. Calculează A= b*i;
5. Calculează d=b+i;
6. Calculează p=d*2;
7. Scrie "aria dreptunghiului este " A;
8. Scrie "perimetrul dreptunghiului este " p;
9. Stop.
5. Numărul de paşi ce trebuie să fie executaţi într-un algoritm trebuie să fie .....................,
iar această propietate poartă denumirea de .......................
“Nivelul“ unui limbaj este apreciat prin poziţia pe care o ocupă pe scara constituită de limbajul
recunoscut de microprocesor (limbaj maşină) şi limbajul natural al programatorului (limba română,
limba engleză …).
Un limbaj de nivel scăzut este foarte apropiat de maşină, el manipulează cu elemente de nivel
hardware, fizic, cum ar fi: registru, microprocesor, locaţie de memorie, port de intrare / ieşire, etc.
Un limbaj de nivel înalt sau foarte înalt manipulează cu concepte apropiate de limbajul natural,
concepte de nivel logic, cum ar fi: colecţie de date, nume de operaţie (sort, writeln, open), variabile,
constante (asemănătoare ca înţeles cu cele din matematică).
Cu ajutorul unui limbaj de nivel înalt programatorul se face mult mai uşor înţeles de către
calculator. Uneori o singură limie de program scrisă cu un astfel de limbaj poate echivala cu sute
de linii de program scrise în limbaj maşină. Deci din punct de vedere al reducerii timpului de
realizare a unui program şi al siguranţei în funcţionare (absenţa erorilor de programare)este de
preferat un limbaj de nivel cât mai ridicat (înalt sau foarte înalt). În schimb, pe măsură ce limbajul
are un nivel mai ridicat, execuţia programului conceput cu ajutorul său va fi mai lentă, decât a unui
program ce realizează aceleaşi operaţii dar este scris în limbaj de asamblare.
O altă diferenţă esenţială între cele două tipuri de limbaje o reprezintă portabilitatea, adică
posibilitatea transferării programelor pe un alt tip de maşină decât cea pe care au fost construite.
Din acest punct de vedere limbajul de asamblare este neportabil, deoarece el este specific
microprocesorului. Programele realizate pe un tip de maşină trebuie rescrise integral pentru noul
tip de maşină, folosind un nou set de instrucţiuni – care deobicei diferă foarte mult. Lucrurile stau
altfel cu programele concepute cu ajutorul unui limbaj de nivel înalt, deoarece acestea sunt
detaşate de maşină. Între un astfel de program şi calculator se interpune compilatorul (sau
interpretorul) care rezolvă corect transformarea fişierului-sursă în fişier-executabil.
Un limbaj procedural oferă posibilitatea utilizării unui nivel ridicat de concepere a unui program şi
duce la realizarea de programe coerente şi protejate la erori. Prin contrast, limbajele
neprocedurale nu favorizează programatorul în a se desprinde de nivelul “instrucţiune” şi duc
deseori la programe greu de controlat – mai ales în cazul programelor de dimensiuni mari.
Limbajele neprocedurale sunt încă preferate de unii utilizatori datorită timpului foarte scurt cât
decurge învăţarea şi utlizarea lor.
Limbaje orientate
Din punctul de vedere al aplicabilităţii unui limbaj, limbajele pot fi orientate pe o anumită problemă
sau concepute pentru soluţionarea oricărui tip de problemă – limbaje de uz general sau altfel spus,
neorientate pe o problemă.
Limbajele orientate prezintă un grad înalt de specificitate, pe când un limbaj neorientat reprezintă
un cadru general ce permite introducerea de către utilizator a conceptelor şi prelucrărilor dorite.
Deci, diferenţa esenţială dintre cele două tipuri de limbaje o constitue nivelul conceptual definit.
Cele specializate posedă deja integral suportul necesar şi permit programatorului să se
concentreze la ansamblul problemei, pe când cele nespecializate lasă în sarcina programatorului
manevrarea nivelelor inferioare ale problemei.
Limbaje concurente
Un limbaj concurent permite definirea de procese (prelucrări) paralele, execuţia sa fiind ramificată
la un anumit moment de timp. Prin contrast, limbajele neconcurente (majoritatea limbajelor) au o
desfăşurare liniară, fiind activ un singur proces la un moment dat. Procesele concurente presupun
în mod obligatoriu un sistem multi-tasking ce poate gestiona mai multe “sarcini” la un moment dat.
Aspectul unui limbaj poate fi schimbat radical de mediul de programare oferit. Pentru limbajul de
asamblare există mai multe implementări disponibile, începând cu pachete ce operează în mod
linie şi culminând cu medii integrate în care toate operaţiile se pot declanşa de la un acelaşi pupitru
de comandă.
Nu sunt luate în considerare decât aceste medii integrate (denumite generic medii Turbo), dintre
care se detaşează Turbo Asamblorul firmei Borland TASM.
BASIC
A fost creat în 1964 la Darmooth College (S.U.A.). Denumirea sa provine de la iniţialele cuvintelor
Beginner’s Allpurpose Symbolic Instruction Code (Cod de instrucţiuni simbolice, de uz general,
destinat începătorilor). Are următoarele caracteristici fundamentale:
- simplu de învăţat; instrucţiunile sale sunt cuvinte din limba engleză sau prescurtări ale
acestora;
- neorientat pe un anumit tip de problemă; permite construirea de aplicaţii;
- este un limbaj nestructurat, ceea ce îi permite să fie uşor învăţat.
Deoarece a cunoscut o largă răspândire, au fost implementate noi versiuni de Basic: GW-BASIC,
QUICK BASIC, TURBO BASIC, VISUAL BASIC (Basic for Windows).
FORTRAN
Limbajul Fortran este decanul de vârstă al limbajelor de largă folosinţă. A apărut în 1956 şi îşi
datorează numele prescurtării cuvintelor: FORmula TRANslation (Traducere de formule). Iniţial
reprezenta un limbaj orientat pe calcule ştiinţifice, având definite concepte precum: matrice, funcţii
trigonometrice, numere reale în dublă precizie. Versiunile ulterioare care au cunoscut o mare
popularitate au extins posibilităţile limbajului trasformându-l într-un limbaj eficient, de uz general.În
prezent există pentru IBM-PC două implementări mai importante ale limbajului: Microsoft Fortran,
Fortran for Windows.
Deşi nu poate fi considerat “depăşit” din punct de vedere conceptual (este un limbaj algoritmic –
structurat) este neindicată folosirea lui datorită absenţei unor medii de programare performante şi
pentru că tendinţa actuală îi este defavorabilă.
PASCAL
Conceptualizat în anul 1970 de către Niklaus Wirth, limbajul PASCAL poartă numele
matematicianului şi filosofului BLAISE PASCAL, în semn de recunoaştere a meritelor sale în
teoretizarea maşinilor de calcul.
Creat după acumularea de cunoştiinţe temeinice în ştiinţa limbajelor formale, din confruntarea cu
probleme concrete ale programării, limbajul PASCAL a constituit la vremea respectivă un limbaj
modern, menţinându-se ca atare şi în prezent, datorită faptului că posedă o solidă bază
conceptuală.
Limbajul C
Acest limbaj de programare, cu cel mai scurt nume, a fost creat în 1971 de
către Dennis Ritchie şi Brian Kernigham pentru dezvoltarea sistemului de
operare UNIX.
Limbajul ADA
A fost creat special pentru a gestiona totalitatea aplicaţiilor dezvoltate şi utilizate de N.A.S.A.
Noutatea limbajului (de tip structurat, algoritmic) o constitue concurenţa, deci posibilitatea lansării
de procese paralele (sincronizate interactiv în finalul execuţiei lor) . Saltul calitativ este evident şi
deschide un nou domeniu în programare, dar nu pentru IBM-PC. Versiunile implementărilor
limbajului ADA pe IBM-PC nu posedă tocmai acestă parte de concurenţă, reducând limbajul la un
simplu limbaj structurat de uz general. Deci, ADA este un limbaj ultramodern din punct de vedere
teoretic, dar ineficient din punct de vedere practic pentru IBM-PC-uri.
Într-un sistem de gestionare a bazelor de date (S.G.B.D.) de tip clasic datele sunt gestionate prin
intermediul unei structuri, organizată ierarhic, la un nivel de organizare logică.
Tendinţa modernă în exploatarea bazelor de date constă în deplasarea interesului către bazele de
date relaţionale. Diferenţa esenţială constă în definirea unui nivel logic suplimentar între datele
gestionate. Acestea nu mai sunt privite ca simple fişe izolate între ele ci pot fi analizate pe baza
legăturilor (relaţiilor) ce există între ele.
Spre deosebire de S.G.B.D. –urile clasice, un mediu relaţional presupune ca cerinţă minimală
posibilitatea manipulării datelor prin intermediul conexiunilor logice stabilite. Pentru aceasta există
definit (şi impus ca standard unanim recunoscut) limbajul de interogare SQL (Structured Query
Language – limbaj de cereri structurate).
dBASE III
Cel mai răspândit sistem de gestiune a bazelor de date este dBASE, în diversele lui versiuni. El
poate fi considerat un “BASIC“ al bazelor de date. La momentul apariţiei a constituit o adevărată
revoluţie în domeniul S.G.B.D.-urilor. Cele mai importante implementări ale sale sunt: dBASE III
Plus şi dBASE IV.
COBOL
A fost creat în 1950 şi reprezenta singura posibilitate de gestionare a unei baze de date.
Reprezintă în primul rând un limbaj de programare special conceput pentru informatica de
gestiune. Dacă facem o comparaţie, sugestivă, COBOL este echivalentul FORTRAN-ului pentru
sistemele de gestiune a bazelor de date (din punct de vedere istoric şi al performanţelor). Limbajul
este considerat greoi şi inflexibil, iar pentru crearea unui program foarte simplu e nevoie de
scrierea unui adevărat eseu. Singurul avantaj real al COBOL-ului este portabilitatea sa ridicată.
FOXBASE
Sistemul dBASE a incintat firmele producătoare de soft, datorită popularităţii sale şi pe de altă
parte a calităţilor scăzute ale implementărilor originale furnizate de firma Ashton-Tate. Au apărut
noi implementări ale limbajului care au încercat să furnizeze unelte profesionale pe baza acestui
suport conceptual. Versiunile FOXBASE 2.10 şi FOXBASE PRO se constitue în medii performante
atât pentru programatori cât şi pentru utilizatori.
Se poate afirma fără teama de a greşi că ORACLE reprezintă cel mai performant S.G.B.D.
disponibil la momentul actual. Pe lângă faptul că posedă avantajele unui mediu de tip relaţional,
ORACLE este gândit ca un sistem exhaustiv pentru rezolvarea problemelor de utilizare sau
programare.
Limbajul intern folosit este SQL Plus şi este permisă conectarea cu alte limbaje externe evoluate
(orientate către C) . Putem menţiona:
viteză de lucru foarte bună;
exploatare interactivă la nivel SQL;
limitări de lucru greu sau imposibil de atins (maxim 65535 caractere într-un
câmp, număr nelimitat de câmpuri, de înregistrări) ;
exploatare eficientă a spaţiului pe disc (memorarea câmpurilor în format
variabil) .
Oracle este implementat pe majoritatea tipurilor de computere mari, ceea ce oferă portabilitatea
aplicaţiilor, dar mai ales posibilitatea conectării la calculatoare puternice.
PARADOX
Reprezintă un S.G.B.D. cu adevărat profesional. El îndeplineşte toate cerinţele unui produs cu
adevărat modern şi performant şi anume:
interactivitate foarte bună;
viteză de lucru mare;
servicii şi auxiliare;
limbaj de programare evoluat (PAL – Paradox Application Language) , dotat
cu compilator.
Acest tip de limbaje diferă esenţial de cele algoritmice. Modalitatea de programare este descriptivă
şi are intenţia declarată de simulare a raţionamentului uman. Pentru rezolvarea unei probleme sunt
furnizate seturile de reguli şi informaţii necesare, iar apoi se descrie în ce constă problema ca
atare. Limbajul este capabil să opereze deducţiile (deciziile) necesare pentru a rezolva problema
într-un caz particular ce apare în practică.
Aşadar, aceste limbaje descriu problema de rezolvat (în termenii deducţiilor logice) pe când
limbajele de tip algoritmic descriu metoda de rezolvare a problemei. Domeniile de aplicabilitate
pentru limbajele de programare a inteligenţei artificiale sunt cu predilecţie: realizarea de sisteme
expert (programe ce înlocuiesc experţii umani), computerizarea procesului de producţie, robotică,
tratarea limbajelor naturale.
I Specificarea problemei
Exemplul 1.3
Găsirea algoritmului constituie de cele mai multe ori cea mai grea etapă a
procesului programării. Pentru obţinerea algoritmului sunt necesare
cunoştinţe din matematică, discipline ştiinţifice şi tehnice. Studiul
algoritmilor constituie un domeniu clar delimitat în aria largă a ştiinţei
calculatoarelor. În general, dezvoltarea algoritmului se realizează iteativ,
trecându-l prin mai multe niveluri de detaliere. Acest mod de detaliere pas
cu pas este denumită proiectarea descendentă, sugerând faptul că se
trece treptat de la o reprezenteare generală, abstractă, a rezolvării
problemei la o prezentare detaliată a sa.
Fiecare limbaj de programare, ca orice alt limbaj, se caracterizează prin anumite reguli de
scriere corectă, numite reguli de sintaxă. Orice instrucţiune a limbajului are o formă şi o
semnificaţie. Sintaxa se referă numai la forma instrucţiunii, în timp ce semnificaţia este
de domeniul semanticii. Semantica se referă la modul în care trebuie interpretată
instrucţiunea respectivă. Este evident că, atunci când se concepe un program, este
necesar să se acorde atenţie atât sintacticii, cât şi semanticii.
Faptul că un program nu mai conţine erori de sintaxă, deci este corect sintactic, nu
înseamnă însă că el este corect şi sub aspectul realizării sarcinii pentru care a fost
conceput. Aşa cum un text scris într-o limbă naturală (în limba română, de exemplu) poate
fi corect gramatical, dar să exprime concepţii greşite, un program poate fi corect sintactic,
dar să descrie un set de date şi/sau un algoritm care nu corespund problemei rezolvate şi
deci nu permit obţinerea soluţiei corecte. Această situaţie nu mai poate fi sesizată de
compilator, ci este în întregime pe răspunderea programatorului.
3. În cadrul etapei de ............... sunt efectuate modificări ale programului, fie în scopul
corectării unor erori identificate în cursul utilizării sale, fie pentru implementarea unor
cerinţe noi.
Răspunsuri corecte:
1F Vezi U1.1 – Noţiunea de algoritm – pag. 8
2F Vezi U1.1 – Noţiunea de algoritm – pag. 8
3A Vezi U1.1 – Noţiunea de algoritm – pag. 8
4A Vezi U1.1 – Noţiunea de algoritm – pag. 8
5F Vezi U1.1 – Noţiunea de algoritm – pag. 8
1 analiza problemei, specificaţia problemei Vezi U1.3.2 – Etapele realizării programelor – pag. 26
2 regulile de sintaxă, mesaje de erori de sintaxă Vezi U1.3.2 – Etapele realizării programelor –
pag. 26
3 întreţinere Vezi U1.3.2 – Etapele realizării programelor – pag. 26
4 limbajelor de programare Vezi U1.3.2 – Etapele realizării programelor – pag. 26
BIBLIOGRAFIE
1. Dorin Stoilescu, Manual de C/C++ - Cap.1 Introducere, Editura Radial, Galati, 1998.
2. Florin. Munteanu, Traian C. Ionescu, Daniela Saru, Gheorghe Musca, Sergiu
Mihai Dascalu, Programarea calculatoarelor - manual pentru liceele de informatică –
Cap.2 Programe. Algoritmi. Elemente de programare structurată, Editura Didactică
şi Pedagogică, Bucureşti, 1995.
3. Valeriu Iorga si colectiv, “Programare in C/C++. Culegere de probleme”, Editura
Niculescu, Bucureşti, 2003.
4. Programe de specialitate elaborate de către Ministerul Educaţiei şi Cercetării pentru
învăţământul preuniversitar
Răspundeţi la următoarele întrebări. Acestea trebuie să fie scurte (câteva rânduri) şi clare.
Fiecare întrebare valorează 20 puncte. Primiţi 20 puncte din oficiu. Punctajul maxim al
testului este de 100 puncte
Cuprins Pagina
Fig. 2.1
Fig. 2.2
v=e
Figura 2.3. conţine mai multe blocuri de calcul. Aici am presupus că toate
variabilele sunt de tip numeric. În primul bloc se atribuie variabilei s
valoarea 2. Al doilea bloc conţine expresia c+3. Aici am presupus că c are
o valoare numerică rezultată dintr-o operaţie anterioară. Valoarea expresiei
se converteşte, dacă este cazul, la o valoare de tipul lui a şi se atribuie lui
a. În al treilea bloc apare expresia b+3. Valoarea acestei expresii se
atribuie lui b. Prin urmare, după execuţia acestei comenzi, valoarea lui b se
măreşte cu 3. Aşadar, semnul = care apare în blocurile de calcul nu trebuie
confundat cu semnul = din matematică, pentru că se ajunge la ceva fără
sens. În fine, în ultimul bloc se cere să se atribuie lui m valoarea 2.3. Dacă
m este o variabilă de tip întreg, atunci numărul 2.3 este convertit la numărul
întreg 2 şi apoi este atribuit variabilei m.
Fig. 2.3
Blocul de decizie are forma unui romb. În interiorul său se scrie o condiţie
care determină ramificarea calculelor. Figura 1.4. conţine un asemenea
bloc. Condiţia din blocul de decizie se citeşte ca o propoziţie interogativă.
Astfel, în cazul din figura 1.4. citim: Este y egal cu x ? Dacă răspunsul la
această întrebare este da, atunci se iese din blocul de decizie pe ramura
pe care este scris cuvântul DA. Dimpotrivă, dacă răspunsul la întrebarea
de mai înainte este nu, atunci se iese din blocul de decizie pe ramura pe
care este scris cuvântul NU.
Fig. 2.4
Exemplul 2.1
Fig. 2.5
În primul bloc de decizie din schema logică apare condiţia a=0. Evident,
condiţia a=0 poate fi adevărată sau falsă. Dacă condiţia a=0 este
adevărată, atunci din blocul de decizie se iese pe ramura pe care este
scris cuvântul DA, iar dacă condiţia a=0 nu este adevărată, atunci din
blocul de decizie se iese pe ramura pe care este scris cuvântul NU.
Desigur, şi condiţia b=0 care apare în celălalt bloc de decizie al schemei
logice determină ramificarea calculelor într-un fel sau altul. În fine, să mai
observăm că în blocul de calcul apare scris x = -b/a. Evident, x = -b/a nu
este o condiţie. Acum se cere să se determine valoarea lui -b/a şi să se
atribuie valoarea calculată lui x.
Facem întâi verificarea schemei pentru a=2 şi b=-8. Prin urmare, dorim să
rezolvăm ecuaţia 2x-8=0. Pe schema logică parcurgem paşii următori:
START
CITESTE a, b ⇒ a=2, b=-8
a=0 ? ⇒ 2=0 ? NU
x=-b/a ⇒ x=4
SCRIE x ⇒ x=4
STOP
START
CITESTE a, b ⇒ a=0, b=-6
a=0 ? ⇒ 0=0 ? DA
b=0 ? ⇒ -6=0 ? NU
SCRIE "INCOMPATIBILITATE" ⇒ INCOMPATIBILITATE
STOP
START
CITESTE a, b ⇒ a=0, b=0
a=0 ? ⇒ 0=0 ? DA
b=0 ? ⇒ 0=0 ? DA
SCRIE "NEDETERMINARE" ⇒ NEDETERMINARE
STOP
La sfârşitul anilor ’60, datorită dezvoltării vertiginoase a prelucrărilor de date cu calculatorul, s-au
putut aborda şi rezolva probleme din ce în ce mai complexe. Programele mari, corespunzătoare
acestor probleme s-au complicat în aşa măsură încât au devenit foarte greu accesibile chiar şi
pentru autorii lor. Înţelegerea, depanarea şi modificarea unor astfel de programe prezintă uneori
dificultăţi de neînlăturat. În acea “criză a software-ului” s-a ivit natural întrebarea: “Se poate elabora
o metodologie generală de realizare în mod sistematic, disciplinat a unor programe elegante?” Ca
răspuns la această întrebare s-a născut metoda programării structurate.
Un program structurat este constituit din unităţi funcţionale bine conturate, ierarhizate conform
naturii intrinseci a problemei. Programarea structurată este o metodă independentă de limbajul
de programare, ea acţionând la nivelul stilului de lucru.
În ce constă de fapt programarea structurată? Programarea structurată reprezintă o maniere de
concepere a programelor potrivit unor reguli bine stabilite, utilizând un anumit set, redus, de tipuri
de structuri de control.
Scopul programării structurate este elaborarea unor programe uşor de scris, de depanat şi de
modificat (actualizat) în caz de necesitate. Programele obţinute sunt clare, ordonate, inteligibile,
fără salturi şi reveniri. Programarea structurată permite ca programele să poată fi scrise în limbaj
pseudocod, limbaj independent de maşină, apropiat de cel natural, convertibil în orice limbaj de
programare.
Prin programarea în mod logic şi clar a structurilor de control admise, programarea structurată
permite abordarea eficientă a funcţiilor de orice grad de dificultate.
Se ştie că programul are la bază un algoritm, iar acesta poate fi reprezentat printr-o schemă
logică. În cazul programelor complexe (care sunt necesare în rezolvarea majorităţii problemelor
reale), numărul de instrucţiuni este foarte mare şi, deci, schema logică poate conţine legături foarte
complicate între aceste instrucţiuni. S-a constatat însă că omul nu poate stăpâni mintal structuri de
complexitate ridicată. La un moment dat, această deficienţă a minţii umane a devenit o piedică
majoră în dezvoltarea programării, având drept consecinţă că programele complexe erau greu de
conceput şi, mai ales, greu de depanat. Devenise necesar să se găsească o cale de a pune de
acord necesitatea de a se elabora programe mari şi complexe, cu particularitatea minţii umane de
a opera numai cu structuri simple.
La originea programării structurate stă un articol al lui E. W. Dijkstra, apărut în anul 1968 şi
intitulat "Go To Considered Harmful" în care se arăta că, pentru a reduce complexitatea
programelor şi a uşura înţelegerea acestora, este preferabil să se elimine din programe
instrucţunea GOTO (mergi la...) prin care, în limbajele de programare procedurale, se indică saltul
Adevărat / Fals
2. Reprezentarea unui algoritm se poate face doar printr-un program realizat într-un limbaj
de programare. A/F
3. Teorema de structură afirmă că orice program poate fi întocmit folosind numai trei
structuri de control fundamentale: structura secvenţială, structura alternativă şi structura
repetitivă. A/F
An
Figura 2.5
Exemplul 2.2
întregi a, b, aux
citeşte a,b
Citeşte a,b aux=a
a=b
b=aux
aux=a scrie a,b
stop
1. Un melc se deplasează cu viteza v km/săptămână. De cât timp (în ore) are nevoie
melcul pentru a străbate distanţa d dată în metri.
2. Perimetrul unui pătrat este egal cu latura altui pătrat. Ştiind că suma perimetrelor este x,
să se calculeze ariile celor două pătrate.
3. Fiind date trei numere întregi a, b ,c, să se interschimbe valorile celor trei numere,
astfel:
b, c, a (a primeşte valoarea lui b, b pe a lui c şi c ia valoarea lui
a);
c, a, b (a primeşte valoarea lui c, b pe a lui a şi c ia valoarea lui
b);
c, b, a (se inversează ordinea variabilelor).
5. Să se calculeze aria unui triunghi, cunoscându-se una din laturile sale şi înălţimea
corespunzătoare.
A B A
Figura 2.7
În limbaj natural, pentru schema logică din partea stângă, execuţia poate fi
descrisă astfel:
se evaluează condiţia;
dacă rezultatul este adevărat, se execută secvenţa A;
în caz contrar, se execută secvenţa B
În limbaj pseudocod, structura alternativă este descrisă astfel:
dacă condiţie atunci
secvenţa A
altfel
secvenţa B
Pentru cea de-a doua schemă, reprezentând decizia cu varianta unei căi
nule, una din ramurile structurii nu conţine nici o instrucţiune. În limbaj
natural, execuţia poate fi descrisă astfel:
se evaluează condiţia;
dacă rezultatul este adevărat, se execută secvenţa A;
în caz contrar, se continuă execuţia programului.
În pseudocod, execuţia se descrie astfel:
dacă condiţie atunci
secvenţa A
Exemplul 2.3
Se citesc două numere reale a şi b. Să se afişeze cel mai mare dintre ele.
citeşte a, b
dacă a>b atunci
scrie a
altfel
scrie b
stop
Exemplul 2.4
Exemplul 2.5
⎧ A2 − B,c < 0
⎪⎪
E= ⎨ A 2 − B , c = 0
⎪ 1 − B,c > 0
⎪⎩ A 2
Schema logică a acestei probleme se află la capitolul de Anexe,
Laboratorul 1.
Exemplul 2.6
Rezolvare:
real x
citeşte x
dacă x<0 atunci
x=-x
scrie x
2. Să se scrie algoritmul de rezolvare a următoarei probleme: acum este ora h1, minutul
m1 şi secunda s1. Cât va fi ceasul peste h2 ore, m2 minute şi s2 secunde? Rezultatul va
fi reprezentat tot în ore, minute şi secunde.
Figura 2.8
Exemplul 2.7
Să se calculeze xn, unde x este un număr real, iar n un număr natural.
real x, putere
întreg n, i
citeşte x, n
i=1
putere = 1
cat_timp i<=n execută
putere =putere * i
i = i+1
scrie putere
stop
Variabila putere este folosită pentru a păstra puterea i a lui x, i fiind o
variabilă întreagă ce „numără” puterea la care este ridicat x, fiind denumită
variabilă de tip contor.
se execută secvenţa A
se evaluează condiţia;
dacă rezultatul este fals, se continuă
cu primul pas;
în caz contrar, se încheie execuţia
ciclului.
repetă
secvenţa A
până_când condiţie
False
Condiţie
NU Această structură mai este cunoscută ca
structura de tip REPEAT UNTIL
DA True Observaţie
Deoarece testarea condiţie se face la
sfârşit, secvenţa se execută cel puţin o
dată (numărul de iteraţii este mai mare
decât zero)
Figura 2.9
Exemplul 2.8
Să se calculeze n! (factorialul numărului n, adică n!=1*2*...*n).
Pentru a rezolva acaeastă problemă sunt necesare variabilele de tip întreg
n, citit de la tastatură, i, variabilă necesară contorizării paşilor efectuaţi în
calcularea produsului şi variabila fact, care va memora valoarea
produsului calculat.
intregi n, i, fact
citeşte n
i=1
fact=1
repetă
fact=fact*i
i=i+1
până_când i>n
scrie fact
stop
Exemplul 2.9
Observaţie
Dacă se compară această problemă cu precedenta, se observă o
asemănare în rezolvarea lor, şi anume o parte de iniţializare a variabilelor
şi o ciclare pentru calculul celor două valori: factorial, respectiv suma.
Diferenţele constau în valorile de iniţializare a factorialului (1, deoarece se
calculează un produs), respectiv a sumei (s=0) şi operaţiile de calcul a
celor două variabile; înmulţire, respectiv adunare.
Exemplul 2.10
În primul capitol a fost prezentat, în limbaj natural, algoritmul de împărţire
a două numere naturale prin scăderi repetate. Iată cum se poate scrie în
pseudocod acest algoritm:
intregi a, b, cat
citeşte a, b
cat=0
cât_timp a>=b execută
a=a-b
cat=cat+1
scrie „cat=”, cat, „rest=”,a
stop
Exemplul 2.11
execuţia instrucţiunii.
1. Să se scrie algoritmul pentru calcularea sumei primelor n numere naturale impare, unde
n este un număr natural strict pozitiv, dat.
Răspunsurile corecte la testele de autoevaluare 2.2, 2.3 şi 2.4 se află în Anexe, Laboratorul 1.
BIBLIOGRAFIE
1. Dorin Stoilescu, Manual de C/C++ - Cap.1 Introducere, Editura Radial, Galati, 1998.
2. Florin. Munteanu, Traian C. Ionescu, Daniela Saru, Gheorghe Musca, Sergiu
Mihai Dascalu, Programarea calculatoarelor - manual pentru liceele de informatică –
Cap.2 Programe. Algoritmi. Elemente de programare structurată, Editura Didactică
şi Pedagogică, Bucureşti, 1995.
3. Valeriu Iorga si colectiv, “Programare in C/C++. Culegere de probleme”, Editura
Niculescu, Bucureşti, 2003.
4. Programe de specialitate elaborate de către Ministerul Educaţiei şi Cercetării pentru
învăţământul preuniversitar
Rezolvaţi următoarele probleme. Acestea trebuie să fie reprezentate prin scheme logice
sau pseudocod. Fiecareproblemă valorează 10 puncte. Primiţi 10 puncte din oficiu.
Punctajul maxim al testului este de 100 puncte.
3. Să se determine cea mai mare şi cea mai mică valoare dintr-un şir de 4 numere reale
citite de la tastatură.
8. Să se afişeze numerele prime mai mici sau egale decât un număr natural n dat
Cuprins Pagina
Etapa iniţiala de dezvoltare a limbajului de programare C a avut loc în cadrul laboratoarelor AT&T
Bell între anii 1969 şi 1973. După spusele lui Dennis Ritchie, cea mai creativă perioadă a avut loc
în 1972. A fost denumit „C“ deoarece multe din caracteristicile sale au fost derivate din limbajul de
programare „B“.
Sunt multe legende despre originea limbajului C şi legătura sa cu sistemul de operare Unix, cum ar
fi:
Începând cu anul 1973, limbajul de programare C a devenit destul de robust, astfel încât mare
parte a kernelului Unix, scris iniţial în limbaj de asamblare pentru PDP 11/20, a fost rescris în C.
Acesta a fost unul din primele kernele ale unui sistem de operare scris într-un limbaj de
programare, altul decât limbajul de asamblare. Încercări anterioare au fost pentru scrierea
sistemului Multics (scris în PL/I) şi TRIPOS (scris în BCPL).
K&R C
În 1978, Dennis Rithie şi Brian Kernighan au publicat prima ediţie a cărţii Limbajul de programare
C (eng. The C Programming Language). Această carte, cunoscută în cercul programatorilor sub
numele K&R, a servit pentru mulţi ani ca un mijloc de informare asupra specificaţiilor limbajului C.
Versiunea limbajului C descrisă este cunoscută sub numele K&R C.
K&R C este adesea considerat limbajul de bază pe care orice compilator C trebuie să-l suporte.
Pentru mulţi ani, chiar şi după introducerea standardului ANSI C, a fost considerat ca fiind „cel mai
mic numitor comun“ pe care programatorii în C trebuie să-l respecte atunci când se vorbeşte de
portabiliitate maximă, deoarece nu toate compilatoarele sunt scrise încă să suporte standardul
ANSI C, iar o secvenţă de cod scrisă în K&R C respectă şi ANSI C.
ANSI C şi ISO C
La sfârşitul anilor 1970, C a început să înlocuiască limbajul BASIC devenind cel mai utilizat limbaj
de programare. În anii 1980 a fost adptat si de calculatoarele IBM PC, popularitatea acestuia
începând să crească semnificativ. În acest timp, Bjarne Stroustrup împreună cu alţi colegi de la
Bell Labs au început să adauge limbajului C caracteristici ale programării orientate pe obiecte.
Limbajul rezultat a fost denumit C++ şi este cel mai popular limbaj de programare pe sistemele de
operare Microsoft Windows; totuşi C-ul rămâne cel mai popular limbaj de programare în Unix. Alt
limbaj de programare dezvoltat în acea vreme se numeşte Objective-C care adaugă de asemenea
C-ului caracteristici ale programării orientate pe obiecte. Deşi nu la fel de popular ca C++,
Obejective-C este folosit pentru dezvoltarea aplicaţiilor pe ce folosesc interfaţa Cocoa a sistemului
de operare Mac OS X.
În 1983, American National Standards Institute (ANSI) a format un comitet, X3J11, pentru a stabili
specificaţiile unui limbaj C standard. După un proces îndelungat, standardul a fost terminat în 1989
şi ratificat ca ANSI X3.159-1989 "Programming Language C". Această versiune a limbajului ne
este cunoscută sub numele ANSI C. în 1990, standardul ANSI C (cu mici modificări) a fost adoptat
de International Organization for Standardization (ISO) ca ISO/IEC 9899:1990.
Una din ţintele procesului de standardizare ANSI C a fost acela de a produce un superset al K&R
C, încorporând multe dintre caracteristicile neoficiale introduse secvenţial. Totuşi, comitetul pentru
standardizare a introdus câteva caracteristici noi, cum ar fi prototipul funcţiilor (împrumutat din
C++) şi un preprocesor mult mai capabil.
ANSI C este suportat de marea majoritate a compilatoarelor folosite astăzi. Mare parte din codul C
scris acum este bazat pe ANSI C. Orice program scris exclusiv în standardul C este garantat să
funcţioneze corect pe orice platformă cu o implementare C conformă. Totuşi, multe programe sunt
scrise astfel încât aceste vor putea fi compilate numai pe anumite platforme, sau folosind un
anumit compilator, deoarece (i) se folosesc biblioteci non-standard, de exemplu pentru interfaţa
grafică, (ii) unele compilatoare ce nu respectă standardul ANSI C, deci şi urmaşii lor în mod implicit
sau (iii) bazarea pe dimensiunea unui anumit tip de date pe anumite platforme.
Limbajul C est singurul limbaj de programare structurat care permite un control rigurosal hardware-
uluişi al perifericelor (facilitate oferită de limbajele de asamblare). Limbajul C a fost folosit iniţial
pentru scrierea programelor de sistem (sisteme de operare, editare, compilatoare, etc), dar o dată
cu creşterea popularităţii lui, programatorii au început să-l folosească şi la scrierea programelor de
aplicaţii datorită în special eficienţei şi portabilităţii crescute a unor astfel de programe.
Datorită calităţilor sale incontestabile, limbajul C a devenit limbajul de bază şi pentru programarea
aplicaţiilor de tip real.
Exemplul 3.1
main()
{
}
Acest program nu realizează nimic. Se remarcă funcţia main, urmată de o
pereche de paranteze rotunde, ce indică că aceasta este o funcţie; între
cele două paranteze pot fi parametri formali, atunci când e nevoie. Se mai
observă existenţa unei perechi de acolade ce încadrează corpul funcţiei,
care în această situaţie este instrucţiunea vidă. Aceste paranteze se
utilizează şi pentru delimitarea altor blocuri întâlnite de exemplu în
structurile iterative sau deczionale.
Exemplul 3.2
#include <stdio.h>
main()
{
printf(“Invatam limbajul C”);
}
Pentru a realiza operaţii de citire/scriere, limbajul C este înzestrat cu funcţii
specifice, în acest caz fiind folosită funcţia printf, ce are un singur
parametru, şi anume textul ce va fi tipărit, cuprins între ghililmele.
numele funcţiei
parantezele pot include
semn de terminare
a unei instrucţiuni
main()
{
printf(“Invatam limbajul C”);
}
instrucţiune
paranteze pentru
delimitarea corpului program constituit din
funcţia numită main()
Figura 3.1
Funcţia printf() din acest exemplu este o funcţie sistem, adică nu este
creată de programator, care permite afişarea la consolă (display) a
constantelor, variabilelor şi caracterelor.
Exemplul 3.3
main()
{
printf(“Acesta este numarul sapte: %d”,7);
}
În urma lansării în execuţie a programului, la consolă va apărea:
Acesta este numarul sapte: 7
În acest caz funcţia printf() are două argumente separate prin virgulă, şi
anume un şir de caractere încadrat între ghilimele şi valoarea întreagă 7.
Simbolul “%d” permite transferarea parametrului din dreapta virgulei –
valoarea 7 – în stânga virgulei, alături de şirul de caractere. Acesta
reprezintă unul din formatele specifice utilizate de funcţia printf(), şi
anume acela pentru scrierea numerelor întregi.
Exemplul 3.4
main()
{
printf(“%s este student in anul %d \n la facultatea ta.”, ”Mihai”, 3);
}
Exemplul 3.5
main()
{
printf(“Litera %c se găseste in cuvantul %s”,’h’, ”Mihai”);
printf(“pe pozitia %d.”,3);
}
După executarea programului, se va afişa:
Litera h se găseste in cuvantul Mihai pe pozitia 3.
Se observă că scrierea textului se face pe un singur rând, cu toate că în
program sunt două linii de instrucţiuni. Aici ‘h’este caracter şi se scrie cu
formatul %c. Caracterele se delimitează de simbolul apostrof, iar şirurile
de caractere de către ghilimele.
Adevărat / Fals
2. Prototipurile funcţiilor care pot fi apelate în cadrul limbajului se găsesc grupate în fişiere
de tip header
3. Pentru fiecare din următorii identificatori indicaţi dacă definirea lor este corectă (A) sau
nu (F):
1) a&b 5) Aa
2) ab_x 6) Barbu
3) 2c3d 7) f1()
4) patru 8) xn
5. Orice program scris în limbajul C este compus dintr-o serie de entităţi numite funcţii.
Exemplul 3.6
main()
{
int num;
num=7;
printf(“Acesta este numarul sapte: %d”,num);
}
În urma execuţiei programului, la consolă va apăreaacelaşi mesaj:
Acesta este numarul sapte: 7
dar programul conţine c’teva elemente noi, şi anume:
instrucţiunea int num; prin care este declaratădrept întreg
variabila num; deci num este numele variabilei, iar int este tipul ei
(întreg);
instrucţiunea num=7; are ca rezultat atribuirea valorii 7
variabilei num. Astfel operatorul “=” este operatorul de atribuire.
În această situaţie, modul de lucru al instrucţiunii printf() din instrucţiunea
următoare este clar: va afişa valoarea variabilei num, care este 7.
Exemple
Corect Incorect
num1 1num
suma_n suma n
a1b2 a#2
Tabelul 3.1
Exemplul 3.7
main()
{
int n;
float v;
char ch;
v=2.53;
n=65;
ch=’A’;
printf(“Caracterul %c are codul ASCII %d”,ch, n);
printf(“ si o frecventa de aparitie de %f %.”,v);
}
În urma execuţiei acestui program se va afişa:
Caracterul A are codul ASCII 65 si o frecventa de aparitie de 2.530000
%.
3. Tipul de date float ocupă de ........ ori mai multă memorie decât tipul de date char.
5. Adevărat sau fals: tipul de date long poate lucra cu numere doar de două ori mai mari
decât tipul de date int.
3.4 Constante
Există mai multe tipuri de constante, dintre care acum se vor prezenta
numai cele corespunzătoare tipurilor predefinite.
Constante întregi
Constante caracter
Acestea se reprezintă între două caractere apostrof (‘). Exemple: ’A’, ‘1’,
‘a’. Pentru memorarea lor se ytiliyeay[ tipul char, memorându-sede fapt
codul ASCII al caracterului respectiv. De exemplu, pentru ‘1’ se
memorează valoarea 49, iar pentru ’A’, valoarea 65.
bazele 8 sau 16: ‘\141’ sau ‘\x61’. Se observă că, atunci când este folosită
baza 16, codul este precedat de caracterul ‘x’.
Constante reale
Declararea constantelor
Tipul enumerare
Exemplul 3.8
altă valoare.
Proiectul pentru Învăţământul Rural 57
Structura programelor în limbajul C. Tipuri de date, operatori şi expresii
Exemplul 3.9
Exemplul 3.10
Exemplul 3.11
f ( x ) = x 5 + ln (x )
Figura 3.2
5. Adevărat / Fals: pentru variabilele de tip logic, ce pot lua valorile true sau false, limbajul
C are definit tipul de variabile boolean.
3.6 Operatori în C
nume_variabila=expresie
Atribuirea multiplă
v1=v2= …. =vn=expresie;
unde v1, v2, ….,vn sunt variabile (lvalue) care se pot modifica.
Exemplul 3.12
char c;
int n,k;
float x;
c=’a’;
n=3;
k=’d’;
x=c+n;
După prima atribuire caracterul c devine egal cu ‘a’. În urma celei de-a
doua atribuiri n devine egal cu 3. La a treia atribuire k devine egal cu 100,
deoarece expresia din membrul drept ‘d’, de tip caracter este convertită la
un tip întreg, având valoarea codului ASCII al caracterului respectiv. După
ultima atribuire x devine egal tot cu 100, deoarece rezultatul adunării
dintre un operand de tip întreg şi unul de tip caracter se converteşte în
întreg. Variabila c, iniţial egală cu ‘a’, convertită în întreg devine egală cu
codul său ASCII, adică 97, care se adună cu 3, valoarea variabilei n.
Rezultatul este deci 100.
Exemplul 3.13
int x, y;
float z;
z=x=y=3;
Exemplul 3.14
int i, j, n;
float x;
//………………
n=10*4-7;
i=9/2;
j=n%i;
x=n;
x=x%i;
Exemplul 3.15
int i;
float x;
i=9./2;
x=9./2;
Exemplul 3.16
În operaţiile cu constante contează dacă ele sunt de tip întreg sau real:
int i;
i=3/2+9/2;
i=3./2+9./2;
După prima atribuire, i devine egal cu 5 (3/2=1, 9/2=4, 1+4=5), iar după
cea de+a doua atribuire i devine egal cu 6 (3./2=1.5, 9/2=4.5, 1.5+4.5=6).
După execuţia acestor paşi, cei doi operanzi sunt de acelaşi tip, iar
rezultatul va fi de tipul comun lor.
Exemplul 3.17
Fie declaraţia: int a=10; Atunci expresia 4*a/3 este de tip int şi la
evaluare se obţine 13 (4*10=40, 40/3=13 – împărţire întreagă). În aceleaşi
condiţii, expresia 4*(a/3) are ca rezultat valoarea 12. Mai întâi se
calculează a/3 , rezultând valoarea 3; apoi se efectuează 4*3=12. Acesta
este un exemplu din care se poate observa că o expresie în C nu este
acelaşi lucru cu o expresie matematică.
Fie declaraţia: float a=10; Atunci expresia 4*a/3 este de tip float şi la
evaluare se obţine 13.3333 (4*10=40, număr real 40/3=13.3333 –
împărţire reală).
x=10;
y=++x;
x=10;
y=x++;
Exemplul 3.18
main()
{
int n=0;
printf(“Numar=%d\n”, n);
printf(“Numar=%d\n”, n++);
printf(“Numar=%d\n”, n);
}
Numar=0
Numar=0
Numar=1
aceasta deoarece la prima afişare variabila n are valoarea zero, la a doua
afişare n are la început aceeaşi valoare, zero, după care se face
main()
{
int n=0;
printf(“Numar=%d\n”, n);
printf(“Numar=%d\n”, ++n);
printf(“Numar=%d\n”, n);
}
Numar=0
Numar=1
Numar=1
Diferenţa apare la cea de-a doua afişare, când se face mai întâi
incrementarea variabilei n – preincrementare – urmată de afişarea ei.
p q p&&q p||q !p
0 0 0 0 1
0 1 0 1 1
1 0 0 1 0
1 1 1 1 0
Tabelul 3.2
Operatori relaţionali
Operator Acţiune
> Mai mare decât
>= Mai mare sau egal
< Mai mic
<= Mai mic sau egal
== Egal
!= Diferit
Operatori logici
Operator Acţiune
&& ŞI – AND
|| SAU – OR
! negare – NOT
Tabelul 3.3
Atât operatorii relaţionali, cât şi cei logici au o prioritate mai redusă decât
operatorii aritmetici. O expresie de forma 7>3+5 este evaluată ca şi cum
ar fi fost scrisă 7>(3+5); reultatul este ”Fals”, adică zero.
Exemplul 3.19
Toate expresiile relaţionale şi logice dau un rezultat egal fie cu zero, fie cu
1 (fals sau adevărat).
main()
{
int n;
n=100;
100>10 da rezultatul 1
100==100 da rezultatul 1
100<=10 da rezultatul 0
100>10 || 100<50 da rezultatul 1
Exemplul 3.25
i<<=j;
Valoarea variabilei i devine 48.
(tip) expresie
Exemplul 3.26
a) Expresia :
float a,n;
......................
a=(int) sqrt(n);
(double) a/b;
sizeof (expresie)
Exemplul 3.27
float f;
printf(”%d ”,sizeof (f));
printf(”%d ”,sizeof (int));
va afişa numerele 8 şi 2.
x = (y=3, y+1);
Exemplul 3.28
Fie declaraţiile:
int a = 1, b = 5; float c;
Expresia: c = a = b+1, a = c+2, b = b+1; se evaluează astfel:
se evaluează atribuirea multiplă, rezultând pentru a
valoarea 6, apoi c devine tot 6 (b+1);
a devine 8 (c+2);
b primeşte valoarea 6.
În ansamblu, expresia este de tipul lui Exp2 sau al lui Exp3, în funcţie de
cea care se evaluează şi produce valoarea corespunzătoare expresiei
evaluate.
Exemplul 3.29
#include <stdio.h>
void main()
{
float x;
printf(“x=”); scanf(“%f”,&x);
printf(“%f”, x>=0? x: -x);
}
Exemplul 3.30
Fie declaraţiile:
double x, y, aux;
Expresia:
x > y ? (aux=x: x=y, y=aux) : y;
are ca efect ordonarea variabilelor x şi y în ordine crescătoare. Ca rezultat
se obţine cea mai mare valoare dintre cele două variabile.
Răspunsuri corecte:
1F Vezi U3.2 – Structura programelor în limbajul C – pag. 46
2A Vezi U3.2 – Structura programelor în limbajul C – pag. 46
3 1)F 2) A 3) F 4) A 5) A 6) A 7) F 8) A
Vezi U3.2 – Structura programelor în limbajul C – pag. 46
4F Vezi U3.2 – Structura programelor în limbajul C – pag. 46
5A Vezi U3.2 – Structura programelor în limbajul C – pag. 46
BIBLIOGRAFIE
6. Care dintre expresiile următoare sunt incorecte, ştiind că operanzii care intervin sunt de
tip întreg?
a) (a!=b) && (c<b)
b) a+-3+b
c) a-a/b (a-3)
d) ! (a<b)
e) b+%a
8. Ştiind că x este o variabilă folosită pentru citirea mai multor numere întregi, cum va fi
declarată aceasta?
a) integer x;
b) x=int;
c) int x;
d) char x;
Cuprins Pagina
Un caz aparte de ieşire este acela în care datele sunt scrise pe monitor,
situaţie în care fişierul poartă o denumire standard: stdout, după cum un
caz aparte de intrare este acela în care datele se preiau de la tastatură –
fişier standard numit stdin.
Cele două fişiere (stdout şi stdin) sunt atribuite automat oricărui program
scris în C. De asemenea, ele sunt deschise automat la lansarea în
execuţie a programului şi închise atunci când execuţia se termină. Din
acest motiv, operaţiile de intrare/ieşire efectuate cu ajutorul lor poartă
denumirea de intrări/ieşiri standard.
Cod Format
%c caracter
%d întreg zecimal cu semn
%i întreg zecimal cu semn
%e număr real, notaţie ştiinţifică (e mic)
%E număr real, notaţie ştiinţifică (E mare)
%f număr real, notaţie zecimală
%g număr real, cea mai scurtă reprezentare dintre %f şi %e
%G număr real, cea mai scurtă reprezentare dintre %f şi %E
%o număr octal, întreg, fără semn
%s şir de caractere
%u întreg zecimal fără semn
%x număr hexazecimal, întreg, fără semn, litere mici
%X număr hexazecimal, întreg, fără semn, litere mari
%p afişează un pointer (adresă)
%% afişează simbolul %
Tabelul 4.1
Exemplul 4.1
main()
{
int num;
num=12345;
printf(”%d\n”, num);
printf(”%3d\n”, num);
printf(”%10d\n”, num);
printf(”%03d\n”, num);
printf(”%010d\n”, num);
}
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
0 0 0 0 0 1 2 3 4 5
Exemplul 4.2
main()
{
printf(”%.4f\n”,12.1234567);
printf(”%3.8d\n”, 1000);
printf(”%10.8d\n”,1000);
printf(”%10.15s\n”, ”Acesta este un text”);
printf(”%10.15s\n”, ”PROGRAM”);
printf(”%3.1d\n”,1000);
}
În urma execuţiei acestui program, se va afişa:
1 2 3 . 1 2 3 5
0 0 0 0 1 0 0 0
0 0 0 0 1 0 0 0
A c e s t a e s t e u n
P R O G R A M
1 0 0 0
Toate datele de ieşire, în mod implicit, sunt aliniate la dreapta, adică, dacă
lăţimea câmpului este mai mare decât datele afişate, datele se plasează
lângă marginea din dreapta a câmpului. Se poate forţa alinierea la stânga
a informaţiei prin plasarea unui semn ”-” imediat după simbolul
procentului. De exemplu, comanda %-10.2f aliniază la stânga, într-un
câmp de 10 caractere, un număr în virgulă mobilă cu două cifre după
virgulă.
Exemplul 4.3
printf(“%10f\n”, val);
printf(“%012f\n”, val);
printf(“%-10f\n”, val);
printf(“%-012f\n”, val);
}
În urma executării acestui program, rezultatele vor fi afişate astfel:
1 2 . 5 5 2 5 . 7
1 2 . 5 5 2 5 . 7
1 0 . 1 2 3 0 4 0
1 0 . 1 2
1 0 . 1 2 3 0 4 0
0 0 0 1 0 . 1 2 3 0 4 0
1 0 . 1 2 3 0 4 0
1 0 . 1 2 3 0 4 0 0 0 0
Adevărat / Fals
Fie declaraţia şi iniţializarea: int a; a=-12;
1. Instrucţiunea printf(”a=%10.7d\n”,a);
tipăreşte a=bb-0000012 (prin b am notat spaţiul).
2. Instrucţiunea printf(”a=%10.7i\n”,a);
nu are acelaşi efect cu instrucţiunea de la întrebarea 1.
3. Instrucţiunea printf(”a=%x\n”,a);
tipăreşte valoarea lui a reprezentată în baza opt.
4. Instrucţiunea printf(”a=%3.7i\n”,a);
tipăreşte a=-0000012
Exemplul 4.4
main()
{
float ani, zile;
printf(“Scrieti varsta in ani: ”);
scanf(“%f”,&ani);
zile=ani*365;
printf(“Aveti varste de %.1f zile.”,zile);
}
În urma interacţiunii programului cu operatorul, la consolă ar putea apărea
următoarele:
Scrieti varsta inani: 42.5
Aveti varste de 15512.5 zile.
În acest program, pe lângă funcţia scanf(), mai apar două alte elemente
noi:
- operatorul de multiplicare (*)
- operatorul adresă (&).
Pentru moment trebuie reţinut faptul foarte important că funcţia scanf()
cere utilizarea simbolului adresă - & - înaintea numelui fiecărei variabile.
Exemplul 4.5
main()
{
int ev;
float timp;
char poz;
printf(“Introduceti poz, ev,timp: ”)
scanf(“%c %d %f”, &poz, &ev, &timp);
printf(“Evenimentul %c are numarul %d”,poz,ev);
printf(“ si a avut loc la %f timp.”,timp);
}
M 5 12.30
poz “M”
ev 5
timp 12.30
Figura 4.1
Exemplul 4.6
Exemplul 4.7
4. Fie declaraţia char s[20]; Care din declaraţiile următoare citesc corect un şir de
caractere?
a. scanf(”%c”,s);
b. scanf(”%c”,&s);
c. scanf(”%s”,s);
d. scanf(”%s”,&s);
e. scanf(”%”,s);
f. scanf(””,s);
Răspunsuri corecte:
1A Vezi U4.2 – Funcţia de scriere cu format – pag. 77
2F Vezi U4.2 – Funcţia de scriere cu format – pag. 77
3F Vezi U4.2 – Funcţia de scriere cu format – pag. 77
4A Vezi U4.2 – Funcţia de scriere cu format – pag. 77
5F Vezi U4.2 – Funcţia de scriere cu format – pag. 77
Primul caracter din şirul parametru este blank, deci alb. În şirul de intrare pointerul marchează un
un blank, deci, în şirul parametru pointerul va marca caracterul %, iar în cel de intrare caracterul a.
După caracterul % urmează caracterul c, deci va fi citit un caracter, şi anume a, ce va fi atribuit
variabilei cu acelaşi nume. În şirul parametru, pointerul marchează caracterul % , iar în cel de
intrare pointerul marchează b blank. Se analizează dacă există un specificator de format, condiţie
îndeplinită - %3d – condiţie care solicită citirea unui întreg de maxim 3 cifre. În şirul de intrare se
trece peste caracterele albe, pointerul marcând caracterul 1. Se citeasc şi următoarele 2 caractere:
2 şi 3, deci variabilei c i se va atribui valoarea 123. În şirul parametru, pointerul indică caracterul %,
iar în cel de intrare, caracterul 4.. După % urmează un specificator de format - %c – deci variabila
b va reţine codul caracterului 4. În şirul parametru, pointerul trece peste caracterul alb, ajungând la
caracterele 1, apoi 2. Se compară aceste caractere cu cele din şirul de intrare, care sunt de
asemenea 1 şi apoi 2. Citirea continuă; în şirul parametru se trece peste blank şi se ajunge la un
nou specificator de format - %f – iar în şirul de intrare se găsesc caracterele – 4 1 . şi 7, deci
rezultatul va fi convertit către numărul real -41.7, ce va fi reţinut de variabila d. Citirea se încheie,
fiind citite corect 4 valori
1. F Vezi Laboratorul 3
2. b Vezi Laboratorul 3
3. d Vezi Laboratorul 3
4. iostream.h Vezi Laboratorul 3
5. 9, respectiv 5 Programul determină valoarea maximă dintre cele trei numere citite.
BIBLIOGRAFIE
a. start()
b. system()
c. main()
d. program()
3. Care este semnul de punctuaţie cu care se termină cele mai multe linii de program
C/C++?
a. .
b. ;
c. :
d. '
8. Scrieţi un program care calculează şi afişează retribuţia unui salariat în funcţie de grupa
de vechime în care se află. Există 3 grupe de vechime (1, 2, şi 3). Retribuţia se calculează
cu relaţia:
retribuţie=salariu +spor
Sporul depinde de grupa de vechime şi este egal respectiv cu 150, 250, 350. Grupa de
vechime şi salariul se introduc de la tastatură. Programul va folosi operatorul condiţional.
Cuprins Pagina
Forma generală:
expresie;
Efect:
Se evaluează expresia.
Exemplul 5.1
Observaţii:
expresie poate fi vidă. Instrucţiunea devine instrucţiunea vidă ;
orice instrucţiune în C / C++ se termină cu ;
este permisă folosirea oricărei expresii sintactic corecte, chiar şi
atunci când instrucţiunea nu generează nici un efect.
Exemplul 5.2
3*( 7-4);
Forma generală:
{
declaraţii
instrucţiune1;
instrucţiune2;
...
instrucţiune n;
}
Efect:
Se execută în ordine instrucţiunile specificate.
Observaţii:
Utilizarea instrucţiunilor compuse este necesară atunci când
sintaxa permite executara unei instrucţiuni ( if, for, do-while, while)
care efectuează mai multe operaţii.
Declaraţiile care apar într-o instrucţiune compusă sunt locale
instrucţiunii. Mai exact, ele sunt valabile numai în corpul instrucţiunii
compuse, din momentul declarării lor până la sfârşitul instrucţiunii.
5.3 Instrucţiunea if
Forma generală:
if ( expresie) instrucţiune1
else instrucţiune2
Efect:
Se evaluează expresia
Dacă valoarea expresiei este diferită de 0, se execută instrucţiune1,
altfel se execută instrucţiune2.
Exemplul 5.3
Observaţii:
expresie se încadrează între paranteze rotunde;
ramura else poate să lipsească dacă instrucţiune2 este vidă.
Exemplul 5.4
# include <iostream.h>
void main()
{
int a,b, max;
cout<<” a=”’ cin>>a;
cout<<” b=”’ cin>>b;
max=a;
if (max<b) max=b;
cout<<” maximul este”<<max;
}
Exemplul 5.5
Varianta 1:
# include <iostream.h>
# include <math.h>
# include <conio.h>
main()
{ flota a,b,c,d;
cout<<”a=”; cin>>a;
cout<<”b=”; cin>>b;
cout<<”c=”; cin>>c;
if (a)
{ d=b*b-4*a*c;
if (d>=0) { cout<<”x1=”<<(-b+sqrt(d))/(2*a));
cout<<”x2=”<<(-b-sqrt(d))/(2*a));}
else cout <<”x1 si x2 nu sunt reale”;
}
else if (b) cout<<”x=”<<(-c/b);
else if(c==0) cout<<”infinitate de soluţii;
else cout<<” ecuaţia nu are soluţii”;
}
Observaţii:
1. funcţia “rădacină pătrată” sqrt() are prototipul în math.h;
2. clrscr() are prototipul în conio.h şi are funcţia de ştergere
3. varianta 2 a programului foloseşte operatorii condiţionali ? :
Alege, prin încercuire, varianta corectă de răspuns pentru următoarele teste. Răspunsul
pentru fiecare cerinţă valorează 25 de puncte. Punctaj minim: 75.
1. Care din următoarele secvenţe de instrucţiuni atribuie variabilei reale k cea mai
mare dintre valorile variabilelor a şi b sau valoarea lor comună, dacă acestea sunt
egale:
a) if (a<=b) k=a; else k=b;
b) if (a<=b) k=b; else k=a;
c) if ( a==b) k=a; else if (b>a) k=b;
d) k=a; if (k<b) k=b;
3. Dacă a şi b sunt variabile de tip int, iar x şi z sunt variabile de tip float, stabiliţi care
dintre secvenţele de instrucţiuni sunt corecte:
a) b=0; if (a>b) b=a/2;
b) a=8; b=10;
c) a:=5; b:=5; if (a==b) x=y;
4. Care dintre instrucţiunile următoare sunt incorecte sintactic, ştiind că operanzii care
intervin sunt de tip întreg?
a) if ( abs(3==3) cout<<” ok”;
b) if ( a%3=b) cout<<” zz”;
c) if ( (b+a)/2) cout<<” yy”;
d) if (!1) cout<<”hm”;
Forma generală:
switch (expresie)
{
case constanta1: secvenţa instrucţiuni1
case constanta2: secvenţa instrucţiuni2
...
case constantan: secvenţa instrucţiunin
default: secvenţa instrucţiunin+1
}
Efect:
Se evaluează expresie;
Se compară succesiv valoarea ei cu valorile expresiilor constante
care etichetează alternativele case.
Dacă se întâlneşte o alternativă case etichetată cu valoarea
expresiei, atunci se execută secvenţa de instrucţiuni
corespunzătoare şi toate secvenţele de după aceasta, până la
întâlnirea instrucţiunii break sau până la sfârşitul instrucţiunii switch.
Dacă nici una dintre valorile etichetelor alternative case nu coincide
cu valoarea expresiei, atunci se execută secvenţa de instrucţiuni de
pe ramura default.
Exemplul 5.6
switch (x)
{
case ‘*’: a*=b; break;
case ‘/’: a/=b; break;
case ‘+’: a+=b; break;
case ‘-’: a-=b; break;
default: cout << “eroare!”;
}
În funcţie de valoarea variabilei char c (‘*’, ‘/’, ‘+’, ‘-‘) vom efectua operaţia
corespunzătoare între variabilele a şi b. Dacă variabila c are orice altă
valoare, vom da mesajul „eroare!”
Observaţii:
Forma generală:
break;
Efect:
Determină ieşirea necondiţionată din instrucţiunea switch, while, for
sau do-while în care apare.
Forma generală:
while (expresie)
instrucţiune
Efect:
1. se evaluează expresie;
2. dacă valoarea expresiei este 0, se iese din instrucţiunea while,
altfel, dacă valoarea este diferită de 0, se execută instrucţiune şi
apoi se revine la pasul 1.
Exemplul 5.7
Linia Efect n x
1 Se iniţializează x cu 0 821 0
2 Se testează dacă n este diferit de 0 821 0
3 Se adaugă la x ultima cifră a lui n 821 1
4 Se elimină ultima cifră din n 82 1
2 Se testează dacă n este diferit de 0 82 1
3 Se adaugă la x ultima cifră a lui n 82 12
4 Se elimină ultima cifră din n 8 12
2 Se testează dacă n este diferit de 0 8 12
3 Se adaugă la x ultima cifră a lui n 8 128
4 Se elimină ultima cifră din n 0 128
2 Se testează dacă n este diferit de 0; se iese 0 128
din while
Observaţii:
instrucţiunea se execută repetat cât timp valoarea expresiei este
nenulă.
Dacă expresia are de la început valoarea 0, instrucţiune nu se
execută nici macar o dată.
Sintaxa permite executarea în while a unei singure instrucţiuni, prin
urmare, atunci când este necesară efectuarea mai multor operaţii,
acestea se grupează într-o instrucţiune compusă.
x0=1
xn= x * x *…* x=x*(x * x *…* x)
Forma generală:
do
instrucţiune
while (expresie)
Efect:
1. se execută instrucţiune;
2. se evaluează expresie;
3. dacă valoarea expresiei este 0, se iese din instrucţiunea repetitivă;
dacă valoarea expresiei este diferită de 0, atunci se revine la pasul
1.
Exemplul 5.8
Observaţii:
instrucţiunea do-while execută instrucţiunea specificată cel puţin o
dată, chiar dacă de la început valoarea expresiei este 0, deoarece
evaluarea expresiei se face după executarea instrucţiunii.
#include< iostream.h>
void main()
{
int a,b, nr=0, i;
cout<<” a=”;cin>>a;
cout<<” b=”;cin>>b;
i=a;
while (i<=b) { if (i%2==0) nr++; i++;
cout<<”nr=”<<nr;}
Barem:
a) 10 puncte
b) 30 puncte
c) 10 puncte
total 50 puncte
Forma generală:
Efect:
1. se evaluează expresia de iniţializare;
2. se evaluează expresia de continuare;
3. daca valoarea expresiei de continuare este 0, se iese din
instrucţiunea repetitivă for; dacă valoarea expresiei de continuare
este diferită de 0, atunci se execută instrucţiune, se evaluează
expresia de reiniţializare şi se revine la pasul 2.
Observaţii:
instrucţiunea for este o instrucţiune repetitivă, ca şi while şi do-
while;
ea poate fi simulată cu ajutorul instrucţiunii while astfel:
expr1;
for( expr1; expr2;expr3) while (expr2)
instrucţiune {
instrucţiune;
expr3;
}
for ( ; ; )
While (1) instrucţiune instrucţiune
Exemplul 5.9
fact=1;
for(i=1;i<=n;i++) fact*=i; // în fact voi obţine produsul
pentru n=4
i fact
1 1*1=1
2 1*2=2
3 2*3=6
4 4*6=24
Alege, prin încercuire, varianta corectă de răspuns pentru următoarele teste. Răspunsul
pentru fiecare cerinţă valorează 25 de puncte. Punctaj minim: 75.
x=4;
while(x<7) x+=2;
for(i=1;i<=x;i++) x+=1;
cin>>n;
cif=2;
for(int i=3;i<=n;i++) // I declarat local in instructiunea for
{ cif*=i;
while(cif%10==0) cif/=10;
cif%=10;
}
cout<<cif;
a) calculează ultima cifră a lui n!
b) calculează ultima cifră nenulă a lui n!
c) Calculează n!
d) Determină numărul de cifre a lui n!
p=1;
for(i=1;i<=n;i++)
{ s=0;
for(j=1;j<=i; j++) s+=j;
p*=s;
}
a) 180 b) 18 c) 9 d) 216 e)1
4.Pentru afişarea numerelor naturale 1,2,…n , unde n este dat, propun următoarele
secvenţe de program:
a) for(i=1;i<=n;i++); cout<<i;
b) for(i=1;i<=n;i++) cout<<i;
Exemplul 5.11
Şirul Fibonacci
Fie şirul 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ... . Fie n un număr natural citit de
la tastatură. Să se scrie un program care afişează cel de-al n-lea termen
din şirul lui Fibonacci.
#include<iostream.h>
void main()
{ int i, n, f0, f1, f2;
cin>>n;
f0=1; f1=1; //iniţializarea primilor doi termeni
for ( i=2;i<=n;i++)
{ f2=f1+f0; // calculez termenul curent
f0=f1; /* reiniţializez variabilele care definesc doi termeni
f1=f2; consecutivi în şir */
}
cout<<” cel de-al”<<n<< „ termen Fibonacci este”<< f2;
}
Soluţiile sarcinilor de lucru 5.1 şi 5.2, ca şi a problemelor propuse pentru laboratorul corespunzător
se găsesc în cadrul laboratorului 4.
Bibliografie
Aplicaţia 1 10 puncte
Aplicaţia 2 15puncte
Aplicaţia 3 15 puncte
Aplicaţia 4 15 puncte
5 puncte – declaraţii corecte
Aplicaţia 5 15 puncte 5 puncte – căutarea secvenţei 13 în număr
5 puncte – afişarea rezultatului
5 puncte – declaraţii corecte
5 puncte – verificarea respectării regulilor de
Aplicaţia 6 15 puncte
construire a sirului
5 puncte – afişarea rezultatului
5 puncte – declaraţii corecte
Aplicaţia 7 15 puncte 5 puncte – determinarea divizorilor care sunt primi
5 puncte – afişarea rezultatului
Total 100 puncte
Care este cea mai mare valoare posibilă pentru variabila n astfel încât algoritmul să
afişeze valoarea 5?
2. Dacă a şi b sunt variabile de tip int, stabileşte care din următoarele structuri repetitive
sunt ciclări infinite:
a) a=10; b=0; c) a=0; b==10;
do{ while((a<=10)&&(b>=0))
a--;b++; { b++;a++;}
}while (a!=b);
b) a=1; b=5; d) a=0; b=10;
while(a+b<=10) while ((a<=10)||(b>=0)
{ a=a+2; b=b-2;} {b++;a++;}
3. Fie programul:
#include<iostream.h>
void main()
{ int a,b,u,aux;
cin>>a>>b;
if(a<b) {aux=a;a=b;b=aux;}
u=0;
while(a>=b) {u++;a-=b;}
cout <<u;
}
Pentru a=2572 şi b=13 programul va afişa:
a) 11 b)91 c)197 d)13 e)199
Cuprins Pagina
tip_de_baza nume_var[dimensiune];
int tabloul_meu[100];
int tabloul_meu[100];
Exemplul 6.1
main()
{int a[20], n, i, min, max;
printf(”Introduceti dimensiunea tabloului:”);
scanf(”%d”, &n);
for (i=0; i<n; i++)
{printf(”a[%d]=”, i);
scanf(”%d”, &a[i]);
}
min=max=a[0];
for (i=1; i<n; i++)
if (a[i]>max)
max=a[i];
else
if (a[i]<min)
min=a[i];
printf(”minim=%d\tmaxim=%d\n”, min,max);}
Exemplul 6.2
main()
{unsigned int a[20], n, i, f, x;
printf(”Introduceti dimensiunea tabloului:”);
scanf(”%ud”, &n);
for (i=0; i<n; i++)
{printf(”a[%ud]=”, i);
scanf(”%ud”, &a[i]);
}
printf(”x=”);
scanf(”%ud”, &x);
f=0;
for (i=0; i<n; i++)
if (a[i]==x)
f++;
if (f==0)
printf(”numarul %ud nu se afla in vector\n”, x);
else
printf(”numarul %ud se afla in vector, aparand de
%ud ori\n”, x,f);}
int a[4]={1,2,3,4};
char s[5]={‘a’, ’b’, ‘c’, ‘d’, ‘\0’};
Dacă lista de valori iniţiale cuprinde mai puţine date decât dimensiunea
declarată a tabloului, celelalte valori se iniţializează cu zero. De exemplu,
în urma declaraţiei:
int a[20]={1,-2,3,-4,5};
Exemplul 6.3
Algoritmul de sortare prin interschimbare este unul din cei mai simpli
algoritmi de sortare, dar nu şi cel mai eficient. Acesta are la bază
următoarea metodă de sortare: fiecare element din vector a[i], 0<=i<n-1,
este comparat cu toate elementele situate în vector după el, a[j], i<j<n;în
cazul în care cele două elemente nu sunt în ordinea dorită, acestea se vor
interschimba.
main()
{int a[20], n, i, j, aux;
....................................
for (i=0; i<n-1; i++)
for (j=i+1, j<n; j++)
if (a[i]>a[j])
{aux=a[i];
a[i]=a[j];
a[j]=aux;
}
………………………….
}
i=0, j=1 este a[0]>a[1]? da, deci se vor interschimba primele 2 elemente:
a devine: 2, 7, 9, 1, 3
i=0, j=2 este a[0]>a[2]? nu, deci nu se întâmplă nimic;
i=0, j=3 este a[0]>a[3]? da, deci se vor interschimba elementele a[0] şi
a[3]:
a devine: 1, 7, 9, 2, 3
i=0, j=4 este a[0]>a[4]? nu, deci nu se întâmplă nimic;
O metodă de sortare mai eficientă şi foarte des folosită este bubble sort,
sau sortarea prin metoda bulelor. Această metodă presupune parcurgerea
vectorului şi compararea elementelor alăturate (a[i] şi a[i+1]); dacă ele nu
respectă ordinea dorită, îşi vor interschimba valorile. Vectorul va fi parcurs
de atâtea ori, până când va fi sortat, adică nu se va mai efectua nici o
interschimbare de valori. În acest scop va fi folosită o variabilă de tip
întreg, care să „ţină minte” dacă s-au mai efectuat interschimbări.
Secvenţa de algoritm corespunzătoare este:
main()
{int a[20], n, i, aux, gata=0;
....................................
while (!gata)
{
gata=1;
for (i=0; i<n-1; i++)
if (a[i]>a[i+1])
{aux=a[i];
a[i]=a[i+1];
a[i+1]=aux;
gata=0;
}
}
………………………….
}
gata =1
i=0 este a[0]>a[1]? da, deci se interschimbă cele două valori
şi gata devine zero; a devine: 2, 7, 9, 1, 3
i=1 este a[1]>a[2]? nu, deci nu se întâmplă nimic;
i=2 este a[2]>a[3]? da, deci se interschimbă cele două valori
şi gata rămâne zero; a devine: 2, 7, 1, 9, 3
i=3 este a[3]>a[4]? da, deci se interschimbă cele două valori
şi gata rămâne zero; a devine: 2, 7, 1, 3, 9
Se reia structura while, deoarece gata este zero:
gata =1
i=0 este a[0]>a[1]? nu, deci nu se întâmplă nimic;
i=1 este a[1]>a[2]? da, deci se interschimbă cele două valori
şi gata devine zero; a devine: 2, 1, 7, 3, 9
i=2 este a[2]>a[3]? da, deci se interschimbă cele două valori
şi gata rămâne zero; a devine: 2, 1, 3, 7, 9,
i=3 este a[3]>a[4]? nu, deci nu se întâmplă nimic;
Se reia structura while, deoarece gata este zero:
gata =1
i=0 este a[0]>a[1]? da, deci se interschimbă cele două valori
şi gata devine zero; a devine: 1, 2, 3, 7, 9
i=1 este a[1]>a[2]? nu, deci nu se întâmplă nimic;
i=2 este a[2]>a[3]? nu, deci nu se întâmplă nimic;
i=3 este a[3]>a[4]? nu, deci nu se întâmplă nimic;
Se reia structura while, deoarece gata este zero:
gata =1
Se mai parcurge o dată vectorul, dar nu se mai efectuează nici o
intershimbare, căci acesta este ordonat crescător. Condiţia de menţinere
în structura repetitivă nu mai este îndeplinită şi algoritmul se încheie.
Exemplul 6.4
2. Se citeşte un şir de numere întregi până la introducerea valorii zero. Să se formeze doi
vectori: unul cu numerele pare introduse, iar celălalt cu cele impare. Să se afişeze
conţinuturile celor doi vectori.
Exemplu: numerele introduse sunt: 7, -5, 8, 1, 2, -6, 3, 0
cei doi vectori vor fi: a[0]=8, a[1]=2, a[2]=-6
b[0]=7, b[1]=-5], b[2]=1, b[3]=3
6.2 Pointeri
Pointerii sunt variabile care conţin (sunt capabile să conţină) adresele
unor altor variabile sau obiecte, deci practic adrese de memorie.
Dimensiunil pointerilor (câţi octeţi ocupă) depind de maşină, de
implementarea limbajului, etc. În general, acest aspect trebuie luat în
consideraţie doar din punct de vedere al portabilităţii programelor; un
program bun nu trebuie să depindă de dimensiunile concrete ale
pointerilor şi, în general, să funcţioneze corect pe orice implementare a
limbajului care respectă standardul ANSI.
Un pointer este asociat unui tip de variabile: există pointeri către char, int,
float etc. Dacă T este un tip de date standard sau definit de utilizator, un
pointer către tipul T se declară prin:
T *p;
Iată câteva exemple de declaraţii de pointeri:
int *pi; float *pf;
char *pc;
ceea ce înseamnă că pi este un pointer către întreg, pf este un pointer
către float (real), iar pc unul către caracter. Se pot declara mai mulţi
pointeri pe acelaşi rând, împreună cu variabile de acelaşi tip, fiecare
variabilă de tip pointer trebuind să fie precedată de simbolul “*”:
char *pc, c, *pa, a;
În această situaţie, pc şi pa sunt pointeri la char, iar a şi c sunt variabile
de tip char.
În exemplul de mai sus, *pc este variabila de tip char, aflată la adresa pc,
adică tocmai variabila c. Avem astfel două moduri de acces la variabila c:
prin specificarea numelui ei şi prin intermediul pointerului pc, care a fost
poziţionat pe c.
Cei doi operatori, & şi * sunt operatori inverşi: dacă x este de tip T1 şi px
este de tip T2*, atunci *(&x) este identic cu x şi &(*px) este identic cu px.
În concluzie:
Exemplul 6.5
main()
{
int i=1, j=5, *p=&i;
*p=2;
(*(p=&j))++;
printf(“i=%d j=%d\n”,i ,j);
}
Exemplul 6.6
#include <stdio.h>
main()
{
int a=59;
printf(“a are adresa %p si continutul %d\n”,&a, a);
int *adr1=&a;
printf(“adr1 are adresa %p si continutul %p\n”,&adr1,
adr1);
int **adr2=&adr1;
printf(“Variabila adr1 are adresa %p si continutul
%p\n”,&adr2, adr2);
printf(“%p %p %p %d”, &adr2, adr2, *adr2, **adr2);
}
Figura 6.1
adresa
a adresa a
adr1
a adr1 adr2
5. Care din următorii termeni este cel care indică rezervarea spaţiului de memorie necesar
unei variabile?
A. new
B. malloc
C. create
D. value
Exemplul 6.8
#include <string.h>
#include <iostream.h>
void main()
{
char s1[100],s2[100];
int p;
cout<<”Introduceti primul sir: ”; cin>>s1;
cout<<”Introduceti al doilea sir: ”; cin>>s2;
p=strcmp(s1,s2);
if (p<0) cout<<”s1<s2”;
else
if (p>0) cout<<”s1>s2”;
else cout<<”s1=s2”;
}
O altă funcţie care compară două şiruri de caractere, dar numai pentru
primele n caractere, este:
Exemplul 6.9
#include <string.h>
#include <iostream.h>
void main()
{
char s1[100]=”sirul copiat”,s2[100]=”sirul destinatie”;
strcpy(s2,s1);
cout<<s2<<endl;
strncpy(s2, s1, 5);
s2[5]=’\0’;
cout<<s2<<endl;
}
Exemplul 6.10
#include <string.h>
#include <iostream.h>
void main()
{
char s[100];
cin.get(s,100);
cout<<”sirul ”<<s<<” are ”<<strlen(s)<<” caractere”<<endl;
}
Exemplul 6.11
#include <string.h>
#include <iostream.h>
void main()
{
char s1[100]=”Astazi ”,s2[100]=”invatam”;
strcat(s1,s2);
cout<<s1<<endl;
strncpy(s1, s2, 5);
s2[5]=’\0’;
cout<<s2<<endl;
}
Exemplul 6.12
#include <string.h>
#include <iostream.h>
void main()
{
char *p=;
p=strchr(“Acesta este un test”,’ ‘);
cout<<p<<endl;
}
Exemplul 6.13
Exemplul 6.14
#include <string.h>
#include <iostream.h>
void main()
{
char s[50]= “Acesta este un test”;
p= (“Acesta este un test”,’ ‘);
cout<< strchr (s,’t’)-s<<endl;
}
118 Proiectul pentru Învăţământul Rural
Tablouri
1. Considerăm declaraţia:
char *c, a[100], b[100];
Să se determine care dintre expresiile următoare sunt corecte:
A. a=”sir de caractere”;
B. c=strcat(a,b);
C. (a<=b &&b!=c);
D. c++;
E. a=strchr(”exercitii”,’ ‘);
F. c=strcpy(a,b);
3. Fie declaraţiile:
char a[50];unsigned int i;
Ştiind că şirul de caractere a se termină cu caracterul punct, care din secvenţele de mai
jos este echivalentă cu funcţia strlen()?:
a) i=0;
while (a[i++]!=’.’) {}
cout<<i;
b) i=0;
while (a[i++]==’.’) {}
cout<<i;
c) i=0;
if (a[i]==’.’) cout<<i;
d) if (a[i]!=’.’) cout<<i;
5. Operaţia de alipire a două şiruri de caractere poartă numele de ………, iar funcţia care
caută un caracter dat într-un şir de caractere se numeşte …....
BIBLIOGRAFIE
#include <iostream.h>
void main()
{ int a[11],I;
for(i=1;i<=10;i++)
a[i]=i-1; a) 2113
cout<<a[2]<<” ”; b) 1003
cout<<a[a[2]]<<” ”; c) 1002
cout<<a[a[a[3]]]<<” ”; d) 3840
cout<<a[a[2]+a[3]]<<” ”;
}
7. Într-un şir de caractere s cuvintele sunt separate de unul sau mai multe
spaţii. Să se elimine spaţiile în plus din şirul s.
Cuprins Pagina
Exemplul 7.1
Observaţii:
Exemplul 7.2
Exemplul 7.3
Observaţie:
Se deduce că fişierul date.txt se află pe hard-disc în directorul curent.
Exemplul 7.4
Observaţie:
Exemplul 7.5
Observaţie:
Exemplul 7.6
Observaţie:
Exemplul 7.7
Exemplul 7.8
ifstream f1(“aplicatie.in”);
char c;
f1>>c; // am citit primul caracter din fişierul f1.
Observaţie:
Exemplul 7.9
ifstream f1(“aplicatie.in”);
char c;
f1.get(c); /* am citit primul caracter din fişierul f1, indiferent
dacă este sau nu character alb, folosind funcţia get()*/
Exemplul 7.10
ofstream f2(“aplicatie.out”);
f2<< “aplicatia mea”;
Observaţii:
1. Există funcţia membru care testează reuşita unei operaţii de intrare
– ieşire: good() – returmează o valoare diferită de 0 dacă operaţia
s-a efectuat cu succes şi 0 în caz contrar..
Exemplul 7.11
ifstream fisier(“text.in”);
char c, car;
int x=0;
cin>>c; // in c retin caracterul a carui frecventa o determin
while (! fisier.eof())
{fisier.get(car); // citesc un caracter din fisier
if(car==c) x++;} // si daca este egal cu c incrementez x
cout<< “frecventa lui”<<car<<” in fisier este”<< x;
Scrie secvenţa de program care numără toate caracterele existente într-un fişier.
Barem:
declaraţii corecte 10 puncte
citirea corectă din fişier 10 puncte
Numărarea caracterelor din fişier 20 puncte
afişarea corectă a rezultatului 10 puncte
total 50 puncte
Exemplul 7.12
f1.close();
Observaţie:
Operaţia de închidere este obligatorie, mai ales pentru fişiere de ieşire.
Dacă nu se închide fişierul de ieşire, există riscul de a pierde informaţii.
Alege, prin încercuire, varianta corectă de răspuns pentru următoarele două teste.
Răspunsul pentru fiecare cerinţă valorează 20 de puncte.
a) 187 abc 6 7 8 gg 5 90
b) 187abc678 gg590
c) 187abc678gg590
d) 187 ab c67 8gg 5 90
a) c)
fstream f; fstream f;
f.open(“test.txt”, ios::in); f.open(“test.txt”, ios::app);
f<<”ultima linie”; f<<endl<<”ultima linie”;
f.close(); f.close();
b) d)
fstream f; fstream f;
f.open(“test.txt”, ios::app); f.open(“test.txt”, ios::out);
f<<”ultima linie”<<endl; f<<endl<<”ultima linie”;
f.close(); f.close();
Exemplul 7.15
{
int x;
ifstream f("NUMERE.TXT");
ofstream g("PARE.TXT");
while(!f.eof())
{ f>>x; /* se citeşte câte un număr din stream-
if((x%2)==0) g<<x<<endl; } ul f atât timp cât nu s-a ajuns la
f.close(); sfârşitul fişierului f, apoi se verifică
g.close(); dacă num[rul e par şi în caz afirmativ
} se scrie în stream-ul g */
Figura 7.2
1. b) Vezi U7.2, pag 124, U7.3, pag 125, U7.6, pag. 127
2. c) Vezi U7.2, pag 124, U7.3, pag 125, U7.6, pag. 127
Bibliografie
1. Un fişier text conţine numere întregi dispuse pe mai multe linii. Se cere înlocuirea în
fişier a tututor apariţiilor unui număr x cu un alt număr y, unde x şi y sunt citite de la
tastatură. Realizează un program care permite efectuarea acestei modificări asupra
conţinutului fişierului.
2. În fişierul lipsa.in există dispuse pe fiecare linie câte un număr din şirul primelor n
(n<100) numere naturale nenule. Excepţie face un singur număr care a fost omis. Scrie un
program care determină numărul lipsă.
Ex: lipsa.in conţine 4 1 3 5 si se va afişa 2
3. În fişierul numar.in există pe prima linie un şir crescător de numere naturale. Citirea din
fişier a unui nou număr este condiţionată de obţinerea, ca sumă de termeni distincţi din
fişier, a unui şir de numere consecutive – începând cu 1. Determină care este numărul
maxim care se poate obţine respectând regula dată.
Ex: numar.in conţine 1, 2, 4, 10, 13, 132, 562, 1200. Se va afişa 7, deoarece citirea din
fişier se încheie odată cu citirea numărului 10. Valoarea 8 nu se poate forma ca sumă de
termeni preluaţi din fişier. Algoritmul verifică valorile şi validează 1, 2, 3(1+2), 4, 5(1+4),
6(2+4), 7(1+2+4).
4. Scrie un program care să testeze dacă două fişiere ale căror nume este cunoscut sunt
identice.
FUNCŢII
Cuprins Pagina
În acest capitol vei învăţa cum să descrii propriile tale funcţii, numite în
continuare funcţii utilizator.
Atenţie!
Într-un program C / C++ toate prelucrările sunt organizate sub forma unei
ierarhii de apeluri de funcţii, baza ierarhiei fiind funcţia principală main().
{
declaratii variabile locale
instructiuni // blocul
funcţiei
}
unde:
tip – este tipul rezultatului returnat de funcţie;
nume – este numele funcţiei;
lista parametrilor formali – este alcătuită din una sau mai multe declaraţii
de parametri cu care funcţia operează, separate prin virgulă. Această listă
poate fi vidă. Parametrii formali se numesc astfel deoarece cu ajutorul lor
voi descrie în mod formal operaţiile care se vor efectua cu datele
transmise de programul apelant.
Exemplul 8.1
Observaţii:
1. funcţia suma are tipul void, adică nu întoarce un rezultat;
2. parametrii formali sunt de tip intreg.
3. funcţia afişează suma celor două numere transmite ca parametri de
programul apelant.
Exemplul 8.2
Observaţii:
1. funcţia suma are tipul intreg şi calculează suma a două numere intregi,
transmite ca parametri de programul apelant;
2. variabilele i şi s sunt declarate în blocul funcţiei şi se numesc variabile
locale;
3. în blocul funcţiei intervine instrucţiunea return. Ea returnează
programului apelant valoarea variabilei s.
Atenţie!
Declaraţia unei funcţii este alcătuită din antetul funcţiei urmat de caracterul
„;”, nu de blocul de instrucţiuni al funcţiei. De aceea, declaraţia funcţiei se
mai numeşte şi prototip.
Atenţie!
Exemplul 8.3
double sqrt(double);
Observaţii:
1. funcţia sqrt() are tipul double şi returnează radicalul valorii primite ca
parametru;
2. are prototipul în math.h.
Exemplul 8.4
Observaţii:
1. funcţia calcul() are tipul real, are doi parametri: unul de tip int şi un
tablou de 10 valori de tip int;
2. în declaraţia funcţiei calcul() este specificat numele parametrilor, nu
doar tipul acestora.
A – F 1) Într-un program toate prelucrările sunt organizate sub forma unei ierarhii de
apeluri de funcţii, baza ierarhiei fiind funcţia principală main().
A – F 4) Lista parametrilor formali este alcătuită din una sau mai multe declaraţii de
parametri cu care funcţia operează, separate prin virgulă.
A- F 5) Orice apel de funcţie este succedat fie de definiţia funcţiei, fie de declaraţia
acesteia.
unde:
- nume – este numele funcţiei;
Atenţie!
Exemplul 8.5
float ma;
int a,b;
ma= suma(a,b)/2;
Observaţii:
1. valoarea parametrului actual a înlocuieşte parametrul formal x, iar
valoarea parametrului actual b înlocuieşte valoarea parametrului formal
y.
Atenţie!
Exemplul 8.6
cout<<”a=”<<a;
cout<<” b=”<<b<<endl;
afisare(a,b);
cout<<”a=”<<a;
cout<<” b=”<<b<<endl;
afişează pe ecran:
a=10 b=75
x=10 y=75
a=10 b=75
Scrie o nouă analogie (maxim 300 cuvinte) prin care să ilustrezi transferul parametrilor prin
valoare. Se notează cu 10 puncte ingeniozitatea ideii, cu 10 puncte coerenţa în exprimare
şi se acordă 30 puncte expunerii analogiei. Punctaj minim: 30.
Exemplul 8.7
Voi considera funcţia din exemplul trecut care afişează valorile a doi
parametri intregi x şi y şi voi schimba modul de transmitere parametri:
cout<<”a=”<<a;
cout<<” b=”<<b<<endl;
afisare(a,b);
cout<<”a=”<<a;
cout<<” b=”<<b<<endl;
afişează pe ecran:
a=10 b=75
x=10 y=75
a=11 b=76
Alege, prin încercuire, varianta corectă de răspuns pentru următoarele teste. Răspunsul
pentru fiecare cerinţă valorează 20 de puncte. Punctaj minim: 80.
#include<iostream.h>
int a;
void f1(int a)
{a=20; cout<<a;}
void f2(int &a)
{a=30; cout<<a;}
void main()
{int a=10;
f1(a);cout<<a;
f2(a);cout<<a;
}
a) 10 10 20 30
b) 20 10 30 10
c) 20 10 30 30
d) 20 20 30 30
a) int f1(int y)
b) int f2(int x,y)
c) iostream f3
d) float f4(char c)
e) double f5(int x, float y)
3. Indicaţi care dintre funcţiile următoare returnează media aritmetică dintre câtul şi restul
la împărţirea a două numere întregi:
a)
int medie(int x,y)
{ return (x/y+x%y)/2;}
b)
float medie(int x, int y)
{ float med;
med=x/y+x%y;
return med/2;}
c)
float medie(int x, int y)
{ return x/y+x%y;}
4. Fie funcţia:
Dacă x şi z sunt două variabile de tip char ce memorează valorile „1” respectiv “2”, ce
valori se vor afişa după executarea secvenţei de instrucţiuni:
interschimbare(x,y);
cout<<x<<” “<<z;
a) 1 2 c) 2 2
b) 2 1 d) 1 1
#include<iostream.h> a) 1
#include< math.h> b) 2
int radical(int p, int q) c) 3
{ return (sqrt(p*q);} d) 4
void main() e) nici una
{cout<<radical(1,2);}
1
Cazurile de omonimie şi regula de omonimie nu sunt obiect de studiu în cadrul acestui manual. Omonimia
poate fi studiată din alte cărţi de specialiate înpreună cu operatorul de rezoluţie „::”.
Exemplul 8.8
Alege, prin încercuire, varianta corectă de răspuns pentru următoarele teste. Răspunsul
pentru fiecare cerinţă valorează 20 de puncte. Punctaj minim: 80.
1. Stabileşte care dintre următoarele funcţii întorc poziţia primei valori strict pozitive din
tabloul unidimensional v, care conţine numere întregi, sau 0 dacă nu conţine nici un număr
pozitiv.
a)
int p(int v[11], int n) c)
{ int i,x; int p(int v[11], int n)
x=0; { int x;
for(i=1;i<=n;i++) if (v[i]>0)x=i; x=0;
return x; while ((v[x+1]<=0)&&(x<=n-1)) x++;
} return x+1;
}
b)
int p(int v[11], int n) d)
{ int x; int p(int v[11], int n)
x=0; { int i;
while (v[x]<=0) x++; for(i=1;i<=n;i++) if (v[i]>0) return i;
return x; return 0;
} }
Stabileşte cu care dintre expresiile de mai jos trebuie înlocuite spaţiile punctate astfel încât
funcţia să întoarcă 1, dacă şirul s este palindrom, sau 0 dacă şirul s nu este palindrom.
a) i<strlen(s)/2 -1
b) (i<=j)&&(p==1)
c) (i!=j)&&(p==1)
d) i<(strlen(s) -1)/2
#include<iostream.h>
int a,b;
void calcul (int &x, int &y)
{int a;
a=x+y;
y+=a; a) 10 110
x+=b; b) 220 110
} c) 110 110
void main() d) 220 210
{a=10; b=100;
calcul(a,b);
cout<<a<<” “<<b;}
4. Consider x o variabilă întreagă a cărei valoare este 2. Ce valoare va avea x după apelul
f(x,x)?
a) 2 b)6 c) 8 d)4
5. Care dintre următoarele funcţii returnează cel mai mare număr natural p cu proprietatea
că 2p<=n.
a)
int f(int n) c)
{int p=0; a=1; int f(int n)
while(e<=n) { p++;a*=2;} {
return p;} int p=0; a=1;
while(e<n) { p++;a*=2;}
b) return p;
int f(int n) }
{int p=0; a=1;
while(e<=n) { p++;a*=2;}
return p-1;}
Considerăm un vector cu n (n<101) componente numere naturale mai mici sau egale cu
30000. Scrie un program care calculează şi afişează suma componentelor prime.
Foloseşte pentru acesta o funcţie pentru citirea vectorului şi o funcţie care verifică dacă un
număr e prim.
Ex:
Pentru n=5 şi numerele 1 4 7 33 5 se afişează 13.
Barem:
Barem:
Exemplul 8. 11
Pentru a verifica dacă un vector este mulţime trebuie să testez dacă există
elemente care se repetă. Pentru a verifica mai uşor acest lucru, voi ordona
vectorul prin metoda „bulelor”.
Voi folosi o funţie pentru citirea componentelor vectorului şi o alta pentru
testarea propriu-zisă.
#include<iostream.h>
int n, x[50];
void main()
{
cout<<”n=”;cin>>n;
citire(n,x);
testare(n,x);
Se dau două mulţimi A şi B, ale căror elemente sunt literele mici ale alfabetului englez.
Scrie un program care determină numărul de elemente ale mulţimilor AUB şi A∩B, folosind
o funţie perntru citirea elementelor unei mulţimi şi câte o funcţie care returnează cardinalul
unei mulţimi pentru fiecare din operaţii ( U , ∩ ).
Ex: pentru mulţimea A={ c, m, p, r, z} şi mulţimea B={ a, b, c, d, p ,z} se va afişa: 8 3.
Barem:
b daca a=1
produs(a,b)=a*b=a+a+a+…+a=(a-1)*b+b=
b+produs(a-1,b),daca a>1
b ori
Figura 8.1
Exemplul 8. 12
Dacă n=0, se va afişa p(0)=1, adică 2*0+1, iar dacă n=3, se va afisa
p(3)=105, adică 1*3*5*7.
#include<iostream.h>
long p(long x)
{ if(x) return;
else return 1;
}
void main()
{ long n;
do{
cout<<”n=”;cin>>n;}while(n>=0);
cout<<p(n);
}
Observaţii:
1. condiţia de ieşire din funcţie este:x=0. Funcţia returnează valoarea 1
dacă x=0.
2. definirea recursivă a funcţiei este dată de formula (2*x+1)*p(x-1), unde
p(x-1) autoapelul.
Atenţie!
Analizează următorul algoritm şi răspunde cerinţelor de mai jos. Fiecare răspuns corect
valorează 30 puncte. Punctaj minim: 70. Se acordă 10 puncte din oficiu.
#include<iostream.h>
int s(int a,int b)
{ if(!b) return a;
else return s(++a,--b);}
void main()
{int a,b;
cin>>a>>b;
cout<<s(a,b);}
a) Ce realizează programul de mai sus?
b) Justificaţi răspunsul de la punctul a) prin construirea unui tabel al evoluţiei
variabileor pe parcursul apelurilor.
c) Scrie forma iterativă a algoritmului propus la punctul a).
Exemplul 8. 13
int fib(int n)
{
if (n==1) return 1;
else if(n==2) return 1;
else return fib(n-1)+fib(n-2);
}
fib(6)=fib(5)+fib(4)=
fib(4)+fib(3)+fib(4)=
.
.
.
=1+1+1+1+1+1+1+1=8
Scrie un program prin care se citeşte numărul n natural de la tastatură. Programul trebuie
să apeleze o funcţie recursivă, care returnează valoarea sumei:
S(n)= 2+5+8+…+( 2+3*n).
Ex: pentru n=3, se va afisa valoarea 26, adica s(3)=2+5+8+11.
Barem:
Exemplul 8. 14
0 daca a≤b
f(a,b)=
1+f(a-b,b) daca a≥b
t x
1 5
2 2
3 1
4 0
Pas 3. Scriu funcţia recursivă care contorizează împărţirile întregi ale lui x
– transmis prin adresă - la 2.
int f (int &x)
{
if(x)
{ x/=2;
return f(x)+1;
}
else return 1;}
Exemplul 8. 15
Recursivitatea indirectă este ilustrată prin următorul exemplu (şirurile lui Gauss):
an-1+bn-1
Fie an= bn=√ an-1 bn-1 , unde a0=a; b0=b
2
Figura 8.2
Pentru a, b şi n numere naturale date, vreau să calculez termenul n al
şirului a şi termenul n al şirului b.
#include<iostream.h>
// variabile globale
double a,b;
int n;
// declaratia functiei bb
double bb(int n);
// definirea functiei aa; calculează termenul n al şirului a
double aa(int n)
Proiectul pentru Învăţământul Rural 151
Funcţii
{if(!n) return a;
else return (aa(n-1)+bb(n-1))/2;
}
Figura 8.3
// definirea functiei bb; calculează termenul n al şirului b
double bb(int n)
{
if(!n) return b;
else return sqrt(aa(n-1)*bb(n-1));
}
void main()
{
cout<<a<<b<<n;
cout<< aa(n);
}
Observaţii:
1. declaraţia funcţiei bb() trebuie să preceadă apelul său;
2. funcţia principală main() apelează numai funcţia aa(), cu care se
porneşte la efectuarea calculului termenilor şirului.
Atenţie!
Pentru calculul 3a[i] poţi folosi o funcţie care determină cifrele acestei puteri într-un vector.
Calculul sumei a două numere naturale se va face pentru numerele date prin doi vectori,
rezultatul fiind tot un vector.
De menţionat este faptul că, cifrele numerelor sunt reţinute în vectori începând cu cifra
unităţilor către prima cifră.
Soluţie:
Construiesc recurenţa:
2 daca n=0
S(n)=
3*n+2+S(n-1) daca n>0
Bibliografie
Aplicaţia 1 5 puncte
Aplicaţia 2 5 puncte
Aplicaţia 3 5 puncte
Aplicaţia 4 5 puncte
Aplicaţia 5 25 puncte 5 puncte –declaraţii corecte
5 puncte – funcţia care determină numărul de
numere din fişierul de intreare
5 puncte – determinarea numărul de numere din
fişierul numere.in care au exact 3 cifre
5 puncte - determinarea celui mai mare număr din
fişierul numere.in
5 puncte - scrierea rezultatelor in fişierul de ieşire
5 puncte – declaraţii corecte
10 puncte – afişează cifrele distincte din n
Aplicaţia 6 25 puncte
10 puncte – afişează câte numere se pot forma cu
toate cifrele distincte din n
5 puncte – a)
Aplicaţia 7 20 puncte 10 puncte – b)
5 puncte – c)
5 puncte – corectitudinea antetultui, a listei de
Aplicaţia 8 10 puncte parametri
5 puncte – scrierea corectă a blocului funcţiei
Total 100 puncte
1. Se consideră programul:
#include<iostream.h>
int a,b,c;
void expresie(int a, int b)
{a+=c;
b+=c;
c=a+b;}
void main()
{ a=1; b=2; c=3;
expresie(a,b);
cout<<a<<b<<c;}
int expresie2(long n)
{
int i,m;
m=0;
for (i=1;i<=10;i++) if(expresie1(n,i)) m++;
}
void main()
{cout<<expresie2(12129002);}
4. Consider funcţia:
int expresie(long k)
{ if (k==0) return 1;
else if( k%10!=0) return expresie(k/10)*(k%10);
else expresie(k/10);
}
Care va fi valoarea expresiei: expresie(192)+expresie(2005) ?
5. În fişierul numere.in se află numere cu cel mult 10 cifre fiecare. Pe aceeaşi linie
numerele sunt separate prin câte un spaţiu. Scrie un program care crează un fişier
numere.out cu următorul conţinut:
- pe prima linie – numărul de numere din fişierul numere.in;
- pe a doua linie – numărul de numere din fişierul numere.in care au exact 3 cifre;
- pe a treia linie – cel mai mare număr din fişierul numere.in.
Ex:
Fişierul numere.in conţine:
12 34 567
1223456 89 789 90 89
13
56 7890
Fişierul numere.out conţine:
11
2
1223456
7. Considerăm programul:
#include<iostream.h>
int x[11], y[11], dx,dy;
void cit(int n, int x[11])
{
cin>>n;
for(int i=1;i<=n;i++) cin>>x[i];}
void main()
{
cit(dx,x);cit(dy,y);
cout<<suma(dx,x)<<endl<<suma(dy,y);
}
a) Ce se va afişa pe ecran după executare dacă dx=3, x=(1,2,3), dy=5, y=(1,2,3,4,5)?
i) 0 0 ii) 6 6 iii) 15 15 iv)6 15
b) Transformă funcţia iterativă suma() într-o funcţie recursivă.
c) Cum se modifică programul astfel încât să se afişeze valorile 6 15.
8. Scrie o funcţie recursivă care determină elementul maxim dintre componentele unui
vector. Funcţia va avea ca parametri vectorul şi lungimea sa.
ANEXE
Laboratorul 1
Exemplul 2.5
⎧ A2 − B,c < 0
⎪⎪
E= ⎨ A 2 − B , c = 0
⎪ 1 − B,c > 0
⎪⎩ A 2
Schema logică a acestei probleme se află pe pagina următoare.
START
CITESTE A,B,C
DA NU
C<0
NU DA
C=0
E=A2-B
NU A2-B>=0
AFISEAZA
E
E= A2 − B
Afiseaza
“Expesia nu
are sens”
AFISEAZA
NU DA E
A=0
E=
1
A2
−B
Afiseaza
“Expesia nu
are sens”
AFISEAZA
E
STOP
1. Un melc se deplasează cu viteza v km/săptămână. De cât timp (în ore) are nevoie melcul pentru
a străbate distanţa d dată în metri.
1km=1 000m;
1 săptămână = 7 zile = 7 . 24 ore = 168 ore;
v km/săptămână = 1 000 / 168 m / oră;
real v, d, T
citeste v,d
T=d / (v * 1 000/168)
scrie T
2. Perimetrul unui pătrat este egal cu latura altui pătrat. Ştiind că suma perimetrelor este x, să se
calculeze ariile celor două pătrate.
Perimetrul P1=4 L1
P1=L2 şi P2=4 L2 ⇒ 4 L1 = L2
P1 + P2 = x ⇒ 4 L1 + 4 L2 = x ⇒ 5 L2 =x ⇒ L2=x/5 şi L1= L2/4. adică L1=x/20
Deci A1 = L12 = (x/20)2 şi A2 = L22 = (x/5)2
real x, A1, A2
citeşte x
A1=(x/20)*(x/20)
A2=(x/5)*(x/5)
scrie A1, A2
3. Fiind date trei numere întregi a, b ,c, să se interschimbe valorile celor trei numere, astfel:
b, c, a (a primeşte valoarea lui b, b pe a lui c şi c ia valoarea lui a);
c, a, b (a primeşte valoarea lui c, b pe a lui a şi c ia valoarea lui b);
c, b, a (se inversează ordinea variabilelor).
Indicaţie: se foloseşte o singură variabilă auxiliară, aux, pentru a putea face interschimbările
necesare
întregi a, b, c, aux
citeşte a, b, c
aux=a a b c
a=b
b=c aux
c=aux
scrie a, b, c
stop
⇒ b c a
4. Se dau patru numere a, b, c, d reale. Să se permute valorile acestor variabile astfel încât la
tipărire ele să aibă valorile rezultate din permutările lor circulare , la stânga, respectiv la dreapta,
cu o poziţie:
b, c, d, a
d, a, b, c
Problema este asemănătoare cu cea anterioară; iată o secvenţă din rezolvarea celui de-al doilea
subpunct:
..........
aux=a Se poate observa modificarea ordinii de permutări ale
a=d variabilelor
d=c
c=b
b=aux
⎧ pd − bq
⎪⎪ x = ad − bc
⎨ daca ad − bc ≠ 0
⎪y = aq − cp
⎪⎩ ad − bc
În cazul în care numitorul fracţiilor este egal cu zero, cele două ecuaţii reprezentate grafic vor fi
două drepte paralele sau confundate; primul caz are loc dacă pd-bq≠0 şi în această situaţie
sistemul nu are nici o soluţie – este incompatibil – iar în caz contrar are o infinitate de soluţii – este
nedeterminat – iar soluţiile vor fi mulţimea punctelor situate pe cele două drepte confundate.
2. Să se scrie algoritmul de rezolvare a următoarei probleme: acum este ora h1, minutul m1 şi
secunda s1. Cât va fi ceasul peste h2 ore, m2 minute şi s2 secunde? Rezultatul va fi reprezentat
tot în ore, minute şi secunde.
Trebuie ţinut cont de faptul că 1min=60 secunde, 1h=60 min şi o zi are 24 de ore. Astfel, dacă
suma secundelor depăşeşte valoarea 60, atunci înseamnă că 60 secunde vor da 1 minut. La fel se
întâmplă şi în cazul minutelor, dacă suma lor este mai mare decâ 60, va fi o oră în plus. De fiecare
dată va trebui să scădem cele 60 de unităţi care au fost transformate într-o unitate de rang
superior.
Trebuie să permutăm valorile celor 3 variabile, astfel încât, la final, ele să fie ordonate crescător.
Valorile variabilelor se compară două câte două şi, dacă nu respectă ordinea dorită, îşi
interschimbă valorile prin intermediul unei variabile auxiliare aux.
b=aux
dacă b>c atunci
aux=b
b=c
c=aux
dacă a>b atunci
aux=a
a=b
b=aux
Indicaţie: După citirea valorilor pentru a, b şi x trebuie evaluată valoarea produaului a*b,
comparată cu zero şi calculată valoarea lui E în funcţie de semnul acestui produs;sunt suficiente
două structuri alternative
1. Să se scrie algoritmul pentru calcularea sumei primelor n numere naturale impare, unde n este
un număr natural strict pozitiv, dat.
n
Trebuie calculată suma: S = 1 + 3 + 5 + … + (2n − 1) = ∑ (2k − 1)
k =1
n ∈N
Problema seamănă foarte mult cu cea referitoare la calcularea sumei primelor n numere naturale,
cu deosebirea că pasul de incrementare al variabilei de tip contor este 2 (Ex. 2.8)
intregi n, k, s
citeşte n
k=1
s=0
repetă
s=s+i
k=k+2
până_când k>2n-1
scrie s
stop
2. Se citeşte un şir de numere naturale până la introducerea valorii zero. Să se determine media
aritmetică a numerelor pare introduse şi produsul numerelor impare.
Pentru rezolvarea problemei trebuie folosită o structură repetitivă cu test iniţial, verificându-se de
fiecare dată dacă numărul citit a fost zero. Pentru a calcula media aritmetică a unui şir de numere,
trebuie calculată mai întâi suma acestora şi, în acelaşi timp, numărându-se câte valori au fost
introduse în sumă. Media lor aritmetică va fi egală cu suma acestora împărţită la numărul de valori
introduse în sumă. Atenţie! Dacă această valoare este zero, nu avem voie să facem
împărţirea!
real medie
întreg x, n, S, P
citeşte x
n=0
S=0
P=1
cat_timp x ≠ 0 execută
daca x%2=0 atunci x este par
S=S+x
n=n+1
altfel
P =P * x
citeşte x
dacă n ≠0 atunci
medie=S/n
scrie medie
altfel
scrie „Nu au fost introduse numere pare”
dacă P ≠1 atunci
scrie P
altfel scrie „Nu au fost introduse numere impare sau ≠ 1”
stop
3. Se citeşte un şir de numere naturale până la introducerea valorii zero. Să se determine suma
numerelor de pe poziţiile pare (suma dintre al doilea, al patrulea, etc) şi produsul numerelor de pe
poziţiile impare (produsul dintre primul, al treilea, al cincilea, etc).
Diferenţa faţă de problema anterioară constă în selectarea elementelor care se introduc în sumă,
respectiv produs. De data aceasta, trebuie verificată paritatea sau imparitatea poziţiilor în şirul
numerelor introduse
întreg x, n, S, P
citeşte x
n=0
S=0
P=1
cat_timp x ≠ 0 execută
n=n+1
daca n%2=0 atunci poziţie pară
S=S+x
altfel
P =P * x
citeşte x
dacă n ≠0 atunci
scrie S, P
altfel
scrie „Nu au fost introduse numere diferite de zero”
stop
real E1, E2
intreg n,i
citeşte n
E1=0 sau E2=0
pentru i=1, n execută
E1=E1+1/(i*(i+1)) sau E2=E2+2*i/((2*i-1)*(2*i+1))
scrie E1 sau scie E2
stop
n ⎬ ⇒ aS n + bS n −1 + cS n − 2 = 0
n −1
ax 2 + bx 21 n−2
+ cx 21 = 0⎪⎭
Pentru determinarea lui S n este necesară cunoaşterea valorilor sumelor de ordin n-1 , respectiv n-
2. Asta înseamnă că la început trebuie cunoscute valorile lui S1 = −b / a şi S 2 = S12 − 2 * c / a , din
care se poate calcula valoarea lui S3, din sumele S2 şi S3 se poate calcula S4 , şi aşa mai departe.
În implementarea acestui algoritm sunt necesare trei variabile pentru sume, şi anume S1, S2 şi S;
la un moment dat, din valorile lui S1 şi S2, folosind relaţia matematică de recurenţă pentru calculul
lui Sn, se obţine o nouă valoare pentru S, se incrementează contorul ce ţine evidenţa numărului de
ordine al sumei calculate şi se determină noile valori pentru S1 şi S2: S1 preia valoarea lui S2, S2
pe a lui S, şi se poate trece la un nou pas în determinarea sumei cerute
Laboratorul 2
3.6.4 Operatori logici pe biţi
Posibilitatea utilizării operatorilor pe biţi oferă limbajului C facilităţi
asemănătoare cu cele ale limbajelor de asamblare.
Exemplul 3.20
Cel de-al optulea bit este în general ”bitul de paritate”. Pentru ca acestuia
să i se dea valoarea zero, se face ŞI logic pe biţi între acest octet şi unul
în care biţii de la 1 la 7 sunt egali cu 1, iar al optulea este zero, adică
numărul 127. Expresia ch & 127 semnifică aplicarea unui ŞI biţilor din ch
cu biţii care alcătuiesc numărul 127. Rezultatul este acela că al optulea bit
din ch este stabilit la zero. Presupunem că ch a primit ca valoare
caracterul ”A” şi avea stabilit bitul de paritate:
Bit de paritate
Exemplul 3.21
Operatorul SAU logic pe biţi poate fi folosit pentru a stabili valoarea unui
bit. Orice bit cu valoarea 1 dintr-unul din operanzi determină ca bitul
corespunzător din rezultat să fie setat la 1. De exemplu, iată operaţia
128 | 3:
10000000 128 în binar
00000011 3 în binar
|
10000011 rezultatul lui SAU pe biţi
Operatorul ^ – SAU EXCLUSIV pe biţi are sintaxa:
expr1 ^ expr2
În urma folosirii acestui operator, biţii pe poziţii egale din cele două
expresii care au valoari diferite vor determina valoarea 1 pe bitul de pe
aceeaşi poziţie din rezultat; Dacă biţii sunt egali, biţii rezultatului vor lua
valoarea 0.
Exemplul 3.22
Exemplul 3.23
Fie biţii b1 şi b2. Conform celor spuse mai sus, rezultatele principalelor
operaţii pe biţi sunt:
Laboratorul 3
Exemplul 4.8
char a;
a=getchar();
putchar(a);
putchar(getchar());
O altă funcţie de intrare este getche() (get character with echo) care
permite preluarea caracterelor imediat ce au fost tastate, fără a mai apăsa
tasta enter. Caracterul tastat este afişat pe ecran în ecou. O funcţie
asemănătoare este getch(), care nu mai afişează caracterul tastat (fără
ecou). Aceste două funcţii aparţin bibliotecii de funcţii conio.h (console
input/output).
Exemplul 4.9
main()
{
char ch;
printf(“Tasteaza un caracter: ”);
ch=getche();
Tasteaza un caracter: A
Caracterul tastat a fost A
Exemplul 4.10
Exemplul 4.11
Aplicaţia din Exemplul 4.5 poate fi rescrisă cu ajutorul lui cin şi cout astfel:
#include <iostream.h>
main()
{
int ev;
float timp;
char poz;
cout<<“Introduceti poz, ev,timp: ”
cin>>poz>> ev>> timp;
cout<<“Evenimentul “<<poz<<” are numarul “<<ev;
cout<<“ si a avut loc la “<<timp<<”timp.”;
}
Observaţii:
sunt citite şi caracterele albe – spaţii, tab-uri;
este inserat caracterul nul - ’\0’ – la sfârşitul şirului de caractere;
caracterul transmis ca ultim parametru nu este inserat în şir;
al treilea parametru este trecut în mod facultativ, dacă nu este
precizat se presupune că este ’\n’.
Exemplul 4.12
Exemplul 4.13
#include <iostream.h>
#include <string.h>
main()
{
char nume[20], pren[30];
cout<<”Dati numele: “;
cin.get(nume,20);
cin.get();
cout<<”Dati prenumele: “;
cin.get(pren,30);
cout<<nume<<” “<<pren;
}
Pentru a vă convinge de cele arătate mai sus, executaţi programul de mai
sus şi în situaţia în care lipseşte instrucţiunea de citire fără parametri şi
comparaţi cele două soluţii.
1. Adevărat / Fals Trebuie să apăsaţi tasta Enter după scrierea unui caracter pentru ca
funcţia getch() să-l citească.
4. Pentru a putea realiza operaţii de intrare/ieşire cu cin şi cout trebuie folosită biblioteca
………………….
Laboratorul 4
Exemplul 5.5
Varianta 2:
# include<iostream.h>
# include<math.h>
void main()
{
float a,b,c,d;
cout<<"a=";cin>>a;
cout<<"b=";cin>>b;
cout<<"c=";cin>>c;
a?d=b*b-4*a*c,
d>=0?cout<<"x1="<<(-b+sqrt(d))/(2*a)<<"\n"<<"x2="<<(-b-sqrt(d))/(2*a):
cout<<" nu are solutii reale":
b?cout<<"x="<<(-c/b):
c?cout<<"ecuatia nu are solutii": cout<<"infinitate de solutii";
}
Observaţii:
Exemplul 5.10
Problema Gard
Olimpiada Judeţeană de Informatică pentru Gimnaziu 2003, clasa a VI-a
#include<iostream.h>
void main()
{ long int n, i, p,q, nec,rosu, albastru, violet;
cout<<"nr. de scanduri n="; cin>>n;
cout<<"p si q: ";cin>>p>>q;
nec=rosu=violet=albastru=0;
for(i=1;i<=n;i++)
if(i%p==0 && i%q==0)violet++;
else if(i%p==0) rosu++;
else if (i%q==0)albastru++;
else nec++;
cout<<nec<<" "<<rosu<<" "<<albastru<<" "<<violet;
}
Analizează algoritmul Exemplului 5.11 şi răspunde cerinţelor de mai jos. Fiecare răspuns
corect valorează 30 puncte. Punctaj minim: 70. Se acordă 10 puncte din oficiu.
1. Urmăreşte pas cu pas execuţia programului din Exemplul 5.11 pentru n=7;
2. Modifică algoritmul din Exemplul 5.11 astfel încât să calculeze suma primilor n
termeni din şirul Fibonacci.
3. Modifică algoritmul din Exemplul 5.11 astfel încăt să calculeze cel mai mare
termen din şirul Fibonacci mai mic sau egal cu n.
1.Să se determine cel mai mare număr care se poate forma cu ajutorul cifrelor unui număr
natural citit de la tastatură. Ex: fie 2781 numărul dat; cu cifrele sale se poate forma
numărul 8721 cu proprietatea dată.
2. Se dau n numere naturale nenule (n<40). Se cere să se afişeze cel mai mare divizor
comun. Ex: fie n=4 şi numerele 16 40 36 8, se va afişa 4.
4. Un mare bogătaş are un seif cu cifru. Pentru a nu uita cifrul, bogătaşul vrea să-l scrie pe
o foaie, dar codificat: fiecare cifră să fie înlocuită cu diferenţa dintre cifra 9 şi cifra
respectivă. Scrie un program care preia cifrul de la tastatură (prima cifră este diferită de 0),
îl codifică după metoda ştiută şi afişează cifrul codificat. Ex: cifrul 43746521 se codifică în
56253478.
5. Se extrag dintr-o urnă bile pe care sunt scrise numere naturale. Extragerea se face
până la întâlnirea bilei cu numărul 1. Scrie un program care simulează aceasta şi afişează
numărul cifrelor 0 în care se termină numărul produs al numerelor citite. Ex: se extrag bile
cu numerele 15 20 4 12 1; numărul cifrelor 0 este 2.
Variantă corectă:
# include <iostream.h>
void main()
{
int n,i;
float x,p=1; // în p voi calcula puterea
cin>>n; cin>>x;
i=1;
while (i<=n) {p*=x; i++;} // la fiecare pas i voi înmulţi valoarea lui p cu x
cout<<”p=”p;
}
Variante corecte:
e) 2
b)
#include< iostream.h>
void main()
{
int a,b, nr=0, i;
cout<<” a=”;cin>>a;
cout<<” b=”;cin>>b;
i=a; nr=0;
if (i<=b) do{ if (i%2==0) nr++; i++; } while (i<=b);
cout<<”nr=”<<nr;
}
c) În variabila nr numărăm valorile pare din intervalul [a,b].
1.
Soluţie: algoritmul realizează numărarea apariţiilor fiecărei cifre în ordine descrescătoare de la 9 la
0 şi afişarea succesivă a acestora.
# include <iostream.h>
main()
{ long nr, a, I, aparitie, j;
cin>>nr;
for(j=9;j>=0;j--)
{ a=nr;
aparitie=0;
do{
if(a%10==j aparitie++;
a/=10;
}while (a>0);
for (i=1;i<=aparitie;i++) cout<<j;
}
}
2.
Soluţie: voi determina cel mai mare divizor comun dintre primul număr şi al doilea, apoi cel mai
mare divizor dintre numărul obţinut şi al treilea, ş.a.m.d.
#include<iostream.h>
void main()
{long n,x,a,b,d,i;
cout<<”n=”; cin>>n;
cin>>x;
d=x;
for(i=2;i<=n;i++)
{ cin>>x;
a=d; b=x;
while(a!=b)
if(a>b) a-=b;
else b-=a;
d=a;
}
cout<<”c.m.m.d.c=”<<d;
}
3.
Soluţie: voi determina succesiv cifrele cele mai semnificative ale numerelor din şir, prin împărţirea
la 10, până când se ajunge la valori mai mici sau egale cu 9. Cu aceste cifre voi forma un număr
nou şi apoi voi verifica dacă este palindrom.
#include< iostream.h>
void main()
{
long a,b,c,n,x,i;
cin>>n; a=0;
for(i=1;i<=n;i++)
{ cin>>x;
while (x>9) x/=10;
a=a*10+x;
}
b=a; c=0;
while( b!=0)
{ c=c*10+b%10;
b/=10;
}
if(c==a) cout<<a<< “ este palindrom”; else cout<<a<<” nu este palindrom”;
}
Laboratorul 5
Exemplul 6.4
main()
{int a[20], n, i, x, gata=0, li, ls, m;
....................................
li=0; ls=n-1;
while (!gata && li<=ls)
{
m=(li+ls)/2;
if (x==a[m])
gata=1;
else
if(x<a[m])
ls=m-1];
else
li=m+1;
}
if (gata)
printf(“%d se afla pe pozitia %d in vector.\n”,x,m);
else
printf(“%d nu se afla in vector.\n”,x);
}
Aritmetica pointerilor
Exemplul 6.7
Figura 6.2
Comparaţi bucla for din acest exerciţiu cu bucla for obişnuită de tipărire a
elementelor tabloului a, împreună cu adresele acestor elemente:
long a[10]={10, 11, 12, 13, 14, 15, 16, 17, 18, 19};
long i;
for (i=0;i<10;i++)
printf("Adresa: %p Elementul: %ld\n",&a[i], a[i]);
1. Considerăm declaraţia:
int n; const int a=10, *pi=&a;
Să se determine care dintre instrucţiuni sunt corecte:
A. n=a;
B. a=3;
C. n=*pi;
D. *pi= 1;
E. pi++;
2. Ce se tipăreşte în urma executării secvenţei de mai jos?
int a=5; *&a=7;
printf(“%d”,a);
B. 5
C. eroare de sintaxă
D. 7
5. Tipăriţi conţinutul în hexazecimal al octetului cel mai semnificativ al unei variabile de tip
long int.
4. Dându-se un şir de caractere s şi un subşir a, să se elimine din şirul dat toate apariţiile
subşirului:
Laboratorul 6
Exemplul 7.13
#include<fstream.h>
#include<string.h>
void main()
{fstream f;
char s[15], t[15];
f.open("test.txt",ios::in); // f este deschis pentru citire
while(f.getline(s,15)) //se citeste câte o linie din fisier si se retine in s
strcpy(t,s); // sirul s se copiaza in t
cout<<t;
f.close();
}
Ştiind că lungimea maximă a unei linii din fişierului „test.txt” este 15, să
verificăm ce afişează programul de mai sus.
Figura 7.1
Observaţii:
2. În figura 7.1 se observă că s-a afişat ultima linie din fişier. În realitate
programul afişează caracterul de sfârşit de fişier care, în această
situaţie este după cuvântul „fişiere”.
Analizează algoritmul Exemplului 7.13 şi răspunde cerinţei de mai jos. Răspunsul corect
valorează 20 puncte.
Modifică fişierul „test.txt” astfel încăt rezultatul să fie afişarea caracterului de sfărşit de
fişier.
Exemplul 7.14
Se dau două fişiere f1 şi f2. Să se concateneze cele două fişiere date, iar
rezultatul să fie fişierul f3.
#include<fstream.h>
void main()
{
char c;
ifstream f1("fis1.txt"); //f1.open("fis1.txt",ios::in);
ifstream f2("fis2.txt"); //f2.open("fis2.txt",ios::in);
ofstream f3("fis3.txt"); //f3.open("fis3.txt",ios::out);
while (!f1.eof()) /* se citeste câte un
{f1.get(c); f3<<c;} caracter din f1 si se scrie
in f3 */
f1.close();
while (!f2.eof())
{f2.get(c); f3<<c;}
/* se citeste un caracter
din f2 si se scrie in f3 */
f2.close(); f3.close();
}
Observaţii:
Figura 7.2
2. Profesorul a dat celor n (n natural) elevi ai săi să realizeze câte un fişier text care să
conţină informaţii despre modul de viaţă al vieţuitoarelor şi le-a spus să salveze lucrările
cu numele: capitolul1.txt, capitolul2.txt, ..., capitoluln.txt. Scrie o aplicaţie care să
concateneze aceste fişiere în stream-ul ecosisteme.txt.
4. Se citeşte din fişierul elevi.in situaţia la învăţătură a fiecărui elev. Pe liniile impare se
găsesc numele şi prenumele elevilor. Pe cele pare se găsesc numere separate prin spaţii,
astfel: primul număr reprezintă clasa (ex: 5 sau 8), apoi se regăsesc mediile pe discipline.
Să se calculeze şi să se afişeze media generală a fiecărui elev; în cazul în care elevul este
corigent se va afişa numărul disciplinelor cu corigentă.
2. Parcurg într-un ciclu toate fişierele de la 1 la n. La fiecare pas în ciclu, deschid fişierul,
adaug conţinutul lui în stream-ul ecosisteme.txt şi trec mai departe la următorul fişier.
3. Fie w vectorul în care voi obţine lista finală. Elementele acestui vector reprezintă
reuniunea celor două liste din fişierele date. Pentru început voi copia în w toate numele din
primul fişier, apoi parcurg al doilea fişier şi adaug în w doar acele nume care nu se află
deja în w.
4. Pentru fiecare elev din fişier citesc numele şi prenumele într-o variabilă de tip string. De
pe linia următoare citesc apoi clasa şi mediile elevului (într+un ciclu până la sfărşitul liniei),
calculez media generală. Totodată număr într-o variabilă mediile sub 5 şi dacă la sfârşitul
ciclului acestă variabilă e diferită de 0, atunci elevul este corigent şi voi putea afişa
numărul disciplinelor la care este corigent. Înainte de a trece la un alt elev se afişează
media generală calculată.
Laboratorul 7
Exemplul 8.9
#include <iostream.h>
int n;
void main()
{
long a[100], b[100];
cin>>n;
citire(n,a);
for( int i; i<=n;i++) b[i]=factorial(a[i]);
cout<<”suma este”<< suma(n,b);
}
Exemplul 8.10
3 5 7
5 7 11
7 11 13
13
#include<iostream.h>
#include<math.h>
int a[21] [21],n,x,k;
int n_prim(int k)
{int p,nr;
p=2; nr=0;
while(nr<k){ if(prim(p))nr++;
p++;
}
return p-1;
}
void construct()
{ int i,j;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) a[i][j]=n_prim(i+j);
}
int cifre_dist(int k)
{
int i,j,nr,b[20],m=0;
while(k!=0){ i=k%10; m++; b[m]=i;k=k/10;}
nr=0;
for(i=0; i<=9;i++)
for (j=1;j<=m;j++)if(i==b[j]){ nr++; break;}
return nr;
}
void main()
{ int i,j,x;
cout<<"n=";cin>>n;
construct();
cout<<" matricea:"<<endl;
for(i=1;i<=n;i++)
{for(j=1;j<=n;j++) cout<<a[i][j]<<" ";
cout<<"\n";}
cout<<"x=";cin>>x;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)if(cifre_dist(a[i][j])==x) cout<<a[i][j]<<" ";
}
1. Să considerăm un vector cu n (n<101) componente numere naturale mai mici sau egale
cu 30000. Afişează numerele din vector care au cele mai multe cifre de 1 în repreyentare
binară. Vei folosi:
- o funcţie pentru citirea vectorului;
- o funcţie pentru determinarea numărului de cifre 1 din reprezentarea binară a unui
număr;
- o funcţie care returmează elementul maxim dintre componente unui vector.
Ex: pentru n=3 si elementele vectorului 13, 9, 7, se va afisa 13 7
2. Să considerăm un vector cu n (n<101) componente numere naturale mai mici sau egale
cu 30000. Determină componentele vectorului care au cei mai mulţi divizori. Pentru
aceasta vei folosi:
- o funcţie pentru citirea vectorului;
- o funcţie pentru calculul numărului de divizori ai unui număr.
Ex: pentru n=5 si elementele 10 29 6 2 11, se va afisa 10 6
1. Scrie un program care conţine o funcţii recursivă care permite citirea unei matrice cu n
linii şi m coloane.
2. Consider date de la tastatură n (1≤n≤10) numere naturale nenule x1, x2, ..., xn. Să se
calculeze suma p(x1)!+p(x2)!+…+p(xn)!, unde prin p(k) am notat prima cifră a numărului k,
iar prin k! produsul 1*2*3…*n. Se va folosi:
- o funcţie pentru citirea şirului de numere;
- o funcţie recursivă pentru găsirea primei cifre dintr+un număr natural;
- o funcţie recursivă pentru calculul factorialului;
- o funcţie recursivă pentru calculul sumei elementelor unui vector.
1. Soluţie:
int cifra_1(int x)
{ int num=0;
while (x)
{ num+=x%2; x/=2;}
return num;
}
int max(int n, int a[ ])
{
int i,max=a[1];
for(i=2;i<=n;i++) if( max<a[i]) max=a[i];
return max;
}
2. Soluţie:
int numar_divizori(int x)
{ int nr=1, i;
for(i=2;i<=x/2;i++) if(x%i==0) nr++;
if(x>1) nr++;
return nr;
}
3. Soluţie:
void ordonare( intp, int u, int v[ ], int t)
{
int i, aux, sem=1;
while(sem)
{sem=0;
for(i=p;i<u;i++) if(v[i]*t>v[i+1]*t)
{ aux=v[i]; v[i]=v[i+1]; v[i+1]=aux; sem=1;}
}
4. Indicaţie:
Calculez valoarea sumei primelor k-1 numele cuburi perfecte nenule şi o reţin în variabila
s. Apoi verific dacă diferenţa dintre n şi sumă este mai mare decât ultimul cub perfect al
sumei. În caz afirmativ există soluţie.
1. Soluţie:
#include<iostream.h>
void citiremat(int a[10][10], int i, int j, int n, int m)
{
if(i<n) if(j<m) { cin>>a[i][j]; citiremat(a,i,j+1,n, m);}
else citiremat(a,i+1,0,n,m);
}
void main()
{
int a[10][10],n,m;
cin>>n>>m;
citiremat(a,0,0,n,m);}
2. Soluţie:
# include<iostream.h>
long x[10], z[10];
int i,n;
int citire(long x[10])
{
int i,d;
cin>>d;
for(i=1;i<=d;i++) cin>>x[i];
return d;
}
int pcifre(long a)
{
if(a<10) return a; else return pcifre(a/10);
}
long factorial(int n)
{
if(n==1) return 1;else return n*factorial(n-1);
}
long suma(long z[10], int n)
{
if( n==1) return z[1];else return suma(z,n-1)+z[n];
}
void main()
{
n=citire(x);
for(i=1;i<=n;i++) z[i]=factorial(pcifre(x[i]));
cout<<suma(z,n);
}
3. Soluţie:
#include<iostream.h> int generare(int n, int i)
#include<math.h> {
int n; if(n>0)
int prim(long a,long i) if(prim(i,2)&&prim(i+2,2)) generare(n-
{ 1,i+1);
if((a==0)||(a==1)) return 0; else generare (n,i+1);
else if(i<=sqrt(a)) if(a%i==0) return 0; else{ cout<<i-1<<” ”<<i+1; return 0;}
else return prim(a,i+1); }
else return 1;
} void main()
{cin>>n;
generare(n,3);
}
BIBLIOGRAFIE