Upload
others
View
1
Download
0
Embed Size (px)
Citation preview
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
Cristian Iosifescu
Programarea calculatoarelor şi limbaje de programare
Iniţiere în limbajul de programare C
Lucrări de laborator
Galaţi
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
Cuprins
Bibliografie .................................................................................................................................. 4 1. Generalităţi ......................................................................................................................... 1
1.1 Tastatura ......................................................................................................................... 1 1.2 Ecranul aplicaţiei Borland C ........................................................................................ 2 1.3 Principalele meniuri şi comenzi ale aplicaţiei ........................................................... 3
2. Scheme logice şi pseudocod ............................................................................................ 6 2.1 Reprezentarea algoritmilor prin scheme logice ........................................................ 6 2.2 Reprezentarea algoritmilor prin pseudocod ............................................................. 6 2.3 Exemple ........................................................................................................................... 7
3. Noţiuni de bază................................................................................................................ 10 3.1 Structura unui program în C++ ................................................................................. 10 3.2 Principalele mesaje de avertizare şi eroare ale compilatorului............................. 11 3.3 Date în limbajului C .................................................................................................... 12 3.4 Exemple ......................................................................................................................... 14
4. Intrări/ieşiri în C/C++ ..................................................................................................... 15 4.1 Citirea/scrierea datelor............................................................................................... 15 4.2 Intrări/ieşiri în C++..................................................................................................... 15 4.3 Intrări/ieşiri în C ......................................................................................................... 16 4.4 Exemple ......................................................................................................................... 17 4.5 Probleme propuse ........................................................................................................ 20
5. Operatori şi expresii........................................................................................................ 21 5.1 Operatori ....................................................................................................................... 21 5.2 Prioritatea operatorilor ............................................................................................... 23 5.3 Conversia între bazele de numeraţie ........................................................................ 23 5.4 Exemple ......................................................................................................................... 24 5.5 Probleme propuse ........................................................................................................ 30
6. Structuri de decizie (alternative, de selecţie) ............................................................. 34 6.1 Structura de decizie: instrucţiunea if ...................................................................... 34 6.2 Structura de selecţie cu ramuri multiple: instrucţiunea switch ......................... 34 6.3 Exemple if, switch ........................................................................................................ 35 6.4 Probleme propuse ........................................................................................................ 36
7. Structura ciclică cu test iniţial ....................................................................................... 39 7.1 Instrucţiunea while.................................................................................................... 39 7.2 Exemple while ............................................................................................................ 39 7.3 Instrucţiunea for ........................................................................................................ 41 7.4 Exemple for ................................................................................................................ 41 7.5 Probleme propuse ........................................................................................................ 43
8. Structura ciclică cu test final ......................................................................................... 45 8.1 Instrucţiunea do - while........................................................................................ 45 8.2 Exemple do - while ...................................................................................................... 45 8.3 Prelucrarea numerelor ................................................................................................ 48 8.4 Facilităţi de întrerupere a unei secvenţe .................................................................. 50 8.5 Exemple break, continue ...................................................................................... 51 8.6 Probleme propuse ........................................................................................................ 52
ii
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
9. Tablouri unidimensionale .............................................................................................. 54 9.1 Declaraţia de tablou ..................................................................................................... 54 9.2 Vectori ............................................................................................................................ 54 9.3 Exemple.......................................................................................................................... 55
10. Şiruri de caractere ............................................................................................................. 61 11. Tablouri multidimensionale .......................................................................................... 65
11.1 Exemple ........................................................................................................................ 65 11.2 Probleme propuse ....................................................................................................... 67
12. Pointeri şi adrese .............................................................................................................. 69 12.1 Exemple ........................................................................................................................ 69 12.2 Probleme propuse ....................................................................................................... 73
13. Funcţii - generalităţi, operaţii cu tablouri.................................................................... 75 13.1 Structura unei funcţii ................................................................................................. 75 13.2 Transferul parametrilor unei funcţii ........................................................................ 75 13.3 Funcţii definite de utilizator ...................................................................................... 76 13.4 Exemple ........................................................................................................................ 77 13.5 Probleme propuse ....................................................................................................... 86
14. Funcţii - analiză matematică, biblioteci de funcţii .................................................... 87 14.1 Exemple ........................................................................................................................ 87 14.2 Funcţii predefinite ...................................................................................................... 90 14.3 Biblioteci de funcţii scrise de către utilizator .......................................................... 95 14.4 Exemple ........................................................................................................................ 95
15. Funcţii recursive ............................................................................................................... 98 15.1 Exemple - Recursivitate directă ................................................................................ 98 15.2 Exemple - Recursivitate indirectă ........................................................................... 107 15.3 Probleme propuse ..................................................................................................... 108
16. Tipuri de date definite de utilizator ........................................................................... 110 16.1 Structuri ...................................................................................................................... 110 16.2 Uniuni ......................................................................................................................... 117 16.3 Exemple uniuni ......................................................................................................... 117 16.4 Enumerări .................................................................................................................. 123 16.5 Exemple ...................................................................................................................... 124 16.6 Declaraţii de tip ......................................................................................................... 124 16.7 Alocarea dinamică a memoriei ............................................................................... 125 16.8 Exemple ...................................................................................................................... 126 16.9 Probleme propuse ..................................................................................................... 127
17. Fişiere................................................................................................................................ 129 17.1 Deschiderea unui fişier ............................................................................................ 129 17.2 Închiderea unui fişier ............................................................................................... 130 17.3 Prelucrarea fişierelor text ......................................................................................... 131 17.4 Intrări/ieşiri binare ................................................................................................... 136 17.5 Poziţionarea într-un fişier ........................................................................................ 141 17.6 Funcţii utilitare pentru lucrul cu fişiere ................................................................ 142 17.7 Alte operaţii cu fişiere .............................................................................................. 143 17.8 Exemple ...................................................................................................................... 143 17.9 Probleme propuse ..................................................................................................... 148
iii
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
Bibliografie
Cerchez, E., Şerban, M., Programarea în limbajul C/C++ pentru liceu - Editura Polirom, 2005.
Deaconu, A., Programare avansată în C şi C++, Univ. "Transilvania" Braşov, 2003. Iorga, V., Chiriţă, P., Opincaru, C., Stratan, C., Programare în C/C++ - culegere de
probleme - Editura Niculescu, 2003. Kernigham Brian W şi Ritchie Dennis M., The ANSI C programming language 2nd ed. -
Prentice Hall, 1998. Negrescu, L., Limbajele C şi C++ pentru începători. Vol. 1: Limbajul C, Editura
Microinformatica SRL, Cluj-Napoca, 1994. Novac, C., Limbajul Turbo C++, Universitatea "Dunărea de Jos", Galaţi, 1993; Pătruţ, B., Aplicaţii în C şi C++. Editura Teora, Bucureşti, 1998. Prisecaru, T., Ene, A.S., Limbajul de programare C++ - Noţiuni de bază, Editura Matrix
Rom B, Editura Bucureşti, 2000. Schildt, H., C - Manual complet, Editura Teora, Bucureşti, 1998. Stoilescu, D., Culegere de C/C++, Editura Radial, Galaţi, 1998. Ştefănescu, D., Segal, C., Iniţiere în limbajele C/C++, Editura Fundaţiei Univ., Galaţi,
2000. Vlad, S., Ursu, M.F., Informatica tehnică, Univ. Tehnică Cluj-Napoca, Cluj-Napoca,
1996.
iv
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
TASTATURA
1. GENERALITĂŢI
1.1 Tastatura
Tastatura este componentă hardware a calculatorului ce permite utilizatorului să introducă date prin apăsarea unor taste. Cele mai folosite tastaturi sunt cele QWERTY. Denumirea vine de la primele şase taste de pe rândul al treilea.
Ea cuprinde următoarele grupuri de taste:
1.1.1 Tastele funcţionale/rapide (Hotkeys)
Sunt simbolizate cu F1…F12, iar rolul lor este să lanseze în mod direct comenzi pentru calculator, comenzi care sunt diferite în funcţie de softul pe care îl folosim la un anumit moment.
1.1.2 Grupul principal de taste (QWERTY)
Acesta conţine tastele alfanumerice (litere, cifre, simboluri), dintre care enumerăm denumirile şi funcţiile tastelor speciale: Shift (⇑), Alt, Ctrl (două din fiecare) - Nu au efect singure (se apasă simultan cu altă tastă)
Tab - inserează mai multe spaţii în textul editat sau trece la câmpul următor din fereastra de dialog
Caps Lock - folosit la scrierea cu majuscule
Enter - lansează în execuţie o comandă
Backspace - şterge caracterul din stânga cursorului
Space (spaţiu) - introduce un blank
Esc - Escape Slash (/) Backslash (\) Tilda (~) Shift+ Asperand (@, "a" rond, ”coadă de maimuţă”) Shift+2
Diez (#) Shift+3
Procent (%) Shift+5 Căciuliţa (^) Shift+6 And (&) Shift+7 Apostrof (') Ghilimele (") - NU două apostrofuri ! Bară verticală (|)
1
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
GENERALITĂŢI
1.1.3 Tastele de navigare
Insert = comută între modul inserare şi suprascriere Delete = şterge caracterul din dreptul cursorului Home = (acasă) mută cursorul la începutul rândului End = (sfârşit) mută cursorul la sfârşitul rândului curent Page up = deplasează conţinutul fişierului cu un ecran către începutul acestuia Page down (pereche) Ctrl + Home = mută cursorul la începutul ecranului (primul rând) Ctrl + End = mută cursorul la sfârşitul ecranului (ultimul rând) Ctrl + Page up = deplasează cursorul (şi implicit conţinutul afişat pe ecran) la
începutul fişierului Ctrl + Page down = deplasează cursorul la sfârşitul fişierului
1.1.4 Tastele numerice
Sunt active dacă led-ul lui Num Lock este aprins, altfel funcţionează ca Taste speciale
1.2 Ecranul aplicaţiei Borland C
Pentru Borland C++ versiunea 3.1, acesta conţine: Bara de meniuri (sus) - prezintă mai multe meniuri (System, File - fişiere, Edit -
editare, Search - căutare) care conţin grupuri de comenzi specifice. Activarea ei se face cu tasta rapida F10 - aşa cum se arată în bara de stare; deschiderea unui meniu se face apăsând simultan tastele Alt şi litera evidenţiată din numele meniului.
Zona de lucru (la mijloc) - conţine una sau mai multe ferestre, din care, la un moment dat, e activă una singură.
Elementele unei ferestre sunt: Rama ferestrei - dublă, dacă fereastra este activă, simplă dacă este inactivă Buton de închidere - în partea din stânga sus a ramei ([■]) Titlul ferestrei - pentru ferestrele de editare este numele fişierului deschis. Numărul ferestrei - automat Buton de maximizare/revenire - în partea din dreapta sus a ramei ([↑]) Bara de defilare verticală, ce conţine săgeţile de deplasare la extremităţi şi
butonul care indică poziţia conţinutului ecranului în „lungul” fişierului (început/sfârşit)
Bara de defilare orizontală, ce conţine săgeţile de deplasare la extremităţi şi butonul care indică poziţia conţinutului ecranului în „latul” fişierului (stânga/dreapta)
Poziţia cursorului - indicată prin numărul liniei şi cel al coloanei - în partea din stânga jos a ramei
Buton care indică modificarea conţinutului ferestrei după ultima salvare - în partea din stânga jos a ramei [*]
Bara de stare (jos) - conţine comenzile disponibile la un moment dat şi combinaţiile de taste pentru lansarea acestora. Conţinutul ei se modifică în funcţie de context (poziţia cursorului în diferitele zone ale ecranului).
2
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
PRINCIPALELE MENIURI ŞI COMENZI ALE APLICAŢIEI
1.3 Principalele meniuri şi comenzi ale aplicaţiei
1. Meniul System [≡] - conţine comenzi de sistem şi pentru programe de transfer
2. Meniul File - conţine comenzi pentru gestiunea fişierelor (Deschidere, Salvare, Tipărire, etc.)
a. New - creează un nou fişier într-o nouă fereastră de editare b. Open (F3) - localizează şi deschide un fişiere (creat deja) c. Save (F2) - salvează fişierul din fereastra de editare activă d. Save as - salvează fişierul din fereastra de editare activă cu un nume nou e. Save all - salvează toate fişierele modificate f. Change dir - schimbă directorul de lucru curent g. Print - tipăreşte conţinutul ferestrei active h. DOS shell - iese temporar în sistemul de operare i. Quit (Alt+X) - iese din aplicaţia Borland C++
3. Meniul Edit - conţine comenzi pentru operaţii de editare, anulare şi acces la Clipboard
a. Undo (Alt+BkSpc) - anulează ultima comandă de editare (consecutiv) b. Redo (Shift+Alt+BkSpc) - reface ultima comandă anulată c. Cut (Shift+Del) - şterge textul selectat şi îl pune în Clipboard d. Copy (Ctrl+Ins)- copiază în Clipboard textul selectat e. Paste (Shift+Ins)- inserează conţinutul Clipboard-ului în fereastra curentă la
poziţia cursorului f. Clear (Ctrl+Del) - şterge textul selectat g. Copy example - copie în Clipboard exemplul dintr-o fereastră Help h. Show Clipboard - arată conţinutul Clipboard-ului
4. Meniul Search - conţine comenzi pentru căutarea textului şi erorilor a. Find - caută un text b. Replace - caută un text şi îl înlocuieşte cu unul nou c. Search again (Ctrl+L) - repetă ultima comandă de căutare sau căutare şi
înlocuire d. Go to line number - mută cursorul la linia specificată e. Previous error - mută cursorul la linia erorii anterioare
3
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
GENERALITĂŢI
f. Next error - mută cursorul la linia erorii următoare g. Locate function - caută la depanare o declaraţie de funcţie
5. Meniul Run - conţine comenzi pentru lansarea în execuţie a programului integral sau pas cu pas
a. Run (Ctrl+F9) - lansează programului în execuţie b. Program reset (Ctrl+F2) - termină sesiunea de depanare c. Go to cursor (F4) - execută programul până la linia cursorului d. Trace into (F7) - execută instrucţiunea următoare; pătrunde în corpul funcţiilor e. Step over (F8) - execută instrucţiunea următoare; “păşeşte” peste corpul
funcţiilor f. Arguments - stabileşte parametrii liniei de comandă cu care va fi executat
programul 6. Meniul Compile - conţine comenzi pentru verificarea corectitudinii
(compilarea) programului a. Compile (Alt+F9) - compilează fişierul din fereastra de editare activă b. Make (F9) - Actualizează ţinta prin compilare şi legare, după caz c. Link - Leagă fişierele ţintei fără recompilare d. Build all - Reconstruieşte toate fişierele
7. Meniul Debug - conţine comenzi pentru inspectare, evaluare, stabilire de puncte de întrerupere şi urmărire a variabilelor
a. Inspect (Alf+F4) - deschide o fereastră inspector pentru a examina valorile unei date
b. Evaluate/Modify (Ctrl+F4) - evaluează o variabilă sau expresie şi afişează valoarea
c. Call stack (Ctrl+F3) - arată funcţiile apelate de program până în punctul curent d. Watches - adaugă, şterge sau editează variabile urmărite e. Toggle breakpoint (Ctrl+F8) - inserează sau şterge un punct de oprire
necondiţionată a programului la linia curentă f. Breakpoints - inserează puncte de oprire necondiţionată; vizualizează sau
editează aceste puncte 8. Meniul Project - conţine comenzi pentru gestiunea proiectelor: adăugare,
ştergere sau vizualizarea fişierelor proiect 9. Meniul Options - conţine comenzi pentru stabilirea opţiunilor mediului de
programare, a compilatorului şi depanatorului 10. Meniul Window - conţine comenzi pentru deschiderea, aranjarea şi afişarea
listei ferestrelor a. Size/Move (Ctrl+F5) - modifică dimensiunea sau poziţia ferestrei active b. Zoom (F5) - maximizează sau readuce fereastră activă la dimensiunea iniţială c. Cascade - dispune ferestrele din zona de lucru suprapuse d. Tile - dispune ferestrele din zona de lucru alăturat e. Next (F6) - activează fereastra următoare f. Close (Alt+F3) -închide fereastra activă g. Close all - închide toate ferestrele h. Message/Output/Watch/User screen (Alt+F5) - deschide una din ferestrele
speciale: de mesaje, de rezultate, de urmărire sau ecranul utilizatorului i. List all (Alt+0) - afişează lista tuturor ferestrelor deschise
11. Meniul Help - conţine comenzi pentru accesarea sistemului de ferestre de ajutor.
4
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
PRINCIPALELE MENIURI ŞI COMENZI ALE APLICAŢIEI
a. Contents - arată cuprinsul sistemului de ajutor b. Index (Shift+F1) - arată index-ul sistemului de ajutor c. Topic search (Ctrl+F1) - arată informaţii despre cuvântul din dreptul
cursorului sau afişează index-ul d. Previous topic (Alt+F1) - arată din nou ultima fereastră de informaţii e. Help on help - arată modul de utilizare a sistemului de ajutor f. About - arată numărul versiunii programului
Obs.: 1. Selectarea unei porţiuni de text se face astfel:
a. Se poziţionează cursorul cu ajutorul săgeţilor la un capăt al textului de selectat; b. Ţinând tasta Shift apăsată, se deplasează cursorul cu ajutorul săgeţilor
(←,→,↑,↓) către celălalt capăt al textului de selectat. 2. Pentru a scurta durata etapei de redactare a programelor se poate proceda astfel:
a. textul de pe o linie de după //, precum şi cel de pe mai multe linii dintre /* şi */ reprezintă comentarii şi poate fi omis
b. instrucţiunile care afişează valorile variabilelor pe ecran (cout, printf) pot fi omise, iar valorile variabilelor pot fi urmărite în fereastra Watches din meniul Debug.
3. Programele au fost scrise cu editorul de texte al aplicaţiei Borland C, iar cartea a fost tehnoredactată cu ajutorul unui procesor de texte. Din acest motiv, uneori instrucţiunile sunt desparţite pe mai multe rânduri. La scrierea programelor la calculator nu se va respecta forma din carte a instructiunilor, ci ele vor fi scrise corect (din punct de vedere al limbajului), o instrucţiune (care se termină cu ";") fiind scrisă întotdeauna pe un singur rând.
5
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
SCHEME LOGICE ŞI PSEUDOCOD
2. SCHEME LOGICE ŞI PSEUDOCOD
2.1 Reprezentarea algoritmilor prin scheme logice
Primitivele utilizate în schemele logice sunt simboluri grafice, cu funcţiuni (reprezentând procese de calcul) bine precizate. Aceste simboluri sunt unite prin săgeţi (arce) orientate care indică ordinea de execuţie a proceselor de calcul.
Simboluri de început şi sfârşit. Simbolul START desemnează începutul unui
program sau al unui subprogram. Simbolul STOP desemnează sfârşitul unui program sau al unui subprogram. Prezenţa lor este obligatorie.
Simbolul paralelogram: semnifică procese (operaţii) de intrare/ieşire (citirea sau scrierea-afişarea).
Simbolul dreptunghi: semnifică o atribuire (modificarea valorii unei date). Simbolul romb este utilizat pentru decizii. Se testează dacă condiţia din blocul de
decizie este adevărată (A) sau falsă (F). Cu ajutorul acestor simboluri grafice se poate reprezenta orice algoritm. Repetarea unei secvenţe se realizează prin combinarea simbolurilor de decizie şi de
atribuire.
2.2 Reprezentarea algoritmilor prin pseudocod
Pseudocodul este inspirat din limbajele de programare, nefiind însă atât de formalizat ca acestea. Pseudocodul reprezintă o punte de legătură între limbajul natural şi limbajele de programare. Nu există un standard pentru regulile lexicale. Limbajul pseudocod permite comunicarea între oameni, şi nu comunicarea om-maşină (precum limbajele de programare). Pseudocodul utilizează cuvinte cheie (scrise cu majuscule subliniate) cu următoarele semnificaţii:
Sfârşit algoritm: SFÂRŞIT Început algoritm: ÎNCEPUT Citire (introducere) date: CITEŞTE lista Scriere (afişare) date: SCRIE lista
CITEŞTE a,b AFIŞEAZĂ a,b
a←6 Condiţie A
START STOP
F
6
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
Atribuire: ← Structura de decizie (alternativă): DACĂ condiţie ATUNCI acţiune1 ALTFEL acţiune2 Structuri repetitive cu test iniţial: CÂT TIMP condiţie REPETĂ acţiune sau: PENTRU contor=val_iniţ LA val_fin [PAS] REPETĂ acţiune Structuri repetitive cu test final: REPETĂ acţiune CÂT TIMP condiţie sau: REPETĂ acţiune PÂNĂ CÂND condiţie
Pe lângă cuvintele cheie, în reprezentarea algoritmilor în pseudocod pot apare şi
propoziţii nestandard a căror detaliere va fi realizată ulterior. În cazul în care se realizează un algoritm modularizat, pot apare cuvintele cheie: SUBALGORITM nume (lista_intrări) CHEAMĂ nume (lista_valori_efective_de_intrare)
2.3 Exemple
2.3.1 Maximul a trei numere
2.3.1.1 Pseudocodul 1. CITEŞTE a, b, c 2. DACĂ a>b ATUNCI max=a ALTFEL max=b 3. DACĂ c>max ATUNCI max=c 4. AFIŞEAZĂ max
2.3.2 Suma primelor n numere naturale
2.3.2.1 Pseudocodul 1. CITEŞTE n 2. suma=0 3.CÂT TIMP i<n 3.1 i++ 3.2 suma=suma+i 4. AFIŞEAZĂ suma
7
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
SCHEME LOGICE ŞI PSEUDOCOD
2.3.3 Ecuaţia de gradul 2
2.3.3.1 Schema logică
Start
Dacă a=0
Dacă ∆>0
Dacă ∆<0
Scrie “Ec are rad dubla”
x1 = x2
Scrie “Ec are rad compl” x1,2 = re±i⋅im
Dacă b=0
Daca c=0
Scrie “Ec are doua rad dif”
x1 şi x2
re = -b2a
im = -∆
2a
Scrie “Ec e de gradul unu x1 = -c/b
x1,2 = -b± ∆
2a x1,2 = -b2a
∆ = b2 – 4ac
Citeşte a, b, c
Stop
Scrie “Ec are o infinit ate de solutii”
Scrie “Ec nu are nici o solutie”
A
A
A
F
F
F
F A
F A
8
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
2.3.4 Maximul a 3 numere, calculul unei sume, etc - scheme logice
Start
Dacă i≤n
Citeşte n
Stop
fact*=i i++
A F
Scrie “n! =”, fact
i=1 fact=1
Start
Dacă a≠0, b≠0
Citeşte a,b
Stop
cmmmc=a*b r=a%b
a=b b=r
A
Scrie cmmdc, cmmmc
F
r=a%b a=b b=r
Dacă r≠0
cmmmc=a cmmdc= cmmmc/ cmmdc
A
F
cmmmc=0 cmmdc=0
Start
Dacă a>b
Dacă c>max
max=b
Citeşte a, b, c
Stop
max=a
max=c
A F
Scrie “Max =” , max
A F
Start
Dacă i≤m, j≤n
Citeşte a,b,m,n
Stop
s=s+sin(a+3*i)*cos(b+5*j)
max=c
A F
Scrie “S =” , s
i=1, j=1, s=0
9
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
NOŢIUNI DE BAZĂ
3. NOŢIUNI DE BAZĂ
3.1 Structura unui program în C++
Un program C obişnuit are următoarea structură (textul dintre /* şi */ reprezintă comentarii): /*directive de preprocesare*/ #include <fisier> /*includeri de fişiere sau biblioteci*/ /*atribuirea de nume simbolice şi definiţii de macrocomenzi*/ #define <def.constante> /*directive de compilare condiţionată*/ /*definiţii de tipuri de date*/ typedef int intreg; /*declaraţii de variabile globale*/ /*definiţii de funcţii sau/şi descrierea unor functii*/ int main(void) /*antetul funcţiei principale main*/ { /*începutul corpului funcţiei main*/ /*declaraţii de variabile locale*/ /*instrucţiunile funcţiei principale*/ return 0; /*valoarea returnată de funcţia main*/ } /*sfârşitul corpului funcţiei main*/ /*descrierea funcţiilor care au definiţiile mai sus*/
Precizare: compilatoarele pentru C şi C++ fac distincţie între litere mari şi mici. Un program C++ constă în una sau mai multe funcţii din care numai una singură este
funcţia principală. Fiecare funcţie are un nume; al funcţiei principale este main. Celelalte funcţii au nume definite de utilizator.
Un nume (identificator) este o succesiune de litere şi eventual cifre, primul caracter fiind o literă. Literele pot fi a-z, A-Z sau caracterul de subliniere (_). Numai primele 32 caractere sunt luate în seamă.
Pentru ca un fişier text să poată fi considerat un program sursă în limbajul C, acesta
trebuie să conţină minim antetul şi corpul funcţiei principale main, adică: void main() { }
Aceste lucruri se găsesc în orice program C, indiferent de scopul acestuia.
10
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
PRINCIPALELE MESAJE DE AVERTIZARE ŞI EROARE ALE COMPILATORULUI
3.2 Principalele mesaje de avertizare şi eroare ale compilatorului
Tabelul 3.1 Mesaje de avertizare şi eroare Text mesaj (alfabetic) Explicaţii
'…' is assigned a value that is never used
Avertisment: Valoarea calculată nu este folosită nicăieri în continuare
Bad file name format in include directive
Denumire greşită în directiva de preprocesare
Compound statement missing }
Caracter ”}” sau ”{” omis la o instrucţiune compusă
Declaration syntax error Eroare de sintaxă a declaraţiei Declaration terminated incorrectly
Declaraţie terminată incorect
Expression syntax Eroare de sintaxă For statement missing ; Caracter omis “;” la scrierea instrucţiunii "for" Function '…' should have a prototype
Funcţia “…” ar trebui să aibă un prototip; pentru a putea fi folosită, ea trebuie fie definită de utilizator, fie folosită o directivă de preprocesare (#include <…>)
Function should return a value
Funcţia ar trebui să returneze o valoare - lipsă "void" la tipul valorii returnate din antet sau lipsă instrucţiune "return" în corpul funcţiei
If statement missing ) Caracter “)” sau ”(” omis la scrierea instrucţiunii “if”
Illegal structure operation
Structură greşită a instrucţiunii (scriere/citire) - la >> sau <<
Incorrect number format Variabilă iniţializată cu un format numeric incorect
Misplaced else Ramura “else” din instrucţiunea “if” este poziţionată greşit
Multiple declaration for …
Variabila … este declarată de mai multe ori
No file name ending Caracter „>” omis la o directivă de preprocesare după numele bibliotecii
Statement missing ; Caracter “;”omis (la instrucţiunea precedentă) Unable to open include file '…'
Numele bibliotecii a fost scris greşit
Undefined symbol '…' Simbol '…' (variabilă sau funcţie) nedefinit Unexpected “…” Simbol neaşteptat - paranteză sau acoladă în plus Unterminated string or character constant
Şir de caractere sau constantă caracter neterminată - lipsă ' sau "
While statement missing )
Caracter “)”sau ”(” omis la scrierea instrucţiunii "while"
Pentru a obţine mai multe informaţii despre o anumită eroare, atunci când eroarea este selectată în fereastra cu mesaje (Message), se apasă tasta F1.
11
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
NOŢIUNI DE BAZĂ
3.3 Date în limbajului C
3.3.1 Tipuri de date
Datele care intervin în programe sunt de mai multe tipuri. În acest laborator vom prezenta tipurile simple, iar tipurile compuse vor fi prezentate în alte laboratoare. Tabelul de mai jos va prezenta tipurile de bază:
Tabelul 3.2 Tipurile de bază de date Cuvânt cheie
Lungime în biţi
Format de reprezentare internă
int 16 Întreg binar reprezentat prin complement faţă de 2 pe 2 octeţi, cuprins în intervalul [-32768, 32767]
char 8 Caracter reprezentat prin codul ASCII, cuprins în intervalul [-128, 127]
float 32 Număr real reprezentat în virgulă flotantă în simplă precizie, cuprins între [3.4⋅10-38, 3.4⋅1038]
double 64 Număr real reprezentat în virgulă flotantă în dublă precizie, cuprins între [1.7⋅10-308, 1.7⋅10308]
short 16 Idem int long 32 Întreg binar reprezentat prin complement faţă de 2 pe 4
octeţi, cuprins în intervalul [-2.147.483.648 to 2.147.483.647] unsigned char
8 Caracter reprezentat prin codul ASCII, cuprins în intervalul [0, 255]
unsigned int
16 Întreg binar fără semn reprezentat prin complement faţă de 2 pe 2 octeţi, cuprins în intervalul [0, 65535]
unsigned long
32 Întreg binar reprezentat prin complement faţă de 2 pe 4 octeţi, cuprins în intervalul [0, 4.294.967.295]
3.3.2 Constante
Sunt caracterizate prin tip şi valoare. Atât tipul cât şi valoarea se definesc prin caracterele care o compun
Tabelul 3.3 Reprezentarea constantelor în C/C++ Tip dată Format de
reprezentare Mod de reprezentare Exemple
zecimal (în baza 10)
[- / +] <cifra de la 1 la 9> [<lista cifre de la 0 la 9>]
125 -11
întreg *)
octal (în baza 8)
[- / +] 0 <cifra de la 1 la 7> [<lista cifre de la 0 la 7>]
0127 -022
hexazecimal (în baza 16)
[- / +] 0 {x / X} <cifra 1-9 sau litera a-f sau A-F> [<lista cifre 0-7 sau litere a-f sau A-F>]
0xa12f -0Xad105
real
în virgulă fixă [- / +] <partea întreagă> . <partea zecimală> Aceasta este scrierea unui
123 123.7 .25
12
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
DATE ÎN LIMBAJULUI C
Tip dată Format de reprezentare
Mod de reprezentare Exemple
număr raţional în baza zece, unde virgula zecimală este înlocuită de punctul zecimal. Partea zecimală poate fi vidă
(flotant) în virgulă mobilă [- / +] <partea întreagă> . <partea zecimală> {e sau E} [- / +] <nr. întreg zecimal> Aceasta reprezintă mantisa (ceea ce este înainte de E) înmulţită cu 10 la puterea dată de exponent (ceea ce este după E)
78E4 .1e-3 1234.567e-4
între apostroafe ‘<caracter>’ ‘a’ ‘A’ ‘\<codul ASCII>‘ ‘\65’ ‘\7’
‘\42’ ‘\140’ caracter cu secvenţe escape ‘\<caracter special>‘ \t Tab
\n Rând nou \a Alarm (sunet) \b Backspace \r Retur de car (poziţ cursorul în rândul curent col 1) \v Tabulator vertical \\ Backslash \’ Apostrof
şir de carac
între ghilimele “<şir>” “Acesta este un sir de caractere”
cu secvenţe escape “şir caractere şi secv.escape”
“Alte \tsecvente \tescape \nintr-un sir”
Obs.: *) Ceea ce am scris anterior era valabil pentru constantele întregi de până la 16
biţi. Constantele de 32 biţi sunt de tip long şi pentru a le nota le postfixăm una din: l sau L.
Pentru a specifica o constantă ca fiind de tip unsigned (fără semn) o postfixăm una din: u sau U. Dacă o constantă este long şi unsigned în acelaşi timp, o postfixăm cu una din:
ul, lu, UL, LU Ex: 123, 0123, 40000, 04000, 0123456, 123L, 0123l, 0x123, 0xa1b2c3, 0XABCFL
13
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
NOŢIUNI DE BAZĂ
3.3.3 Variabile
3.3.3.1 Declararea variabilelor Modul general de declarare a variabilelor este:
tip_variabile listă_nume_variabile; Se specifică tipul variabilei(lor) şi o listă formată din unul sau mai mulţi identificatori ai variabilelor de tipul respectiv.
Ex.: int i, j; /*declararea var. simple i, j, de tip int. Se rezervă pentru i şi j câte 16 biţi (2 octeţi)*/ char c; /*declararea variabilei simple c, de tip char. Se rezervă un octet.*/ float lungime; /* declararea variabilei simple lungime de tip float; se rezervă 4 octeţi */
3.3.3.2 Iniţializarea variabilelor în declaraţii În momentul declarării unei variabile, acesteia i se poate atribui o anumită valoare. În acest caz, în memorie se rezervă numărul de locaţii corespunzător tipului variabilei respective, iar valoarea va fi memorată în acele locaţii. Forma unei declaraţii de variabile cu atribuire este:
tip_variabilă nume_variabilă=expresie; Se evaluează expresia, iar rezultatul acesteia este atribuit variabilei specificate.
3.4 Exemple
char backslash=’\\’; /*declararea şi iniţializarea variabilei simple de tip caracter backslash */ int a=7*9+2; /* declararea variabilei simple a, de tip int şi iniţializarea ei cu rezultatul unei expresii - valoarea 65*/ float pi=3.14; /*declararea şi iniţializarea variabilei pi*/ short int z=3; //declararea şi iniţializarea variabilei simple z char d=’\011’; char LinieNoua=’\n’; double x=9.8, y=0;
14
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
INTRĂRI/IEŞIRI ÎN C++
4. INTRĂRI/IEŞIRI ÎN C/C++
4.1 Citirea/scrierea datelor
Prin citirea datelor vom înţelege operaţia prin care una sau mai multe variabile primesc valori prin introducerea lor de la tastatură sau prin extragerea lor de pe un suport de memorare extern.
Prin scrierea datelor vom înţelege operaţia prin care rezultatele obţinute în urma prelucrării datelor de intrare sunt fie afişate pe ecranul monitorului, fie stocate pe un suport extern de memorare.
Aceste operaţii sunt denumite frecvent şi operaţii de intrare/ieşire. În acest capitol vom prezenta doar citirea datelor de la tastatură şi afişarea datelor pe ecran.
În limbajul C/C++ nu există instrucţiuni specializate pentru citirea/scrierea datelor. Aceste operaţii se realizează prin intermediul unor funcţii existente în bibliotecile standard ale limbajului.
Aceste operaţii de intrare/ieşire diferă în limbajul C++ faţă de limbajul C, diferenţele fiind majore, deoarece operaţiile de intrare/ieşire din C++ sunt proiectate din perspectiva programării orientate pe obiect.
4.2 Intrări/ieşiri în C++
Conceptul central în operaţiile de intrare/ieşire în limbajul C++ este fluxul de intrare/ieşire (denumirea originală fiind stream). Simplificând, putem privi un stream ca pe o succesiune de caractere. Dacă stream-ul este de intrare, secvenţa de caractere „curge" dinspre exterior (în cazul nostru, dinspre tastatură) către memoria calculatorului. Dacă stream-ul este de ieşire, secvenţa de caractere "curge" dinspre memoria calculatorului către exterior (în cazul nostru, ecranul monitorului).
În fişierul antet iostream.h sunt declarate două fluxuri standard: un flux de intrare de la tastatură, denumit cin (console input) şi un flux de ieşire către ecran, denumit cout (console output). Pentru a le utiliza trebuie să declarăm în program:
#include <iostream.h> Dacă dorim să scriem date pe ecran, vom utiliza operatorul de inserţie în fluxul de
ieşire “<<” (care poate fi utilizat înlănţuit atunci când dorim să scriem mai multe date). Instrucţiunea din C++ care scrie (pe ecran) valori şi/sau text este:
cout<<expr.1[<<var1<<expr.2 [...]] unde var.1, var.2 - reprezintă nume de variabile iar expr.1, expr.2 - reprezintă
expresii. Ex.: Pentru a afişa pe ecran pe o linie nouă, în cadrul unui mesaj, valorile a două
variabile a şi b folosim instrucţiunea: cout<<"\na="<<a<<"\tb="<<b;
Instrucţiunea are următorul efect: 1. se trece pe o linie nouă (\n)
15
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
INTRĂRI/IEŞIRI ÎN C/C++
2. se afişează textul a= 3. se afişează valoarea variabilei a 4. se lasă un spaţiu (tab) (\t) 5. se afişează textul b= 6. se afişează valoarea variabilei b
Dacă a=2 şi b=5, atunci rezultatul instrucţiunii este: a=2 b=5
Când dorim să citim date de la tastatură, le vom extrage din fluxul de intrare,
folosind operatorul de extragere “>>” (care poate fi utilizat înlănţuit atunci când dorim să citim succesiv mai multe variabile). Instrucţiunea care citeşte (de la tastatură) una sau mai multe variabile este:
cin >>var.1[>>var.2 [...]] Ex.: Pentru a citi de la tastatură valorile a două variabile a şi b folosim instrucţiunea:
cin>>a>>b;
4.3 Intrări/ieşiri în C
Citirile şi scrierile în limbajul C se realizează prin intermediul unor funcţii specifice.
4.3.1 Citirea datelor cu format specificat
Funcţia scanf (din biblioteca stdio.h) are următoarea sintaxă: scanf(sir_car_ctrl,adr_var.1[,adr_var.2 [...]])
unde: sir_car_ctrl - Şir de caractere de control ce indică tipul variabilelor ce se vor citi: %d - variabilă de tip decimal (întreg); %f - variabilă de tip float (real); %c - variabilă de tip caracter; %s - variabilă de tip sir de caractere; adr_var.1 - adresa variabilei 1 Obs.: Numărul caracterelor de control trebuie să coincidă cu cel al variabilelor care se
vor citi. Ex. Pentru a se citi de la tastatură variabilele denumite: car (de tip caracter - char),
intrg (de tip întreg - int), re (de tip real - float) şi sir (de tip şir de caractere) sintaxa instrucţiunii este: scanf("%c%d%f%s",&car,&intrg,&re,sir);
4.3.2 Afişarea datelor cu format specificat
Funcţia printf (din biblioteca stdio.h) are următoarea sintaxă: printf(sir_car_ctrl,var.1[,var.2 [...]])
unde:
16
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
sir_car_ctrl - şir de caractere de control reprezentat de o succesiune de simboluri “%” urmate de caractere şi/sau cifre, ce indică tipul şi eventual formatul numeric al variabilelor ce se vor scrie. Caracterele de formatare au următoarea semnificaţie: c - variabilă de tip caracter d - variabilă de tip decimal (întreg) e - în format ştiinţific f - variabilă de tip float (real) g - cel mai scurt dintre f şi e o - în octal s - variabilă de tip şir de caractere x - în hexazecimal 0 - cu zerouri nesemnificative - - aliniere la stânga
Formatul numeric se indică prin numărul total şi numărul de zecimale pentru cifrele variabilelor numerice, separate prin “.”.
Obs.: Numărul caracterelor de control trebuie să coincidă cu cel al variabilelor care se vor scrie.
Ex. Pentru a se afişa pe ecran variabilele denumite: car (de tip caracter - char), intrg (de tip întreg - int), re (de tip real - float) - pe şase spaţii dintre care trei zecimale - şi sir (de tip şir de caractere) sintaxa instrucţiunii este: printf("%c %d %6.3f %s",car,intrg,re,sir);
Sintaxa lor detaliată şi completă poate fi obţinută din Help-ul aplicaţiei BC.
4.4 Exemple
4.4.1 cout
#include <iostream.h> void main(void) { cout<<"ACESTA ESTE PRIMUL PROGRAM\n"; }
4.4.2 cin, cout
#include <iostream.h> void main() //Citeste o data calendaristica sub forma zzllaaaa (ziua-2 cifre, luna-2 cifre, anul-4 cifre) si o rescrie in forma aaaa/ll/zz { int ziua, luna, anul; cin>>ziua>>luna>>anul; cout<<anul<<‘/‘<<luna<<‘/‘<<ziua; }
4.4.3 Operatorul sizeof
Să se scrie un program care ilustrează folosirea operatorului sizeof. #include <iostream.h> #include <values.h> #define PI 3.1415926 void main () { cout<<"tipul int memorat pe: "<<sizeof(int)<< " octeti\n";
17
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
INTRĂRI/IEŞIRI ÎN C/C++
cout<<"tipul int memorat pe: "<<sizeof(23)<<" octeti\n"; //23-const.zecimala int cout<<"int maxim="<<MAXINT<<'\n'; //const simbolice MAXINT,MAXLONG, ETC. -definite in<values.h> cout<<"Const. octala 077 are val decimala:"<<077<<'\n'; cout<<"Const. hexagesimala d3 are val decimala :"<<0xd3<<'\n'; cout<<"Tipul unsigned int memorat pe: "<<sizeof(unsigned int)<<" octeti\n"; cout<<"Tipul unsigned int memorat pe: "<<sizeof(23U)<<" octeti\n"; cout<<"Tipul unsigned int memorat pe: "<<sizeof(23u)<<" octeti\n"; cout<<"Tipul long int memorat pe: "<<sizeof(long int)<<" octeti\n"; cout<<"Tipul long int memorat pe: "<<sizeof(23L)<<" octeti\n"; cout<<"Tipul long int memorat pe: "<<sizeof(23l)<<" octeti\n"; //23 sau 23l-const. decimala long int cout<<"Long int maxim="<<MAXLONG<<'\n'; cout<<"Tipul unsigned long memorat pe: "<<sizeof(unsigned long int)<<" octeti\n"; cout<<"Tipul unsigned long memorat pe: "<<sizeof(23UL)<<" octeti\n"; cout<<"Tipul unsigned long memorat pe: "<<sizeof(23Ul)<<" octeti\n"; //23UL sau 23ul-const. decimala unsigned long int cout<<"Tipul unsigned long memorat pe: "<<sizeof(long long int)<<" octeti\n";long long int d; cout<<"Tipul unsigned long memorat pe: "<<sizeof(d)<<" octeti\n"; cout<<"Tipul short int memorat pe: "<<sizeof(short int)<<" octeti\n"; cout<<"Short int maxim="<<MAXSHORT<<'\n'; cout<<"Un char este memorat pe "<<sizeof('m')<<" octeti\n"; cout<<"sirul jhgkk este memorat pe "<<sizeof("jhgkk")<<" octeti\n"; cout<<"sirul j\thgkk este memorat pe "<<sizeof("j\thgkk")<<" octeti\n"; cout<<"Tipul float memorat pe: "<<sizeof(float)<<" octeti\n"; cout<<"Tipul float memorat pe: "<<sizeof(23.7f)<<" octeti\n"; //23.7f-const. decimala float cout<<"Float maxim="<<MAXFLOAT<<'\n'; cout<<"Float minim="<<MINFLOAT<<'\n'; cout<<"Tipul double memorat pe: "<<sizeof(double)<<" octeti\n"; cout<<"Tipul double memorat pe: "<<sizeof (23.7)<<" octeti\n"; //23.7-const. decimala double cout<<"Const. decim. doubla in notatie stiintifica: "<<23.7e-5<<'\n'; cout<<"Const. PI este:"<<PI<<'\n'; cout<<"Constanta PI este memorata pe: "<<sizeof(PI)<<"octeti\n"; cout<<"Double maxim="<<MAXDOUBLE<<'\n'<<"Double minim ="<<MINDOUBLE<<'\n';
18
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
cout<<"Tipul long double memorat pe: "<<sizeof(long double)<<" octeti\n"; cout<<"Tipul long double memorat pe: "<<sizeof(23.7L)<<" octeti\n"; //23.7L-const. decimala long double cout<<"Cifra A din HEXA are val.: "<<0xA<<"\n"; cout<<"Cifra F din HEXA are val.: "<<0xF<<"\n"; cout<<"valoarea B+C din hexa in baza 10 este "<<0xB+0xc<<"\n"; cout<<"Val. const. hexa 0x7acle este: "<<0x7ac1e<<'\n'; cout<<"Val. const. octale 171 este: "<<0171<<'\n'; cout<<"O const. octala se memoreaza pe "<<sizeof(011)<<" octeti\n"; cout<<"O const.oct.long. se mem pe "<<sizeof(011L)<<" octeti\n"; cout<<"2<9:"<<(2<9)<<'\n'; }
4.4.4 Intrări-ieşiri standard (scanf, printf)
Să se scrie un program care ilustrează folosirea funcţiilor scanf, printf. //Intrari/iesiri standard #include<conio.h> #include<stdio.h> void main() { char c;int i;float f;char sir[10]; clrscr(); printf("Introduceti un char/intreg/float/sir: \n"); scanf("%c%d%f%s",&c,&i,&f,sir); //caracter si cod caracter printf("\nc=%c cod=%d",c,c); //intreg printf("\ni=%d",i); //cu lungime de cimp printf("\ni=%6d",i); //aliniat la stinga printf("\ni=%-6d;i=%d",i,i); //cu zerouri nesemnificative printf("\ni=%06d",i); //in octal printf("\ni in octal=%o",i); //in hexa printf("\ni in hexa=%x",i); //float printf("\nf=%f",f); //cu lungime si precizie impusa printf("\nf=%10.2f",f); //stiintific printf("\nf=%e",f); //stiintific cu precizie data printf("\nf=%.3e",f); //c m scurt dintre f si e
19
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
INTRĂRI/IEŞIRI ÎN C/C++
printf("\nf=%g",f); //sir cu lungime fixa printf("\nsir=%4.6s",sir); getch(); }
4.5 Probleme propuse
1. Să se scrie un program care să tipărească următoarele: ************************* * Bine ai venit la ore! * *************************
2. Care dintre programele de mai jos nu conţin erori şi afişează cuvintele pe câte un rând ?
#include <iostream.h> void main() ; {cout<<”Program”; cout<<” \n”<<”simplu”;}
#include <iostream.h> void main () {cout<<”Program \n”; cout<<”simplu”;}
#include <iostream.h> void main () {cout<<”Program \nsimplu”; cout<<” \n”;}
#include <iostream.h> void main () {cout<<”Program”; cout<<simplu”<<” \n”;}
20
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
OPERATORI
5. OPERATORI ŞI EXPRESII
5.1 Operatori
Operatorul de atribuire: = În tabelul de mai jos sunt prezentate principalele variante ale instrucţiunii de atribuire.
Tabelul 5.1 Principalele variante ale instrucţiunii de atribuire operaţia sintaxa exemple observaţii
Atribuire simplă
<variabilă> = <expresie>;
x=y+z/3;
Atribuirea combinată cu un operator
<variabilă> <op> = <expresie>;
x+=y; i-=2; a*=ln(a); alfa /=n;
Este echivalentă cu: <variabilă> = <variabilă> op <expresie>;
Operatori aritmetici unari (3): -, ++ , --
“++” - Incrementare - Măreşte valoarea variabilei cu 1, “--“ - Decrementare - Micşorează valoarea variabilei cu 1. Pot fi în formă prefixată (Ex. ++a), sau postfixată (Ex. b--). În cazul în care un
operator de incrementare sau decrementare este prefixat, se foloseşte valoarea operandului la care s-a aplicat operatorul respectiv, iar în cazul în care un operator de incrementare sau decrementare este postfixat, se foloseşte valoarea operandului dinaintea aplicării operatorului respectiv.
Operatori aritmetici binari (5): +, -, *, /, % (restul împărţirii întregi). Obs.: În C, prin împărţirea a doi întregi se obţine tot un întreg Operatori aritmetici binari compuşi (cu atribuire) (5): +=, -=, *=, /=, %=
Semnificaţie: expr1 op = expr2 ⇔ expr1 = expr1 op expr2. Ex. a+=2 ⇔ a=a+2
Operatori relaţionali binari (6): >, >=, <, <=, == (egal cu), != (diferit de) Operatori logici pe cuvânt (3): && (ŞI), || (SAU), ! (NOT) Ordinea descrescătoare a priorităţii: !, >, >=, <, <=, &&, ||
Tabelul 5.2 Compunerea operatorilor logici pe cuvânt a b a&&b a||
b aXORb !a
0 0 0 0 0 1 0 1 0 1 1 1 1 0 0 1 1 0 1 1 1 1 0 0
Pentru aXORb nu există operator, dar se poate folosi (a||b)&&!(a&&b).
21
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
OPERATORI ŞI EXPRESII
Operatori logici pe bit (6): ~ (NOT), & (ŞI), | (SAU), ^ (XOR), <<, >> (deplasare biţi stânga/dreapta) Operatorul condiţional " ? :"
Este un operator ternar (necesită 3 operanzi), utilizat în construcţii de forma: expresie1 ? expresie2:expresie3
Se evaluează expresie1. Dacă aceasta are o valoare diferită de zero, atunci tipul şi valoarea întregii expresii vor fi aceleaşi cu tipul şi valoarea expresie2. Altfel (dacă expresie1 are valoarea zero), tipul şi valoarea întregii expresii vor fi aceleaşi cu tipul şi valoarea expresie3. Deci operatorul condiţional este folosit pentru a atribui întregii expresii tipul şi valoarea expresie2 sau a expresie3, în funcţie de o anumită condiţie. Acest lucru este echivalent cu:
DACĂ expresie1 ≠ 0 ATUNCI evaluează expresie2 ALTFEL evaluează expresie3
Tabelul 5.3 Prioritatea operatorilor Nr. Clasă de
operatori Operatori Asociativitate
1. Primari () [] . -> :: de la stânga la dreapta
2. Unari ! (NOT pe cuvânt) ~ (NOT pe bit) ++ -- sizeof (tip)
de la stânga la dreapta
-(unar) *(deferenţiere) &(referenţiere) de la dreapta la stânga
3. Multiplicativi * / % de la stânga la dreapta 4. Aditivi + - de la stânga la dreapta
5. Deplasare pe bit << >> de la stânga la dreapta
6. Relaţionali < <= > >= de la stânga la dreapta 7. De egalitate == != de la stânga la dreapta 8. & (ŞI logic pe bit) de la stânga la dreapta 9. ^ (XOR pe bit) de la stânga la dreapta 10. | (SAU logic pe bit) de la stânga la dreapta 11. && (ŞI logic pe cuvânt) de la stânga la dreapta
12. || (SAU logic pe cuvânt) de la stânga la dreapta
13. Condiţional ?: de la dreapta la stânga
14. De atribuire
= += -= *= %= &= ^= |= <<= >>=
de la dreapta la stânga
15. Virgulă , de la stânga la dreapta Operatorul de forţare a tipului sau de conversie explicită (expresie cast)
Adesea dorim să specificăm conversia valorii unui operand spre un tip dat. Acest lucru este posibil folosind o construcţie de forma:
22
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
CONVERSIA ÎNTRE BAZELE DE NUMERAŢIE
(tip) operator Printr-o astfel de construcţie, valoarea operandului se converteşte spre tipul indicat
în paranteze. În construcţia de mai sus (tip) se consideră că este un operator unar. Îl vom numi operator de forţare a tipului sau de conversie explicită. Construcţia de mai sus o vom numi expresie cast. Exemplu: int x; float y; y= (float)n/2;
5.2 Prioritatea operatorilor
Tabelul 5.3 prezintă ierarhia tuturor operatorilor (grupaţi pe categorii) folosiţi în limbajul C cu priorităţile lor şi regulile de asociativitate. Operatorii dintr-o categorie au aceeaşi prioritate. Reţineţi că toţi operatorii, cu excepţia operatorilor unari, a acelor combinaţi cu atribuire şi a operatorului ?, se asociază de la stânga la dreapta. Operatorii unari (*, &, -) şi operatorul ? se asociază de la dreapta la stânga.
5.3 Conversia între bazele de numeraţie
5.3.1 Conversia zecimal-binar
Aceasta se realizează prin împărţiri succesive la doi până când câtul devine zero; şirul resturilor în ordine inversă formează numărul în baza doi.
Ex.: 2410 = 110002. Acest lucru s-a obţinut conform operaţiilor din tabelul alăturat.
5.3.2 Conversia binar-zecimal
Numărul în baza 10 este suma produselor dintre cifrele numărului în baza doi şi doi ridicat la o putere egală cu poziţia cifrei în număr; numerotarea începe din dreapta cu poziţia zero.
Ex.: 110102 = 1∙24 + 1∙23 + 0∙22 + 1∙21 + 0∙20 = 2610
5.3.3 Conversia hexazecimal-binar
Se scrie fiecare simbol al numărului hexazecimal sub formă binară. Ex.: DFH = 110111112 deoarece DH = 1310 = 11012, iar FH = 1510 = 11112
5.3.4 Conversia binar-hexazecimal
Numărul binar se împarte în grupuri de câte patru cifre, începând de la dreapta la stânga, iar apoi fiecare grup de cifre este scris în baza şaisprezece.
Ex.: 1101010 = 01101010 = 6AH deoarece 0110 = 610 = 6H, iar 1010 = 1010 = AH
Operaţie Cât Rest 24:2 12 0 12:2 6 0 6:2 3 0 3:2 1 1 1:2 0 1
23
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
OPERATORI ŞI EXPRESII
5.4 Exemple
5.4.1 Operatori aritmetici
//Program cu operatii aritmetice #include<iostream.h> void main(void) { float a,b,c,d,e; cout<<“Dati doua numere:”; cin>>a>>b; cout<<“Suma= “<<a+b<<“\nProdusul= ”<<a*b<<“\nDiferenta= ”<<a-b<<“\nCâtul= ”<<a/b; }
5.4.2 Aria şi perimetrul unui disc de rază r
Fie r un număr real, citit de la tastatură, care reprezintă lungimea razei unui cerc. Să se scrie un program care să calculeze şi să afişeze aria şi perimetrul discului de rază r.
5.4.2.1 Soluţie Vom citi valoarea razei în variabila r. Vom calcula aria discului după formula πr2, iar perimetrul, după formula 2πr. Numărul π este un număr iraţional. Calculatorul nu poate memora numere iraţionale (care au o infinitate de zecimale), ci doar aproximări ale acestora. În fişierul antet math.h este definită o constantă numită M_PI care reprezintă o aproximare a numărului iraţional π.
5.4.2.2 Programul //Cerc #include <iostream.h> #include <math.h> void main() { double r; cout<<"\nRaza r= "; cin>>r; cout<<"Aria=\t\t"<<M_PI*r*r <<"\nPerimetrul=\t" << 2*M_PI*r; }
5.4.3 Aria triunghiului - formula lui Heron
Să se calculeze aria S a unui triunghi cu laturile a,b,c citite de la tastatură folosind
formula lui Heron: S = p(p-a)(p-b)(p-c) , unde p = a+b+c
2 .
//Aria triunghiului- formula lui Heron #include <iostream.h> #include <math.h> main() { unsigned int a,b;
24
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
float c,S,p; cout<<"\nIntroduceti prima latura a ";cin>> a; cout<<"\nIntroduceti a doua latura b ";cin>> b; cout<<"\nIntroduceti a treia latura c ";cin>> c; //c=hypot(a,b); p=(a+b+c)/2; S=sqrt(p*(p-a)*(p-b)*(p-c)); //cout<<"\nIpotenuza este "<<c; cout<<"\nSemiperimetrul este "<<p; cout<<"\nAria este "<<S; }
5.4.4 Rezolvarea unui sistem de două ecuaţii
Să se rezolve sistemul de 2 ecuaţii cu 2 necunoscute: a11⋅x + a12⋅y = b1
a21⋅x + a22⋅y = b2E
1.CITEŞTE a11,a12,a21,a22,b1,b2 2.det = a11*a22-a21*a12 3.detx = b1*a22-b2*a12 4.dety = a11*b2-a21*b1 5.x = detx/det; y = dety/det 6.SCRIE x,y
5.4.5 Incrementări/decrementări/atribuiri
Care sunt valorile variabilelor a,b şi după execuţia succesivă a următoarelor instrucţiuni (Valori iniţiale: a= 0; b= 0; c= 0):
a=(++b)+(++c) a=b+++c++ a=(++b)+c++ a=b--+--c a=(++c)+c a+=2 b-=3 c*=4 a/=2 Rezultatele programului se vor interpreta urmărind valorile variabilelor a, b şi c în
fereastra Watch
5.4.6 Operatori relaţionali şi logici - exemplul 1
//Operatori relationali si logici #include<conio.h> #include<stdio.h> void main () { int x1=1,x2=20,x,cond;
25
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
OPERATORI ŞI EXPRESII
printf("\nx= "); scanf("%d",&x); //verifica daca un nr indepl o conditie cond=x1<x&&x<x2||(x%2); printf("\nconditia x1<x&&x<x2||(x%%2) este %d",cond); cond=10>5&&!(10<9)||3<=4; printf("\nconditia 10>5&&!(10<9)||3<=4 este %d",cond); printf("\n!0&&0||0 este %d, dar",!0&&0||0); printf("\n!(0&&0)||0 este %d",!(0&&0)||0); getch(); }
5.4.7 Operatori relaţionali şi logici - exemplul 2
#include <iostream.h> void main() { int a=0, b=10, c=100, d=200; int rezult; rezult=a&&b; cout<<”a&&b=”<<rezult<<’\n’; //Afisare a&&b=0 rezult=a||b; cout<<”a||b=”<<rezult<<’\n’; //Afisare a||b=1 (sau valoare nenula) rezult=!a;cout<<”!a=”<<rezult<<’\n’; //Afisare !a=1 (sau valoare nenula) rezult=!b; cout<<”!b=”<<rezult<<’\n’; //Afisare !b=0 rezult= (a>b) || (b>c); cout<< ”(a>b) || (b>c)=” <<rezult<<’\n’; //Afisare (a>b) || (b>c) =1(sau valoare nenula) rezult=!(c<d);cout<<”!(c<d)=”<<rezult<<’\n’; //Afisare !(c>d)=0 rezult=(a-b)&&1;cout<<”(a-b)&&1=”<<rezult<<’\n’; //Afisare (a-b)&&1 =1(sau valoare nenula) rezult=d||b&&a;cout<<”d||b&&a=”<<rezult<<’\n’; //Afisare d||b&&a =1 }
5.4.8 An bisect
Să se scrie un program care citeşte un întreg din intervalul [1600, 4900], ce reprezintă un an calendaristic, afişează 1 dacă anul este bisect şi 0 în caz contrar sau dacă anul nu aparţine intervalului indicat mai sus.
Un an, din calendarul gregorian, este bisect dacă este multiplu de patru şi nu este multiplu de 100 sau dacă este multiplu de 400. Această regulă este valabilă pentru anii care nu sunt anteriori anului 1600.
Dacă notăm cu an anul calendaristic, atunci el este bisect dacă de exemplu: an%4==0 (an este multiplu de 4) an%100!=0 (an nu este multiplu de 100). Deci anul este bisect dacă expresia (1) an%4==0 && an%100!=0 este adevărată. De asemenea, anul este bisect şi în cazul în care expresia
26
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
(2) an%400==0 (an este multiplu de 400) este adevărată. Deci anul este bisect dacă este adevărată expresia (1) sau (2), adică dacă este
adevărată expresia: an%4==0 && an%100! =0 || an%400==0
5.4.8.1 Programul //An bisect #include <stdio.h> void main ( ) { int an, bisect; printf("Anul: "); scanf("%d", &an); bisect=an>=1600 && an<=4900 && (an%4==0 && an%100!=0 || an%400==0); printf("an=%d\t%d\n",an,bisect); }
5.4.9 Operatori pe biţi
Programul afişează rezultatul următoarelor expresii: Val iniţială x= 7, în binar 00000111 Deplasare biţi x=x<<1 dă x= 14, în binar 00001110 x=x<<3 dă x= 112, în binar 01110000 x=x<<2 dă x= 192, în binar 11000000 x=x>>1 dă x= 96, în binar 01100000 x=x>>2 dă x= 24, în binar 00011000 x=~x dă x= 231, în binar 11100111 SI 7, în binar 00000111; 14, în binar 00001110 x=(7&14) dă x= 6, în binar 00000110 SAU 128, în binar 10000000; 3, în binar 00000011 x=(128|3) dă x= 131, în binar 10000011 XOR 127, în binar 01111111; 120, în binar 01111000 x=(127^120) dă x= 7, în binar 00000111
5.4.9.1 Programul //Operatii pe biti #include<conio.h> #include<iostream.h> //Functie de afisare a rezultatelor void dectobin(int x) { int i=8,bin,r[8]={0,0,0,0,0,0,0,0}; do
27
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
OPERATORI ŞI EXPRESII
{ r[i-1]=x%2; x/=2; i--; } while(x); for(i=0;i<8;i++) cout<<r[i]; } void main() { unsigned char x=7; clrscr(); cout<<"\n\t\tx= "<<int(x)<<"\tin binar ";dectobin(x); x=x<<1; cout<<"\nx=x<<1 dă\tx= "<<int(x)<<"\tin binar "; dectobin(x); x=x<<3; cout<<"\nx=x<<3 dă\tx= "<<int(x)<<"\tin binar ";dectobin(x); x=x<<2; cout<<"\nx=x<<2 dă\tx= "<<int(x)<<"\tin binar "; dectobin(x); x=x>>1; cout<<"\nx=x>>1 dă\tx= "<<int(x)<<"\tin binar "; dectobin(x); x=x>>2; cout<<"\nx=x>>2 dă\tx= "<<int(x)<<"\tin binar "; dectobin(x); x=~x; cout<<"\nx=~x dă\tx= "<<int(x)<<"\tin binar "; dectobin(x); //SI cout<<"\n\nSI\t\t7\tin binar ";dectobin(7); cout<<"\n\t\t 14\tin binar ";dectobin(14); x=7&14; cout<<"\nx=(7&14) dă\tx= "<<int(x)<<"\tin binar "; dectobin(x); //SAU cout<<"\n\nSAU\t\t128\tin binar "; dectobin(128); cout<<"\n\t\t 3\tin binar "; dectobin(3); x=128|3; cout<<"\nx=(128|3) dă\tx= "<<int(x)<<"\tin binar "; dectobin(x); //SAU exclusiv cout<<"\n\nXOR\t\t127\tin binar "; dectobin(127); cout<<"\n\t\t120\tin binar "; dectobin(120); x=127^120; cout<<"\nx=(127^120) dă\tx= "<<int(x)<<"\tin binar "; dectobin(x); getch(); }
5.4.10 Operatorul ternar - maximul a două numere
Să se scrie un program care citeşte două numere şi afişează maximul dintre ele. // Operatorul ternar - maximul a 2 numere #include <stdio.h> void main () { double a,b; scanf("%lf %lf",&a,&b); printf("a=%g\tb=%g\tmax(a,b)=%g\n", a,b, a > b ? a : b); }
28
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
5.4.11 Operatorul ternar - modulul unui număr
Să se scrie un program care citeşte un număr şi afişează valoarea lui absolută. //modulul unui numar #include <stdio.h> void main() { double a; scanf("%lf", &a); printf("a=%g\tabs(a)=%g\n",a, a < 0 ? -a : a ); }
5.4.12 Operatorul cast - rădăcina pătrată a unui număr
Să se scrie un program care citeşte un întreg şi afişează rădăcina pătrată din numărul respectiv. #include <stdio.h> #include <math.h> void main( ) {/* - citeste pe n; - calculează si afisează rădăcina pătrata din n * long n; scanf("%ld", &n); printf("n=%ld\tsqrt(n)=%g\n",n, sqrt((double)n)); }
Obs.: în acest program, pentru extragerea rădăcinii pătrate s-a utilizat funcţia sqrt. Ea are prototipul: double sqrt(double). Acest prototip este definit în fişierul math.h.
5.4.13 Operatorul cast - calculul unei expresii
Să se scrie un program care citeşte pe n de tip întreg şi afişează valoarea expresiei n/(n+1) cu 15 zecimale. #include <stdio.h> void main( ) { long n; scanf("%ld", &n); printf("n=%ld\tn/(n+1)=%.15g\n", n, (double)n/(n+1)); }
Obs.: Expresia n/(n+1) realizează împărţirea întreagă a lui n la n + 1. Pentru a obţine câtul împărţirii cu 15 zecimale, este necesar să se efectueze împărţirea neîntreagă. În acest scop s-a convertit operandul n spre tipul double. În felul acesta, conform regulii conversiilor implicite, se converteşte spre double şi cel de al doilea operand şi apoi se face împărţirea celor doi operanzi flotanţi.
29
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
OPERATORI ŞI EXPRESII
5.4.14 Operatorul virgulă
Să se scrie un program care citeşte doi întregi şi afişează maximul dintre valorile lor absolute. #include <stdio.h> void main( ) { int a,b,c,d; scanf("%d%d", &a,&b); printf("a=%d\tb=%d\tmax(abs(a),abs(b))=%d\n", a, b, ((c=a<0 ?-a:a), (d=b<0 ? -b : b), (c>d)) ? c : d); }
Obs.: Expresia: (c = a<0 ?-a), (d = b<0 ?-b:b), (c>d) se compune din trei expresii care se evaluează de la stânga la dreapta.
Prima atribuie lui c valoarea absolută a lui a, a doua atribuie lui d valoarea absolută a lui b, iar a treia testează relaţia c>d. Valoarea întregii expresii coincide cu 1 dacă c>d şi cu zero în caz contrar.
5.5 Probleme propuse
1. Să se scrie declaraţiile pentru definirea constantelor simbolice: pi, g (acceleraţia gravitaţională), unghi_drept, dimensiune_MAX.
2. Care va fi rezultatul afişat pe ecran în urma execuţiei următoarelor secvenţe de instrucţiuni:
double a=9/2; cout<<a*5<<’\n’; double a=9.7, b=5.6; cout<<(a+6<b)<<’\n’; double a=9/4; cout<<a*6<<’\n’; double x=3;int y=++x+5;cout<<y<<’\n’; int a=7; cout<<(!a)<<’\n’; int a=10.5; cout<<a++<<’\n’; cout<<a<<’\n’; int a=7; cout<<++a<<’\n’; cout<<a<<’\n’; int a=10; cout<<a++<<’\n’; cout<<a<<’\n’; double a=7/2; cout<<a<<’\n’; int x=3; int y=x++-2; cout<<y<<’\n’; int x=3; int y=++x+5; cout<<y<<’\n’; double a=5.6, b=7.45; cout<<(a>b)<<’\n’;
3. Să se verifice corectitudinea următoarelor secvenţe. Pentru cele incorecte, explicaţi sursa erorilor.
double a=9.7, b=5.2; int c=(a+6<b)++; cout<<c<<’\n’; double a=7/5; double c=a*5++; cout<<c<<’\n’; double a=9.7, b=5.6; int c=(a%6<b)++; cout<<c<<’\n’; double a=5.6, b=7.45; cout<<++(a+5>b)<<’\n’; double a=9.8; double b=9.7; cout<<a%b<<’\n’; cout<<&(a+8)<<'\n'; int I=8; cout<<(I+10)++<<'\n'; double a=8.7; A=(a+8)/56; cout<<A<<'\n'; int x=3/5; int y=x++; char x='J'; cout<<"y="<<y<<'\n'; char a='X'; const int b=89; b+=8; cout<<"b="<<b<<"
a="<<a<<'\n'; 4. Să se scrie un program care afişează următoarele mesaje:
30
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
PROBLEME PROPUSE
Sirul "este dupa-amiaza" este memorat pe .... octeti. marime intreaga este memorata pe ... octeti. marime reala, in simpla precizie este memorata pe ... octeti! marime reala, in dubla precizie este memorata pe ... byti! Constanta caracter 'Q' memorata pe ... octeti! Sirul "a\n\n" este memorat pe ... octei! Sirul "\n" este memorat pe ... biti! Caracterul '\' este memorat pe .... biti.
5. Să se evalueze expresiile, ştiind că: int i=1; int j=2; int k=-7; double x=0; double y=2.3;
-i - 5 * j >= k + 1 3 < j < 5 i + j + k == -2 * j x && i || j - 3
6. Ce operaţie logică şi ce mască trebuie să folosiţi pentru a converti codurile ASCII ale literelor mici în litere mari ? Dar pentru conversia inversă ?
7. Să se seteze pe 1 toţi biţii dintr-un octet, cu excepţia bitului cel mai semnificativ. 8. Să se scrie un program care citeşte o valoare întreagă. Să se afişeze un mesaj care să
indice dacă numărul citit este par sau impar. 9. Să se citească două valori întregi. Să se calculeze şi să se afişeze restul împărţirii
celor două numere. 10. Să se realizeze programe care execută următoarele acţiuni:
a. Se citeşte un unghi în grade; se cere să se transforme în radiani (360° = 2π rad);
b. Calculează perimetrul şi aria unui cerc de rază r citită de la tastatura; c. Calculează perimetrul şi aria unui triunghi de laturi date; d. Calculează expresia: -3∙x2 + x∙y - y/x.
11. Să se scrie un program care să convertească o temperatură în grade Celsius în echivalentul ei în grade Fahrenheit. Formula de conversie este F = 32 + 9/5 C. Programul trebuie să tipărească ambele valori ale temperaturii (în grade Celsius şi grade Fahrenheit) cu mesaje corespunzătoare.
12. Care dintre variabilele care intervin în secvenţa de operaţii următoare îşi vor păstra valoarea avută iniţial?
a ← b+c; a şi c; c ← a-c; b şi c b ← c; b şi a; c ← a-b; a, b şi c
13. Care dintre operaţiile următoare atribuie variabilei întregi x una din cifrele sale, ştiind că x > 10000:
x ← x mod 100; x ← x mod 10; x ← x div 10 mod 10; x ← x div 100 mod 10; x ← x mod 10 div 1; x ← x mod 50;
14. Fie a, b, c şi d patru variabile reale. Care dintre următoarele instrucţiuni atribuie variabilei d media aritmetică a valorilor variabilelor a, b şi c?
d=(a+b+c)/2; d=a/3+b/3+c/3; d=a+b+c/3; d=(a+b+c)/4-1;
15. Care dintre următoarele declaraţii de variabile sunt eronate sintactic şi de ce? float a=b=0; double z=x/2;
31
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
OPERATORI ŞI EXPRESII
char d=120; int k;i; long a=0, b=a+3; unsigned float a;
16. Care dintre următoarele expresii sunt adevărate dacă şi numai dacă numărul întreg x este impar negativ?
x%2==l) && (x<0) (x%2!=0) || (x<0) !((x%2==0) || (x>=0)) !((x%2==0) && (x>=0)) x%2=l && x<0
17. Care dintre următoarele expresii sunt adevărate dacă şi numai dacă valorile variabilelor x şi y sunt numere naturale consecutive?
x-y==1 (x==1) && (y==2) (x-y==1) && (y-x==1) y==x±1 (x-y==1) || (y-x==1)
18. Să considerăm următoarele declaraţii de variabile: int x=0XF0A8, v=0XFFFD; unsigned y=0XF0A8, z=1; float a=s.5, b=4; char c=8;
Evaluaţi următoarele expresii: a+z/2 -1 > z (v+z)/2 c>='0' && c <= '9' ? "da" : "nu" (v+1) /2 x>>3&z<<4 c-'0' y>>10|z
19. În contextul declaraţiilor de variabile de la exerciţiul precedent, care sunt erorile din următoarele expresii?
(a+z)%2 a+++x b*b-4ac x=(a»2) c=a?"da" : "nu" x&&=10
20. În condiţiile următoarelor declaraţii şi iniţializări de variabile: unsigned char x=250, z=x+7, a='8';
Care este valoarea expresiei: z | (a-' 0') ? Expresia nu se poate evalua, deoarece este eronată sintactic, 1 265 0 true 9
21. Se consideră x, y şi z trei variabile întregi. Care dintre următoarele expresii are valoarea diferită de 0 dacă şi numai dacă y=max (x, y, z) ?
x>z?y>=x?1:0:y>=z?1:0
32
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
PROBLEME PROPUSE
!(y<x || y<z) !(y<x && y<z) x>z && y>x || z>x && y>z y>x && y>z
22. Pentru a atribui variabilei reale x rezultatul expresiei A
2ab - c2
0.25 E A,unde a, b şi c
desemnează variabile reale, se utilizează instrucţiunea: x=(2*a*b)-(c*c)/0.25; x=2*a*b-c*c/0.25; x=(2*a*b)-(c*c)*4; x=(2*a*b-c*c)*4;
23. Fie A şi B două puncte în plan, specificate prin coordonatele lor carteziene. Să se scrie un program care să calculeze şi să afişeze lungimea segmentului AB.
33
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
STRUCTURI DE DECIZIE (ALTERNATIVE, DE SELECŢIE)
6. STRUCTURI DE DECIZIE (ALTERNATIVE, DE SELECŢIE)
6.1 Structura de decizie: instrucţiunea if
Aceasta corespunde cazurilor când în algoritmul problemei intervine o decizie. Este instrucţiunea principală în C care descrie structura alternativă. Pentru un
pseudocod de forma: DACĂ (<condiţie>) ATUNCI <instrucţiune>
instrucţiunea if este: if (<condiţie>) <instrucţiune>;
iar pentru un pseudocod de forma: DACĂ (<condiţie>) ATUNCI <instr1> ALTFEL <instr2>
instrucţiunea if este: if (<condiţie>) <instr1>; else <instr2>;
Obs.: Dacă una din instrucţiunile de pe ramura "if" sau "else" este o instrucţiune compusă, atunci ea se încadrează între acolade: { <instr1>; <instr2>; ... }
şi nu se mai termină cu punct-virgulă. În caz contrar, programul va executa numai prima instrucţiune de pe ramură.
6.2 Structura de selecţie cu ramuri multiple: instrucţiunea switch
În unele cazuri este necesară o decizie multiplă specială. Instrucţiunea switch permite acest lucru.
DACĂ expresie=expr_const_1 instrucţiune1; [ieşire;] ALTFEL DACĂ expresie=expr_const_2 instrucţiune2; [ieşire;] … ALTFEL DACĂ expresie=expr_const_n-1 instrucţiune_n-1; [ieşire;] ALTFEL instrucţiune_n; Se testează dacă valoarea pentru expresie este una dintre constantele specificate
(expr_const_1, expr_const_2, etc.) şi se execută instrucţiunea de pe ramura corespunzătoare. În schema logică, test_expresie este una din condiţiile: expresie=expr_const_1, expresie=expr_const_2, etc.
Sintaxa: switch (expresie) { case expresie_const_1: instructiune_1; [break;]
34
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE IF, SWITCH
case expresie_const_2: instructiune_2; [break;] . . . . . . . . . . . . . . case expresie_const_n-1: instructiune_n-1;[break;] [ default: instructiune_n; ] }
Instrucţiunea switch este o generalizare a instrucţiunii if. Spre deosebire de if, care permite selectarea unei alternative din maximum două posibile, switch permite selectarea unei alternative din maximum n+1 posibile. O altă diferenţă majoră constă în faptul că în if se execută instrucţiunea corespunzătoare valorii expresiei şi atât, în timp ce în switch se execută şi toate secvenţele de instrucţiuni ale alternativelor case următoare.
6.3 Exemple if, switch
6.3.1 Maximul a trei numere
6.3.1.1 Pseudocodul 1.CITEŞTE a,b,c 2.DACĂ a>b ATUNCI max=a ALTFEL max=b 3.DACĂ c>max ATUNCI max=c 4.SCRIE max
6.3.1.2 Programul #include<iostream.h> main() { int a,b,c,max; cout<<"Dati a b c"; cin>>a>>b>>c; if(a>b) max=a; else max=b; if(c>max) max=c; cout<<"maximul="<<max; }
6.3.2 Calculator de buzunar
//Instruc de selectie switch #include<stdio.h> void main() { float x,y,z; char op; printf("\nIntroduceti expresia (valoare operator valoare): "); scanf("%f %c %f",&x,&op,&y); switch(op) { case '+':z=x+y; break; case '-':z=x-y; break;
35
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
STRUCTURI DE DECIZIE (ALTERNATIVE, DE SELECŢIE)
case '*':z=x*y; break; case '/':z=x/y; break; default: printf("\nOperator eronat"); z=0; } printf("%.2f %c %.2f= %.2f",x,op,y,z); }
6.3.3 Sumă
Orice sumă de bani S (S>7) poate fi plătită numai cu monede de 3 lei şi de 5 lei. Dat fiind S>7, scrieţi un program care să determine o modalitate de plată a sumei S numai cu monede de 3 lei şi de 5 lei. Cum se poate obţine numărul minim de monede ?
6.3.3.1 Soluţie Problema cere, de fapt, să găsim două numere naturale x şi y, astfel încât s să poată fi scris sub forma S = 3*x+5*y.
Vom analiza următoarele trei cazuri: 1. S%3 (restul împărţirii lui S la 3) este 0. În acest caz, x = S/3, iar y = 0. 2. S%3 este 1. Deoarece S>7, vom considera x = S/3 - 3 şi y = 2, pentru că S = 3 * S/3
+ l = 3 * (S/3 - 3) + 3*3 + 1 = 3*(S/3 - 3) + 10 = 3*(S/3 - 3) + 5*2. 3. S%3 este 2. În acest caz vom considera x = S/3 - l şi y = l, deoarece S = 3*S/3 + 2 =
3*(S/3 - l) + 3 + 2 = 3*(S/3 - l) + 5.
6.3.3.2 Programul #include <stdio.h> int main (void) { int S, x, y, r; printf("Introduceti suma S: "); scanf("%d", &S); r=S%3; switch (r) { case 0: x=S/3; y=0; break; case 1: x=S/3-3; y=2; break; case 2: x=S/3-1; y=1; } printf("%d = 3*%d + 5*%d\n",S,x,y); return 0; }
6.4 Probleme propuse
Să se alcătuiască programe care să rezolve următoarele probleme: 1. Calculul valorii unei funcţii - Să se calculeze şi să se afişeze valoarea funcţiei f pentru
un x dat: 4x3 + 5x2 - 2x + 1, x<0 f(x)= 100, x=0 ex - ln x, x>0
36
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
PROBLEME PROPUSE
2. Ecuaţia de gradul 2 (vezi şi schema logică). Pseudocodul: 1.CITEŞTE a,b,c 2.DACĂ a=0 ATUNCI 2.1.DACĂ b=0 ATUNCI 2.1.1.DACĂ c=0 ATUNCI 2.1.1.1 SCRIE "ec.are o infinitate de sol." 2.1.1.2 ALTFEL SCRIE "ec.nu are sol" 2.1.2 ALTFEL SCRIE "ec.are sol.unică x=",-c/b ALTFEL 2.2 d=b*b-4*a*c 2.2.1 DACĂ d>0 ATUNCI 2.2.1.1. x1=(-b- A dE A)/(2*a) 2.2.1.2. x2=(-b+A dE A)/(2*a) 2.2.1.3. SCRIE "x1=",x1,"x2=",x2 ALTFEL 2.2.1.2 DACĂ d=0 ATUNCI 2.2.1.2.1 SCRIE "ec.are rad.dubla x=",-b/(2*a) ALTFEL 2.2.1.2.2 re = -b/(2*a), im = A -dE A/(2*a) SCRIE "ec.are sol.complexe re = ", re," im = ",im
3. Modulul şi argumentul unui număr complex. Pseudocodul: 1.CITEŞTE re,im 2.modul = A re*re+im*im E 3.DACĂ re=0 ATUNCI 3.1 DACĂ im>=0 ATUNCI 3.1.1 arg=pi/2 ALTFEL 3.1.2 arg = -pi/2 3.2 ALTFEL DACĂ re>0 ATUNCI 3.2.1 arg=arctg(im/re) ALTFEL 3.2.2 arg=-arctg(im/re) 4.SCRIE modul, arg
4. Calculul volumului unui corp geometric - Să se scrie un program care afişează un mesaj de tip meniu şi în funcţie de un caracter citit de la tastatură (1 - paralelipiped, 2 - cilindru, 3 - con, 4 - sferă, 0 - terminare program), citeşte dimensiunile necesare şi calculează şi afişează în cadrul unui mesaj volumul corpului respectiv (Vp = H·B·L; Vcil = π·R2·H; Vcon = π·R2·H/3; Vsf = π·D3/6).
5. Care este efectul următoarei secvenţe de instrucţiuni? int a, b, c, x; a=3; b=5; c=7; if (a-b/2<0) x=1; else if (a+b-c/2<b) x=2; else if (a%b+c>b) x=3;
37
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
STRUCTURI DE DECIZIE (ALTERNATIVE, DE SELECŢIE)
else x<-4; cout<<x;
6. Ce valoare iniţială ar putea avea variabila x, astfel încât la sfârşitul execuţiei următoarei secvenţe de instrucţiuni variabila y să aibă valoarea 2? if (x>3) if (x<7) if (x%2==0) y=1; else y=2; else y=3; else
y=4; 7. Fie x şi y două numere reale, citite de la tastatură. Scrieţi un program care calculează
şi afişează valoarea funcţiei:
A
x + y5xy E A dacă x, y > 0
f(x,y)= min (x, y), dacă x = 0 sau y = 0
A
1
x + 1Ey E AA
1
x + 1Ey + x2 + y2
E A, altfel 8. Fie x un număr natural de trei cifre. Scrieţi un program care să elimine una dintre
cifrele numărului astfel încât numărul de două cifre rămas să fie maxim.
38
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE WHILE
7. STRUCTURA CICLICĂ CU TEST INIŢIAL
Aceasta corespunde cazurilor când în algoritmul problemei intervine iteraţia unei acţiuni până la o condiţie de oprire.
7.1 Instrucţiunea while
Este principala instrucţiune în C++ care descrie structura ciclică cu test iniţial. Pentru un pseudocod de forma:
CÂT TIMP (<condiţie>) EXECUTĂ <instrucţiune> instrucţiunea while este:
while (<condiţie>) <instrucţiune>;
7.2 Exemple while
7.2.1 Algoritmul lui Euclid
7.2.1.1 Pseudocodul (vezi şi schema logică de la 2.3.4) 1.CITEŞTE a,b 2.cmmmc=a*b 3.CÂT TIMP b<>0 2.5.1.r = a%b //restul 2.5.2.a = b 2.5.3.b = r 2.6.cmmdc = a 2.7.cmmmc = cmmmc/cmmdc 2.8.SCRIE cmmmc, cmmdc
7.2.1.2 Programul //Algoritmul lui Euclid #include<iostream.h> int main() { long int a,b,rest,cmmmc,cmmdc; cout<<"\na=";cin>>a; cout<<"b=";cin>>b; cmmmc=a*b; while(b) { rest=a%b; cout<<"\n"<<a<<" = "<<b<<" * "<<a/b<<" + "<<rest; a=b; b=rest; } cmmdc=a; cmmmc=cmmmc/cmmdc;
39
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
STRUCTURA CICLICĂ CU TEST INIŢIAL
cout<<"\n\ncmmmc= "<<cmmmc<<" cmmdc= "<<cmmdc; return 0; }
Obs.: Nu se verifică dacă iniţial a > b; acest lucru nu este necesar, deoarece, dacă iniţial a < b, după prima executare a instrucţiunii compuse subordonate instrucţiunii while, valorile lui a şi b vor fi schimbate.
7.2.2 Produsul primelor “n” numere naturale (factorialul)
#include <iostream.h> void main() {int prod=1,i=0,n; char c; cout << "\nSpecificati numarul n:"; cin >> n; while(i<n) { i++; prod=prod*i; } cout << "\nFactorial de " << n << "=" << prod << "\n"; cin >> c; }
7.2.3 Suma primelor “n” numere naturale
#include <iostream.h> void main() {int suma=0,i=0,n; cout << "\nSpecificati numarul n:"; cin >> n; while(i<n) { i++; suma=suma+i; } cout << "\nSuma primelor " << n << " numere naturale=" << suma << "\n"; }
7.2.4 Descompunerea unui număr în factori primi
7.2.4.1 Pseudocodul 1. CITEŞTE n 2. n=abs(n) 3. f=2 //factorul prim de testat 4. CÂT TIMP (f<=n) 4.1.e=0 //exponentul la care apare factorul în descompunere 4.2.CÂT TIMP (n%f==0) //n se divide la f 4.2.1.n=n/f
40
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE FOR
4.2.2.e=e+1 4.3.DACĂ (e≠0) SCRIE f," la ",e 4.4.DACĂ (f=2) f=f+1 ALTFEL f=f+2
7.3 Instrucţiunea for
În majoritatea limbajelor de programare de nivel înalt, instrucţiunea for implementează structura ciclică cu număr cunoscut de paşi. În limbajul C, instrucţiunea for poate fi utilizată într-un mod mult mai flexibil. Reprezentare în pseudocod: evaluare expresie1 CÂT TIMP expresie2 REPETĂ ÎNCEPUT instructiune evaluare expresie3 SFÂRSIT
Sintaxa: for (expresie1; expresie2; expresie3)
instructiune; unde: expresie1 - reprezintă iniţializarea contorului; expresie2 - condiţia de rămânere în ciclu; expresie3 - modificarea contorului şi/sau instrucţiuni. Nu este obligatorie prezenţa expresiilor, ci doar a instrucţiunilor vide.
7.4 Exemple for
7.4.1 Calculul factorialului
//Calculul factorialului #include<iostream.h> #include<conio.h> void main() { long int i,n,fact=1; clrscr(); cin>>n; for(i=1;i<=n;i++) fact*=i; cout<<fact; getch(); }
41
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
STRUCTURA CICLICĂ CU TEST INIŢIAL
7.4.2 Calculul unei sume duble
Să se calculeze suma dublă A∑i=1
m
∑j=1
n sin(a+3*i)*cos(b+5*j).
7.4.2.1 Pseudocodul 1.CITEŞTE a,b,m,n 2.i=1 3.j=1 4.s=0 5.CÂT TIMP (i<=m) 5.1.CÂT TIMP (j<=n) 5.1.1.s=s+ sin(a+3*i)*cos(b+5*j) 5.1.2.j=j+1 5.2.i=i+1 6.SCRIE s
7.4.2.2 Programul #include<iostream.h> #include<math.h> main() { float s=0,a,b; int m,n,i,j; cout<<"a="; cin>>a; cout<<"b="; cin>>b; cout<<"m="; cin>>m; cout<<"n="; cin>>n; for(i=1,j=1; i<=m,j<=n; i++,j++) s=s+sin(a+3*i)*cos(b+5*j); cout<<"Suma="<<s; }
7.4.3 Şirul lui Fibonacci, termenii < n.
Dacă n=0: f0=0, n=1: f1=1, altfel: fi = fi-2 + fi-1
7.4.3.1 Pseudocodul 1. CITEŞTE n 2. DACĂ n>=2 2.1.PENTRU f0=0 şi f1=1, CÂT TIMP f1≤n, f0=f1, f1=fi, REPETA 2.1.1.fi=f0 + f1 2.1.2.SCRIE fi
7.4.3.2 Programul //Genereaza numerele Fibonacci #include<stdio.h> #include<conio.h> void main() {
42
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
PROBLEME PROPUSE
int f0,f1,fi,n; clrscr(); printf("Introd n: "); scanf("%d",&n); if(n>=2) { for(f0=0,f1=1,fi=1;fi<=n;f0=f1,f1=fi,fi=f0+f1) {printf("\nf0=%d; \tf1=%d; \tfi=%d;",f0,f1,fi); } } getch(); }
7.4.4 Afişarea codurilor ASCII ale caracterelor
//Coduri ASCII caractere #include<conio.h> #include<stdio.h> void main() { int i,j; clrscr(); // printf("\ncaracASCII\tcod zecimal\tcod octal"); for(i=0;i<=255;i+=10) { printf("\n"); for(j=1;j<=10;j++) if(i+j<=255) printf("%d: %c ",i+j,i+j); //if(!(i%25)) getch(); } getch(); }
7.5 Probleme propuse
1. Se consideră următoarea secvenţă de instrucţiuni: int n, d=2; cin>>n; while (n>l) if (n%d==*0) n/=d; cout<<d;
a. Ce valoare va fi afişată dacă valoarea citită pentru variabila n este 720? b. Daţi exemplu de valori (cel puţin două) care ar putea fi introduse pentru variabila n, astfel încât valoarea afişată să fie 11. c. Care este efectul acestei secvenţe de instrucţiuni?
2. Se consideră următoarea secvenţă de instrucţiuni: int x, a, b, i; cin>>a>>b; i=a; x=0; while (i<=b) { x+=i;i++; } cout<<x;
43
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
STRUCTURA CICLICĂ CU TEST INIŢIAL
a. Ce valoare va fi afişată pe ecran dacă se introduc valorile 1 şi 10? b. Ce valori ar putea fi introduse pentru a şi b astfel încât programul să afişeze valoarea 22? c. Daţi exemplu de valori distincte care ar putea fi introduse astfel încât programul să afişeze valoarea 0. d. Scrieţi un program echivalent mai eficient.
3. Care dintre următoarele secvenţe de instrucţiuni atribuie variabilei întregi u valoarea primei cifre a numărului natural reprezentat de variabila x ?
u=x/10; u=x; while (u>=10) u=u%10; u=x%10; while (x>=10) x=x/10; u=x;
4. Ce valoare iniţială ar trebui să aibă variabila x astfel încât după execuţia următoarei secvenţe de instrucţiuni să se afişeze valoarea 640?
d=2; while (d<50) { x=x*d; d=d*d;} cout«x;
5. Numere prietene - Două numere naturale a şi b se numesc prietene dacă a este egal cu suma divizorilor lui b (exclusiv b), iar b este egal cu suma divizorilor lui a (exclusiv a). De exemplu, a=220 şi b=284 sunt prietene. Scrieţi un program care să determine primele trei perechi de numere prietene, cu a<b.
6. Plata sumei - Se citesc de la tastatură două numere naturale S şi x (0<S<10000, 0<x<l00). S reprezintă o sumă pe care trebuie să o plătim, utilizând un număr minim de bancnote. Bancnotele au ca valori numai puteri ale lui x (1, x, x2, x3, ...) şi presupunem că dispunem de un număr suficient de mare de bancnote. Scrieţi un program care afişează pe ecran o modalitate de a plăti suma, utilizând un număr minim de bancnote. De exemplu, pentru S=107 şi x=5, veţi afişa:
4 bancnote cu valoarea 25 1 bancnote cu valoarea 5 2 bancnote cu valoarea 1
44
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE DO - WHILE
8. STRUCTURA CICLICĂ CU TEST FINAL
8.1 Instrucţiunea do - while
Pentru un pseudocod de forma: <instrucţiune 1>
CÂT TIMP (<condiţie>) EXECUTĂ <instrucţiune 1> instrucţiunile C++ sunt:
<instrucţiune 1>; while (<condiţie>) <instrucţiune 1>; Aceste instrucţiuni se pot înlocui cu o singură instrucţiune do-while astfel:
do <instrucţiune 1> while (<condiţie>); Aceasta nu reprezintă decât structura iterativă cu test final, "repetă instrucţiune cât
timp condiţie".
8.2 Exemple do - while
8.2.1 Calculul sumei unor numere citite de la tastatură până la introducerea numărului zero
8.2.1.1 Pseudocodul 1.s=0 2.REPETĂ 2.1. CITEŞTE x 2.2. s=s+x CÂT TIMP (x!=0) 3. SCRIE s
8.2.1.2 Programul #include<iostream.h> void main() { float s,x; s=0; cout<<"Dati numerele de adunat (0-oprire)"; do { cin>>x; s+=x;} while (x!=0); cout<<"suma este: "<<s; }
8.2.2 Calculul unei sume cu o precizie impusă
Să se calculeze suma S = ∑k=1
(-1)k·xk
k! până când |T/S| < ε.
45
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
STRUCTURA CICLICĂ CU TEST FINAL
Obs.: Tk = -Tk-1·x/k, iar Sk = Sk-1 + Tk
8.2.2.1 Pseudocodul 1. CITEŞTE x, eps, 2. T = S = k = 1, 3. REPETĂ 3.1. T = -T·x/k, 3.2. S = S + T, 3.3. k = k + 1 CÂT TIMP |T/S| ≥ ε 4. SCRIE S
8.2.2.2 Programul //Calculul unei sume #include<conio.h> #include<math.h> #include<stdio.h> void main() { int k=1; float x,T,S,eps=1e-05; //clrscr(); printf("\nIntroduceti val x: "); scanf("%f",&x); T=S=1; do { printf("\nk= %d;\tT= %12.4f;\tS= %14.10f;\t|T/S|= %14.10f;",k,T,S,fabs(T/S)); T=-T*x/k; S+=T; k++; } while(fabs(T/S)>=eps); getch(); }
8.2.3 Radical de ordinal 3
Fie x un număr real. Să se calculeze 3 x (radical de ordin 3 din x), folosind relaţia de recurenţă:
r1 = 1 ; ri = (2*ri - 1 + x/(ri-1 * ri-1))/3, dacă i>1 Rezultatul trebuie să fie obţinut cu o precizie mai bună decât 10-4.
8.2.3.1 Soluţie Observăm că pentru a calcula termenul i din acest şir recurent este necesar numai termenul i-1. Prin urmare, vom utiliza două variabile r1 (în care reţinem termenul calculat la pasul precedent) şi r2 (în care reţinem termenul pe care urmează să îl calculăm).
46
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE DO - WHILE
Pentru a obţine precizia cerută în problemă, vom calcula termeni din şir până când diferenţa în valoare absolută dintre doi termeni consecutivi este mai mică decât precizia specificată. Pentru a calcula diferenţa în valoare absolută dintre doi termeni consecutivi, vom utiliza funcţia fabs() din biblioteca de funcţii matematice (această funcţie calculează modulul unui număr de tip double specificat ca parametru).
8.2.3.2 Programul //Radical de ord 3 #include <iostream.h> #include <math.h> #define EPS 0.0001 void main() { double x, r1, r2=1; cout<<"\nx= "; cin>>x; do { r1=r2; r2=(2*r1+x/(r1*r1))/3; } while (fabs(r2-r1)>=EPS); cout<<"Radical de ord 3: "<<r2; }
8.2.4 Funcţii pentru ridicarea lui 2 la o putere întreagă şi pentru calculul radicalului de ordinul doi
Să se alcătuiască un program în care să fie implementate o funcţie pentru ridicarea lui 2 la o putere întreagă şi una pentru calculul radicalului de ordinul 2 pe baza şirului lui Newton.
8.2.4.1 Strategia de rezolvare Funcţia care va calcula puterea întreagă a lui 2 se bazează pe efectul de deplasare a biţilor din reprezentarea binară a unui număr. Astfel, o deplasare la stânga a lui a de b ori (a<<b) presupune o înmulţire a lui a cu 2 de b ori: a<<b este echivalentă cu a⋅2b. La fel, o deplasare la dreapta la nivel de bit, a lui a cu b poziţii (a>>b) presupune o împărţire a lui a cu 2 de b ori (a⋅2-b).
Construcţia funcţiei ce calculează rădăcina pătrată a unui număr x are la bază şirul
lui Newton, dat prin relaţia de recurenţă an+1 = 0.5
an +
xan
, unde primul element a1 = 1,
iar n>2. Funcţia calculează termenii succesivi ai şirului până când diferenţa, în valoare absolută, dintre doi termeni succesivi este mai mică decât eroarea acceptată pentru calcul.
8.2.4.2 Programul /*Calculul ridicarii lui 2 la o putere intreaga -i calculul radacinii patrate fara utilizarea funct sqrt */ #include<iostream.h> #include<conio.h>
47
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
STRUCTURA CICLICĂ CU TEST FINAL
#include<math.h> void main() { int a; float p, q=1, err=1e-6; char Exit; do { clrscr(); cout<<"\nDati un numar A ="; cin>>a; cout<<"\n2^"<<a<<" = "<<(1<<a); //Se calculeaza radacina patrata a lui x. do { p=q; q=(p+a/p)/2; //cout<<"\n"<<p<<'\t'<<q; } while(fabs(q-p)>err); cout<<"\nRadical din "<<a<<"="<<q; cout<<"\nPentru iesire apasati-> e.."; Exit=getch(); } while(Exit!='e'); }
8.3 Prelucrarea numerelor
Programele următoare se bazează pe următoarele instrucţiuni: 1. împărţire întreagă (modulo) a unui număr întreg la 10 prin care se obţine cifra unităţilor numărului. Ex: 1234%10 → 4
2. împărţire propriu-zisă a unui număr întreg la 10 prin care se obţine tot un întreg. Ex: 1234/10 → 123 şi NU 123.4
Secvenţele următoare descriu strict metoda prezentată şi nu întreg programul !
8.3.1 Suma cifrelor unui număr "n"
s=0;nl=n; do { s+=nl%10; //se obtine pe rind fiecare cifra nl/=10; //incepind cu cea a unitatilor } while(nl); cout<<"\nSuma cifrelor nr. "<<n<<" = "<<s;
8.3.2 Ştergerea unei cifre "a" dintr-un număr "n"
nl=0;
48
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
PRELUCRAREA NUMERELOR
do { if (n%10!=a) nl=nl*10+n%10; n/=10; } while(n); do { n=n*10+nl%10; nl/=10; } while(nl); cout<<"\nNoul numar: "<<n;
8.3.3 Oglindirea unui număr "n"
n_o=0;nl=n; do { n_o=n_o*10+nl%10; nl/=10; } while(nl); cout<<"\nOglinditul lui "<<n<<" este "<<n_o;
8.3.4 Trecerea unui număr "n" din baza 10 în baza b∈[2…9]
n_b=0; ord=1; aux=n; do { c=aux%b; n_b+=c*ord; ord*=10; aux/=b; } while(aux); cout<<"\nNumarul "<<n<<" in baza "<<b<<" este "<<n_b;
8.3.5 Trecerea unui număr "n" din baza b∈[2…9] în baza 10
n_10=0;p=l; do { n_10=n_10+n%10*p; n/=10; p*=b; } while(n); cout<<n_10;
8.3.6 Apariţia unei cifre "a" într-un număr "n"
nr=0;nl=n;
49
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
STRUCTURA CICLICĂ CU TEST FINAL
do { if(nl%10==a) nr++; nl/=10; } while(nl); cout<<"\nCifra "<<a<<" apare de "<<nr<<" ori";
8.3.7 Inserarea unei cifre "a" pe o poziţie "k" a unui număr "n"
nl=0;i=0;//poz.se numără de la sfârsit while(i++<k) { nl=nl*10+n%10; n/=10; } nl=nl*10+a; do { n=n*lD+nl%10; nl/=10; } while(nl); cout<<"\nNoul numar este: "<<n;
8.3.8 Cifra maximă "cmax" a unui număr "n"
cmax=0;nl=n; do { if(cmax<n%10) cmax=nl%10; nl/=10; } while (nl) ; cout<<"\ncmax="<<cmax;
8.4 Facilităţi de întrerupere a unei secvenţe
8.4.1 Instrucţiunea break
Utilizată în cadrul instrucţiunilor ciclice, instrucţiunea break "forţează" ieşirea din acestea. Fără a se mai testa valoarea expresiei (condiţia) care determină repetarea corpului instrucţiunii ciclice, se continuă execuţia cu instrucţiunea care urmează instrucţiunii ciclice. Astfel, se întrerupe repetarea corpului instrucţiunii ciclice, indiferent de valoarea condiţiei de test.
Utilizarea în cadrul instrucţiunii switch: în situaţia în care s-a ajuns la o valoare a unei expresii constante egală cu cea a expresiei aritmetice, se execută instrucţiunea corespunzătoare acelei ramuri. Dacă se întâlneşte instrucţiunea break, parcurgerea este întreruptă (nu se mai compară valoarea expresiei aritmetice cu următoarele constante), deci se va trece la execuţia primei instrucţiuni de după switch. Dacă nu este întâlnit
50
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE BREAK, CONTINUE
break, parcurgerea continuă. Instrucţiunea break cauzează deci, ieşirea imediată din switch.
8.4.2 Instrucţiunea continue
Întâlnirea instrucţiunii continue determină ignorarea instrucţiunilor care o urmează în corpul instrucţiunii ciclice şi reluarea execuţiei cu testarea valorii expresiei care determină repetarea sau nu a corpului ciclului.
8.4.3 Modul de utilizare a instrucţiunilor break şi continue
do { instructiune1; instructiune2; if (expresie2) break; else continue; instructiune3; } while (expresie1); …
while (expresie1) { instructiune1; instructiune2; if (expresie2) break; else continue; instructiune3; } …
for (expr1;expr2;expr3) { instructiune1; instructiune2; if (expresie2) break; else continue; instructiune3; } …
8.5 Exemple break, continue
8.5.1 break - ziua din săptămână
Să se scrie un program care citeşte o cifră din intervalul [1,7] şi afişează denumirea zilei din săptămână corespunzătoare cifrei respective (1-luni, 2-marţi, etc.). #include <stdio.h> #include <stdlib.h> void main( ) { int i; scanf("%d", &i); switch(i) { case 1: puts("luni");break; case 2: puts("marti");break; case 3: puts("miercuri"); break; case 4: puts("joi"); break; case 5: puts("vineri"); break; case 6: puts("simbata"); break; case 7: puts("duminica"); break; default: puts("Valoare gresita !");exit(1); }
51
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
STRUCTURA CICLICĂ CU TEST FINAL
}
8.5.2 continue - inversele unor numere
Să se calculeze inversele unor numere reale introduse pe rând de la tastatură #include<iostream.h> void main() { float n; for(int i=0; i<=3; i++) { cout<<"\nn= "; cin>>n; if(n==0) continue; cout<<”1/”<<n<<”= "<<1/n; } }
8.6 Probleme propuse
1. Să se calculeze aria unui triunghi, cunoscându-se mărimea laturilor sale. Numerele care reprezintă mărimile laturilor vor fi introduse de utilizator. Se va testa mai întâi dacă cele 3 numere reprezentând mărimea laturilor pot forma un triunghi (a <= b+c, b <= c+d, c <= a+b).
2. Să se rescrie următoarea secvenţă, folosind o singură instrucţiune if. if (n<0)
if (n>=90) if (x!=0) int b= n/x;
3. Să se găsească toate numerele de două cifre care satisfac relaţia: xy¯¯ = (x+y)2 4. Să se citească un şir de numere reale, până la întâlnirea numărului 800 şi să se
afişeze valoarea minimă introdusă, suma şi produsul elementelor şirului. 5. Scrieţi un program care să verifice inegalitatea 1/(n+1) < ln[(n+1)/n] < 1/n, unde n
este un număr natural pozitiv, introdus de la tastatură. 6. Fie funcţia
ex-3 , x ∈ [0, 1) f(x)= sin(x)+cos(x) , x ∈ [1, 2) 0,9·ln(x+3) , x ∈ [2, 100] Să se calculeze f(x), unde x e citit de la tastatură. 7. Să se scrie un program care calculează şi afişează maximul şi minimul a 3 numere
reale (a, b şi c) citite de la tastatură. 8. Să se citească 2 caractere care reprezintă 2 litere mari. Să se afişeze caracterele citite
în ordine alfabetică. 9. Să se citească 3 caractere care reprezintă 3 litere mici. Să se afişeze caracterele citite
în ordine alfabetică. 10. Să se calculeze valoarea polinomului Cebîşev de ordin n într-un punct x dat,
cunoscând relaţia:
52
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
PROBLEME PROPUSE
T0(x)=1, T1(x)=x şi Tk+1(x) - 2xTk(x) + Tk -1(x) = 0 11. Să se citească câte 2 numere întregi, până la întâlnirea perechii (0, 0). Pentru
fiecare pereche de numere, să se calculeze şi să se afişeze cel mai mare divizor comun.
12. Se citesc câte 3 numere reale, până la întâlnirea numerelor 9, 9, 9. Pentru fiecare triplet de numere citit, să se afişeze maximul.
13. Se citeşte câte un caracter până la întâlnirea caracterului @. Să se afişeze numărul literelor mari, numărul literelor mici şi numărul cifrelor citite; care este cea mai mare (lexicografic) literă mare, literă mică şi cifră introdusă.
14. Se citesc câte 2 numere întregi, până la întâlnirea perechii de numere 9, 9. Pentru fiecare pereche de numere citite, să se afişeze cel mai mare divizor comun al acestora.
15. Să se calculeze suma seriei 1 + x3/3 - x5/5 + x7/7 - … cu o eroare mai mică decât ε (citit de la tastatură). Să se afişeze şi numărul de termeni ai sumei.
16. Să se citească un număr întreg format din 4 cifre ( abcd ¯¯¯¯ ). Să se calculeze şi să se afişeze valoarea expresiei reale: 4*a + b/20 -c + 1/d.
17. Să se scrie un program care afişează literele mari ale alfabetului în ordine crescătoare, iar literele mici - în ordine descrescătoare.
18. Să se scrie un program care generează toate numerele perfecte până la o limită dată, LIM. Un număr perfect este egal cu suma divizorilor lui, inclusiv 1 (exemplu: 6=1+2+3).
19. Să se calculeze, pentru 0<=x<=1, x citit de la tastatură, valoarea sumei următoare, cu o eroare ε < 0.0001:
S=1+(x+1)/ 2! + (x+2)/ 3! + (x+3)/ 3! + ... , 20. Să se genereze toate numerele naturale de 3 cifre pentru care cifra sutelor este
egală cu suma cifrelor zecilor şi unităţilor. 21. Să se citească câte un număr întreg, până la întâlnirea numărului 90. Pentru
fiecare număr, să se afişeze un mesaj care indică dacă numărul este pozitiv sau negativ. Să se afişeze cel mai mic număr din şir.
22. Să se genereze toate numerele naturale de 3 cifre pentru care cifra zecilor este egală cu diferenţa cifrelor sutelor şi unităţilor.
23. Să se calculeze suma: (1 + 2!) / (2 + 3!) - (2+3!) / (3+4!) + (3+4!) / (4+5!) - .....
53
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
TABLOURI UNIDIMENSIONALE
9. TABLOURI UNIDIMENSIONALE
Numim tablou o colecţie (grup, mulţime ordonată) de date, de acelaşi tip, situate într-o zonă de memorie continuă (elementele tabloului se află la adrese succesive şi pot fi referite prin indici.).
Unui tablou i se dă un nume; tipul comun al elementelor este şi tipul tabloului respectiv. De exemplu, o mulţime ordonată de întregi reprezintă un tablou de tip întreg.
În cazul în care elementele care se grupează într-un tablou sunt ele însele tablouri vom avea nevoie de mai mulţi indici pentru a ne referi la ele; în acest caz avem un tablou multidimensional (n-dimensional, n fiind numărul de indici), altfel - tablou unidimensional.
Exemple simple de tablouri unidimensionale sunt vectorii cu componentele de acelaşi tip. O matrice este un tablou bidimensional.
Referirea la elementele unui tablou se face printr-o variabilă cu indici. O variabilă cu indici se compune din numele tabloului urmat de valorile indicilor, fiecare indice fiind reprezentat de o expresie inclusă între paranteze pătrate.
Valoarea inferioară a indicilor este 0, iar cea superioară este (dimensiunea-1). De exemplu, dacă vect este un tablou cu 10 elemente (de dimensiune 10), atunci ne referim la elementele lui cu ajutorul variabilelor cu indici:
vect[0] primul element ............ vect[9] ultimul element Dacă mat este o matrice de 3 linii a două coloane fiecare, atunci elementele vor fi
referite prin: mat[0][0] mat[0][1] prima linie mat[1][0] mat[1][1] a doua linie mat[2][0] mat[2][1] a treia linie
9.1 Declaraţia de tablou
Un tablou, ca orice variabilă simplă, trebuie declarat înainte de a fi utilizat. Declaraţia de tablou în forma cea mai simplă conţine tipul comun elementelor sale, numele tabloului şi limitele superioare pentru fiecare indice incluse între paranteze pătrate:
tip nume_tabl [lim_1][lim_2]...[lim_n] = {lista valori} unde tip este tipul de bază al tabloului, iar lim_i este limita superioară a celui de-al i-
lea indice; înseamnă că indicele al i-lea poate lua valorile: 0, 1,..., lim_n-1 (lim_n - sunt expresii constante).
La întâlnirea unei declaraţii de tablou, compilatorul alocă o zonă de memorie necesară păstrării valorii elementelor sale.
9.2 Vectori
Vectorii sunt tablouri unidimensionale. Declararea (şi eventual iniţializarea) lor se face astfel:
54
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
tip nume_tabl[lim_1] = {lista valori} Ex.:
int v[3]; float vec[2] = {66.1, 39.7} //Tablou unidimensional numit vec[2] cu 2 elemente reale, initializat
9.3 Exemple
9.3.1 Citirea primelor n elemente ale unui vector
for(i=0; i<n; i++) cin>>a[i];
9.3.2 Scrierea primelor n elemente ale unui vector
for(i=0; i<n; i++) cout<<a[i];
9.3.3 Operaţii cu elementele unui vector
Să se alcătuiască un program care să determine valoarea minimă, maximă, suma şi media elementelor unui şir de numere reale.
9.3.3.1 Strategia de rezolvare Va fi citit mai întâi numărul curent de elemente ale şirului, iar apoi vor fi citite succesiv elementele şirului folosind o variabilă intermediară temp.
Pentru determinarea valorii minime şi maxime a şirului se iniţializează atât minimul, cât şi maximul cu prima poziţie din şir, după care, succesiv, vor fi comparate elementele şirului cu minimul curent şi respectiv cu maximul curent. Dacă valoarea comparată a elementului şirului este mai mare decât maximul curent, atunci această valoare devine maximul curent. Similar se petrec lucrurile pentru valoarea minimă.
Pentru calculul sumei elementelor şirului, variabila suma se iniţializează cu zero, după care fiecare element al şirului se adaugă la valoarea curentă a sumei, conform relaţiei: suma= suma + a[i], relaţie ce poate fi scrisă simplificat astfel: suma+=a[i]. Media aritmetică se calculează prin raportarea sumei elementelor la numărul de elemente din şir.
9.3.3.2 Programul /* Operaţii cu elementele unui vector*/ #include<stdio.h> #include<conio.h> void main() { int i,N; float temp,suma,media,min,max,a[100]; clrscr(); printf("Dati nr. de elem ale sirului N="); scanf("%2d",&N); for(i=0;i<N;i++) {
55
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
TABLOURI UNIDIMENSIONALE
printf("A[%2d]=",i); scanf("%f",&temp); a[i]=temp; } min=a[0];max=a[0]; for(i=1;i<N;i++)//de la al doilea element { if(a[i]<min) min=a[i]; if(a[i]>max) max=a[i]; } suma=0; for(i=0;i<N;i++) suma+=a[i]; media=float(suma)/N; printf("Valoarea minima a sirului MIN =%g\n",min); printf("Valoarea maximii a siruJui MAX =%g\n",max); printf("Suma elementelor sirului SUMA =%g\n",suma); printf("Valoarea medie a sirului MED =%g\n",media); N=getche(); }
9.3.4 Produsul scalar a doi vectori
9.3.4.1 Programul #include<iostream.h> void main() { unsigned n,i; float a[100],b[100],p; cout<<“\nDati dimensiunea:“;cin>>n; for (i=0;i<n;i++) { cout<<“a[“<<i<<“]“; cin>>a[i]; } for (i=0;i<n;i++) { cout<<“b[“<<i<<“]“; cin>>b[i]; } p=0; for (i=0;i<n;i++) p+=a[i]*b[i]; cout<<“Produsul=“<<p; }
9.3.5 Sortarea crescătoare a elementelor unui vector
9.3.5.1 Pseudocodul 1. CITEŞTE n 2. PENTRU i=0,n-1 CITEŞTE v[i] 3. m=n, sort=0 4. CÂT TIMP (m>0) ŞI (sort=0) 4.1. sort=1 4.2. PENTRU i=0,m-1 DACĂ (v[i]>v[i+1]) 4.2.1. sort=0
56
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
4.2.2. aux=v[i] 4.2.3. v[i]=v[i+1] 4.2.4. v[i+1]=aux 4.3. m=m-1 5. PENTRU i=0,n-1 SCRIE v[i]
9.3.5.2 Programul //Sortarea elementelor unui vector #include<iostream.h> void main() { int i,n,m,sort=0,v[10],aux; cout<<"\nDati dimens vect n: ";cin>>n; for(i=0;i<n;i++) { cout<<"Elem v["<<i<<"]= "; cin>>v[i]; } m=n; while((m>0)&&(sort==0)) { sort=1; for(i=0;i<m-1;i++) if(v[i]>v[i+1]) { sort=0; aux=v[i]; v[i]=v[i+1]; v[i+1]=aux; } m--; } for(i=0;i<n;i++) cout<<"\nv["<<i<<"]= "<<v[i]; }
9.3.6 Casierul automat
Să se scrie algoritmul pentru "casierul automat" care citeşte de pe mediul de intrare suma (întreagă) datorată de un client şi calculează "restul" pe care acesta îl primeşte în număr minim de bancnote şi monezi de 100000, 50000, 10000, 5000, 1000, 500, 100, 50, 25, 10, 5, 3 şi 1 leu considerând că suma plătită este cel mai mic multiplu de 100000 mai mare decât suma datorată.
9.3.6.1 Rezolvare: Vom folosi o metodă care întoarce cel mai mic multiplu de 100000 mai mare decât suma datorată (pentru a afla suma plătită). Plata se va face "iterativ": se vor da cât mai multe bancnote de 100000 posibile, apoi cât mai multe bancnote de 50000 posibile, apoi de 10000, etc. până se epuizează suma datorată.
9.3.6.2 Programul //Casier automat #include <stdio.h>
57
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
TABLOURI UNIDIMENSIONALE
#include <stdlib.h> #include <conio.h> #include <math.h> void main (void) { long suma; int i ; // Valorile monezilor const long valori[13] = {100000, 50000, 10000, 5000, 1000, 500, 100, 50, 25, 10, 5, 3, 1}; // Cantitatile din fiecare moneda int cantitati[13]; // Cel mai mic multiplu de 100000 al sumei de plata long platit; // Restul de plata long rest; clrscr(); printf ("Introduceti suma de plata: "); scanf ("%ld", &suma); // Prelucrarea datelor // Calculeaza cel mai mic multiplu de 100000 al sumei date platit = ((suma / 100000) + 1) * 100000; rest = platit - suma; printf ("Restul de plata de la %ld este: %ld\n", platit, rest); // Resetam cantitatile din fiecare bancnota for (i = 0; i < 13; i++) cantitati [i] = 0; // Calculam cantitatile din fiecare bancnota for (i = 0; (i < 13) && (rest > 0); i++) { cantitati[i] = rest / valori[i] ; rest %= valori[i]; } for(i=0; i<13; i++) if(cantitati[i]) printf ("Avem %d bancnote de valoare %ld\n", cantitati[i], valori[i]); getch(); }
9.3.7 Valoarea unui polinom într-un punct, unde coeficienţii polinomului sunt memoraţi într-un vector
9.3.7.1 Pseudocodul 1 CITEŞTE g,x 2 i=0 3 CÂT TIMP i<n 3.1 CITEŞTE p[i] 3.2 i=i+1
58
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
4 v=p[0], xi=x, i=1 // v - valoarea, xi - xi 5 CÂT TIMP i<n 5.1 xi=xi*x 5.2 v=v+xi*p[i] 5.3 i=i+1 6 SCRIE v
9.3.8 Produsul a două polinoame
9.3.8.1 Pseudocodul 1 CITEŞTE g1,g2 2 i=0 3 CÂT TIMP i<g1 3.1 CITEŞTE p1[i] 3.2 i=i+1 4 i=0 5 CÂT TIMP i<g2 5.1 CITEŞTE p2[i] 5.2 i=i+1 6 i=0 7 CÂT TIMP i<(g1+g2) 7.1 q[i]=0 7.2 i=i+1 8 i=0 9 CÂT TIMP i<g1 9.1 j=0 9.2 CÂT TIMP j<g2 9.2.1 q[i+j]= q[i+j]+p1[i]*p2[j] 9.2.2 j=j+1 9.3 i=i+1 10 i=0 11 CÂT TIMP i<g1+g2 10.1 SCRIE q[i] 10.2 i=i+1
9.3.9 Numărul din an al unei zile
Dându-se trei numere întregi reprezentând data unei zile (an, lună, zi), să se stabilească a câta zi din an este aceasta.
9.3.9.1 Rezolvare Definim doi vectori ce conţin numărul de zile din fiecare lună şi numele fiecărei luni (de fapt, vom defini trei vectori, deoarece numărul de zile din luna februarie este diferit în anii normali şi cei bisecţi). Nu rămâne decât să facem o simplă adunare.
9.3.9.2 Programul #include <stdio.h>
59
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
TABLOURI UNIDIMENSIONALE
#include <stdlib.h> #include <conio.h> #include <math.h> void main (void) { // Numarul de zile din fiecare luna (an normal si bisect) const int zile[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; const int zile_b[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // Numele fiecarei luni
const char nz[12][15] = {"Ianuarie", "Februarie", "Martie", "Aprilie", "Mai", "Iunie", "Iulie", "August", "Septembrie", "Octombrie", "Noiembrie", "Decembrie"}; int an, luna, zi; int nr_zilei = 0; int index; // Indexul lunii curente // Citim datele de intrare
printf("Introduceti anul:"); scanf("%d",&an); printf("Introduceti luna:"); scanf("%d",&luna); printf("Introduceti ziua:"); scanf("%d",&zi); // Testam daca anul este bisect
if((an%4==0) && ((an%100!=0)||(an%400==0))) { // Adaugam lunile anterioare for(index=0;index<luna-1;index++) nr_zilei += zile_b[index]; // Adaugam numarul zilei din luna curenta
nr_zilei += zi; } else { // Adaugam lunile anterioare for(index=0; index<luna-1;index++) nr_zilei += zile[index]; // Adaugam numarul zilei din luna curenta
nr_zilei += zi; } // Afisare rezultate printf("Ati introdus ziua de %d %s, a %d-a zi din %d\n", zi, nz[luna-1], nr_zilei, an); getch();}
60
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
10. ŞIRURI DE CARACTERE
Şirurile sunt tablouri unidimensionale de caractere, care au ca ultim element un terminator de şir, caracterul NULL (zero ASCII), ’\0’.
10.1.1 Prefixele unui cuvânt Fiind dat un cuvânt, să se afişeze toate prefixele acestuia.
Se va determina mai întâi lungimea cuvântului folosind funcţia strlen. Întrucât nu se cere o anumită ordine a prefixelor, le vom genera de la cel mai lung (întregul cuvânt) la cel mai scurt (prima literă). Pentru a reduce dimensiunea, vom înlocui la fiecare pas ultima literă cu terminatorul de şir.
10.1.1.1 Programul #include<stdio.h> #include<string.h> void main() { int n; char cuv[128]; printf("\nIntroduceti cuvantul: ");scanf ("%s",cuv); n=strlen(cuv); while(n--) {printf ("\n%s",cuv); cuv[n]=0; } }
10.1.2 Palindrom
Să se verifice dacă un număr este palindrom. Un număr este considerat palindrom dacă citit de la stânga la dreapta sau invers, are
aceeaşi valoare. Exemple: 1221, 121, 50905. Numărul se va converti într-un şir de caractere cu ajutorul funcţiei ltoa din biblioteca standard, apoi şirul se caractere se va compara cu inversul său. Pentru obţinerea inversului unui şir se va folosi funcţia strrev din biblioteca string.h.
10.1.2.1 Programul #include <string.h> #include <stdio.h> #include <stdlib.h> void main() { long n; char sir1[100], sir2[100]; printf("Introduceti numarul: "); scanf("%ld",&n); ltoa(n,sir1,10); //transforma numarul in sir
61
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
ŞIRURI DE CARACTERE
strcpy(sir2,sir1); strrev(sir2); //inverseaza ordinea caracterelor din sir if(strcmp(sir1,sir2)==0) puts("\nNumarul este palindrom!"); else puts("\nNumarul nu este palindrom!"); }
10.1.3 Rime cuvinte
Fiind date n şiruri de caractere care reprezintă n cuvinte, să se determine toate perechile de rime formate.
Pentru aceasta se vor compara cu ajutorul funcţiei strcmp pe rând ultimele două litere ale fiecărui cuvânt cu ultimele două litere ale celorlalte cuvinte. Dacă acestea coincid, atunci se va tipări perechea de şiruri găsită.
10.1.3.1 Programul #include<string.h> #include<stdio.h> void main() { char a[20][20]; int i,n,j; printf("Numarul de cuvinte: ");scanf("%d",&n); puts("Cuvintele: "); for(i=0;i<n;i++) scanf("%s", &a[i]); puts("Se formeaza rimele:"); for(i=0;i<n-1;i++) for (j=i+1;j<n;j++) if(strcmp(&a[i][strlen(a[i])-2], &a[j][strlen(a[j])-2]) == 0) printf("%s------------%s\n",a[i],a[j]); }
10.1.4 Cel mai lung cuvânt citit Să se scrie un program care citeşte o succesiune de cuvinte şi îl afişează pe cel mai lung dintre ele.
Prin cuvânt înţelegem o succesiune de caractere diferite de spaţii. Vom presupune că un cuvânt nu are mai mult de 100 de caractere. Cuvintele sunt separate prin spaţii. La sfârşit se tastează sfârşitul de fişier (Ctrl+Z) pentru a termina succesiunea de cuvinte.
10.1.4.1 Programul #include <stdio.h> #include <string.h> #define MAX 100 void main () /* citeste o succesiune de cuvinte si-l afiseaza pe cel mai lung dintre ele */ { int max=0,i; char cuvant[MAX+1]; char cuvant_max[MAX+1];
62
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
printf("\nIntroduceti cuvintele urmate de Ctrl-Z: \n"); while(scanf("%100s",cuvant) != EOF) if(max < (i=strlen(cuvant))) { max = i; strcpy(cuvant_max,cuvant);} if(max) printf("Cel mai lung cuvant: %s", cuvant_max); }
Obs.: 1. Cuvântul citit se păstrează în tabloul cuvant de MAX+1 elemente. La citire se
utilizează specificatorul de format: %100s care permite să se citească cel mult 100 de caractere diferite de cele albe. Funcţia scanf păstrează caracterul NULL după ultimul caracter citit. Deci, un cuvânt de 100 de caractere ocupă 101 octeţi.
2. După citirea unui cuvânt, se apelează funcţia strlen pentru a determina numărul caracterelor citite prin scanf şi păstrate în tabloul cuvant. În acest caz s-a utilizat expresia: i = strlen(cuvant)
Apoi se compară lungimea cuvântului citit cu max. Variabila max are ca valoare lungimea maximă a cuvintelor citite înaintea celui
curent. Iniţial max = 0, deoarece nu există nici un cuvânt citit. Dacă max este mai mic decât lungimea cuvântului citit curent, atunci lui max i se atribuie această valoare, iar cuvântul citit este transferat în zona de memorie alocată tabloului cuvânt_max. În acest scop se apelează funcţia strcpy:
strcpy(cuvant_max, cuvant);
10.1.5 Citire şi ordonare cuvinte Să se scrie un program care citeşte două cuvinte şi le afişează în ordine crescătoare.
Cuvântul se defineşte ca o succesiune de cel mult 100 de caractere care nu sunt albe. Cuvintele sunt separate prin spaţii (caractere albe).
10.1.5.1 Programul #include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX 100 void main () /* citeste doua cuvinte si le afiseaza in ordine crescatoare */ { char cuv1[MAX+1]; char cuv2[MAX+1] ; if(scanf("%100s",cuv1) != 1) { printf("nu s-a tastat un cuvant\n"); exit(1); } if(scanf("%100s",cuv2) != 1) { printf("nu s-a tastat un cuvant\n"); exit(1); } if(strcmp(cuv1,cuv2) < 0) { /* primul cuvant tastat este mai mic decit cel de-al doilea */ printf("%s\n",cuv1) ; printf("%s\n",cuv2); } else { printf("%s\n",cuv2) ; printf("%s\n",cuv1); }
63
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
ŞIRURI DE CARACTERE
}
10.1.6 Cel mai mare cuvânt Să se scrie un program care citeşte o succesiune de cuvinte şi îl afişează pe cel mai mare. Prin cuvânt înţelegem o succesiune de cel mult 100 de caractere care nu sunt albe. Cuvintele sunt separate prin caractere albe. Succesiunea de cuvinte se termină cu sfârşitul de fişier.
10.1.6.1 Programul #include <stdio.h> #include <string.h> #define MAX 100 void main() /* citeste o succesiune de cuvinte si-l afiseaza pe cel mai mare */ { char cuv_crt[MAX+1]; char cuv_max[MAX+1]; cuv_max[0] = '\0'; /* cuv_max se initializeaza cu cuvintul vid */ while(scanf("%100s",cuv_crt) != EOF) if(strcmp(cuv_crt,cuv_max) > 0) /* cuvintul curent este mai mare decit cel pastrat in cuv_max */ strcpy(cuv_max,cuv_crt); printf("cel mai mare cuvant este\n"); printf("%s\n", cuv_max); }
64
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
11. TABLOURI MULTIDIMENSIONALE
11.1 Exemple
11.1.1 Declararea unui tablou bidimensional
int mat1[2][3]; //Tablou bidimensional numit mat1 cu 2x3 elemente intregi float mat2[10][10]; //Tablou bidimensional numit mat2 cu 10x10 elemente reale
11.1.2 Citirea primelor m linii şi n coloane ale unei matrice
for(i=0; i<m; i++) for(j=0; j<n; j++) cin>>a[i][j];
11.1.3 Scrierea primelor m linii şi n coloane ale unei matrice
for(i=0; i<m; i++,cout’\n’) for(j=0; j<n; j++) cout<<a[i][j];
11.1.4 Rearanjarea liniilor unei matrice
Să se facă rearanjarea liniilor unei matrice astfel încât elementele de pe diagonala principală să fie elementele de maxim ale fiecărei linii. Se consideră că elementele matricei sunt distincte.
Vom determina mai întâi coloanele elementelor de maxim ale fiecărei linii într-un vector c. Apoi vom verifica dacă valorile coloanelor sunt distincte, în caz contrar nu este posibilă rearanjarea liniilor conform cerinţelor problemei.
Exemplu: Dimensiunea matricei: 3. Elementele matricei:
2 1 8
9 2 05 7 6
. O soluţie este:
9 2 0
5 7 62 1 8
.
11.1.4.1 Programul #include<stdio.h> int c[5], mat1[5][5], mat[5][5],i, j, poz, max1, n=3; void main() {// Citire dimensiune printf("Dimensiunea matricei: "); scanf("%d",&n); // Citire matrice
65
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
TABLOURI MULTIDIMENSIONALE
printf("Elementele matricei: "); for(i=1;i<=n;i++) for(j=1;j<=n;j++) scanf("%d",&mat[i][j]); // Aflarea maximelor pe linii for(i=1;i<=n;i++) { // Se determina coloana poz a unui element de maxim al liniei i poz=1; max1=mat[i][1]; for(j=2;j<=n;j++) { if(mat[i][j]>max1) { max1=mat[i][j]; poz=j; } c[i]=poz; } } // Se verifica daca coloanele obtinute sunt unice for(i=1;i<n;i++) for(j=i+1;j<=n;j++) if(c[i]==c[j]) {puts ("Problema nu are solutie"); return; } // Copierea liniilor cu maximul pe diagonala principala in alta matrice for(i=1;i<=n;i++) for(j=1;j<=n;j++) mat1[c[i]][j]=mat[i][j]; puts("O solutie este: "); for(i=1;i<=n;i++) { for(j=1;j<=n;j++) printf ("%5d",mat1[i][j]); puts(" "); } }
11.1.5 Suma a două matrice
11.1.5.1 Programul #include<iostream.h> void main() { unsigned m,n,j,i; float a[10][10],b[10][10],c[10][10]; cout<<“nr de linii:”;cin>>m; cout<<“nr de coloane:”;cin>>n; for (i=0;i<m;i++) for (j=0;j<n;j++) { cout<<“a[“<<i<<“,”<<j<<“]= ”; cin>>a[i][j]; } for (i=0;i<m;i++) for (j=0;j<n;j++) { cout<<“b[“<<i<<“,”<<j<<“]= ”; cin>>b[i][j]; } for (i=0;i<m;i++)
66
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
PROBLEME PROPUSE
for (j=0;j<n;j++) c[i][j]=a[i][j]+b[i][j]; for (i=0;i<m;i++,cout<<’\n’) for (j=0;j<n;j++) cout<<c[i][j]<<’\t’; }
11.1.6 Produsul a două matrice
11.1.6.1 Pseudocodul 1. CITEŞTE m, n, p 2. PENTRU i=1,m PENTRU j=1,n CITEŞTE a[i][j] 3. PENTRU i=1,n PENTRU j=1,p CITEŞTE b[i][j] 4. PENTRU i=1,m PENTRU j=1,p 4.1 c[i][j]=0 4.2 PENTRU k = 1,n c[i][j]= c[i][j] + a[i][k]*b[k][j] 5. PENTRU i=1,m PENTRU j=1,p SCRIE c[i][j]
11.2 Probleme propuse
Să se alcătuiască programe care să rezolve următoarele probleme: 1. Se citesc de la tastatura elementele unei matrice de caractere (nr. linii=nr. coloane),
A(NxN), N<=10. a) Să se afişeze matricea A; b) Să se formeze şi să se afişeze cuvântul format din caracterele de pe diagonala
principală a matricei A; c) Să se calculeze şi să se afişeze numărul de litere mari, litere mici şi cifre din
matrice; d) Să se afişeze cuvântul format din caracterele de pe diagonala secundară; e) Să se afişeze procentul literelor mari, al literelor mici şi al cifrelor de pe cele 2
diagonale; f) Să se afişeze caracterele comune aflate pe liniile p şi q (p, q < N, p şi q citite de
la tastatură); g) Să se afişeze în ordine alfabetică, crescătoare, literele mari aflate pe coloanele
impare. 2. Se citesc de la tastatură elementele unei matrice cu elemente reale, B (NxN), N<=8.
a) Să se afişeze matricea B;
67
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
TABLOURI MULTIDIMENSIONALE
b) Să se calculeze şi să se afişeze produsul elementelor de pe coloanele impare; c) Să se calculeze şi să se afişeze matricea A, unde: A = ( B + BT)2; d) Să se formeze şi să se afişeze vectorul V, ale cărui elemente sunt elementele
pozitive din matricea A; e) Să se calculeze şi să se afişeze sumele şi produsele elementelor matricei A,
aflate în triunghiurile haşurate: f) Să se calculeze procentul elementelor pozitive aflate pe diagonala secundară; g) Să se calculeze şi să se afişeze matricea C, unde: C = 3 * BT + B2; h) Să se calculeze şi să se afişeze matricea D, unde: D = B + B2+ B3 + B4; i) Să se interschimbe coloanele matricei A astfel: prima cu ultima, a doua cu
antepenultima, etc. 3. Se citesc de la tastatură elementele unei matrice de numere întregi C (NxN), N<=10.
a) Să se afişeze matricea C; b) Să se calculeze şi să se afişeze procentul elementelor impare de pe liniile pare; c) Să se calculeze şi să se afişeze matricea B, unde: B = C2; d) Să se calculeze şi să se afişeze matricea E, unde: E = (C + CT)2 + I, unde I este
matricea unitate; e) Să se afle elementul minim din matricea C; f) Să se înlocuiască elementul maxim din matricea C cu valoarea val, introdusă
de la tastatură; g) Să se afişeze elementele matricei C care sunt numere prime; h) Să se calculeze şi să se afişeze sumele şi produsele elementelor matricei A,
aflate în triunghiurile haşurate:
68
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
12. POINTERI ŞI ADRESE
Există doi operatori unari care permit utilizarea variabilelor pointer: & - operatorul adresă (de referenţiere) - pentru aflarea adresei din memorie a unei
variabile; * - operatorul de indirectare (de deferenţiere) - care furnizează valoarea din zona de
memorie spre care pointează pointerul operand. Sintaxa declaraţiei unui pointer de date este:
tip *identificator_pointer; Simbolul * precizează că identificator_pointer este numele unei variabile
pointer de date, iar tip este tipul obiectelor a căror adresă o va conţine. Ex.: int u, v, *p, *q; // *p, *q sunt pointeri de date (către int) double a, b, *p1, *q1; // *p1, *q1 sunt pointeri către date de tip double
Operatorul "*" se numeşte operatorul de referenţiere şi este aplicat unei adrese,
întorcând valoarea memorată la acea adresă. De exemplu, în declaraţia:
int *n; n este adresa unei variabile de tip întreg, iar *n este valoarea memorată la adresa n. Obs.: Orice adresă este memorată sub forma unui număr întreg, pe 2, 4 sau 8 octeţi
(în mod implicit 2). Operatorul invers se notează "&" şi se numeşte operatorul de dereferenţiere
(operatorul adresă). De exemplu, instrucţiunea: &x=y are semnificaţia: adresa lui x ia valoarea y.
12.1 Exemple
12.1.1 Pointeri
//Pointeri - exemple #include<iostream.h> void main() { int x=5, y, *ptr; // ptr - variabila pointer catre un int; x,y-variabile predefinite, simple, de tip int cout<<"\n\nValoarea lui x: "<<x<<"\nAdresa variabilei x este: "<<&x<<'\n'; ptr=&x;// atribuire: variabila ptr contine adresa variabilei x
69
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
POINTERI ŞI ADRESE
cout<<"Variabila pointer ptr are valoarea: "<<ptr<<" si adreseaza obiectul: "<< *ptr<<'\n'; y=*ptr; cout<<"y="<<y<<'\n'; // y=5 x=4; cout<<"x= "<<x<<'\n'; cout<<"*ptr= "<<*ptr<<'\n'; // x si *ptr reprezinta acelasi obiect, un intreg cu valoarea 4 x=70; // echivalenta cu *ptr=70; y=x+10; // echivalenta cu y=*ptr+10 int *q; q=&x; *q=8; // echivalenta cu x=8; //q=&5; // invalida - constantele nu au adresa //*x=9; // invalida - x nu este variabila pointer //x=&y; //invalida: x nu este variabila pointer, deci nu poate fi folosita cu operatorul de indirectare y=*q+3; // echivalenta cu y=x+3; q=0; // seteaza x pe 0 q+=1; // echivalenta cu ( q)++ sau cu x++ int *r; r=q; /* copiaza continutul lui q(adresa lui x) in r, deci r va pointa tot catre x (va conîine tot adresa lui x)*/ double w=3.5, *r1, *r2; r1= &w; r2=r1; cout<<"r1="<<r1<<'\t'; //afiseaza valoarea pointerului r1(adresa lui w) cout<<"&r1="<<&r1<<'\t'; // afiseaza adresa variabilei r1 cout<<"*r1= "<<*r1<<'\n'; double z=*r1; // echivalenta cu z=w cout<<"z="<<z<<'\n'; }
12.1.2 Legătura pointeri - şiruri de caractere
Să se scrie următorul program şi să se urmărească rezultatele execuţiei acestuia. //Pointeri si siruri de caractere #include <iostream.h> #include<conio.h> void main(void) { textmode(3); int a=-5, b=12, *pi=&a; double v=-2.24, *pd=&v; char sir1[]="Sirul 1", sir2[]="Sirul 2", *psir=sir1; cout<<"a="<<a<<"\t&a="<<&a<<"\tb="<<b<<"\t&b="<<&b<<'\n'; cout<<"*pi="<<*pi<<"\tpi="<<pi<<"\t&pi="<<&pi<<'\n'; cout<<"*pd="<<*pd<<"\tpd="<<pd<<"\t &pd="<<&pd<<'\n';
70
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
cout<<"*sir1="<<*sir1<<"\tsir1="<<sir1<<"\t&sir1="<<&sir1<<'\n'; // *sir1=s sir1=Sirul 1 &sir1=0xffd6 cout<<"*sir2="<<*sir2<<"\tsir2="<<sir2<<"\t&sir2="<<&sir2<<'\n'; // *sir2=s sir2=Sirul 2 &sir1=0xffce cout<<"*psir="<<*psir<<"\tpsir="<<psir<<"\t&psir="<<&psir<<'\n'; // *psir=s psir=Sirul 1 &sir1=0xffcc cout<<"sir1+2="<<(sir1+2)<<"\tpsir+2="<<(psir+2)<<'\n'; // sir1+2=rul 1 psir+2=rul 1 cout<<"*(sir1+2)="<< *(sir1+2)<<'\n'; // *(sir1+2)=r valoarea elementului de indice 2 void *pv1, *pv2; pv1=psir; pv2=sir1; cout<<"pv1="<<pv1<<"\t&pv1="<<&pv1<<'\n'; cout<<"pv2="<<pv2<<"\t&pv2="<<&pv2<<'\n'; pi=&b; pd=&v; psir=sir2; cout<<"*pi="<<*pi<<"\tpi="<<pi<<"\t&pi="<<&pi<<'\n'; cout<<"*pd="<<*pd<<"\tpd="<<pd<<"\t&pd="<<&pd<<'\n'; cout<<"*psir="<<*psir<<"\tpsir="<<psir<<"\t&psir="<<&psir<<'\n'; }
În limbajul C, cazul parametrilor tablou constituie o excepţie de la regula transferului parametrilor prin valoare. Numele unui tablou reprezintă, de fapt, adresa tabloului, deci a primului element din tablou.
12.1.3 Pointer la vector - exemplul 1
Să se scrie următorul program (care ilustrează legătura dintre pointeri şi vectori) şi să se urmărească rezultatele execuţiei acestuia. #include <iostream.h> void main(void) {int a[10] = {0,1,2,3,4,5,6,7,8,9}; int *pi1 = a; int *pi2 = &a[0]; int *pi3; cout<<"a="<<a<<"&a="<<&a<<"*a="<<*a<<'\n'; cout<<"a+1="<<(a+1)<< " &a[1]="<< &a[1]<<'\n'; cout<<"a[1]="<<a[1]<< " *(a+1)="<< *(a+1)<<'\n'; cout<<"pi1="<<pi1<<"pi2="<<pi2<<'\n'; int x=*pi1; /* x primeste valoarea locatiei a carei adresa se afla in variabila pointer pi1, deci valoarea lui a[0] */ cout<<"x="<<x<<'\n'; x=*pi1++; // x = *pi1 = a[0] = 0, iar apoi *pi1= a[1] = 1 cout<<"x="<<x<<'\n'; x=(*pi1)++; /* x = 1: intai atribuirea, apoi incrementarea valorii spre care indica pi1.
71
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
POINTERI ŞI ADRESE
In urma incrementarii, valoarea lui a[1] devine 2 */ cout<<"x="<<x<<'\n'; cout<<*pi1<<'\n'; x=*++pi1; //echivalent cu *(++pi1) cout<<"x="<<x<<'\n'; x=++(*pi1); cout<<"x="<<x<<'\n'; pi1=a; pi3=pi1+3; cout<<"pi1="<<pi1<<"*pi1="<<*pi1<<"&pi1="<<&pi1<<'\n'; cout<<"pi3="<<pi3<<"*pi3="<<*pi3<<"&pi3="<<&pi3<<'\n'; cout<<"pi3-pi1="<<(pi3-pi1)<<'\n'; //pi3-pi1=3 }
12.1.4 Pointer la vector - exemplul 2
//Pointer la vector #include <iostream.h> #define DIM 3 void main() { int i; float tablou[DIM], *ptablou; ptablou=tablou; cout<<"Introduceti elementele tabloului\n"; for(i=0;i<DIM;i++) { cout<<"a("<<(i+1)<<")="; cin>>tablou[i]; } cout<<"Elementele tabloului sunt:\n"; for(i=0;i<DIM;i++) cout<<"a("<<(i+1)<<")="<<*(ptablou+i)<<"\n"; }
12.1.5 Pointer la matrice - exemplul 1
#include<iostream.h> #include<conio.h> void main() {int a[3][3]={{5,6,7}, {55,66,77}, {555,666,777}}; clrscr(); cout<<"a="<<a<<" &a="<<&a<<" &a[0]="<<&a[0]<<'\n'; cout<<"Pointeri catre vectorii linii\n"; for (int i=0; i<3; i++){ cout<<" *(a+"<<i<<")="<<*(a+i); cout<<" a["<<i<<"]="<<a[i]<<'\n'; } // afişarea matricei for (int i=0; i<3; i++){ for (int j=0; j<3; j++) cout<<*(*(a+i)+j)<<'\t'; //sau: cout<<*(a[i]+j)<<'\t'; cout<<'\n';
72
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
PROBLEME PROPUSE
} }
12.1.6 Pointer la matrice - exemplul 2
//Pointer la matrice #include <iostream.h> #define DIM1 3 #define DIM2 2 float cere_element(int i,int j) { float elem; cout<<"a("<<(i+1)<<","<<(j+1)<<")="; cin>>elem;cout<<"\n"; return elem; } void afis_tablou(float **ptablou) { int i,j; for(i=0;i<DIM1;i++) for(j=0;j<DIM2;j++) cout <<"a(" <<(i+1) <<"," <<(j+1)<< ")=" << *((*ptablou)+i*DIM2+j)<< "\n"; } void main() { float tablou[DIM1][DIM2]; int i,j; float *ptablou; ptablou=*tablou; cout<<"Introduceti elementele tabloului\n"; for(i=0;i<DIM1;i++) for(j=0;j<DIM2;j++) tablou[i][j]=cere_element(i,j); cout<<"Elementele tabloului sunt:\n"; afis_tablou(&ptablou); }
12.2 Probleme propuse
1. Analizaţi următoarele secvenţe de instrucţiuni. Identificaţi secvenţele incorecte (acolo unde este cazul) şi sursele erorilor: int a,b,*c; a=7; b=90; c=a; double y, z, *x=&z; z=&y; char x, **p, *q; x = 'A'; q = &x; p = &q;
cout<<”x=”<<x<<’\n’; cout<<”**p=”<<**p<<’\n’; cout<<”*q=”<<*q<<’\n’; cout<<”p=”<<p<<” q=”<<q<<”*p=”<<*p<<’\n’;
73
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
POINTERI ŞI ADRESE
char *p, x[3] = {'a', 'b', 'c'}; int i, *q, y[3] = {10, 20, 30}; p = &x[0]; for (i = 0; i < 3; i++) { cout<<”*p=”<<*p<<” p=”<<p<<’\n’; p++; } q = &y[0]; for (i = 0; i < 3; i++) { cout<<”*q=”<<*q<<”q=”<<q<<’\n’; q++; }
const char *sirul=”să programăm”; *(sirul)++; double a, *s; s=&(a+89); cout<<”s=”s<<’\n’; double a1, *a2, *a3; a2=&a1; a2+=7.8; a3=a2; a3++; int m[10], *p;p=m;
for (int i=0; i<10; i++) cout<<*m++;
void *p1; int *p2; int x; p2=&x; p2=p1; char c=’A’; char *cc=&c; cout<<(*cc)++<<’\n’;
74
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
TRANSFERUL PARAMETRILOR UNEI FUNCŢII
13. FUNCŢII - GENERALITĂŢI, OPERAŢII CU TABLOURI
13.1 Structura unei funcţii
O funcţie este formată din antet şi corp: antet_functie { corp_functie }
Sau: tip_val_return nume_func (lista_declaratiilor_param_ formali) { declaratii_variabile_locale instructiuni [return valoare] //optional }
Antetul funcţiei conţine deci următoarele 3 elemente obligatorii: • tipul valorii returnate de funcţie • numele funcţiei • lista declaraţiilor parametrilor formali
O funcţie poate fi apelată printr-o construcţie urmată de punct şi virgulă, numită
instrucţiune de apel, de forma: nume_functie (lista_parametrilor_efectivi);
Parametrii efectivi trebuie să corespundă cu cei formali ca ordine şi tip.
13.2 Transferul parametrilor unei funcţii
Funcţiile comunică între ele prin argumente (parametri). Există următoarele moduri de transfer (transmitere) a parametrilor către funcţiile apelate:
13.2.1 Transferul prin valoare
Exemplul devenit clasic este cel al funcţiei de permutare (interschimbare) a două variabile. Fie funcţia schimb_v definită astfel: void schimb_v (float x, float y) { float t=x; x=y; y=t; } void main() { float a=4.7, b=9.7; . . . . . . . . . . . schimb_v(a, b); // apel functie . . . . . . . . . . . }
75
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FUNCŢII - GENERALITĂŢI, OPERAŢII CU TABLOURI
Parametri funcţiei schimb_v sunt transmişi prin valoare: parametrilor formali x, y li se atribuie (la apel) valorile parametrilor efectivi a, b. Funcţia schimb_v permută valorile parametrilor formali x şi y, dar permutarea nu are efect asupra parametrilor efectivi a şi b.
13.2.2 Transferul prin pointeri
Pentru ca funcţia de interschimbare să poată permuta valorile parametrilor efectivi, în limbajul C/C++ parametrii formali trebuie să fie pointeri către valorile care trebuie interschimbate: void schimb_p(float *x, float *y) { float t=*x; *x=*y; *y=t; } void main() { float a=4.7, b=9.7; . . . . . . . . . . . schimb_p(&a, &b); // apel functie /* SAU: float *pa, *pb; pa=&a; pb=&b; schimb_p(pa, pb);*/ . . . . . . . . . . . }
Se atribuie pointerilor x şi y valorile pointerilor pa, pb, deci adresele variabilelor a şi b. Funcţia schimb_p permută valorile spre care pointează pointerii x şi y, deci valorile lui a şi b.
13.2.3 Transferul prin referinţă
În limbajul C++, aceeaşi funcţie de permutare se poate defini cu parametri formali de tip referinţă. void schimb_r(float &x, float &y) { float t=x; x=y; y=t; } void main() { float a=4.7, b=9.7; . . . . . . . . . . . . schimb_r(a, b); // apel funcţie . . . . . . . . . . . }
În acest caz, x şi y sunt sinonime cu a şi b (nume diferite pentru aceleaşi grupuri de locaţii de memorie). Interschimbarea valorilor variabilelor x şi y înseamnă interschimbarea valorilor variabilelor a şi b.
13.3 Funcţii definite de utilizator
În afară de funcţiile predefinite existente în header-ele <stdlib.h>, <math.h>, <iostream.h>, <string.h> - există posibilitatea de a se construi noi funcţii de către programator (utilizator).
76
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
Sintaxa definiţiei unei funcţii este: <tip valoare returnată> <nume funcţie> (<tip parametru> [*] <nume parametru> [,...]) { <lista variabile auxiliare>; <instructiuni>; [return <variabila>;] }
unde: • <tip valoare returnată> - poate fi oricare din tipurile de bază sau void (tipul vid) • <tip parametru> - poate avea orice tip cu excepţia lui void • [*] - este un parametru opţional, utilizat numai pentru parametrii a căror valoare
se modifică (spunem că funcţia are efecte laterale) • <instrucţiuni> - au aceeaşi sintaxă cu cele dintr-un program, servesc la calculele
intermediare din corpul funcţiei • <lista variabile auxiliare> - sunt variabile locale funcţiei, nu sunt văzute în afara
funcţiei Instrucţiunea return este folosită pentru întoarcerea de către funcţie a rezultatului
care va fi transmis programului principal sau altei funcţii care o apelează; ea este obligatorie în toate funcţiile cu excepţia celor de tip void.
Sintaxa apelului unei funcţii este:
<nume funcţie> ( <nume parametru> [,...]) deci numele funcţiei urmat de lista parametrilor între paranteze; aceştia poartă
numele de parametrii actuali, iar parametrii din definiţia funcţiei se numesc parametrii formali. Este necesar ca parametrii actuali să corespundă ca număr şi tip cu parametrii formali.
Obs.: De obicei, funcţiile se declară şi se definesc la începutul programului, dar se mai pot declara şi astfel: se declară la început prototipul şi apoi la sfârşit definirea, adică descrierea detaliată (inclusiv prototipul).
13.4 Exemple
13.4.1 Funcţie pentru calculul maximului a două numere reale
float max(float x, float y) { float a; if (x>y) a=x; else a=y; return a; }
13.4.2 Schimbarea valorilor a două variabile - transferul parametrilor unei funcţii
//Transferul parametrilor unei functii #include<iostream.h>
77
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FUNCŢII - GENERALITĂŢI, OPERAŢII CU TABLOURI
//Transfer prin valoare void schimb_v (float x, float y) { float t=x; x=y; y=t; } //Transfer prin pointeri void schimb_p(float *x, float *y) { float t=*x; *x=*y; *y=t; } //Tansfer prin referinta void schimb_r(float &x, float &y) { float t=x; x=y; y=t; } void main() { float a=4.5, b=9.3; cout<<"\nInitial\ta= "<<a<<"\tb= "<<b; schimb_v(a, b); // apel functie cout<<"\nValoare\ta= "<<a<<"\tb= "<<b; schimb_p(&a, &b); // apel functie cout<<"\nPointer\ta= "<<a<<"\tb= "<<b; schimb_r(a, b); // apel functie cout<<"\nRef\ta= "<<a<<"\tb= "<<b; }
13.4.3 Cel mai mare pătrat perfect mai mic sau egal cu un număr dat
De la tastatură se citesc n valori întregi pozitive. Pentru fiecare element să se indice cel mai mare pătrat perfect mai mic sau egal cu el.
13.4.3.1 Rezolvare Definim o funcţie int patrat(int), care introduce pătratul perfect cel mai mare, mai mic sau egal cu numărul dat.
13.4.3.2 Programul //Cel mai mare patrat perfect mai mic sau egal cu un nr #include <stdio.h> #include <stdlib.h> #include <conio.h> #include <math.h> // Calculeaza cel mai mare patrat perfect mai mic sau egal cu a int patrat (int a) { int i=0; while(i*i<=a) i += 1; return (i*i>a)?(i-1)*(i-1):i*i; } void main (void) { int n, a;
78
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
clrscr () ; printf("Introduceti nr de valori: "); scanf("%d",&n); // Prelucrare date si afisare rezultate for(int i=0;i<n;i++) { printf("Introduceti elementul %d: ",i+1); scanf("%d", &a); printf("Patratul perfect mai mic sau egal cu %d este: %d\n", a, patrat(a)); } getch(); }
13.4.4 Perechi
Se citeşte un întreg n şi n perechi (a, b) de întregi. Să se afişeze, acele perechi al căror cmmdc este un număr prim.
13.4.4.1 Programul #include<stdio.h> #include<conio.h> //cmmdc cu algoritmul lui Euclid int cmmdc(int a, int b) { int r; do { r = a % b; a=b; b=r;} while (r); return a; } // stabileste daca n este prim int prim(int n) { int div; for (div=2; div*div<=n; (div==2) ? div=3 : div+=2) if(n%div==0) return 0; return 1; } void main (void) { int n; int a, b; // Citire date de intrare printf ("Introduceti numarul de perechi: "); scanf ("%d", &n); for(int i=0; i<n; i++) { printf (" Introduceti perechea %d: ", i); scanf("%d%d", &a, &b);
79
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FUNCŢII - GENERALITĂŢI, OPERAŢII CU TABLOURI
if (prim(cmmdc(a, b))) printf("cmmdc(%d,%d)=%d\n", a, b, cmmdc(a,b)); } getch(); }
13.4.5 Elementul de valoare minimă al unui tablou
13.4.5.1 Programul //Minimul elementelor unui tablou #include <iostream.h> #define DIM 5 float min2v(float a,float b) {return (a<b?a:b);} int sorttab(float tablou[DIM]) { int i,indmin; float valmin; valmin=tablou[0]; indmin=0; for(i=1;i<DIM;i++) { valmin=min2v(valmin,tablou[i]); if(valmin==tablou[i]) indmin=i; } return indmin; } void tiptab(float tablou[DIM]) { int i; for(i=0;i<DIM;i++) cout<<"tabl("<<i<<")="<<tablou[i]<<"\n"; } void main() { float tabl [DIM]; int imin,i; cout<<"introduceti elementele tabloului\n"; for(i=0;i<DIM;i++) { cout<<"tabl ("<<i<<")="; cin>>tabl[i]; cout<<"\n"; } cout<<"Tabloul initial\n"; tiptab(tabl); imin=sorttab(tabl); cout<<"Elementul minim din tablou este: tabl("<<imin<<")="<<tabl[imin]<<"\n"; }
80
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
13.4.6 Operaţii cu matrice cu ajutorul unor funcţii
13.4.6.1 Programul //Operatii cu matrice realizate cu functii #include<iostream.h> #include<stdio.h> #define DIM 10 void citire(int nl,int nc,int mat[DIM][DIM]) { int i,j; for(i=0;i<nl;++i) { cout<<"\n ***** Linia "<<i<<"\n"; for(j=0;j<nc;++j) { cout<<"Introduceti elementul ["<<i<<","<<j<<"]: "; cin>>mat[i][j]; } } } int suma(int mat1[DIM][DIM], int mat2[DIM][DIM],int nl,int nc,int summat[DIM][DIM]) { int i,j; for(i=0;i<nl;++i) { for(j=0;j<nc;++j) summat[i][j]=mat1[i][j]+mat2[i][j]; } return 0; } void prod(int mat1[DIM][DIM], int mat2[DIM][DIM], int m,int n,int p,int prodmat[DIM][DIM]) { int i,j,k; for(i=0;i<m;++i) for(j=0;j<n;++j) { prodmat[i][j]=0; for(k=0;k<p;++k) prodmat[i][j]=prodmat[i][j]+mat1[i][k]*mat2[k][j]; } } void afisare(int nl,int nc,int mat[DIM][DIM]) { int i,j; for(i=0;i<nl;++i) { for(j=0;j<nc;++j)
81
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FUNCŢII - GENERALITĂŢI, OPERAŢII CU TABLOURI
cout<<mat[i][j]<<" "; cout<<"\n"; } } void main() { int m1[DIM][DIM], m2[DIM][DIM], sum[DIM][DIM]; int a,b,c,d,i,j; char selector; cout<<"\nIntr. nr-le de linii si coloane pentru prima matrice, m: ";cin>>a; cout<<" si n: ";cin>>b; cout<<"\nIntr. nr-le de linii si coloane pentru a doua matrice, m: ";cin>>c; cout<<" si n: ";cin>>d; cout<<"\n\nPrima matrice:\n"; citire(a,b,m1); cout<<"\n\nA doua matrice:\n"; citire(c,d,m2); printf("Tastati:'s' pentru suma\n 'd' pentru diferenta\n 'p' pentru produs\nAici: "); cin>>selector; switch (selector) { case's': { if ((a==c)&&(b==d)) { suma(m1,m2,a,b,sum); afisare(a,b,m1); cout<<"\n +\n\n"; afisare(c,d,m2); cout<<"\n=\n"; afisare(c,d,sum); } else cout<<"Nu se poate efectua suma deoarece numerele de linii si coloane au nereguli"; break; } case'd': { cout<<"FACETI VOI DIFERENTA"; break; } case'p': { if(b==c) { prod(m1,m2,a,d,b,sum); afisare(a,b,m1); cout<<"\n*\n\n";
82
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
afisare(c,d,m2); cout<<"\n=\n\n"; afisare(a,d,sum); } break; } default: cout<<"Nu s-a introdus una din literele cerute !"; } }
13.4.7 Calculul puterii şi transpusei unei matrice pătrate
Să se alcătuiască un program pentru ridicarea la putere a unei matrice pătratice şi pentru calculul transpusei acesteia.
13.4.7.1 Strategia de rezolvare În cazul matricelor pătratice A(n,n) numărul de linii şi de coloane este egal cu ordinul matricei. Transpusa se obţine prin interschimbarea elementelor din partea dreaptă a diagonalei principale cu cele având indicii liniei şi coloanei inversaţi.
13.4.7.2 Programul /* Ridicarea la o putere a unei matrice patratice. Calculul transpusei unei matrice patratice.*/ #define NMAX 20 //Nr maxim de linii/coloane al matricelor #include <stdio.h> #include <conio.h> /*Functia citeste valorile elementelor unei matrice */ void citire (float ta[NMAX][NMAX], int ordin, char numev) { float temp; printf("\nElementele matricei %c\n",numev); for (int i = 1,j; i<ordin+1; i++) for(j=1; j<ordin+1; j++) { printf("%c[%d,%d]= ",numev,i,j); scanf ("%f",&temp); ta[i][j]=temp; } } /*Functia scrie valorile elementelor unei matrice */ void scriere(float ta[NMAX][NMAX], int ordin, char numev) { int trec; printf("\nAfisarea valorii elementelor pentru matricea %c:\n",numev); trec=1; for(int i=1,j; i<ordin+1; i++) for(j=1; j<ordin+1; j++) { printf("%c[%d,%d]= %f",numev, i,j,ta[i][j]); if(trec++==ordin) {printf("\n"); trec=1;}
83
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FUNCŢII - GENERALITĂŢI, OPERAŢII CU TABLOURI
else printf("\t"); } printf("\nApasa orice tasta!");getch(); } /*Functia efect ridicarea la patrat, a unei matrice */ void patrat(float ta[NMAX][NMAX],float tb[NMAX][NMAX], int ordin) { for (int i=1,j,k; i<ordin+1; i++) for(k=1; k<ordin+1; k++) { tb[i][k]=0.0; for(j=1; j<ordin+1; j++) tb[i][k]+=ta[i][j]*ta[j][k]; } } /*Functia calculeaza transpusa unei matrice*/ void transpusa(float ta[NMAX][NMAX], int ordin) { float temp; for(int i=1,j; i<ordin; i++) for(j=i+1; j<ordin+1; j++) { temp=ta[i][j]; //interschimba valorile a doua variabile de tip float ta[i][j]=ta[j][i]; ta[j][i]=temp; } } void main(void) { //Functia principala float a[NMAX][NMAX], b[NMAX][NMAX]; int n; clrscr(); printf("Ordinul matricei A = "); scanf("%d",&n); citire(a,n,'A'); patrat(a,b,n); puts("\nMatricea B=A*A: "); scriere(b,n,'B'); transpusa(b,n); puts("\nMatricea transpusa:"); scriere(b,n,'B'); }
Pentru ca elementele matricei să nu se piardă în timpul operaţiei de transpunere, se utilizează o variabilă intermediară care stochează valoarea uneia dintre variabilele ce trebuie interschimbate:
temp=ta[i][j]; ta[i][j]=ta[j][i]; ta[j][i]=temp;
84
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
Dacă am fi aplicat direct relaţia: ta[i][j]=ta[j][i];
valoarea variabilei ta[i][j] s-ar fi pierdut, fiind înlocuită cu cea a variabilei ta[j][i] şi astfel (valoarea variabilei ta[j][i] nefiind modificată) matricea ar fi fost alterată, devenind simetrică faţă de diagonala principală.
În apelul funcţiei pătrat o scriere de tipul: patrat(a,a,n); nu ar fi dus la calculul pătratului matricei a, ci la alterarea valorilor elementelor acesteia. În cazul şirurilor, aceeaşi variabilă şir nu poate constitui pentru o funcţie şi argument "valoare" şi argument "variabilă".
13.4.8 Funcţie cu pointer la tablou unidimensional
//Pointer la vector #include <iostream.h> #define DIM 3 float cere_element(int i) {float elem; cout<<"a("<<(i+1)<<")="; cin>>elem; cout<<"\n"; return elem; } void afis_tablou(float *ptablou) {int i; for(i=0;i<DIM;i++) cout<<"a("<<(i+1)<<")="<<*(ptablou+i)<<"\n"; } void main() { float tablou[DIM]; int i; float *ptablou; ptablou=tablou; cout<<"Introduceti elementele tabloului\n"; for(i=0;i<DIM;i++) tablou[i]=cere_element(i); cout<<"Elementele tabloului sunt:\n"; afis_tablou(ptablou); }
13.4.9 Funcţie cu pointer la tablou bidimensional
//Pointer la matrice #include <iostream.h> #define DIM1 3 #define DIM2 2 float cere_element(int i,int j) { float elem; cout<<"a("<<(i+1)<<","<<(j+1)<<")=";
85
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FUNCŢII - GENERALITĂŢI, OPERAŢII CU TABLOURI
cin>>elem;cout<<"\n"; return elem; } void afis_tablou(float **ptablou) { int i,j; for(i=0;i<DIM1;i++) for(j=0;j<DIM2;j++) cout <<"a("<<(i+1)<<","<<(j+1)<<")="<<*((*ptablou)+i*DIM2+j)<<"\n"; } void main() { float tablou[DIM1] [DIM2]; int i,j; float *ptablou; ptablou=*tablou; cout<<"Introduceti elementele tabloului\n"; for(i=0;i<DIM1;i++) for(j=0;j<DIM2;j++) tablou[i][j]=cere_element(i,j); cout<<"Elementele tabloului sunt:\n"; afis_tablou(&ptablou); }
13.5 Probleme propuse
1. Să se realizeze un program care implementează operaţii cu vectori utilizând funcţii (citire, scriere, produs scalar, sortare).
2. Să se realizeze un program care calculează valoarea unui polinom utilizând o funcţie pentru calculul puterii.
86
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
14. FUNCŢII - ANALIZĂ MATEMATICĂ, BIBLIOTECI DE FUNCŢII
14.1 Exemple
14.1.1 Calculul derivatei unei funcţii
Derivata unei funcţii într-un punct reprezintă panta tangentei la graficul funcţiei în punctul respectiv, adică:
f'(x) = limh→0 h
f(x) - f(x-h)
14.1.1.1 Programul //Calculul derivatei unei functii #include <stdio.h> #include <math.h> double fd(double); double deriv(double,double,double(*)(double)); void main() { double d,x,h; printf("\nx= "); scanf("%lf",&x); for(h=0.1;h>=1e-06;h/=10) { d=deriv(x,h,fd); printf("\nx=%f; h= %f; d= %lf",x,h,d); } printf("\nx=%f; d= %lf",x,-sin(x)); } double deriv(double x,double h,double (*f)(double)) { double it; it=((*f)(x)-(*f)(x-h))/h; return it; } double fd(double x) { return cos(x); }
14.1.2 Calculul integralei definite a unei funcţii prin metoda trapezelor
Relaţia de calcul:
87
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FUNCŢII - ANALIZĂ MATEMATICĂ, BIBLIOTECI DE FUNCŢII
I = ⌡⌠a
bf(x) dx = h 2 +f(a+h) +f(a+2h)+…f(a+(n-1)h)
f(a)+f(b) ,
unde: h = b-an , n fiind numărul de diviziuni
f(x)
a x1 x2 xn-1 b
x h
14.1.2.1 Programul //Calculul integralei prin metoda trapezelor #include <stdio.h> #include <math.h> double fc(double); double ing(double,double,double(*)(double)); void main() { double i,a,b; printf("\nLimitele a,b: "); scanf("%lf %lf",&a,&b); i=ing(a,b,fc); printf("\na=%f; b=%f; i= %lf",a,b,i); } double ing(double x,double y,double (*f)(double)) { int n=120,k; double it,h,S; h=(y-x)/n; for(k=1,S=0.0;k<n;k++) S=S+(*f)(x+k*h); it=(h/2)*((*f)(x)+(*f)(y))+h*S; return it; } double fc(double x) { return x*x; }
88
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
14.1.3 Rezolvarea ecuaţiilor neliniare prin metoda bisecţiei
Să se rezolve ecuaţia neliniară cos(x)-x = 0 prin metoda bisecţiei.
14.1.3.1 Algoritmul DATE DE INTRARE: • a, b {capetele intervalului} • ε {eroarea maximă admisibilă}
DATE DE IEŞIRE: • x {rădăcina} • zero {variabilă logică de control}
1. CITEŞTE a, b, ε 2. zero = adevărat {există o rădăcină} 3. x = a; fa = f(x);
DACĂ |fa| ≤ ε ATUNCI EXIT {rădăcina este x=a} 4. x = b; fb = f(x);
DACĂ |fb| ≤ ε ATUNCI EXIT {rădăcina este x=b} 5.
DACĂ fa ⋅ fb < 0 ATUNCI {există rădăcină în intervalul (a,b)} REPETĂ
x = (a+b)/2; fx = f(x) {f((a+b)/2)} DACĂ fa ⋅fx < 0 ATUNCI b = x ALTFEL a = x dx = b-a; DACĂ x ≠0 ATUNCI dx = dx/x {eroarea}
PÎNĂ CÂND |dx|≤ ε sau |fx|≤ ε {testează convergenţa} ALTFEL zero = fals {nu există rădăcină}
6. STOP
14.1.3.2 Programul /*Rezolvarea ecuatiilor neliniare prin metoda injumatatirii intervalului xs,xd - limitele intervalului in care se presupune ca se afla solutia; eps - toleranta admisa; it_lim - limita numarului de iteratii;*/ #include<conio.h> #include<math.h> #include<stdio.h> float xs=0,xd=5,sol,eps=1e-05; float f(float x) { return cos(x)-x;} float bisec(float xs, float xd, float eps, float (*f)(float)) { float x,ys,y,yd; int it=0,it_lim=100,gata=0; ys=f(xs); yd=f(xd); if(ys*yd>0) { printf("f(xs)*f(xd) > 0"); x=0;}
89
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FUNCŢII - ANALIZĂ MATEMATICĂ, BIBLIOTECI DE FUNCŢII
else { while(!gata) { gata=0; it++; x=(xs+xd)/2; y=f(x); printf("%2d %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f\n",it,xs,x,xd,ys,yd,fabs((yd-ys)/2)); if(it>it_lim) {printf("\nS-a depasit numarul maxim de iteratii !"); gata=1; } else if(fabs(x-xs)<eps) gata=1; else {if(ys*y<=0) {xd=x; yd=y;} else {xs=x; ys=y;} } } } return x; } void main() { clrscr(); printf(" it xs x xd f(xs) f(xd) |f(xd)-f(xs)|/2\n"); printf("--------------------------------------------------------------\n"); sol=bisec(xs, xd, eps, f); printf("\nRadacina aproximata= %g",sol); }
14.2 Funcţii predefinite
14.2.1 Biblioteca matematică (math.h)
Este bibliotecă care conţine toate funcţiile matematice. Unele dintre cele mai utilizate sunt prezentate în următorul tabel:
Tabelul 14.1 Funcţii matematice Nume Sintaxa Ce
returneaza Exemplu
abs double abs (double x)
valoarea absolută a unui număr real
#include <iostream.h> #include <math.h> void main(void) { int number = -1234; cout<<"valoarea absoluta a nr."<<number<<‘=‘<<abs(number));}
sqrt double sqrt (double x) radical
90
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FUNCŢII PREDEFINITE
Nume Sintaxa Ce returneaza Exemplu
acos double acos (double x) arccosinus
asin double asin (double x) arcsinus
cos double cos (double x)
cosinus (la toate funcţiile trigonometrice argumentul e în radiani)
#include <iostream.h> #include <math.h> void main(void) { double result, x = 0.5; result = cos(x); cout<<"cos("<<x<<”)=“<<result);}
cosh double cosh (double x)
cosinus hiperbolic
exp double exp (double x) exponenţiala
floor double floor (double x)
rotunjire prin lipsă
#include <stdio.h> #include <math.h> void main(void) { double number=123.54; double down, up; down=floor(number); up=ceil(number); cout<<"numarul original="<<number<<"nr.rotunjit prin lipsa”<<down<<"nr.rotunjit prin adaus”<<up;}
ceil double ceil (double x)
rotunjire prin adaus
fmod double fmod (double x,double y)
restul împărţirii lui x la y
#include <stdio.h> #include <math.h> void main(void) { double x=5.0, y = 2.0; double result; result=fmod(x,y); cout<<"restul lui"<<x<<“la”<<y<<‘=‘<<result;}
hypot double hypot (double x,double y)
ipotenuza triunghiului de catete x şi y
91
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FUNCŢII - ANALIZĂ MATEMATICĂ, BIBLIOTECI DE FUNCŢII
Nume Sintaxa Ce returneaza Exemplu
ldexp double ldexp(double x, int exp);
calculează produsul dintre primul parametru şi 2 la puterea dată de cel de al doilea parametru
#include <stdio.h> #include <math.h> int main(void) { double value; double x=7; /* ldexp ridica 2 la puterea 3 apoi inmulteste rezultatul cu 7*/ value = ldexp(x,3); cout<<"ldexp="<<value;}
log double log(double x);
logaritm natural
log10 double log10(double x);
logaritm zecimal
pow double pow(double x, double y);
puterea unui număr la alt număr
pow10 double pow10(int p);
puterea lui 10 la un număr întreg
sin double sin(double x);
sinus
sinh double sinh(double x);
sinus hiperbolic
sin_hyp = sinh(x); sin_hyp = (exp(x) - exp(-x))/2
tan double tan(double x);
tangenta
tanh double tanh(double x);
tangenta hiperbolică
14.2.2 Biblioteca pentru şiruri de caractere (string.h)
Conţine funcţii pentru şiruri de caractere
Tabelul 14.2 Funcţii pentru şiruri de caractere Nume Sintaxa Ce face Exemplu
strcat strcat(s1,s2)
Concatenează şirul s2 la sfârşitul şirul s1
#include <string.h> #include <stdio.h> int main(void) { char destination[25]; char *blank = " ", *c = "C++", *turbo = "Turbo"; strcpy(destination,
92
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FUNCŢII PREDEFINITE
Nume Sintaxa Ce face Exemplu turbo); strcat(destination, blank); strcat(destination, c); printf("%s\n", destination); }
strcmp strcmp(s1,s2)
Comparare de şiruri; dă valoarea 0 dacă s1=s2, negativ dacă s1<s2 şi pozitiv dacă s1>s2.
#include <string.h> #include <stdio.h> int main(void) { char *buf1 = "aaa", *buf2 = "bbb", *buf3 = "ccc"; int ptr; ptr = strcmp(buf2, buf1); if (ptr > 0) printf("buffer 2 is greater than buffer 1\n"); else printf("buffer 2 is less than buffer 1\n"); ptr = strcmp(buf2, buf3); if (ptr > 0) printf("buffer 2 is greater than buffer 3\n"); else printf("buffer 2 is less than buffer 3\n"); }
strcpy strcpy(s1,s2) Copiază şirul s2 în s1
#include <stdio.h> #include <string.h> int main(void) { char string[10]; char *str1 = "abcdefghi"; strcpy(string, str1); printf("%s\n", string); }
strlen strlen(s1) Determina lungimea sirului s1
#include <stdio.h> #include <string.h> int main(void) { char *string = "Borland Internat"; printf("%d\n", strlen(string)); }
93
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FUNCŢII - ANALIZĂ MATEMATICĂ, BIBLIOTECI DE FUNCŢII
14.2.3 Biblioteca standard (stdlib.h)
Aceasta conţine funcţiile de conversie pe care le vom prezenta în următorul tabel:
Tabelul 14.3 Funcţii de conversie Nume Sintaxa Ce face Exemplu
atof double atof(const char *s);
conversia unui şir la real dublă precizie
atol long atol(const char *s);
conversia unui şir la întreg long
#include <iostream.h> #include<stdlib.h> void main (void) { long l; char* str=“9876”; l=atol(str); cout<<“atol(“<<str<<“)=“<<l;}
atoi int atoi(const char *s);
conversia unui şir la întreg simplu
itoa
char* itoa(int value;char* string;int radix);
conversia unui întreg la şir de caractere cu lungimea dată de al treilea parametru
#include <stdlib.h> #include <iostream.h> void main(void) { int n=123; char str[5]; itoa(n,str,4); cout<<“itoa(“<<n<<“)=“<<str;}
ltoa
char* ltoa(long value;char* string;int radix);
conversia unui întreg long la şir de caractere cu lungimea dată de al treilea parametru
ultoa
char* ultoa(unsigned long value;char* string;int radix);
conversia unui întreg unsigned long la şir de caractere cu lungimea dată de al treilea parametru
ftoa
char* ftoa(float value;char* string;int radix);
conversia unui real dublă precizie la şir de caractere cu lungimea dată de al treilea parametru
rand int rand(void) generează un număr aleator cuprins între 0
#include <stdlib.h> #include <iostream.h> void main(void) { int i;
94
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
Nume Sintaxa Ce face Exemplu şi 10000 cout<<“zece nr aleatoare de
la 0 la 99”; for (i=0; i<10; i++) cout<<rand()%100<<‘\n’;}
random int rand(int num)
generează un număr aleator cuprins între 0 şi num-1
system void system(char* string)
lansează în execuţie o comandă DOS
#include <stdlib.h> #include <iostream.h> void main(void) { cout<<“Continutul directorului curent:\n”; system("dir");}
14.3 Biblioteci de funcţii scrise de către utilizator
În cazul folosirii mai frecvente a anumitor funcţii, acestea pot fi scrise grupat într-un fişier bibliotecă, şi apelate apoi ori de câte ori este nevoie.
Programul următor apelează funcţia suma, care se găseşte într-un fişier header User_Lib.H //Biblioteci de functii #include "USER_LIB.H" void main() { int a=2,b=3,c; //functia suma se gaseste in fisierul antet USER_LIB.H c=suma(a,b); }
Biblioteca de funcţii este un fişier header/antet (cu extensia h) scris de către utilizator, căruia îi pot fi adăugate funcţii după nevoie. #ifndef _USER_LIB_ #define _USER_LIB_ int suma(int x,int y) {return x+y;} #endif
14.4 Exemple
14.4.1 Funcţii din biblioteca matematică
//Functii din biblioteca matematica #include<math.h> #include<iostream.h>
95
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FUNCŢII - ANALIZĂ MATEMATICĂ, BIBLIOTECI DE FUNCŢII
#include<stdio.h> main() { float a,b,c,d; cout<<"introduceti a: ";cin>>a; cout<<"introduceti b: ";cin>>b; cout<<"\nvaloarea lui "<<a<<" la puterea "<<b<<" este: "<<pow(a,b); cout<<"\nvaloarea lui "<<10<<" la puterea "<<b<<" este: "<<pow10(b); cout<<"\nvaloarea log nat din "<<b<<" este: "<<log(b); cout<<"\nvaloarea log zecimal din "<<b<<" este: "<<log10(b); cout<<"\nvaloarea lui e la puterea "<<b<<" este: "<<exp(b); cout<<"\nvaloarea lui "<<a<<"*2 la "<<b<<" e: "<<ldexp(a,b); cout<<"\nvaloarea absoluta a nr real "<<b<<" este: "<<fabs(b); cout<<"\nvaloarea partii intregi a nr real "<<b<<" este: "<<floor(b); }
14.4.2 Operaţii cu şiruri de caractere utilizând funcţii predefinite
#include <iostream.h> #include <string.h> void main() { char sir1[] = ”abcd”, sir2[] = ”abcde”, sir3 = "abcdef”, sir4 = "de”; cout<<strcmp(sir1, sir2)<<’\n’; // afisare:-101 // ’e’ = 101, ’a’ = 97, ’d’ = 100 //’0’ - ’e’ = -101 cout<<strcmp(sir2, sir1)<<’\n’; //afisare: 101 cout<<strcmp(sir1, "")<<’ '; //compararea variabilei sir1 cu constanta sir vid char str1[20]=”hello”; char str2[20]=”goodbye”; char str3[20]; int difer, lungime; cout<<”str1=”<<str1<<” str2=”<<str2<<’\n’; difer=strcmp(str1, str2); if (difer == 0) cout<<”Siruri echivalente!\n”; else if (difer>0) cout<<str1<<” mai mare (lexicografic) decât “<<str2<<’\n’; else cout<<str1<<” mai mic (lexicografic) decât “<<str2<<’\n’; cout<<”str1=”<<str1<<’\n’; cout<<”str3=”<<str3<<’\n’; strcpy (str3, str1); cout<<”str1=”<<str1<<’\n’; cout<<”str3=”<<str3<<’\n’; strcat (str3, str1); cout<<”str1=”<<str1<<’\n’;
96
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
cout<<”str3=”<<str3<<’\n’; }
97
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FUNCŢII RECURSIVE
15. FUNCŢII RECURSIVE
O funcţie este numită funcţie recursivă dacă ea se autoapelează, fie direct (în definiţia ei se face apel la ea însăşi), fie indirect (prin apelul altor funcţii).
În cadrul acestui capitol vom aborda ambele tipuri de recursivitate: ■ recursivitate directă ■ recursivitate indirectă. Vă reamintim câteva observaţii fundamentale de care e bine să ţineţi cont: a) Studiaţi felul în care apare recursivitatea într-un program şi dacă sunt şi alte
moduri de elaborare a programului. Dacă sunt, atunci verificaţi dacă scrierea lor este mai eficientă şi dacă în cele din urmă optaţi pentru recursivitate.
b) Puneţi în evidenţă modul în care o problemă se apelează pe ea însăşi. c) Fiţi atenţi la modul în care definiţi parametrii funcţiilor recursive, variabilele
interne şi globale. Unele definiţii sunt fundamentale pentru execuţia programului. Spre exemplu, variabilele folosite pentru a parcurge valorile permise ale componentelor unei soluţii trebuie să fie locale funcţiei, altfel nu se generează corect soluţia. Unele definiţii bine alese pot optimiza destul de mult spaţiul alocat pe stivă şi timpul de execuţie.
d) Pentru corectitudinea recursivităţii realizate, fiţi atenţi la modul în care se păstrează valorile datelor la ieşirea dintr-un apel recursiv. Aveţi grijă ca după ieşirea din apelul recursiv al unei funcţii să refaceţi datele modificate pentru noul apel.
e) Aveţi grijă la stocarea datelor intermediare. Dacă este necesară o determinare a unui optim, se va lucra cu două seturi de date: unul pentru stocarea optimului şi unul pentru generarea soluţiei curente. În acest caz, tipărirea soluţiei nu se face în interiorul recursivităţii, ci după terminarea tuturor apelurilor.
f) Aveţi grijă să puneţi corect condiţiile de ieşire din recursivitate. Fără acestea, programul nu se va opri niciodată.
g) Faceţi pregătirile necesare şi stabiliţi valorile parametrilor pentru primul apel. Atragem atenţia că orice nerespectare a uneia dintre observaţiile enumerate mai sus
poate determina erori.
15.1 Exemple - Recursivitate directă
15.1.1 Calculul permutărilor, aranjamentelor şi combinărilor:
Pn = n! ; Anm = n!
(n-m)! ; Cnm = n!
m!·(n-m)!
15.1.1.1 Programul //Analiza combinatorica #include<stdio.h> int fact (int n) { if (n==0) return 1.0; else return n*fact(n-1);
98
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE - RECURSIVITATE DIRECTĂ
} void main() { int n,m,p,A,C; printf("\nintroduceti n="); scanf("%d",&n); printf("introduceti m="); scanf("%d",&m); p=fact(n); A=fact(n)/fact(n-m); C=fact(n)/(fact(m)*fact(n-m)); printf ("%d! =%d",n,p); printf ("\nA(%d,%d) = %d",n,m,A); printf ("\nC(%d,%d) = %d",n,m,C); }
15.1.2 Funcţia recursivă Ackerman
Să se calculeze matricea A(LxL), L≤10 unde: ACK2(i,j), dacă i>j, a(i,j)= 1, dacă i=j, sqrt(ACK(j,i)), dacă i<j, unde funcţia ACK(m,n) este o funcţie recursivă Ackerman definită pentru m≥0 şi
n≥0 prin: ACK(0,n) = n+1; ACK(m,0) = ACK(m-1,1); ACK(m,n) = ACK(m-1, ACK(m,n-1);
15.1.2.1 Programul: //Functii recursive - Ackerman #include<conio.h> #include<stdio.h> #include<math.h> #define DIM 4 double ack(int m, int n);//prototipul void scrie(double mat[DIM][DIM]);//prototipul void main() { double a[DIM][DIM]; int i,j; clrscr(); for(i=0;i<DIM;i++) for(j=0;j<DIM;j++) if(i>j) a[i][j]=ack(i,j)*ack(i,j); else if(i==j) a[i][j]=1; else a[i][j]=sqrt(ack(j,i));
99
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FUNCŢII RECURSIVE
scrie(a); getch(); } //Definirea functiilor double ack(int m, int n) { if(m==0) return n+1; else if(n==0) return ack(m-1,1); else return ack(m-1,ack(m,n-1)); } void scrie(double mat[DIM][DIM]) { int i,j; for(i=0;i<DIM;i++) { printf("\n"); for(j=0;j<DIM;j++) printf("A[%d,%d]= %5.2f;",i,j,mat[i][j]); } }
15.1.3 CMMDC
Să se se scrie un program care citeşte doi întregi pozitivi m şi n, de tip long, calculează şi afişează pe cel mai mare divizor comun al lor. Programul va folosi o funcţie care are ca parametri doi întregi m şi n de tip long şi care calculează şi returnează cel mai mare divizor comun al lor.
Notăm cu: (m,n) cel mai mare divizor comun al numerelor m şi n. Calculul celui mai mare divizor comun a două numere se poate realiza recursiv astfel:
(m,n) = m dacă n = 0; (m,n) = n dacă m = 0; (m,n) = (n,m%n) dacă atît m, cât şi n sunt diferiţi de zero şi m > n (prin m%n s-a
notat restul împărţirii lui m la n). #include <stdio.h> #include <stdlib.h> //FUNCTIA long cmmdc(long m, long n) /* calculeaza si returneaza pe cel mai mare divizor comun al numerelor m si n */ { if(m==0) return n; else if(n==0) return m; else if(m>n) return cmmdc(n, m%n); else return cmmdc(m, n%m); }
100
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE - RECURSIVITATE DIRECTĂ
void main() /* citeste pe m si n de tip long, calculeaza si afiseaza (m,n) */ { long m,n; printf("\nValorile lui m si n: "); if(scanf("%ld %ld", &m, &n)!=2 || m<0 || n<0) { printf("nu s-au tastat doi intregi pozitivi\n"); exit(1); } printf("m=%ld\tn=%ld\t(m,n)=%ld\n",m,n,cmmdc(m,n)); }
15.1.4 Generarea tuturor permutărilor unei mulţimi
În prima variantă vom defini funcţia recursivă permutare. Aceasta va genera permutările verificând la fiecare poziţie dacă elementul curent a fost deja selectat sau nu. Dacă nu este selectat, el poate fi folosit pentru această poziţie. Ieşirea din recursivitate se va face în momentul când s-au generat toate cele n componente. #include<stdio.h> int k,n,poz[20],p[20]; void permutare(int i); void main () { printf("Numarul de elemente: "); scanf("%d",&n); permutare(1); } void permutare(int i) { int j; for(j=1;j<=n;j++) if(poz[j]==0) { p[i]=j; poz[j]=1;/* selectam elementul j pe pozitia i */ if(i==n)/*Daca s-au generat toate pozitiile se afiseaza solutia*/ { for(k=1;k<=n;k++) printf("%d",p[k]); printf("\t"); } else permutare(i+1); poz[j]=0; /* deselectam elementul j */ } }
Varianta a doua va defini funcţia recursivă permuta de generare a permutărilor, care face generarea tuturor permutărilor prin interschimbarea elementului de pe poziţia
101
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FUNCŢII RECURSIVE
curentă k, pe rând cu elementele din poziţiile anterioare, de la 1 la k-1. Când se ajunge la prima poziţie, se tipăreşte permutarea generată. //Generarea tuturor permutarilor unei multimi. #include <stdio.h> int a[100] ; int n, k, i ; void tipareste(int n) { int i; for (i=1;i<=n;i++) printf ("%d ", a[i]); putchar('\n'); } void permuta(int k) { int i; if (k==1) tipareste (n); else { permuta(k-1) ; for (i=1;i<k;i++) { a[i] ^=a[k] ^=a[i] ^=a[k] ; permuta(k-1); a[i] ^=a[k] ^=a[ i] ^=a[ k] ; } } } void main() { printf("Introduceti n :" ) ; scanf(" %d" , &n) ; for(i=1; i<=n; i++) a[i] =i; permuta(n); }
15.1.5 Problema reginelor
Să se afişeze toate posibilităţile de aranjare a n regine pe o tablă de şah de dimensiuni n x n astfel încât ele să nu se atace.
Pentru a simplifica determinarea configuraţiilor corecte, vom folosi pentru fiecare linie o regină. Coloanele pentru fiecare regină se vor stoca în vectorul r. Generarea reginelor se face cu ajutorul funcţiei recursive regina care va avea ca parametru numărul liniei.
Pentru a accepta poziţia curentă, se verifică dacă regina aşezată acum se atacă pe coloană sau pe diagonală cu reginele plasate anterior.
Pentru aceasta vom defini funcţia ataca pentru a verifica dacă la adăugarea reginei de pe linia i aceasta se atacă cu una din reginele 1, 2,..., i-1. Ea va returna valoarea 0,
102
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE - RECURSIVITATE DIRECTĂ
dacă regina i nu atacă nici o regină şi valoarea 1 în caz contrar. Două regine se atacă dacă sunt pe aceeaşi coloană sau pe aceeaşi diagonală. A doua condiţie revine la a verifica dacă diferenţa dintre liniile pe care sunt situate reginele este egală cu diferenţa dintre coloanele acestora, în valoare absolută.
Pentru afişarea unei table de şah şi a configuraţiei reginelor am folosit funcţia scrie. Pentru numărarea soluţiilor generate am folosit variabila nr.
15.1.5.1 Programul //Problema reginelor #include<stdio.h> #include<conio.h> #include<stdlib.h> int r[20],n,nr; int ataca(int); void regina(int); void scrie(void); void main() { textmode(C80); textcolor(YELLOW); printf("\nNumarul de regine: "); scanf("%d",&n); regina(1); } void regina(int i) { int j; for(j=1;j<=n;j++) { r[i]=j; if(!ataca(i)) if(i<n) regina(i+1); else scrie(); } } int ataca(int i) { int j; for(j=1;j<=i-1;j++) if(r[i]==r[j]||abs(r[i]-r[j])==abs(i-j)) return 1; return 0; } void scrie() { int i,j; textbackground(BLACK); clrscr(); printf("Solutia %d:\n",++nr); for(i=1;i<=n;i++) {
103
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FUNCŢII RECURSIVE
printf("\t"); for(j=1;j<=n;j++) { if(i%2==j%2) textbackground(WHITE) ; else textbackground(BLACK); if(r[i]==j) cprintf("R"); else cprintf(" "); } cprintf("\n\r"); } printf("Ptr continuare apasati orice tasta!"); getch(); }
15.1.6 Problema rucsacului
O persoană are un rucsac cu care poate transporta o greutate maximă G. Persoana are la dispoziţie n obiecte diferite şi cunoaşte pentru fiecare obiect greutatea şi câştigul care se obţine în urma transportului său la destinaţie. Se cere să se precizeze care obiecte trebuie să le transporte persoana astfel încât câştigul să fie maxim.
Varianta recursivă a problemei va utiliza funcţia rucsac. Aceasta va calcula pentru fiecare obiect dacă selecţia sa duce la depăşirea greutăţii maxime admisibile. Dacă nu, se verifică dacă actuala configuraţie are o valoare maximă. În caz afirmativ, se stochează obiectele care dau pentru selecţie o valoare maximă. Tipărirea obiectelor care au împreună valoarea maximă se va face la ieşirea din recursivitate.
15.1.6.1 Programul //Problema rucsacului #include<stdio.h> #include<stdlib.h> #include<conio.h> #define DIM 10 float gx, vx, gmax=9, vmax, g[DIM] = {0,1,2,4,5,8}, v[DIM] = {0,5,9,12,15,25}; int s[DIM],smax[DIM],n=4; void rucsac(int i) //i - nr curent max de obiecte { int j,k; for(j=0;j<=1;j++) /* Daca nu se depaseste greutatea maxima obiectul este selectat */ if(gx+j*g[i]<=gmax) { /* Se actualizeaza greutatea si valoarea */ s[i]=j; gx+=j*g[i]; vx+=j*v[i]; /* Daca valoarea selectiei actuale este mai mare decat maximul de pana acum se actualizeaza selectia de maxim */ if(vx>vmax)
104
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE - RECURSIVITATE DIRECTĂ
{ vmax=vx; printf("\nvmax=%5.2f: ",vmax); for(k=1;k<=i;k++) { smax[k]=s[k]; printf("%2d*%4.2f(%4.2f)",smax[k],v[k],g[k]); } for(k=i+1;k<=n;k++) { smax[k]=0; printf("%2d*%4.2f",smax[k],v[k]); } } /*Apelul recursiv pentru trecerea la urmatorul obiect*/ if(i<n) rucsac(i+1); /*Refacerea starii dupa iesirea din recursivitate*/ gx-=j*g[i]; vx-=j*v[i]; } } void main() { int i; FILE *f; clrscr(); /* Introducerea datelor */ //Citire din fisier /* f=fopen("rucsac.txt","r"); fscanf(f,"%d",&n); fscanf(f,"%g",&gmax); for(i=1;i<=n;i++) fscanf(f,"%g %g",&g[i],&v[i]); fclose(f);*/ gx=vx=0; vmax=-1; /* Apelul recursiv */ rucsac(1); /* Tiparirea solutiei maxime obtinute */ printf("\nValoarea maxima:\t%g \nGreut max:\t%g \nObiectele:\t",vmax, gmax); for(i=1;i<=n;i++) if(smax[i]==1) printf("%d, ",i); }
Observaţi modul în care s-a modificat programul atunci când se cere o configuraţie de optim:
1. în interiorul funcţiei recursive se face doar verificarea de optim şi stocarea în cazul îndeplinirii condiţiilor de optim a datelor intermediare într-un set de date separat;
2. tipărirea soluţiei s-a făcut la ieşirea din apelul recursiv şi nu în interior.
105
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FUNCŢII RECURSIVE
15.1.7 Prăjituri
Fiind date n tipuri de prăjituri cu costul c[1], c[2], ..., c[n], să se determine toate modurile posibile de a cumpăra m prăjituri care să nu depăşească suma s. Se consideră că pot fi cumpărate oricâte prăjituri de un anumit tip.
Notaţii făcute: x, stochează câte prăjituri s-au cumpărat din fiecare tip; suma, valoarea prăjiturilor cumpărate în momentul de faţă; nr, numărul de prăjituri cumpărate în momentul de faţă. În procedura recursivă rec, numărul maxim de prăjituri care se pot cumpăra este
minimul dintre numărul de prăjituri rămase de cumpărat, m, şi numărul posibil de cumpărat cu suma rămasă din prăjiturile de tipul i, adică (s-suma)/c[i]. Datele se citesc din fişierul "prajitur.in", iar soluţiile se scriu în fişierul "prajitur.out".
15.1.7.1 Programul //Prajituri #include<iostream.h> #include<fstream.h> long x[100] ,c[100]; short k,i,j,n,m,nr; unsigned nr_sol; unsigned long s,suma; fstream f; void rec(int i) { int max,j; max=(s-suma)/c[i] ; if(max>m-nr) max=m-nr; for(j=0;j<=max;j++) { suma+=c[i]*j; nr+=j; x[i]=j ; if(suma<=s) if(nr<m&&i<n) rec(i+1); else if(nr==m) { //Tip ?rire nr_sol++; f<<"Suma totala: "<<suma<<endl; for(k=1;k<=i;k++) if(x[k]>0) f<<"prajitura "<<k<<" de "<<x[ k]<<" ori\n"; f<<"-------------------------------------------\n"; } nr-=j; suma-=c[i]*j; } } void main() {
106
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE - RECURSIVITATE INDIRECTĂ
f.open("prajitur.in",ios::in); f>>n; // Numarul de tipuri de prajituri: f>>s; // suma data f>>m; // numarul de prajituri pentru cumparat for(i=1;i<=n;i++) f>>c[i]; //costul fiecarei prajituri f.close(); // Se deschide fisierul "prajitur.out" pentru scrierea solutiilor f.open("prajitur.out",ios::out); nr_sol=0; rec(1); f<<"Numarul de solutii: "<<nr_sol ; f.close(); }
15.2 Exemple - Recursivitate indirectă
15.2.1 N din 4
Se ştie că din numărul 4 se obţine orice număr natural n scris în baza zece prin aplicarea următoarelor operaţii:
• se scrie la sfârşit cifra 4; • se adaugă cifra 0; • se împarte la doi dacă numărul este par.
Se cere să se scrie un program care produce un şir de numere conform regulilor precedente în care primul număr este 4 iar ultimul este n.
Se pleacă de la numărul n şi se generează operaţiile inverse celor menţionate. Programul este format din 2 funcţii între care se face recursivitatea indirectă: proc2 - se înmulţeşte numărul cu 2. Dacă ultima cifră este 0 sau 4, se apelează
proc0, altfel se apelează proc2. proc0 - se şterge ultima cifră dacă este 0 sau 4. Apelul recursiv este asemănător cu
proc0: dacă ultima cifră este 0 sau 4 se apelează proc0, altfel se apelează proc2. #include<conio.h> #include<stdio.h> int n,a[100]; /*numarul initial si sirul de transformari*/ void proc2(int k);/*proceduri de transformare*/ void procO(int k); void proc2(int k) /* se inmulteste numarul cu 2 */ { int x; if(k!=4) { a[++a[0]]=k*=2; x=k%10; if(x==0||x==4) procO(k); else proc2(k);
107
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FUNCŢII RECURSIVE
} } void procO(int k) /* se elimina ultima cifra */ { int x; if(k!=4) { a[++a[0]]=k/=10; x=k%10; if(x==0||x==4) procO(k); else proc2(k); } } void main(void) { int p; printf("\nNumarul care se obtine: ") ; scanf("%d",&n) ; a[1]=n;a[0]=1; if(n!=4) { p=n%10; if(p==0||p==4 ) procO(n); else proc2(n); } printf("Sirul de numere este: "); for(p=a[0];p>=1;p--) printf(" %d ",a[p]); getch(); }
15.3 Probleme propuse
1. Să se scrie un program care citeşte câte două numere, până la întâlnirea perechii de numere 0, 0 şi afişează, de fiecare dată, cel mai mare divizor comun al acestora, folosind o funcţie care îl calculează.
2. Se introduce de la tastatura un număr întreg. Să se afişeze toţi divizorii numărului introdus. Se va folosi o funcţie de calcul a celui mai mare divizor comun a 2 numere.
3. Secvenţele următoare sunt corecte din punct de vedere sintactic ? Dacă nu, identificaţi sursele erorilor.
void a(int x, y) {cout<<"x="<<x<<" y="<<y<<'\n';} void main( ) { int b=9; a(6, 7); }
void main( ) { int x=8; double y=f(x); cout<<"y="<<y<<'\n';} int f(int z) {return z+z*z;}
4. Scrieţi o funcţie găseste_cifra care returnează valoarea cifrei aflate pe poziţia k în cadrul numărului n, începând de la dreapta (n şi k vor fi argumentele funcţiei).
5. Să se calculeze valoarea funcţiei g, cu o eroare EPS (a, b, EPS citite de la tastatură):
108
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
PROBLEME PROPUSE
g(x)=⌡⌠a
bx2 + x + 1 *ln|x+a|dx +
⌡⌠
a
b
x*arctg
b
b+x dx
6. Implementaţi funcţii iterative şi recursive pentru calculul valorilor polinoamelor Hermite Hn(y), ştiind că: H0(y) = 1, H1(y) = 2y, Hn(x) = 2yHn-1(y)-2Hn-2(y) dacă n>1. Comparaţi timpul de execuţie al celor două funcţii.
7. Să se scrie un program care generează toate numerele palindrom, mai mici decât o valoare dată, LIM. Un număr palindrom are cifrele simetrice egale (prima cu ultima, a doua cu penultima, etc). Se va folosi o funcţie care testează dacă un număr este palindrom.
8. Fie matricea C (NXN), N<=10, ale cărei elemente sunt date de relaţia:
j! +∑=
j
kkx
0)sin( , dacă i<j
Ci,j = xi, dacă i=j
i! + ∑=0
)cos(k
kxi , dacă i>j
unde x∈[0,1], x introdus de la tastatură. a) Să se implementeze următoarele funcţii: de calcul a elementelor matricei; de
afişare a matricei; de calcul şi de afişare a procentului elementelor negative de pe coloanele impare (de indice 1, 3, etc);
b) Să se afişeze matricea B, unde: B = C - C2 + C3 - C4 + C5. 9. Să se creeze o bibliotecă de funcţii pentru lucrul cu matrice, care să conţină funcţiile
utilizate frecvent (citirea elementelor, afisarea matricei, adunare a două matrice, etc). Să se folosească această bibliotecă.
10. Să se creeze o bibliotecă de funcţii pentru lucrul cu vectori, care să conţină funcţiile utilizate frecvent. Să se folosească această bibliotecă.
109
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
TIPURI DE DATE DEFINITE DE UTILIZATOR
16. TIPURI DE DATE DEFINITE DE UTILIZATOR
16.1 Structuri
Structurile grupează date de tipuri diferite, constituind definiţii ale unor noi tipuri de date. Componentele unei structuri se numesc membrii (câmpurile) structurii. La declararea unei structuri se pot preciza tipurile, identificatorii elementelor componente şi numele structurii.
Forma generală de declarare a unei structuri: struct identificator_tip_structura
{ lista_de_declaratii_membri;
} lista_identificatori_variabile; în care: • struct este un cuvânt cheie (obligatoriu); • identificator_tip_structura reprezintă numele noului tip (poate lipsi); • lista_de_declaratii_membri este o listă în care apar tipurile şi
identificatorii membrilor structurii; • lista_identificatori_variabile este o listă cu identificatorii variabilelor
de tipul declarat. Membrii unei structuri pot fi de orice tip, cu excepţia tipului structură care se
declară.
16.1.1 Punctul mediu
Să se găsească coordonatele x şi y ale punctului mediu situat la jumătatea distanţei dintre două puncte date dintr-un plan. //Structuri #include <iostream.h> typedef struct{float x,y;} punct2D; punct2D punct_mediu(punct2D p1, punct2D p2) { punct2D pm, ptemp; pm.x=(p1.x+p2.x)/2; pm.y=(p1.y+p2.y)/2; return pm; } void main () { punct2D a={0,3}, b={6,4}, c; c=punct_mediu(a,b); cout<<"\na("<<a.x<<","<<a.y<<")"; cout<<"\nb("<<b.x<<","<<b.y<<")";
110
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
STRUCTURI
cout<<"\nc("<<c.x<<","<<c.y<<")"; }
16.1.2 Punctul în oglindă
Să se găsească imaginea în oglindă a unui punct A(x,y) faţă de axa Oy. //Structuri-pointer #include <iostream.h> struct punct2D {float x,y;}; void oglinda_oy(struct punct2D *pct) { //in cazul utilizarii pointerilor catre structuri accesarea campurilor structurii se face cu ajutorul operatorului "->" pct->x=-pct->x; } void main () { struct punct2D A={5,3}; cout<<"\nPunctul original A are x="<<A.x<<" si y= "<<A.y; oglinda_oy(&A); cout<<"\nPunctul oglindit A' are x="<<A.x<<" si y=" <<A.y; }
16.1.3 Modulul unui număr complex
Să se calculeze modulul unui număr complex folosind o funcţie. //Functie cu structuri #include<math.h> #include<stdio.h> #include<conio.h> typedef struct{ double real; double imag; } COMPLEX; double modul(COMPLEX *);//prototipul void main() { COMPLEX nr; clrscr(); while(scanf("%lf %lf",&nr.real,&nr.imag)==2) printf("\nreal=%.2f imag=%.2f modul=%.2f",nr.real,nr.imag,modul(&nr)); getch(); } double modul(COMPLEX *z)//definitie
111
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
TIPURI DE DATE DEFINITE DE UTILIZATOR
{ return sqrt(z->real*z->real+z->imag*z->imag);}
16.1.4 Modul şi argument
Să se scrie un program care citeşte numere complexe şi le afişează împreună cu modulul şi argumentul lor.
Programul foloseşte o funcţie care calculează şi returnează modulul unui număr
complex z. Dacă: z = x + iy atunci modulul numărului complex este rădăcina pătrată din: x*x +
y*y. Programul mai foloseşte şi o funcţie care calculează şi returnează argumentul unui
număr complex. Dacă: z = x + iy atunci arg z se calculează astfel: a. DACĂ x = y = 0, arg z = 0. b. DACĂ y = 0 şi x ≠ 0, ATUNCI DACĂ x > 0, arg z =0; ALTFEL arg z = π = 3.14. c. DACĂ x = 0 şi y ≠ 0, ATUNCI DACĂ y > 0, arg z = π/2; ALTFEL arg z = 3*pi/2. d. DACĂ x şi y ≠ 0, ATUNCI fie:
a = arctg(y/x) d1. DACĂ x > 0 şi y > 0, ATUNCI arg z = a. d2. DACĂ x > 0 şi y < 0, ATUNCI arg z = 2*π + a. d3. DACĂ x < 0 şi y > 0, ATUNCI arg z = π + a. d4. DACĂ x < 0 şi y < 0, ATUNCI arg z = π + a. Se observă că pentru x < 0 şi y ≠ 0:
arg z = pi + a; ALTFEL, DACĂ x > 0 şi y < 0, ATUNCI arg z = 2*π + a
#include <stdio.h> #include <math.h> typedef struct { double x; double y; } COMPLEX; double d_modul(COMPLEX *z) /*calculeaza si returneaza modulul numarului complex z */ { return sqrt(z->x*z->x+z->y*z->y) ;} /* functia foloseste constanta M_PI=3.1415... definita in headerul math.h */ double d_arg(COMPLEX *z) { double a; if(z->x==0 && z->y==0) return 0.0; if(z->y==0) if(z->x>0) return 0.0; else /*y=0 si x<0 */ return M_PI; if(z->x==0)
112
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
STRUCTURI
if(z->y>0) return M_PI/2; else /*x=0 si y<0*/ return (3*M_PI)/2; /*x!=0 si y!=0 */ a=atan(z->y/z->x); if(z->x<0) /*x<0 si y!=0*/ return a+M_PI; else /*x>0*/ if(z->y<0) /*x>0 si y<0*/ return 2*M_PI+a; else /*x>0 si y>0*/ return a; } void main() /* citeste numere complexe si le afiseaza impreuna cu modulul si argumentul corespunzator */ { COMPLEX complex; printf("Introduceti elementele nr complex: "); while(scanf("%lf %lf", &complex.x, &complex.y) == 2) { printf("a+ib= %g + i*(%g)\n", complex.x, complex.y); printf("modul=%g\targ=%g\n", d_modul(&complex),d_arg(&complex)); } }
16.1.5 Ordinea a două date calendaristice
Scrieţi o funcţie având ca parametri două date calendaristice (precizate prin an, lună şi zi), care stabileşte una din situaţiile:
•Prima dată o precede pe cea de-a doua •Cele două date sunt egale •A două dată o precede pe prima Funcţia va întoarce una din valorile -1,0, 1.
#include <stdio.h> typedef struct { unsigned int an; unsigned int luna; unsigned int zi; } Data; /* vector in care retinem ultima zi pentru fiecare luna: */ int zile[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; /* verificare daca anul este bisect (daca da, se intoarce o valoare nenula): */ int bisect(int an) { return ((an%4==0 && an%100!=0) || an%400==0); } /* verifica daca o data este valida (daca da, se intoarce o valoare nenula):*/
113
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
TIPURI DE DATE DEFINITE DE UTILIZATOR
int e_valida(Data d) { /* daca anul este bisect si luna este februarie: */ if (bisect(d.an) && d.luna==2) return (d.zi <= 29); /* anul nu este bisect sau luna nu este februarie: */ return (d.zi <= zile[d.luna-1]); } /* Functie care compara 2 date calendaristice * Rezultat intors. -1 daca d1 precede d2 * 1 daca datele sunt egale * 1 daca d2 precede d1 */ int compara_date(Data d1, Data d2) { if(d1.an<d2.an) return -1; if(d1.an>d2.an) return 1; /* d1.an = d2.an : */ if(d1.luna<d2.luna) return -1; if(d1.luna>d2.luna) return 1; /* d1.an = d2.an si d1.luna = d2.luna */ if(d1.zi<d2.zi) return -1; if(d1.zi>d2.zi) return 1; /* d1.an = d2.an si d1.luna = d2.1una si d1.zi=d2.zi */ return 0; } void main(void) { Data d1, d2; do { printf("introduceti data d1 (zi luna an):\n"); scanf("%d %d %d", &d1.zi, &d1.luna, &d1.an); if(!e_valida(d1)) printf("Data nu este valida, introduceti una corecta:\n"); } while(!e_valida(d1)); do { printf("introduceti data d2 (zi luna an):\n"); scanf("%d %d %d", &d2.zi, &d2.luna, &d2.an); if(!e_valida(d2)) printf("Data nu este valida, introduceti una corecta:\n"); } while(!e_valida(d2)); switch(compara_date(d1,d2)) { case -1: printf("d1 precede d2\n"); break; case 0: printf("Datele sunt egale\n"); break;
114
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
STRUCTURI
case 1: printf("d1 urmeaza dupa d2\n"); } }
16.1.6 Prelucrare informaţii elevi
Să se citească (cu ajutorul unei funcţii de citire) următoarele informaţii despre elevii participanţi la un concurs de admitere: nume, numărul de înscriere şi cele trei note obţinute. Să se afişeze, printr-o funcţie, informaţiile citite. Să se afişeze o listă cu elevii participanţi la concurs, ordonaţi alfabetic, notele şi media obţinută (funcţie de ordonare, funcţie de calculare a mediei). Să se afişeze lista elevilor înscrişi la concurs, în ordinea descrescătoare a mediilor.
#include <stdio.h> #include <string.h> #include <iostream.h> #include <conio.h> #define DIM_PAG 24 // dimensiunea paginii de afisare #define FALSE 0 #define TRUE 1 struct elev{ char nume[20];int nr_matr;int note[3]; }; //definirea tipului elev void cit_elevi(elev *a, int n) { for (int i=0; i<n; i++){ cout<<"Nume elev:"; cin>>(a+i)->nume; //sau cin>>(*(a+i)).nume; cout<<"Nr. inscriere:"; cin>>(a+i)->nr_matr; for (int j=0; j<3; j++){ do{ cout<<"Nota :"<<(j+1)<<" ="; cin>>(a+i)->note[j]; if((a+i)->note[j]<0 || (a+i)->note[j]>10) cout<<"Nota incorecta!....Repeta!\n"; }while ((a+i)->note[j]<0 || (a+i)->note[j]>10); } } } void ord_medii(elev *a, int n) { int gata =FALSE;int i;double med1, med2;elev aux; while (!gata){ gata=TRUE; for(i=0; i<=n-2; i++){ med1=0;med2=0; for (int j=0; j<3; j++){
115
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
TIPURI DE DATE DEFINITE DE UTILIZATOR
med1+=(a+i)->note[j]; med2+=(a+i+1)->note[j];// calculul mediilor pentru elementele vecine } med1/=3; med2/=3; if (med1<med2){ aux=*(a+i); *(a+i)=*(a+i+1);*(a+i+1)=aux; gata=FALSE;} } } } void ord_alf(elev *a, int n) { int gata =FALSE; int i; double med1, med2; elev aux; while(!gata){ gata=TRUE; for (i=0; i<=n-2; i++){ if(strcmp((a+i)->nume,(a+i+1)->nume) >0) {aux=*(a+i); *(a+i)=*(a+i+1);*(a+i+1)=aux; gata=FALSE;} } } } //void cit_elevi(elev *a, int n); // functie implementata anterior void antet_afis(const char *s) {printf("%s\n", s); } void afis_elev(elev *a, int n, char c) {clrscr(); if(c=='A') antet_afis(" LISTA INSCRISILOR\n"); if(c=='O') antet_afis(" LISTA ALFABETICA\n"); if(c=='R') antet_afis(" LISTA MEDII\n"); printf("Nr.crt. | Nr. Matricol | NUME | Nota1 | Nota2 | Nota3 | MEDIA |\n"); printf("------------------------------------------\n"); int lin=3; for(int i=0; i<n; i++){ printf("%7d|%12d|%-20s|",i+1,(a+i)->nr_matr,(a+i)->nume); double med=0; for (int j=0; j<3; j++){ printf("%-5d|", (a+i)->note[j]); med+=(a+i)->note[j]; } med/=3;printf("%-9.2f|\n", med);lin++; if (lin==(DIM_PAG-1)){ printf(" Apasa o tasta...."); getch(); clrscr(); if(c=='A') antet_afis(" LISTA INSCRISILOR\n"); if(c=='O') antet_afis(" LISTA ALFABETICA\n"); if(c=='R') antet_afis(" LISTA MEDII\n");
116
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE UNIUNI
printf("Nr.crt.| NUME |Nota1|Nota2|Nota3| MEDIA\ |\n"); printf("------------------------------------------\n"); int lin=3; } } printf(" Apasa o tasta...."); getch(); } void main() { int nr_elevi; clrscr(); cout<<"Nr. elevi:";cin>>nr_elevi; elev *p; p=new elev[nr_elevi]; cit_elevi(p, nr_elevi); afis_elev(p, nr_elevi, 'A');// afisarea înscrisilor ord_medii(p, nr_elevi); afis_elev(p, nr_elevi, 'R');// afisarea în ordinea descrescatoare a mediilor ord_alf(p, nr_elevi); //ordonare alfabetica afis_elev(p, nr_elevi, 'O');// afisarea în ordinea descrescatoare a mediilor }
16.1.7 Media notelor la un examen
Să se calculeze media notelor la un examen pentru mai mulţi studenţi şi media notelor la toate examenele pentru un singur student. Se vor folosi date de tip structură (denumită student) cu următoarele câmpuri: Nume, nota1, nota2, nota3.
16.2 Uniuni
Aceeaşi zonă de memorie poate fi utilizată pentru păstrarea unor obiecte (date) de diferite tipuri, prin declararea uniunilor. Uniunile sunt similare cu structurile, singura diferenţă constând în modul de memorare. Declararea uniunilor:
union identificator_tip_uniune { lista de declaratii_membri;
} lista_identificatori_variabile; Spaţiul de memorie alocat corespunde tipului membrului de dimensiune maximă. Tipul
uniune foloseşte aceeaşi zonă de memorie, care va conţine informaţii organizate în mai multe moduri, corespunzător tipurilor membrilor.
16.3 Exemple uniuni
16.3.1 Dată de tip dublu
//Uniuni #include <iostream.h> #include<conio.h>
117
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
TIPURI DE DATE DEFINITE DE UTILIZATOR
union tip_dublu { int i; float f; } ddata; void main () {//ddata.f=1234.56e+5; ddata.i=1234; cout<<"ddata.f="<<ddata.f<<"\n"; cout<<"ddata.i="<<ddata.i<<"\n"; getch(); }
16.3.2 Citirea şi afişarea datelor despre mai multe persoane
Să se exemplifice folosirea uniunilor (union) pentru citirea şi afişarea datelor despre mai multe persoane de ambele sexe.
Vom folosi o structură pentru a memora numele, vârsta şi sexul unei persoane, indiferent dacă aceasta este femeie sau bărbat. Dar, în funcţie de sex, persoana respectivă va avea un soţ (dacă e femeie), respectiv o soţie (dacă e bărbat). O înregistrare de tip union va fi folosită, aşadar, pentru a memora partenerul unei persoane oarecare.
O înregistrare union este similară cu o înregistrare de tip struct, cu excepţia faptului că union va permite să definiţi variabile (câmpuri) care să-şi împartă acelaşi spaţiu de memorare.
#include<stdio.h> #include<conio.h> #include<stdlib.h> union partener { char sotie[20]; char sot[20]; }; struct persoana { char nume[20]; char sex; int varsta; union partener p; }; void Citeste(int nr_p, struct persoana *x) { int vs; char sx; printf("Se citesc datele persoanei a %d-a:\n",nr_p); fflush(stdin); //goleste fluxul de date printf("Dati numele: "); gets(x->nume);
118
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE UNIUNI
printf("Dati varsta: "); scanf("%d",&vs); x->varsta=vs; fflush(stdin) ; printf("Dati sexul: "); scanf("%c",&sx) ; x->sex=sx; fflush(stdin); if (x->sex=='F'|| x->sex=='f') { printf("Dati numexe sotului: "); gets(x->p.sot); } else { printf("Dati numele sotiei: "); gets(x->p.sotie); } } void Scrie(int nr_p, struct persoana x) { if (wherey()==20) { printf("\nApasati o tasta ...\n"); getch(); } printf("Datele persoanei a %d-a:\n",nr_p); printf("Numele: %s.\n",x.nume); printf("Varsta: %d.\n",x.varsta); printf("Sexul: %c. \n",x.sex); if(x.sex=='F'|| x.sex=='f') printf("Numele sotului: %s.\n",x.p.sot); else printf("Numele sotiei: %s.\n",x.p.sotie); } void main() { struct persoana om[20]; int i,n; // textmode(C80); clrscr(); printf("Dati numarul de persoane: "); scanf("%d",&n); for(i=0; i<n; i++) Citeste(i+1,&om[i]); printf("\n Rezultate:\n"); for(i=0; i<n; i++) Scrie(i+1,om[i]); getch(); }
16.3.3 Arii figuri
Fie tipul FIG declarat ca mai jos:
119
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
TIPURI DE DATE DEFINITE DE UTILIZATOR
typedef struct { int tip; /* tipul figurii */ union { double raza; /* cerc */ double lat_p; /* patrat */ double lat_d[2 ];/* dreptunghi */ double lat_t[3]; /* triunghi */ } fig; } FIG;
O dată de tip FIG conţine elementele unei figuri necesare pentru a calcula aria figurii respective. Figurile avute în vedere sunt:
o cerc o pătrat o dreptunghi o triunghi.
În cazul primelor două figuri, data de tip FIG conţine o valoare de tip double care, în cazul cercului reprezintă lungimea razei acestuia, iar în cazul pătratului, lungimea laturii pătratului. În cazul dreptunghiului, data conţine două elemente de tip double: lungimea şi lăţimea. În sfirşit, în cazul triunghiului, data conţine trei valori de tip double care reprezintă lungimile celor trei laturi ale triunghiului.
Componenta tip defineşte elementele (figura) prezente într-o dată de tip FIG şi are valorile:
0 Pentru cerc 1 Pentru pătrat 2 Pentru dreptunghi 3 Pentru triunghi -1 Pentru eroare. În locul acestor valori, considerăm constantele simbolice: #define EROARE -1 #define CERC 0 #define PATRAT 1 #define DREPTUNGHI 2 #define TRIUNGHI 3 Funcţia aria din program are ca parametru o dată de tip FIG, calculează şi
returnează aria figurii ale cărei elemente sunt conţinute în zona definită de parametru. Funcţia returnează 0 în cazul în care datele sunt eronate.
La calculul arici unui triunghi se foloseşte formula lui Heron. Funcţia citire_fig din program are ca parametru un pointer spre o dată de tip
FIG şi citeşte şi păstrează elementele figurii definite de componenta tip a datei de tip FIG.
#include <stdio.h> #include <stdlib.h> #include <math.h> typedef struct { int tip; union { double raza; double lat_p; double lat_d[2]; double lat_t[3]; } fig;
120
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE UNIUNI
} FIG; #define EROARE -1 #define CERC 0 #define PATRAT 1 #define DREPTUNGHI 2 #define TRIUNGHI 3 #define PI 3.14159265358979 double aria(FIG *p) /* calculeaza si returneaza aria figurii definite de elementele prezente in zona spre care pointeaza p; la eroare returneaza 0 */ { double sp,a,b,c; switch(p->tip) { case CERC: return PI*p->fig.raza*p->fig.raza; case PATRAT: return p->fig.lat_p*p->fig.lat_p; case DREPTUNGHI: return p->fig.lat_d[0]*p->fig.lat_d[1]; case TRIUNGHI: sp=(p->fig.lat_t[0] + p->fig.lat_t[1] + p->fig.lat_t[2])/2; if((a=sp - p->fig.lat_t[0]) > 0 && (b=sp - p->fig.lat_t[1]) > 0 && (c=sp - p->fig.lat_t[2]) > 0 ) return sqrt(sp*a*b*c); else { /* cele 3 valori nu reprezinta lungimile laturilor unui triunghi */ printf("a= %g\tb= %g\tc= %g\tnu\ formeaza un triunghi\n", p->fig.lat_t[0], p->fig.lat_t[1], p->fig.lat_t[2] ); return 0; } default:/* eroare */ return 0; }/*switch*/ } int citire_fig(FIG *p) /* - citeste elementele figurii definite de p->tip; - returneaza: 0 - la intilnirea sfirsitului de fisier sau la eroare; 1 - altfel. */ { char t[255]; switch(p->tip) { case CERC: for( ; ; ) { printf("raza= "); if(gets(t) == 0 ) return 0; if(sscanf(t,"%lf",&p->fig.raza)== 1 && p->fig.raza>0) return 1;
121
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
TIPURI DE DATE DEFINITE DE UTILIZATOR
printf("nu s-a tastat un numar pozitiv\n"); } case PATRAT: for( ; ; ) { printf("latura patratului= "); if(gets(t) == 0 ) return 0; if(sscanf(t,"%lf",&p->fig.lat_p)==1 && p->fig.lat_p>0) return 1; printf("nu s-a tastat un numar pozitiv\n"); } case DREPTUNGHI: for( ; ; ) { printf("lungimea si latimea pe aceeasi linie: "); if(gets(t)==0) return 0; if(sscanf(t,"%lf %lf",&p->fig.lat_d[0], &p->fig.lat_d[1])==2 && p->fig.lat_d[0] > 0 && p->fig.lat_d[1] > 0) return 1; printf("nu s-au tastat 2 numere pozitive\n"); } case TRIUNGHI: for( ; ; ) { printf("laturile triunghiului pe aceeasi linie: "); if(gets(t) == 0 ) return 0; if(sscanf(t,"%lf %lf %lf",&p->fig.lat_t[0], &p->fig.lat_t[1], &p->fig.lat_t[2])==3 && p->fig.lat_t[0]>0 && p->fig.lat_t[1]>0 && p->fig.lat_t[2]> 0 ) return 1; printf("nu s-au tastat 3 numere\ pozitive\n"); } default: return 0; } } void main () /* citeste o litera mare care defineste o figura geometrica, apoi citeste elementele figurii respective; - calculeaza si afiseaza aria acelei figuri. */ { char t[255]; char er[]="s-a tastat EOF\n"; char lit[2]; FIG f; double a; for( ; ; ) { printf("Tastati una din literele mari: C\tD\tP\tT\n"); if(gets(t)==0) { printf(er); exit(1); } sscanf(t,"%ls",lit); switch(lit[0]) { case 'C': /* cerc */ f.tip = CERC; break; case 'D': /* dreptunghi */ f.tip = DREPTUNGHI; break;
122
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
ENUMERĂRI
case 'P': /* patrat */ f.tip = PATRAT; break; case 'T': /* triunghi */ f.tip = TRIUNGHI; break; default: /* eroare */ printf("Nu s-a tastat una din literele mari C,D,P sau T\n"); f.tip = EROARE; } if(f.tip != EROARE) break; } /* sfirsit for */ /* citeste elementele figurii */ if(citire_fig(&f)==0) { printf(er); exit(1); } /* calculeaza si afiseaza aria figurii */ if((a=aria(&f))==0) exit(1); printf("Aria figurii= %g\n", a); }
16.4 Enumerări
Tipul enumerare permite programatorului să folosească nume sugestive pentru valori numerice. De exemplu, în locul numărului unei luni calendaristice este mai sugestiv să folosim denumirea lunii respective sau eventual o prescurtare:
ian - Pentru ianuarie în locul cifrei 1 feb - Pentru februarie în locul cifrei 2 şi aşa mai departe. Un alt exemplu se referă la posibilitatea de a utiliza cuvintele FALS şi ADEVĂRAT
pentru valorile 0, respectiv 1. În felul acesta se obţine o mai mare claritate în programele sursă, deoarece valorile numerice sunt înlocuite prin sensurile atribuie lor într-un anumit context.
În acest scop se utilizează tipul enumerare. Un astfel de tip se declară printr-un format asemănător cu cel utilizat în cadrul structurilor. Un prim format general este:
enum nume {nume0, nume1, nume2,..., numek} d1,d2,...,dn; unde: nume - este numele tipului de enumerare introdus prin această declaraţie. nume0, nume1,..., numek - sunt nume care se vor utiliza în continuare în locul
valorilor numerice şi anume numei are valoarea i. d1,d2,...,dn - sunt date care se declară de tipul nume. Aceste date sunt similare
cu datele de tip int. Ca şi în cazul structurilor, în declaraţia de mai sus nu sînt obligatorii toate
elementele. Astfel, poate lipsi nume, dar atunci va fi prezent cel puţin d1. De asemenea, poate lipsi în totalitate lista d1, d2, ..., dn, dar atunci va fi prezent nume. În acest caz, se vor defini ulterior date de tip nume folosind un format de forma:
enum nume d1,d2,...,dn;
123
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
TIPURI DE DATE DEFINITE DE UTILIZATOR
16.5 Exemple
16.5.1 Exemplul 1 - enumerare nume luni
enum { ileg, ian, feb, mar, apr, mai, iun, iul, aug, sep, oct, nov, dec } luna;
Prin această declaraţie, numărul lunii poate fi înlocuit prin denumirea prescurtată a lunii respective. De exemplu, o atribuire de forma: luna = 3 se poate înlocui cu una mai sugestivă: luna = mar deoarece, conform declaraţiei de mai sus, mar are valoarea 3.
În mod analog, o expresie de forma: luna == 7 este identică cu expresia: luna == iul
Dacă în locul declaraţiei de mai sus s-ar fi utilizat declaraţia de tip enumerare: enum dl {ileg, ian, feb, mar, apr, mai, iun, iul, aug, sep, oct, nov, dec };
atunci putem declara ulterior data luna de tip dl astfel: enum dl luna;. Data luna declarată în acest fel este o dată identică cu data luna declarată la început.
16.5.2 Exemplul 2 - enumerare tip Boolean
Fie tipul enumerare Boolean declarat astfel: enum Boolean {false, true};
Declarăm data bisect de tip Boolean: enum Boolean bisect;
Atribuirea: bisect = an%4 == 0&&an%100 || an%400 ==0;
atribuie variabilei bisect valoarea 1 sau 0, după cum anul definit de variabila an este bisect sau nu (se presupune că anul aparţine intervalului [1600,4900]).
În continuare se pot folosi expresii de forma: bisect == false
sau bisect == true
16.6 Declaraţii de tip
Limbajul C permite atribuirea unui nume pentru un tip (predefinit sau utilizator) de date. Pentru aceasta se folosesc declaraţiile de tip. Forma generală a acestora este:
typedef tip nume_tip; Nume_tip poate fi folosit la declararea datelor în mod similar cuvintelor cheie
pentru tipurile predefinite. Exemplu: //1
typedef int INTREG; INTREG x, y; INTREG z=4;
//2
124
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
ALOCAREA DINAMICĂ A MEMORIEI
typedef struct{ double parte_reală; double parte_imaginară; } COMPLEX; COMPLEX x, y;
16.7 Alocarea dinamică a memoriei
Alocarea memoriei se poate realiza în următoarele moduri: alocare statică; alocare dinamică; alocare pe stivă.
Se alocă static memorie în următoarele cazuri: o pentru instrucţiunile de control propriu-zise; o pentru variabilele globale şi variabilele locale declarate în mod explicit static. Se alocă memorie pe stivă pentru variabilele locale. Se aloca dinamic memorie în mod explicit, cu ajutorul funcţiilor de alocare dinamica,
aflate în headerul <alloc.h>. În limbajul C, alocarea memoriei în mod dinamic se face cu ajutorul funcţiilor
malloc, calloc, realloc; eliberarea zonei de memorie se face cu ajutorul funcţiei free. Funcţiile de alocare/dezalocare a memoriei au prototipurile în header-ele <stdlib.h> şi <alloc.h>.
16.7.1 Funcţia malloc
Sintaxa: void *malloc(size_t nr_octei_de_alocat);
Funcţia malloc necesită un singur argument (numărul de octeţi care vor fi alocaţi) şi returnează un pointer generic către zona de memorie alocată (pointerul conţine adresa primului octet al zonei de memorie rezervate).
16.7.2 Funcţia calloc
Sintaxa: void *calloc(size_t nr_elemente, size_t mărimea_în_octeti_
a_unui_elem); Funcţia calloc alocă memorie pentru un tablou de nr_elemente, numărul de octeţi
pe care este memorat un element este mărimea_în_octeţi_a_unui_elem şi returnează un pointer către zona de memorie alocată.
16.7.3 Funcţia realloc
void *realloc(void *ptr, size_t mărime); Funcţia realloc permite modificarea zonei de memorie alocată dinamic cu ajutorul
funcţiilor malloc sau calloc.
125
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
TIPURI DE DATE DEFINITE DE UTILIZATOR
Obs.: În cazul în care nu se reuşeşte alocarea dinamică a memoriei (memorie insuficientă), funcţiile malloc, calloc şi realloc returnează un pointer null. Deoarece funcţiile malloc, calloc, realloc returnează un pointer generic, rezultatul poate fi atribuit oricărui tip de pointer. La atribuire, este indicat să se utilizeze operatorul de conversie explicită (vezi exemplu).
Eliberarea memoriei (alocate dinamic cu una dintre funcţiile malloc, calloc sau
realloc) se realizează cu ajutorul funcţiei free. void free(void *ptr);
16.8 Exemple
16.8.1 malloc
#include <iostream.h> #include <malloc.h> #include <string.h> #include <stdlib.h> void main() {char *sirstoc="SIR DE STOCAT IN MEMORIE"; char **psir; int nrart=5,i; char ch; if((psir=(char **) malloc(nrart*sizeof(char*)))==NULL) {cout << "Alocare esuata!\n"; exit(1);} else {for(i=0;i<nrart;i++) if( (psir[i] = (char *) malloc((strlen(sirstoc) + 1) * sizeof(char)))== NULL ) {cout << "Alocare esuata!\n"; exit(1);} else strcpy(psir[i],sirstoc); } cout << "Sirul " << sirstoc << " a fost alocat in " << nrart << "blocuri distincte.\n" for (i=0;i<nrart;i++)cout << psir[i] <<"\n"; cout << "Memoria pentru cele " << nrart << " blocuri " << sirstoc << \n";va fi eliberata apasind o tasta\n"; cin >> ch; for(i=0;i<nrart;i++)free(psir[i]); free(psir); }
16.8.2 calloc
//calloc #include <iostream.h> #include <malloc.h>
126
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
PROBLEME PROPUSE
float cere_element(int i) {float elem; cout << "a(" << (i+1) << ")="; cin >> elem; cout << "\n"; return elem; } void afis_tablou(int n,float *tablou) {int i; for(i=0;i<n;i++) cout << "a(" << (i+1) << ")=" << *(tablou+i) << "\n"; } void main() {int n,i; float *tablou; cout << "Specificati numarul de elemente ale tabloului, n="; cin >> n; tablou=(float *)calloc(n,sizeof(float)); if(tablou!=NULL) {cout << "\nIntroduceti elementele tabloului\n"; for(i=0;i<n;i++) *(tablou+i)=cere_element(i); cout << " Elementele tabloului sunt:\n"; afis_tablou(n,tablou); free(tablou); } else cout << "Alocare esuata!\n"; }
16.9 Probleme propuse
1. Realizaţi următoarele modificări la exemplul 16.1.6: a. Completaţi cu o funcţie de calcul şi afişare a mediei notelor tuturor candidaţilor
pentru fiecare probă (media tuturor elevilor la proba1, media la proba2, etc); b. Modificaţi lista alfabetică, astfel încât la elevii cu medie peste 5, să apară (alături
de medie) mesajul "Promovat", iar la ceilalţi, mesajul "Nepromovat"; c. Considerând că rezultatelor obţinute sunt utilizate la un concurs de admitere, la
care există N locuri (N introdus de la tastatură), şi de faptul că pentru a fi admis media trebuie să fie cel puţin 5, să se afişeze lista admişilor şi lista respinşilor, în ordinea descrescătoare a mediilor, în limita locurilor disponibile.
2. Să se scrie un program care să permită memorarea datelor privitoare la angajaţii unei firme mici: nume angajat, adresă, număr copii, sex, data naşterii, data angajării, calificare, salariul brut. Se vor implementa următoarele funcţii: a. Citirea informaţiilor despre cei N angajaţi (N introdus de la tastatură); b. Căutarea - după nume - a unui angajat şi afişarea informaţiilor despre acesta; c. Modificarea informaţiilor despre un anumit angajat; d. Lista alfabetică a angajaţilor, în care vor apare: nume, adresă, data angajării,
calificare, salariu; e. Lista angajaţilor în ordine descrescătoare a vechimii; f. Lista angajatilor cu un anumit numar de copii, C, introdus de la tastatură;
127
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
TIPURI DE DATE DEFINITE DE UTILIZATOR
g. Lista angajaţilor cu vârsta mai mare decât V (V introdus de la tastatură); h. Salariul minim, salariul mediu şi cel maxim din firmă; i. Lista de salarii, în care vor apare: numele, calificarea, salariul brut şi salariul net.
La sfârşitul listei vor apare totalurile pentru salariile brute, impozite, salarii nete. Pentru calculul salariului net se aplică următoarele reguli de impozitare:
i. I=15% pentru salariul brut (SB)<600 ii. I=50+20% pentru 600<=SB<1500 (20% din ceea ce depăşeşte
600) iii. I=100+30% pentru 1500<=SB<3000 iv. I=250+40% pentru 3000<=SB<15000 v. I=45% pentru SB>=1500
128
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
DESCHIDEREA UNUI FIŞIER
17. FIŞIERE
Noţiunea de fişier desemnează o colecţie de informaţii memorată pe un suport permanent (de obicei discuri magnetice), percepută ca un ansamblu, căreia i se asociază un nume (în vederea conservării şi regăsirii ulterioare).
Operaţiile care pot fi realizate asupra fişierelor sunt: deschiderea unui fişier, scrierea într-un fişier, citirea dintr-un fişier, poziţionarea într-un fişier, închiderea unui fişier.
17.1 Deschiderea unui fişier
17.1.1.1 Funcţia fopen Crează un flux de date între fişierul specificat prin numele extern (nume_fisier) şi
programul C. Parametrul mod specifică sensul fluxului de date şi modul de interpretare a acestora. Funcţia returnează un pointer spre tipul FILE, iar în caz de eroare - pointerul NULL (prototip în stdio.h).
FILE *fopen(const char *nume_fisier, const char *mod); Parametrul mod este o constantă şir de caractere, care poate conţine caracterele cu
semnificaţiile: r: flux de date de intrare; deschidere pentru citire; w: flux de date de ieşire; deschidere pentru scriere (crează un fişier nou sau
suprascrie conţinutul anterior al fişierului existent); a: flux de date de ieşire cu scriere la sfârşitul fişierului, adăugare, sau crearea
fişierului în cazul în care acesta nu există; +: extinde un flux de intrare sau ieşire la unul de intrare/ieşire; operaţii de
scriere şi citire asupra unui fişier deschis în condiţiile r, w sau a; b: date binare; t: date text (modul implicit).
Exemple: "r+" – deschidere pentru modificare (citire şi scriere); "w+" – deschidere pentru modificare (citire şi scriere); "rb" – citire binară; "wb" – scriere binară; "r+b" – citire/scriere binară.
17.1.1.2 Funcţia freopen (stdio.h) FILE *freopen(const char*nume_fis,const char*mod,FILE
*flux_date); Asociază un nou fişier unui flux de date deja existent, închizând legătura cu vechiul
fişier şi încercând să deschidă una nouă, cu fişierul specificat. Funcţia returnează pointerul către fluxul de date specificat, sau NULL în caz de eşec (prototip în stdio.h).
17.1.1.3 Funcţia open int open(const char *nume_fisier, int acces [,int mod]);
129
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FIŞIERE
Deschide fişierul specificat conform cu restricţiile de acces precizate în apel. Returnează un întreg care este un indicator de fişier sau -1 (în caz de eşec) (prototip în io.h).
Restricţiile de acces se precizează prin aplicarea operatorului "|" (disjuncţie logică la nivel de bit) între anumite constante simbolice, definite în fcntl.h, cum sunt :
O_RDONLY - citire O_WRONLY - scriere O_RDWR - citire şi scriere O_CREAT - creare O_APPEND - adăugare la sfârşitul fişierului O_TEXT - interpretare CR-LF O_BINARY - nici o interpretare
Restricţiile de mod de creare se realizează cu ajutorul constantelor: S_IREAD - permisiune de citire din fişier S_IWRITE - permisiune de scriere din fişier, eventual legate prin
operatorul "|"
17.1.1.4 Funcţia creat int creat(const char *nume_fişier, int un_mod);
Crează un fişier nou sau îl suprascrie în cazul în care deja există. Returnează indicatorul de fişier sau -1 (în caz de eşec). Parametrul un_mod este obţinut în mod analog celui de la funcţia de deschidere (prototip în io.h).
17.1.1.5 Funcţia creatnew int creatnew(const char *nume_fişier, int mod);
Crează un fişier nou, conform modului specificat. Returnează indicatorul fişierului nou creat sau rezultat de eroare (-1), dacă fişierul deja există (prototip în io.h).
După cum se observă, informaţia furnizată pentru deschiderea unui fişier este aceeaşi în ambele abordări, diferenţa constând în tipul de date al entitaţii asociate fişierului. Implementarea din io.h oferă un alt tip de control la nivelul comunicării cu echipamentele periferice (furnizat de funcţia ioctrl), asupra căruia nu vom insista, deoarece desfăşurarea acestui tip de control este mai greoaie, dar mai profundă.
17.2 Închiderea unui fişier
17.2.1.1 Funcţia fclose int fclose(FILE *pf);
Funcţia închide un fişier deschis cu fopen şi eliberează memoria alocată (zona tampon şi structura FILE). Returnează valoarea 0 la închiderea cu succes a fişierului şi -1 în caz de eroare (prototip în stdio.h).
17.2.1.2 Funcţia fcloseall int fcloseall(void);
Închide toate fluxururile de date şi returnează numărul fluxurilor de date închise (prototip în stdio.h).
17.2.1.3 Funcţia close
130
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
PRELUCRAREA FIŞIERELOR TEXT
int close(int indicator); Închide un indicator de fişier şi returnează 0 (în caz de succes) sau -1 în caz de eroare
(prototip în io.h).
17.3 Prelucrarea fişierelor text
17.3.1 Prelucrarea unui fişier la nivel de caracter
Fişierele pot fi scrise şi citite caracter cu caracter folosind funcţiile putc (pentru scriere) şi getc (citire).
17.3.1.1 Funcţia putc int putc (int c, FILE *pf);
c – este codul ASCII al caracterului care se scrie în fişier; pf – este pointerul spre tipul FILE a cărui valoare a fost returnată de funcţia fopen. Funcţia putc returnează valoarea lui c (valoarea scrisă în caz de succes), sau –1
(EOF) în caz de eroare sau sfârşit de fişier.
17.3.1.2 Funcţia getc int getc (FILE *pf);
Funcţia citeşte un caracter dintr-un fişier (pointerul spre tipul FILE transmis ca argument) şi returnează caracterul citit sau EOF la sfârşit de fişier sau eroare.
17.3.2 Exemplul 1
Să se scrie un program care crează un fişier text în care se vor scrie caracterele introduse de la tastatură (citite din fişierul standard de intrare), până la întâlnirea caracterului ^Z = Ctrl+Z. #include <stdio.h> #include <process.h> void main() { int c, i=0; FILE *pfcar; char mesaj[]="\nIntrodu caractere urmate de Ctrl+Z (Ctrl+D sub Linux):\n"; char eroare[]="\n Eroare deschidere fisier \n"; while(mesaj[i]) putchar(mesaj[i++]); pfcar=fopen("f_car1.txt","w"); // crearea fişierului cu numele extern f_car1.txt if(pfcar==NULL) { i=0; while(eroare[i]) putc(eroare[i++],stdout); exit(1); } while((c=getchar())!=EOF)// sau while((c=getc(stdin))!= EOF) putc(c,pfcar); // scrierea caracterului în fişier fclose(pfcar); // închiderea fişierului
131
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FIŞIERE
}
17.3.3 Exemplul 2
Să se scrie un program care citeşte un fişier text, caracter cu caracter, şi afişează conţinutul acestuia. #include <stdio.h> #include <process.h> void main() { int c, i=0; FILE *pfcar; char eroare[]="\n Eroare deschidere fisier \n"; pfcar=fopen("f_car1.txt","r"); //deschiderea fişierului numit f_car1.txt în citire if(pfcar==NULL) { i=0; while(eroare[i])putc(eroare[i++],stdout); exit(1); } while((c=getc(pfcar))!=EOF) //citire din fişier, la nivel de caracter putc(c,stdout); //scrierea caracterului citit în fişierul standard de ieşire (afişare pe monitor) fclose(pfcar); }
17.3.4 Exemplul 3
#include <stdio.h> #include <process.h> void main() { int c, i=0; FILE *pfcar; char mesaj[]="\nIntrodu caractere urmate de Ctrl+Z (Ctrl+D sub Linux):\n"; char eroare[]="\n Eroare deschidere fisier \n"; while(mesaj[i]) putchar(mesaj[i++]); pfcar=fopen("f_car1.txt","w"); // crearea fisierului cu numele extern f_car1.txt if(pfcar==NULL) { i=0; while(eroare[i]) putc(eroare[i++],stdout); exit(1); }
132
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
PRELUCRAREA FIŞIERELOR TEXT
while((c=getchar())!=EOF) // sau: while ((c=getc(stdin)) != EOF) putc(c,pfcar); // scrierea caracterului in fisier fclose(pfcar); // Inchiderea fisierului }
17.3.5 Prelucrarea unui fişier la nivel de cuvânt
Funcţiile putw şi getw (putword şi getword) sunt echivalente cu funcţiile putc şi getc, cu diferenţa că unitatea transferată nu este un singur octet (caracter), ci un cuvânt (un int).
int getw(FILE *pf); int putw(int w, FILE *pf);
Se recomandă utilizarea funcţiei feof pentru a testa întâlnirea sfârşitului de fişier.
17.3.6 Exemplul 1
int tab[100]; FILE *pf; // . . . deschidere fisier while (!feof(pf)){ for (int i=0; i<100; i++){ if (feof(pf)) break; tab[i]=getw(pf); //citire din fisier la nivel de cuvânt si memorare în vectorul tab // . . . } } printf("Sfarsit de fisier\n");
17.3.7 Prelucrarea unui fişier la nivel de şir de caractere
Într-un fişier text, liniile sunt considerate ca linii de text separate de sfârşitul de linie ('\n'), iar în memorie, ele devin şiruri de caractere terminate de caracterul nul ('\0'). Citirea unei linii de text dintr-un fişier se realizează cu ajutorul funcţiei fgets, iar scrierea într-un fişier - cu ajutorul funcţiei fputs.
Funcţia fgets este indentică cu funcţia gets, cu deosebirea că funcţia gets citeşte din fişierul standard de intrare (stdin). Funcţia fputs este indentică cu funcţia puts, cu deosebirea că funcţia puts scrie în fişierul standard de ieşire (stdout).
17.3.7.1 Funcţia fputs int fputs(const char *s, FILE *pf);
Funcţia scrie un şir de caractere într-un fişier şi primeşte ca argumente pointerul spre zona de memorie (buffer-ul) care conţine şirul de caractere (s) şi pointerul spre structura FILE. Funcţia returnează ultimul caracter scris, în caz de succes, sau -1 în caz de eroare.
17.3.7.2 Funcţia fgets
133
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FIŞIERE
char *fgets(char *s, int dim, FILE *pf); Funcţia citeşte maximum dim-1 octeţi (caractere) din fişier, sau până la întâlnirea sfârşitului de linie. Pointerul spre zona în care se face citirea caracterelor este s. Terminatorul null ('\0') este plasat automat la sfârşitul şirului (buffer-lui de memorie). Funcţia returnează un pointer către buffer-ul în care este memorat şirul de caractere, în caz de succes, sau pointerul NULL în cazul eşecului.
17.3.8 Exemplul 1
Să se scrie un program care crează un fişier text în care se vor scrie şirurile de caractere introduse de la tastatură. #include <stdio.h> void main() { int n=250; FILE *pfsir; char mesaj[]="\nIntrodu siruri car.urmate de Ctrl+Z(Ctrl+D sub Linux):\n"; char sir[250],*psir; fputs(mesaj,stdout); pfsir=fopen("f_sir.txt","w"); //deschiderea fisierului f_sir.txt pentru scriere psir=fgets(sir,n,stdin); // citirea sirurilor din fisierul standard de intrare while(psir!=NULL) { fputs(sir,pfsir); // scrierea în fisierul text psir=fgets(sir,n,stdin); } fclose(pfsir); }
17.3.9 Exemplul 2
Să se scrie un program care citeşte un fişier text, linie cu linie, şi afişează conţinutul acestuia. #include <stdio.h> void main() { int n=250; FILE *pfsir; char sir[250],*psir; pfsir=fopen("f_sir.txt","r"); psir=fgets(sir,n,pfsir); while(psir!=NULL) { fputs(sir,stdout); //sau: puts(sir); //afisarea (scrierea în fisierul standard de iesire) sirului (liniei) citit din fisierul text psir=fgets(sir,n,pfsir); //citirea unei linii de text din fisier } fclose(pfsir);}
134
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
PRELUCRAREA FIŞIERELOR TEXT
17.3.10 Exemplul 3
Să se scrie un program care creează un fişier text “tabel”. #include <stdio.h> #include <stdlib.h> #include <math.h> #include <string.h> #define PI 3.1415926 void main() { const n=250; int i,j,dec,sg; FILE *pfsir; char all[n],sir[n],*psir,*tab="\t",*cr="\n"; float x; pfsir=fopen("f_tab.xls","w"); //deschiderea fisierului f_tab.txt pentru scriere fputs("i\tsin\tcos\n",pfsir); // scrierea antetului fisierului text for(i=0;i<=90;i+=10) // for(j=0;j<=90;j+=10) { gcvt(i,5,sir); //conversie valoare reala->sir caractere strcpy(all,sir); //copiere caractere in sirul de scris strcat(all,tab); //concatenare caracter TAB x=sin(PI/180*i); gcvt(x,5,sir); strcat(all,sir); strcat(all,tab); x=cos(PI/180*i); gcvt(x,5,sir); strcat(all,sir); printf("\n%s",all); strcat(all,cr); fputs(all,pfsir); // scrierea în fisierul text } fclose(pfsir); }
17.3.11 Exemplul 4
Scrieţi un program care să facă o copie (caracter cu caracter) a unui fişier text dat. #include <stdio.h> void main(void) { FILE *in, *out; char sursa[13], dest[13]; fflush(stdin); printf("Dati sursa: "); scanf("%s",&sursa); fflush(stdin) printf("Dati destinatia: "); scanf("%s",&dest); if ((in = fopen (sursa, "rt")) == NULL)
135
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FIŞIERE
{ printf("Nu se poate deschide fisierul sursa.\n"); return; } if ((out = fopen(dest, "wt")) == NULL) { printf("Nu se poate crea fisierul destinatie.\n"); return; } // se copiaza caracterele din "in" in "out" while (!feof(in)) fputc(fgetc(in),out); fclose(in); fclose(out); }
17.4 Intrări/ieşiri binare
17.4.1 Exemplul 1
Să se scrie un program care creează un fişier binar în care se vor introduce numere reale, nenule. #include <iostream.h> #include <stdio.h> int main() { FILE *f; double nr; int x; if ((f= fopen("test_nrb.dat", "wb")) == NULL) //deschidere flux binar, scriere { cout<<"\nNu se poate deschide fisierul test_nrb.dat"<<'\n'; return 1; } cout<<"\nIntroduceti numere(diferite de 0) terminate cu un 0:"<<'\n'; cin>>nr; while(nr!=0) { x=fwrite(&nr, sizeof(nr), 1, f); //scriere în fisier cin>>nr; } fclose(f); return 0; }
17.4.2 Exemplul 2
Să se scrie un program care citeşte dintr-un fişier binar numere reale, nenule. #include <iostream.h> #include <stdio.h> int main()
136
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
INTRĂRI/IEŞIRI BINARE
{ FILE *f; double buf; if ((f= fopen("test_nrb.dat", "rb")) == NULL) { cout<<"\nNu se poate deschide fisierul test_nrb.dat"<<'\n'; return 1; } cout<<"\nNumerele nenule citite din fisier sunt:"<<'\n'; while((fread(&buf, sizeof(buf), 1, f))==1) // functia sizeof(buf) care returneaza numarul de octeti necesari variabilei buf. cout<<buf<<" "; fclose(f); cout<<'\n'; return 0; }
17.4.3 Fişier binar cu structuri
Să se scrie un program pentru crearea unui fişier binar, având articole structuri cu următoarele câmpuri:
• Nume depunător - şir de maxim 30 de caractere; • Data depunerii - o structură având câmpurile întregi: zi, lună, an; • Suma depusă - o valoare reală. Articolele sunt grupate pe zile în ordine cronologică. Datele se introduc de la consolă,
fiecare pe trei linii. Să se afişeze apoi conţinutul fişierului.
17.4.3.1 Rezolvare Vom introduce mai întâi datele într-o ordine aleatoare, apoi le vom sorta după dată. În final, vectorul de structuri va fi scris în fişierul "output.dat".
17.4.3.2 Programul //Fisiere binare - Depuneri #include <stdio.h> #include <stdlib.h> #include <conio.h> void main (void) { // Cream un vector de articole pentru a le sorta ulterior dupa data depunerii. // Articolul suplimentar este necesar la sortare. // In plus, vom citi ceea ce am scris in fisier intr-un vector separat de articole. struct { char nume[30]; struct { int zi, luna, an; } data; double suma; } articole [20], articol, citite[20];
137
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FIŞIERE
FILE *f; int n; // Numarul de articole int found;// Folosit la sortare // Citire date de intrare printf("Introduceti numarul de articole: "); scanf ("%d", &n); for (int i=0; i<n; i++) { printf ("Introduceti numele depunatorului: "); scanf ("%s", articole[i].nume); printf ("Introduceti data depunerii <ZZ/LL/AAAA>: ") ; scanf ("%d/%d/%d", &articole[i].data.zi, \ &articole[i].data.luna, &articole[i].data.an); printf("Introduceîi suma depusa: "); scanf ("%lf", &articole[i].suma); } // Sortam dupa data depunerii do { found=0; for (i=0; i<n-1; i++) // Testam cazurile in care data articolului curent este 'mai mare' decat data articolului urmator if ( (articole[i].data.an > articole[i+1].data.an) \ || (articole[i].data.an == articole[i+1].data.an \ && articole[i].data.luna > articole[i+1].data.luna) \ || (articole[i].data.an == articole[i+1].data.an \ && articole[i].data.luna == articole[i+1].data.luna \ && articole[i].data.zi > articole[i+1].data.zi) ) { articol = articole[i]; articole[i] = articole[i+1]; articole[i+1] = articol; found = 1; } } while (found); // Deschidere fisier if((f=fopen("output.dat","wb")) == NULL) { printf(" Eroare la deschiderea fisierului! "); exit (1); } // Scriem in fisier si il inchidem // Scriem intai numarul de articole fwrite(&n, sizeof(int), 1, f) ; fwrite(&articole, sizeof(articol), n, f); fclose(f); if ((f=fopen ("output.dat","rb")) == NULL ) { printf (" Eroare la deschiderea fi-ierului! "); exit (1); }
138
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
INTRĂRI/IEŞIRI BINARE
fread (&n, sizeof(int), 1, f); fread (&citite, sizeof(articol), n, f); for (i=0; i<n; i++) printf (" Articolul %d: %s, %d/%d/%d, %lf\n", i+1, \ citite[i].nume, citite[i].data.zi, \ citite[i].data.luna, citite[i].data.an, \ citite[i].suma); fclose(f); getch(); }
17.4.4 Fisier cu structuri - linie de comanda cu parametri
Un fişier conţine articole cu structura: cod (şir de caractere), nume (şir de caractere) şi cantitate (real). Să se scrie un program care permite:
creare; consultare; ştergere. Opţiunea se introduce ca argument al liniei de comandă, prin numele complet al
operaţiei: • Creare Nume_fisier - Se creează fişierul Nume_fisier prin citirea de la tastatură a
articolelor. După fiecare linie introdusă se interoghează dacă se continuă; • Consultare Nume_fisier - Conţinutul fişierului Nume_fisier este listat pe ecran, câte
20 de linii. Pentru continuarea afişării se apasă ENTER; • Ştergere Nume_fisier cod_articol - Este căutat articolul în fişier şi se marchează
punându-i codul xxx.
17.4.4.1 Programul #include <stdio.h> #include <stdlib.h> #include <string.h> #include <conio.h> #define FALSE 0 #define TRUE 1 struct ARTICOL { char cod[10]; char nume[30]; float cantitate; }; // Executa functia de creare fisier void creare(char *fisier) { FILE *f; struct ARTICOL a; // Deschid fisierul pentru scriere in mod binar if ((f=fopen(fisier,"wb")) == NULL) { printf (" Nu pot deschide fisierul. \n"); exit (1); } do
139
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FIŞIERE
{ //Articolele citite unul cate unul si scrise in fisier printf (" Introduceti codul, numele si cantitatea: "); scanf("%s %s %f", &a.cod, &a.nume, &a.cantitate); fwrite(&a,sizeof(ARTICOL),1,f); printf("Doriti sa continuati ? (d/n)\n"); } while (getch()=='d'); fclose(f); } // Executa functia de consultare fisier void consultare(char *fisier) { FILE *f; struct ARTICOL a; int i=1; // Deschid fisierul pentru citire in mod binar if ((f=fopen(fisier,"rb")) == NULL) { printf("Nu pot deschide fisierul. \n"); exit (1) ; } while(fread(&a,sizeof(ARTICOL),1,f)>0) // Am grija sa nu afisez articolele care au fost sterse if(strcmp(a.cod,"xxx")!=0) { printf("%10s %30s %10.2f\n",a.cod,a.nume,a.cantitate); // Daca am afisat 20 de articole, ma opresc si intreb if (i++%20==0) { printf("Doriti sa continuati ? (d/n)\n"); if (getch()=='n') break; } } fclose(f); } // Executa functia de stergere void stergere(char *fisier,char *cod) { FILE *f; struct ARTICOL a; int gasit=FALSE; // Fisierul este deschis pentru citire/scriere in mod binar f=fopen(fisier,"r+b"); while(fread(&a,sizeof(ARTICOL),1,f)>0) if(strcmp(a.cod,cod)==0) { // Marchez articolul ca fiind sters strcpy(a.cod,"xxx") ; //Ma pozitionez cu o Inregistrare inainte pentru a suprascrie articolul fseek(f,ftell(f)-sizeof(ARTICOL),SEEK_SET); fwrite(&a,sizeof(ARTICOL),1,f);
140
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
POZIŢIONAREA ÎNTR-UN FIŞIER
gasit=TRUE; break; } if (!gasit) printf("Eroare: Articolul nu a fost gasit\n"); fclose(f); } void main(int argc, char **argv) { if(strcmp(argv[1],"Creare")==0) creare(argv[2]); if (strcmp(argv[1],"Consultare")==0) consultare(argv[2]); if (strcmp(argv[1],"Stergere")==0) stergere(argv[2],argv[3]); }
17.5 Poziţionarea într-un fişier
Pe lângă mecanismul de poziţionare implicit (asigurat prin operaţiile de citire şi scriere) se pot folosi şi operaţiile de poziţionare explicită.
17.5.1.1 Funcţia fseek int fseek(FILE *pf, long deplasament, int referinta);
Funcţia deplasează capul de citire/scriere al discului, în vederea prelucrării înregistrărilor fişierului într-o ordine oarecare. Funcţia setează poziţia curentă în fluxul de date la n octeţi faţă de referintă. deplasament – defineşte numărul de octeţi peste care se va deplasa capul discului; referinta – poate avea una din valorile: 0 - începutul fişierului (SEEK_SET); 1 - poziţia curentă a capului (SEEK_CUR); 2 - sfârşitul fişierului (SEEK_END). Funcţia returnează valoarea zero la poziţionarea corectă şi o valoare diferită de zero
în caz de eroare (prototip în stdio.h).
17.5.1.2 Funcţia lseek int lseek(int indicator, long n, int referinta);
Seteaza poziţia curentă de citire/scriere în fişier la n octeţi faţa de referintă. Returnează valoarea 0 în caz de succes şi diferită de zero în caz de eroare (prototip în io.h).
17.5.1.3 Funcţia fgetpos int fgetpos(FILE *flux_date, fpos_t *pozitie);
Determină poziţia curentă (pointer către o structură, fpos_t, care descrie această poziţie în fluxul de date). Înscrie valoarea indicatorului în variabila indicată de pozitie. Returnează 0 la determinarea cu succes a acestei poziţii sau valoare diferită de zero în caz de eşec. Structura care descrie poziţia poate fi transmisă ca argument funcţiei fsetpos (prototip în stdio.h).
141
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FIŞIERE
17.5.1.4 Funcţia fsetpos int fsetpos(FILE *flux_date, const fpos_t *pozitie);
Setează poziţia curentă în fluxul de date (atribuie indicatorului valoarea variabilei indicate pozitie), la o valoare obţinută prin apelul funcţiei fgetpos. Returnează valoarea 0 în caz de succes, sau diferită de 0 în caz de eşec (prototip în stdio.h).
Există funcţii pentru modificarea valorii indicatorului de poziţie şi de determinare a poziţiei curente a acestuia.
17.5.1.5 Funcţia ftell long ftell(FILE *pf);
Indică poziţia curentă a capului de citire în fişier. Funcţia returnează o valoare de tip long int care reprezintă poziţia curentă în fluxul de date (deplasamentul în octeţi a poziţiei capului faţă de începutul fişierului) sau -1L în caz de eroare (prototip în stdio.h).
17.5.1.6 Funcţia tell long tell(int indicator);
Returnează poziţia curentă a capului de citire/scriere în fişier (exprimată în număr de octeţi faţă de începutul fişierului), sau -1L în caz de eroare (prototip în io.h).
17.5.1.7 Funcţia rewind void rewind(FILE *flux_date);
Poziţionează indicatorul la începutul fluxului de date specificat ca argument (prototip în stdio.h).
17.6 Funcţii utilitare pentru lucrul cu fişiere
17.6.1 Funcţii de testare a sfârşitului de fişier
17.6.1.1 Funcţia feof int feof(FILE *flux_date);
Returnează o valoare diferită de zero în cazul întâlnirii sfârşitului de fişier sau 0 în celelalte cazuri (prototip în stdio.h).
17.6.1.2 Funcţia eof int eof(int indicator);
Returnează valoarea 1 dacă poziţia curentă este sfârşitul de fişier, 0 dacă indicatorul este poziţionat în altă parte, sau -1 în caz de eroare (prototip în io.h).
17.6.2 Funcţii de golire a fluxurilor de date
17.6.2.1 Funcţia fflush int fflush(FILE *flux_date);
Goleşte fluxul de date specificat ca argument. Returnează 0 în caz de succes şi -1 (EOF) în caz de eroare (prototip în stdio.h).
17.6.2.2 Funcţia flushall
142
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
int flushall(void); Goleşte toate fluxurile de date existente, pentru cele de scriere efectuând şi scrierea în
fişiere. Returnează numărul de fluxuri asupra cărora s-a efectuat operaţia (prototip în stdio.h).
17.7 Alte operaţii cu fişiere
Funcţii care permit operaţii ale sistemului de operare asupra fişierelor
17.7.1.1 Funcţia remove int remove(const char *nume_fisier);
Şterge un fişier. Returnează valoarea 0 pentru operaţie reuşită şi -1 pentru operaţie eşuată (prototip în stdio.h).
17.7.1.2 Funcţia rename int rename(const char *nume_vechi, const char *nume_nou);
Redenumeşte un fişier. Returnează 0 pentru operaţie reuşita şi -1 în cazul eşecului (prototip în stdio.h).
17.7.1.3 Funcţia unlink int unlink(const char *nume_fisier);
Şterge un fişier. Returnează 0 la operaţie reuşită şi -1 la eşec; dacă fişierul are permisiune read-only, funcţia nu va reuşi operaţia (prototip în io.h, stdio.h).
17.8 Exemple
17.8.1 Fişier despre angajaţii unei întreprinderi
Să se creeze un fişier binar, care va conţine informaţiile despre angajaţii unei întreprinderi: nume, marca, salariu. Să se afişeze apoi conţinutul fişierului. #include<iostream.h> #include <stdio.h> #include <ctype.h> typedef struct { char nume[20];int marca;double salariu; }angajat; union {angajat a;char sbinar[sizeof(angajat)];}buffer; int main() {angajat a; FILE *pf; char cont;char *nume_fis; cout<<"Nume fisier care va fi creat:"; cin>>nume_fis; if ((pf= fopen(nume_fis, "wb")) == NULL) { cout<<"\nEroare creare fisier "<<nume_fis<<"!\n"; return 1; } do {cout<<"Marca : ";cin>>a.marca; cout<<"Nume : ";cin>>a.nume;
143
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FIŞIERE
cout<<"Salariu :";cin>>a.salariu; buffer.a=a; fwrite(buffer.sbinar,1,sizeof(angajat),pf); cout<<"Continuati introducerea de date (d/n) ?"; cin>>cont; } while(toupper(cont)!='N'); fclose(pf); //citirea informaţiilor if ((pf= fopen(nume_fis, "rb")) == NULL) { cout<<"\nEroare citire fisier "<<nume_fis<<"!\n"; return 1; } for(;;) { fread(buffer.sbinar,1,sizeof(a),pf); a=buffer.a1; if(feof(pf)) exit(1); cout<<" Marca : "<<a.marca; cout<<" Numele : "<<a.nume<<'\n'; cout<<" Salariul : "<<a.salariu<<'\n'; } fclose(pf); }
17.8.2 Aplicaţie pentru gestiunea materialelor dintr-un depozit
Aplicaţia va avea un meniu principal şi va permite gestiunea următoarelor informaţii: codul materialului (va fi chiar "numărul de ordine"), denumirea acestuia, unitatea de măsură, preţul unitar, cantitatea contractată şi cea recepţionată (vectori cu 4 elemente). Memorarea datelor se va face într-un fişier de date (un fişier binar cu structuri), numit "material.dat". Aplicaţia conţine următoarele funcţii: help() - informare privind opţiunile programului Funcţii pentru fişierele binare, care să suplinească lipsa funcţiilor standard pentru
organizarea directă a fişierelor binare: citireb() - citire în acces direct din fişier; scrieb() - scriere în acces direct în fişier; citmat() - citirea de la terminal a informaţiilor despre un material; afismat() - afişarea informaţiilor despre un material (apelată de list); lungfisis() - determinarea lungimii fişierului existent; crefis() - creare fişier. Funcţii pentru adăugarea, modificarea, ştergerea şi listarea de materiale.
#include <process.h> #include <iostream.h> #include <stdio.h> #include <ctype.h> typedef struct material { int codm,stoc,cant_c[4],cant_r[4]; char den_mat[20],unit_mas[4]; float pret; }; material mat; FILE *pf;
144
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
void crefis(),adaug(),modif(),sterg(),list(),help(); void main() { char optiune; do //afisarea unui meniu de optiuni si selectia optiunii { cout<<'\n'<<"Optiunea Dvs. de lucru este"<<'\n' <<"(c|a|m|s|l|e|h pentru help) : "; cin>>optiune; switch(optiune) { case 'c':case 'C':crefis();break; case 'a':case 'A':adaug();break; case 'm':case 'M':modif();break; case 's':case 'S':sterg();break; case 'l':case 'L':list();break; case 'h':case 'H':help();break; case 'e':case 'E': break; default:help(); break; } }while(toupper(optiune)!='E'); } void help() // afisare informatii despre utilizarea meniului si optiunile acestuia {cout<<"Optiunile de lucru sunt :"<<'\n'; cout<<" C,c-creare fisier"<<'\n'; cout<<" A,a-adaugare"<<'\n'; cout<<" M,m-modificare"<<'\n'; cout<<" L,l-listare"<<'\n'; cout<<" S,s-stergere"<<'\n'; cout<<" H,h-help"<<'\n'; cout<<" E,e-exit"<<'\n'; } long int lungfis(FILE *f) // returnează lungimea fisierului {long int posi,posf; posi=ftell(f); fseek(f,0,SEEK_END); posf=ftell(f); fseek(f,posi,SEEK_SET); return posf; } void scrieb(int nr,void *a,FILE *f) //scriere în fisierul binar {long depl=(nr-1)*sizeof(material); fseek(f,depl,SEEK_SET); if(fwrite(a,sizeof(material),1,f)!=1) {cout<<"Eroare de scriere in fisier !"<<'\n'; exit(1); } } void citireb(int nr,void *a,FILE *f) //citire din fisierul binar {long depl=(nr-1)*sizeof(material);
145
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FIŞIERE
fseek(f,depl,SEEK_SET); if(fread(a,sizeof(material),1,f)!=1) {cout<<"Eroare de citire din fisier !"<<'\n'; exit(2); } } void afismat(material *a) //afisarea informatiilor despre un anumit material { int i; if(a->codm) {cout<<"Cod material : "<<a->codm<<'\n'; cout<<"Denumire material: "<<a->den_mat<<'\n'; cout<<"Cantitati contractate:"<<'\n'; for(i=0;i<4;i++) cout<<"Contractat "<<i<<" : "<<a->cant_c[i]<<'\n'; cout<<"Cantitati receptionate:"<<'\n'; for(i=0;i<4;i++) cout<<"Receptionat "<<i<<" : "<<a->cant_r[i]<<'\n'; cout<<"Stoc : "<<a->stoc<<'\n'; cout<<"Unitate de masura: "<<a->unit_mas<<'\n'; cout<<"Pret unitar : "<<a->pret<<'\n'; } else cout<<"Acest articol a fost sters !"<<'\n'; } void citmat(material *a) //citirea informatiilor despre un anumit material { int i;float temp; cout<<"Introduceti codul materialului (0=End): ";cin>>a->codm; if(a->codm==0) return; cout<<"Introduceti denumirea materialului : ";cin>>a->den_mat; cout<<"Introduceti unitatea de măsură : ";cin>>a->unit_mas; cout<<"Introduceti pretul : ";cin>>temp;a->pret=temp; cout<<"Introduceti cantitatile contractate : "<<'\n'; for(i=0;i<4;i++) {cout<<"Contractat "<<i+1<<" : ";cin>>a->cant_c[i]; } cout<<"Introduceti cantitatile receptionate : "<<'\n'; for(i=0;i<4;i++) {cout<<"Receptionat "<<i+1<<" : ";cin>>a->cant_r[i]; } } void crefis() //deschidere fisier { if((pf=fopen("material.dat","r"))!=NULL) cout<<"Fisierul exista deja !"<<'\n'; else pf=fopen("material.dat","w"); fclose(pf); }
146
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
EXEMPLE
void adaug() //adăugare de noi materiale { int na; pf=fopen("material.dat","a");//deschidere pentru append na=lungfis(pf)/sizeof(material); do {citmat(&mat); if(mat.codm) scrieb(++na,&mat,pf); } while(mat.codm); fclose(pf); } void modif() //modificarea informatiilor despre un material existent { int na; char ch; pf=fopen("material.dat","r+"); do {cout<<"Numarul articolului de modificat este (0=END): ";cin>>na; if(na) {citireb(na,&mat,pf); afismat(&mat); cout<<"Modificati articol (D/N) ? :"; do { cin>>ch; ch=toupper(ch); } while(ch!='D' && ch!='N'); if(ch=='D') {citmat(&mat); scrieb(na,&mat,pf); } } }while(na); fclose(pf); } void sterg() //stergerea din fisier a unui material { int n;long int na; pf=fopen("material.dat","r+"); mat.codm=0; na=lungfis(pf)/sizeof(material); do { do {cout<<"Numarul articolului de sters este (0=END): ";cin>>n; if(n<0||n>na) cout<<"Articol eronat"<<'\n'; }while(!(n>=0 && n<=na)); if(n) scrieb(n,&mat,pf); }while(n); fclose(pf); } void list() //afisare informatii despre un anumit material
147
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
FIŞIERE
{ int na; pf=fopen("material.dat","r"); do {cout<<"Numarul articolului de listat este (0=END): ";cin>>na; if(na) {citireb(na,&mat,pf); afismat(&mat); cout<<'\n'; } }while(na); fclose(pf); }
17.9 Probleme propuse
1. Scrieţi un program de tipărire a conţinuturilor mai multor fişiere, ale căror nume se transmit ca parametri către funcţia main. Tipărirea se face pe ecran (lungimea paginii = 22) sau la imprimantă (lungimea paginii = 61). Conţinutul fiecărui fişier va începe pe o pagină nouă, cu un titlu care indică numele fişierului. Pentru fiecare fişier, paginile vor fi numerotate (cu ajutorul unui contor de pagini).
2. Scrieţi un program care citeşte un fişier text. Pornind de la conţinutul acestuia, se va crea un alt fişier, prin înlocuirea spaţiilor consecutive cu unul singur. Se vor afişa pe ecran conţinutul fişierului de la care s-a pornit şi conţinutul fişierului obţinut.
3. Să se consulte conţinutul unui fişier şi să se afişeze următoarele informaţii statistice: numărul de cuvinte din fişier, numărul de caractere, numărul de linii, numărul de date numerice (nu cifre, numere!).
4. Scrieţi un program care să compare conţinutul a două fişiere, şi afişaţi primele linii care diferă şi poziţia caracterelor diferite în aceste linii.
5. Scrieţi un program care citeşte conţinutul unui fişier sursă scris în limbajul C şi afişează în ordine alfabetică fiecare grup al numelor de variabile care au primele n caractere identice (n este citit de la tastatură).
6. Scrieţi un program care consultă un fişier text şi afişează o listă a tuturor cuvintelor din fişier. Pentru fiecare cuvânt se vor afişa şi numerele liniilor în care apare cuvântul.
7. Scrieţi un program care citeşte un text introdus de la tastatură şi afişează cuvintele distincte, în ordinea crescătoare a frecvenţei lor de apariţie. La afişare, fiecare cuvânt va fi precedat de numărul de apariţii.
8. Scrieţi un program care citeşte un text introdus de la tastatură, ordonează alfabetic liniile acestuia şi le afişează.
9. Scrieţi o aplicaţie pentru gestiunea informatiilor despre cărţile existente într-o bibliotecă. Aplicaţia va avea un meniu principal care va permite:
• Memorarea datelor într-un fişier (un fişier binar cu structuri), al cărui nume se introduce de la tastatură. Fişierul va conţine informaţiile: nume carte, autor, editura, anul apariţiei, preţ. Pentru fiecare carte, se va genera o cotă (un număr unic care să constituie cheia de căutare).
• Adăugarea de noi cărţi; • Afişarea informaţiilor despre o anumită carte;
148
Programarea calculatoarelor
şi limbaje de programare
Cristian Iosifescu
Universitatea "Dunarea de Jos"
Galati
PROBLEME PROPUSE
• Căutarea titlurilor după un anumit autor; • Modificarea informaţiilor existente; • Lista alfabetică a tuturor autorilor; • Ştergerea unei cărţi din bibliotecă; • Ordonarea descrescătoare după anul apariţiei; • Numele celei mai vechi cărţi din bibliotecă; • Numele celei mai scumpe cărţi din bibliotecă; • Numele autorului cu cele mai multe cărţi; • Valoarea totală a cărţilor din bibliotecă.
149