FisierFinal

108
UNIVERSITATEA DE STAT DIN MOLDOVA Eleonora Seiciuc Lucia Bitcovschi Programarea în limbajul C Instrucţiunu metodice, probleme rezolvate, lucrări de laborator 1

Transcript of FisierFinal

Page 1: FisierFinal

UNIVERSITATEA DE STAT DIN MOLDOVA

Eleonora Seiciuc Lucia Bitcovschi

Programarea în limbajul C

Instrucţiunu metodice, probleme rezolvate, lucrări de laborator

Chişinău 2010

1

Page 2: FisierFinal

Cuprins

Introducere......................................................................................................................................2

Lucrare de laborator N1..................................................................................................................3

Lucrare de laborator N2..................................................................................................................8

Lucrare de laborator N3................................................................................................................14

Lucrare de laborator N4................................................................................................................20

Lucrare de laborator N5................................................................................................................25

Lucrare de laborator N6................................................................................................................33

Lucrare de laborator N7................................................................................................................41

Lucrare de laborator N8................................................................................................................48

Lucrare de laborator N9................................................................................................................56

Lucrare de laborator N10..............................................................................................................65

Bibliografie...............................................................................................................................................................78

2

Page 3: FisierFinal

Introducere

Disciplina „Fundamentele programării” se studiază de studenţii facultăţii „Matematică şi Informatică” în semestrele 1 şi 2 şi prevede studierea limbajului de programare C.

Broşura dată se doreşte a fi un supliment la manualele de C/C++ existente pe piaţa lucrărilor de informatică. Ea este o culegere de lucrări de laborator, dar nu se limitează doar la asta. Fiecare lucrare de laborator este precedată de un set de sugestii şi indicaţii teoretice de lucru care au ca scop oferirea în mod succint a funcţiilor şi instrucţiunilor limbajului referitor la tema lucrării. La fel fiecare lucrare de laborator conţine mai multe probleme rezolvate, fiind prezentate programele respective (cu explicaţiile necesare), şi un set de probleme propuse spre rezolvare. La fiecare lucrare sunt propuse şi un şir de de întrebări de control pentru testarea cunoştinţelor.

Sunt propuse 10 lucrări de laborator:

№ lucr. Denumirea lucrării № ore1. Funcţii de intrare/ieşire, tipuri de bază. 6-82. Operatori, operanzi, expresii şi funcţii matematice în limbajul C. 4-63. Instrucţiuni ciclice. 6-84. Pointeri şi tablouri. 6-85. Prelucrarea şirurilor de caractere. 4-66. Lucrul cu tablourile unidimensionale. 4-67. Lucrul cu tablourile bidimensionale. 4-68. Subprograme. 6-89. Tipuri de date definite de utilizator, redenumirea tipurilor. 6-810. Prelucrarea fişierelor. 4-6

Toate lucrările de laborator şi exemplele respective pot fi rulate pe un calculator PC, cu compilatorul Borland C++ 3.1. Astfel, majoritatea exemplelor din lucrare, chiar dacă sunt scrise în limbajul C standard (deci neobiectual), folosesc un minim de facilităţi aduse de limbajul C++, cum ar fi comentariile cu simbolurile “//” şi declararea variabilelor simultan cu iniţializarea lor, în cadrul unor instrucţiuni repetitive.

Studenţii efectuează fiecare lucrare de laborator, o salvează pe calculator şi susţin lucrarea. Susţinerea lucrări se face, de regulă, în mod practic la calculator prin prezentarea lucrării şi testarea asistată de calculator pe întrebările de control venite din partea profesorului.

3

Page 4: FisierFinal

Lucrare de laborator N1

Tema: Funcţii de intrare/ieşire, tipuri de bază.

Scopul lucrării: Însuşirea funcţiilor de intrare/ieşire, utilizarea lor la introducerea şi extragerea datelor sub controlul unor formate şi fără aceasta.

Indicaţii şi sugestii de lucru:

Funcţia clrscr() şterge ecranul. Are prototipul void clrscr(void) şi se află în fişierul <conio.h>.

Funcţia getch() citeşte fără ecou un caracter de la intrarea standard direct în memorie, fără acţionarea tastei Enter. La citirea unui caracter ASCII funcţia returnează codul caracterului citit. La citirea unui caracter ne ASCII funcţia se apelează de două ori: la primul apel ea returnează valoarea 0, iar la cel de al doilea apel ea returnează o valoare specifică tastei acţionate. Are prototipul int getch(void), în fişierul <conio.h>.

Funcţia getche() citeşte cu ecou un caracter de la intrarea standard direct în memorie, fără acţionarea tastei Enter. La citirea unui caracter ASCII funcţia se apelează de două ori: la primul apel ea returnează valoarea 0, iar la cel de al doilea apel ea returnează o valoare specifică tastei acţionate. Are prototipul int getche(void), în fişierul <conio.h>.

Funcţia putch(e) scrie un caracter la ieşirea standard. Ea are un singur parametru. Funcţia returnează codul imaginei extrase, adică valoarea lui e. De exemplu, putch(‘\n’), trece cursorul pe linia următoare în aceeaşi coloană.

Funcţia getchar() citeşte cu ecou caractere ASCII de la intrarea standard într-un tampon special până la acţionarea tastei Enter. La acţionarea tastei Enter, ea returnează codul caracterului curent din tampon. La următorul apel funcţia returnează codul caracterului următor din tampon. Dacă în tampon nu mai sunt caractere, atunci apelul funcţiei impune citirea unui nou set de caractere de la intrarea standard în tampon. Prototipul este: int putchar(int c), în fişierul <stdio.h>.

Funcţia getc() citeşte din flux un caracter.Funcţia gets() citeşte cu ecou un şir de caractere ASCII de la intrarea standard care se

termină cu <Enter>. Ea are un parametru valoarea căruia este adresa de început a zonei de memorie unde se păstrează şirul de caractere citit. De obicei acest parametru este numele unui tablou unidimensional de tip char. La apăsarea tastei Enter funcţia nu scrie caracterul newline (‘\n’) în memorie, ci caracterul NUL (‘\0’), care semnifică sfârşitul şirului. Deci, ‘\n’ se substitute prin ‘\0’. Fiecare caracter ocupă un octet în memorie. Rezultă că un şir de n caractere ocupă n+1 octeţi.

Funcţia puts(s) scrie la ieşirea standard un şir de caractere ASCII, care în memorie se termină cu caracterul NUL (‘\0’), Ea are un parametru, valoarea căruia este adresa de început a şirului de extras. De obicei, acest parametru este numele unui tablou unidimensional de tip char. La întâlnirea caracterului NUL, funcţia nu scrie acest caracter, ci trece cursorul la începutul liniei următoare, adică se substituie caracterul ‘\0’ prin ‘\n’.

Funcţia returnează adresa de început a zonei de memorie unde se păstrează şirul citit, adică adresa primului caracter. Dacă întâlneşte caracterul EOF, funcţia returnează valoarea 0. Are prototipul în fişierul <stdio.h>.

Funcţia putchar(e) scrie un caracter ASCII la ieşirea standard. Ea returnează codul caracterului extras sau -1 în caz de eroare. Aici putchar(‘\n’), ca şi putchar(10), trece cursorul la începutul liniei următoare.

Funcţia are prototipul int putchar(int e), în fişierul <stdio.h>.Funcţia printf(c, p1, p2, p3, ...) scrie la ieşirea standard date sub controlul unor formate.

Are unul sau mai mulţi parametri. De obicei, parametrul c este un şir de caractere scris în

4

Page 5: FisierFinal

ghilimele, care conţine textele eventuale de extras şi specificatorii de format eventuali pentru datele de extras. Textele din parametrul c sunt extrase fără schimbare. Secvenţele escape, cum ar fi ‘\n’, ‘\t’, ‘\0’ ş.a., nu sunt extrase ci sunt executate. Parametrii p1, p2, p3, ... sunt expresii, valorile cărora vor fi extrase. La fiecare din aceşti parametri, în şirul de caractere c, îi corespunde un specificator de format, care indică cum se va extrage valoarea respectivă. Un specificator de format începe cu % şi se termină cu una sau două litere anumite. El determină conversia valorii de extras din formatul intern în formatul extern. Parametrii p1, p2, p3, pot lipsi. Atunci vor fi extrase numai textele din parametrul c.

Funcţia returnează numărul de octeţi (caracter) extraşi la ieşirea standard sau -1 în caz de eroare. Ea are prototipul în fişierul <stdio.h>.

Funcţia scanf(c, p1, p2, p3, ...) citeşte de la intrarea standard date sub controlul unor formate. Are mai mulţi parametri. De obicei, parametrul c este un şir de caractere scris în ghilimele, care conţine specificatori de format pentru datele de la intrare. El poate conţine şi caractere albe care sunt neglijate. Parametrii p1, p2, p3, ... sunt adresele zonelor de memorie unde se vor păstra datele citite. De obicei, adresa unei zone de memorie se exprimă prin operatorul & în faţa numelui unei variabile simple sau cu indice. La fiecare dintre aceşti parametri, în şirul de caractere c, îi corespunde un specificator de format, care indică cum se va citi data respectivă de la intrare. Un specificator de format începe cu % şi se termină cu una sau două litere anumite. El determină conversia datei de citit din formatul extern în formatul intern.

Se cunosc următorii specificatori: %d, %i - întreg, %f - real, %lf - real lung, %ld - întreg lung, %u-întreg fără semn, %c - citeşte caracterul curent, %s - citeşte şirul, %e - real în format exponenţial, %p - pointer.

Funcţia citeşte toate datele ce corespund specificatorilor de format din parametrul c. Dacă o dată de la intrare nu corespunde specificatorului de format, atunci citirea se întrerupe. Funcţia returnează numărul datelor citite corect. Ea are prototipul în fişierul <stdio.h>.

Funcţia fflush(stdin) goleşte stream-ul intrării standard (şterge conţinutul buferului tastaturii). Ea are prototipul în fişierul <process.h>.

Funcţia exit(c) întrerupe execuţia programului. Parametrul c defineşte starea programului în momentul apelului funcţiei. De obicei, valoarea 0 a parametrului c defineşte o stare normală de terminare a execuţiei programului, iar o valoare diferită de 0 semnifică prezenţa unei erori. Se foloseşte pentru a termina execuţia unui program. Funcţia are prototipul în fişierul <stdlib.h> .

sizeof este un operator care determină dimensiunea în octeţi a unei date sau a unui tip de date. De exemplu, sizeof(int) returnează numărul de octeţi necesari pentru a păstra o valoare de tipul int, iar sizeof d returnează numărul de octeţi alocaţi datei cu numele d.

Tipuri de dateTipuri de date

statice

dinamice

simple

structurate

caracter

reale

întregi

enumerativ

logic

mulţime

şir

articol

masiv

fişier

5

Page 6: FisierFinal

Tipuri simple de dateTipuri simple de date

3.4*10-4932.. 3.4*10493210long double

1.7*10-308.. 1.7*103088double

3.4*10-38..3.4*10384float

Real

-231..231-14long [int]

0..232-14unsigned long

-32768..327672[short] [int]0..655352unsigned [int]

0..255 (0..28-1)1unsigned char

-128..127 (-27..27-1)1[signed] char

Întreg

DomeniuDomeniu de de valorivaloriLungimeLungime

((octeocte ţţii ))TipulTipul

GrupaGrupa

de de datdatăă

Exemple de programe:

Exemplul 1.1. Programul citeşte o literă minusculă şi extrage caracterul precedent acestei litere din setul de caractere al calculatorului.#include<conio.h>#include<stdio.h>void main(void){ char c; clrscr(); c=getchar(); putchar(c-1); getch();}

Exemplul 1.2. Programul citeşte un şir de caractere şi extrage lungimea şirului citit.#include<conio.h>#include<stdio.h>#include<string.h>void main(void){ char s[256]; clrscr(); gets(s); printf(“şirul are %d caractere”,strlen(s)); getch();}

Exemplul 1.3. Programul defineşte şi citeşte 4 numere de la tastatură de tip int, float, long double, char şi le afişează la ecran.#include<conio.h>#include<stdio.h>void main(void){ char c=’a’; int k=3; float f=5.9; double d=9.999; clrscr(); printf(“%c\t%d\t%f\t%lf”,c,k,f,d); getch();

6

Page 7: FisierFinal

}

Exemplul 1.4. Programul afişează între două caractere ‘*’ constanta 123.456f (definită prin directiva #define) cu diferiţi specificatori de format pentru date de tip float.#include<conio.h>#include<stdio.h>#define a 123.456fvoid main(void){ clrscr(); printf(“*%f*\n”,a); printf(“*%2f*\n”,a); printf(“*%20f*\n”,a); printf(“*%-20f*\n”,a); printf(“*%020f*\n”,a); printf(“*%.2f*\n”,a); printf(“*%.10f*\n”,a); printf(“*%2.2f*\n”,a); printf(“*%2.10f*\n”,a); printf(“*%20.10f*\n”,a); printf(“*%-20.10f*\n”,a); printf(“*%020.10f*\n”,a); getch();}

Exemplul 1.5. Programul citeşte cu getch() caractere ne ASCII şi apoi extrage codul fiecăruia cu printf().#include<conio.h>#include<stdio.h>void main(void){char a;clrscr();getch(); // primul apelprintf("al doilea apel:%d\n",getch());getch(); // primul apel a=getch(); // al doilea apelprintf("al doilea apel:%d\n",a);getch(); // primul apel printf("al doilea apel:%d\n",a=getch());getch();

}

Exemplul 1.6. Este dat numărul întreg a. Folosind numai operaţia de înmulţire să se calculeze a8 prin trei operaţii. #include<conio.h>#include<stdio.h>void main(void){ int a,k,l,f; clrscr(); printf("introduceţi valoarea lui a”); scanf(“%d”,&a); k=a*a; //a2

l=k*k; //a4

f=l*l; //a8

printf("rezultat=%d",f); getch();}

Probleme propuse spre rezolvare:

1. Programul citeşte două numere întregi şi afişează media lor aritmetică.

7

Page 8: FisierFinal

2. Programul afişează între două caractere ‘*’ constanta 123.456 (definită prin directiva #define) cu următorii specificatori de format: %d, %2d, %10d, %-10d, %010d, %ld, %u, %lu.3. Programul afişează în zecimal, octal şi hexazecimal constanta 123456789 definită prin directiva #define.4. Programul citeşte un caracter ne ASCII (cu getchar()) şi apoi afişează (cu printf()) codul caracterului citit şi caracterul.5. Programul citeşte (cu scanf()) un număr întreg zecimal format din cel mult nouă cifre şi apoi afişează (cu printf()) numărul citit în zecimal, octal şi hexazecimal.6. Sunt date trei numere de tipul: int, float, double. Calculaţi suma lor, produsul şi diferenţa lor şi afişaţi rezultatele la ecran.7. Programul citeşte (cu scanf()) o dată calendaristică sub forma ddmmyy (o succesiune de 6 cifre) şi apoi o afişează (cu printf()) sub forma 20yy/mm/dd. Aici dd, mm şi yy sunt numere din două cifre care reprezintă respectiv ziua, luna şi anul.8. Programul citeşte (cu scanf()) numele şi prenumele unei persoane separate prin spaţii albe, apoi afişează (cu printf()) numele pe un rând şi prenumele pe alt rând.

9. Sunt date numere întregi x şi y. Să se obţină: .

10. Dat a întreg. Folosind doar operaţia de înmulţire să se calculeze a2, a5, a17 prin şase operaţii.11. Dat a întreg. Folosind doar operaţia de înmulţire să se calculeze a4, a12, a28 prin şase operaţii.12. S - au amestecat v1 litri de apă de temperatura t1 cu v2 litri de apă de temperatura t2. Să se calculeze volumul şi temperatura compoziţiei obţinute.13. Sunt date x şi y numere întregi. Să se găsească media aritmetică şi media geometrică a modulului lor.14. Este dat x întreg. Folosind numai operaţia de înmulţire, adunare şi scădere, să se calculeze expresia: 2x4-3x3+4x2-5x+6. Se permit nu mai mult de 4 operaţii de înmulţire, 4 operaţii de adunare şi scădere.15. Sunt date lungimile catetelor triunghiului drept. Să se găsească ipotenuza şi aria lui.16. Sunt date numerele întregi x şi y. Folosind numai operaţiile de înmulţire, adunare şi scădere, să se calculeze: 3x2y2-2xy2-7x2y-4y2+15xy+2x2-3x+10y+6. Se permite folosirea nu mai mult de opt operaţii de înmulţire, de adunare şi scădere.17. Programul citeşte (cu scanf()) o majusculă şi apoi afişează (cu printf()) minusculele corespunzătoare.18. Folosind operatorul sizeof afişaţi câtă memorie se rezervă pentru fiecare tip de date (char, signed char, unsigned char, short, signed short, unsigned short, int, signed int, unsigned int, long int, long signed int, long unsiged int, float, double, long double).

Întrebări de control:

1. Cum se lansează un program la execuţie în Turbo C++ ?2. În care fişiere se află prototipurile funcţiilor standard ?3. Cum se afişează Help-ul pentru o funcţie standard, de exemplu clrscr() ?4. Care sunt deosebirile dintre funcţiile getche() şi getchar() ?5. Ce valori returnează funcţiile de intrare ?6. Ce valori returnează funcţiile de ieşire ?7. Cum şi pentru ce se utilizează funcţia exit() ?8. Care sunt funcţiile de citire cu ecou ?9. Care funcţii de intrare cer acţionarea tastei Enter ?10. char a;

unsigned char b;a=200; b=200;printf(“întreg %d\t caracter %c”,a, a);

printf(“\n întreg %d\t caracter %c”,b, b);

Ce se va extrage la ecran? Explicaţi.

8

Page 9: FisierFinal

Lucrare de laborator N2

Tema: Operatori, operanzi, expresii şi funcţii matematice în limbajul C.

Scopul lucrării: .Utilizarea corectă a operatorilor, alcătuirea corectă a expresiilor cu respectarea regulilor de conversie implicită şi conversia forţată a datelor.

Suport teoretic:

O expresie este o secvenţă de caractere care specifică o regulă pentru calculul unei valori. Această valoare poate fi: numerică, alfanumerică, booleană sau de tip structurat. Trebuie să vă mărturisim că acum a sosit momentul să definim acest termen mult mai precis.

O expresie poate fi foarte simplă. Cifra 7 singura (o constantă) şi litera M (o variabila) sunt expresii valide. Dar, o expresie poate fi de asemenea foarte complicată.

Observaţi membrul drept al enunţului de mai jos:m:=7*a+b*(j+sqrt(x))

unde: 7, a, j si x sunt toate expresii; 7*a este o expresie; Funcţia sqrt(x) este o expresie; j+sqrt(x), cu sau fără paranteze exterioare, este o expresie; Tot membrul drept este o expresie.

O expresie are sens, în timpul compilării, dacă toate elementele componente au fost în prealabil declarate şi au fost respectate regulile de sintaxă a limbajului. O expresie se calculează în timpul execuţiei dacă, după momentul când s-a ajuns la codul obiect, tuturor identificatorilor li s-au atribuit valori (specifice) care permit să fie evaluaţi.

Fiecare din cei trei operatori (+,-, | |) care pot fi folosiţi pentru conectarea termenilor unor expresii simple se numesc operatori de adăugare (adding operators).

Fiecare din cei patru operatori (*, /, % şi &&) care pot fi folosiţi pentru conectarea factorilor se numesc operatori de multiplicare (multiplying operator).

Pentru mişcarea biţilor spre stânga şi spre dreapta, se folosesc operaţiile << şi >>. Deoarece biţii sunt mutaţi către un capăt, la celălalt capăt se adaugă zerouri. (În cazul unui întreg negativ cu semn o deplasare la dreapta va determina introducerea unui 1, astfel încât bitul de semn se va păstra.) Biţii deplasaţi dincolo de capăt nu se întorc la capătul celălalt, ci sunt pierduţi.

Operaţiile de deplasare a biţilor pot fi foarte utile atunci când decodificaţi intrarea de la un dispozitiv extern. O deplasare la dreapta împarte efectiv un număr cu 2, iar o deplasare la stânga îl înmulţeşte cu 2.

Funcţiile matematice: pow(x,y), poly(x, n, c[]), sin(x), sqrt(x), cos(x), exp(x), log(x), log10(x), asin(x), acos(x), atan(x) au prototipul în fişierul <math.h>. Toate funcţiile trigonometrice presupun argumentul exprimat în radiani. Pentru a transforma gradele în radiani se înmulţesc gradele cu , unde constanta .

Tabela 2.1: Funcţii matematice din fişierul math.h

Prototipul funcţiei Efect

double acos(double x); arccosinus de x

double asin(double x); arcsinus de x

double atan(double x); arctangenta de x

double atan2(double y, double x); arctangenta de y/x

double ceil(double x); cel mai mic intreg mai mare sau egal cu x

9

Page 10: FisierFinal

double cos(double x); cosinus de x

double exp(double x); exponenţiala

double fabs(double x); valoarea absoluta a lui x

double floor(double x); cel mai mare intreg mai mic sau egal cu x

double log(double x); ln de x

double log10(double x); lg de x

double pow(double x, double y); x la puterea y

double sin(double x);calculează valoarea funcţiei sinus de unghiul x

exprimat în radiani.

double sqrt(double x); radicalul lui x

double tan(double x); tangenta lui x

double poly(x, n, c[])calculează valoarea polinomului p=cnxn+cn-1xn-1+...+c2x2+c1x+c0

Media geometrică a numerelor a1, a2,...,an este (a1*a2*...*an)(1/n).

Tabela 2.2: Operatori şi descrierea lor.

Operatorul Descrierea

< mai mic

<= mai mic şi egal

> mai mare

>= mai mare şi egal

!= diferit

== egal

&& a&&b are valoarea 1, atunci şi numai atunci, când şi a şi b au valori diferite de 0.

!negarea logică, !a are valoarea 0 (false), dacă a are valoarea diferit de 0 şi 1 (true), dacă a are

valoarea 0.

| | sau

~ complement faţă de 1

<< deplasare la stânga

>> deplasare la dreapta

^ sau logic pe biţi

+= suma cu atribuire

++ increment

-- decrementul

/ împărţire

%= restul împărţirii egal

?: condiţie

10

Page 11: FisierFinal

Tabela 2.3: Codurile ASCII.

0 Ctrl | 25 Ctrl Y 50 2 75 K 105 I

1 Ctrl A 26 Ctrl Z 51 3 76 L 106 J

2 Ctrl B 27 ESCAPE 52 4 77 M 107 K

3 Ctrl C 28 Ctrl < 53 5 78 N 108 L

4 Ctrl D 29 Ctrl / 54 6 79 O 109 M

5 Ctrl E 30 Ctrl = 55 7 80 P 110 n

6 Ctrl F 31 Ctrl - 56 8 81 Q 111 o

7 Ctrl G 32 BLANK 57 9 82 R 112 p

8 Ctrl H 33 ! 58 : 83 S 113 q

9 Ctrl I 34 " 59 ; 84 T 114 r

10 \n 35 # 60 < 85 U 115 s

11 Ctrl K 36 $ 61 = 86 V 116 t

12 Ctrl L 37 % 62 > 87 W 117 u

13 Return 38 & 63 ? 88 X 118 v

14 Ctrl N 39 ' 64 @ 89 Y 119 w

15 Ctrl O 40 ( 65 A 90 Z 120 x

16 Ctrl P 41 ) 66 B 92 \ 121 y

17 Ctrl Q 42 * 67 C 97 a 122 z

18 Ctrl R 43 + 68 D 98 b 123 {

19 Ctrl S 44 , 69 E 99 c 124 |

20 Ctrl T 45 - 70 F 100 d 125 }

21 Ctrl U 46 . 71 G 101 e 126 ~

22 Ctrl V 47 / 72 H 102 f

23 Ctrl W 48 0 73 I 103 g

24 Ctrl X 49 1 74 J 104 h

Exemple de programe:

Exemplul 2.1. Sunt date 2 variabile de tip real. Să se efectueze operaţiile suma, produs şi împărţire.#include<stdio.h>#include<conio.h>void main(){ float k,l; clrscr(); printf("dati k si l:"); scanf("%f%f",&k,&l); printf("suma=%.2f",k+l); printf("\nimpartirea=%.2f",k/l); printf("\nprodus=%.2f",k*l); getch();}

11

Page 12: FisierFinal

Exemplul 2.2. Este dat un număr întreg. Programul verifică dacă numărul introdus este pozitiv, negativ sau zero.#include <stdio.h>void main(){ int nr; printf("Numar="); scanf("%d",&nr); (nr<0)?printf("negativ\n"):((nr>0)?printf("pozitiv\n") : printf("zero\n"));}

Exemplul 2.3. Programul citeşte două numere întregi şi testează operatorii >> şi <<. Tastaţi programul pentru: x=1, u=4; x=2, u=8; x=3, u=5; x=-1, u=-1; x=-5, u=-5.#include<stdio.h>#include<conio.h>void main(){ long x,y; int u,v; clrscr(); printf("dati x,u:"); scanf("%ld%d",&x,&u); //deplasare la stânga a lui u, înseamnă înmulţirea lui cu 2 v=u<<2; printf("\nu=%d\t%d<<2=%d\n",u,u,v); //deplasare la dreapta a lui x, înseamnă împărţirea lui cu 2 y=x>>2; printf("\nx=%ld\t%ld>>2=%ld\n",x,x,y); getch();}

Exemplul 2.4. Programul determine maximul şi minimul dintre două numere întregi date.#define max(x,y) x>y?x:y#define min(x,y) x<y?x:y#include <stdio.h>void main(){ int x,y;printf(“daţi x şi y”);scanf(“%d%d”,&x,&y);printf(“maximul=%d”,max(x,y));printf(“\nminimul=%d”,min(x,y));getch();

}

Exemplul 2.5. Să se determine aria unui triunghi în funcţie de lungimile laturilor sale.#include<stdio.h>#include<conio.h>#include<math.h>void main(){float a,b,c,p,aria;printf(“Daţi lungimile laturilor:\n”);scanf(“%f%f%f”,&a,&b,&c);p=(a+b+c)/2;aria=sqrt(p*(p-a)*(p-b)*(p-c));printf(“Aria este: %7.3f”,aria);getch();

}

Exemplul 2.5. Este dat n întreg. Să se afle ultima cifră a lui n.#include<stdio.h>#include<conio.h>void main(){ int n,c;

12

Page 13: FisierFinal

clrscr(); printf("n="); scanf("%d",&n); n=n%10; printf("c=%d",c); getch();}

Probleme propuse spre rezolvare:1. Să se calculeze puterea a n-a a lui 2, unde n este un întreg dat de la tastatură, folosind

operatorul de deplasare la stânga.2. Să se găsească lungimea dintre două puncte cu coordonatele x1, y1 şi x2, y2.3. Fie a, b, c trei numere reale. Să se verifice dacă a, b pot reprezenta lungimile laturilor

unui dreptunghi, respectiv c să fie diagonala în acel dreptunghi.4. Sunt date a, b, c numere întregi. Să se verifice, dacă se execută expresia: a < b < c.5. Sunt date x, y, z. Să se calculeze:

a. max(x, y, z);b. max(x+y+z, xyz);c. min2(x+y+z/2, xyz)+1.

6. Sunt date c,d. Să se calculeze: , unde x1-

rădăcina mare, iar x2 - rădăcina mică a ecuaţiei .7. Sunt date a, b. Să se calculeze s:

a. ;

b. ;

c. ;

d. ;

e. .

8. Sunt date x, y. Să se calculeze a, b, dacă:

a. , ;

b. , ;

c. , ;

d. , ;

e. , ;

13

Page 14: FisierFinal

f. , ;

g. , ;

h. , ;

Întrebări de control:

1. Ce este o expresie, un operand, un operator. Ce operatori cunoaşteţi?2. Explicaţi cum se utilizează operatorul adresă & ?

3. Explicaţi cum se utilizează operatorul condiţionat ? :.4. Ce specificatori de format se folosesc pentru a citi şi a scrie date numerice flotante de tipul long double? 5. Fie int x=2, y; y=--x; x=y--; Care este valoarea lui x?6. Fie int x=2, y; y=x++; x=++y; Care este valoarea lui x?7. Fie char c; c=’R’+’m’-‘M’; Care este tipul valorii lui c şi ce va afişa printf(“%d”,c)?8. Explicaţi cum lucrează funcţiile abs(), log10(), pow(x, z) şi daţi exemple?9. Care sunt specificatorii pentru tipurile: int, float, char, double şi care este diapazonul acestor tipuri?10.Fie int x=1, y=2, n=3, m=4; n=x/y; m=x%y; Care sunt valorile lui n şi m?

14

Page 15: FisierFinal

Lucrare de laborator N3

Tema: Instrucţiuni ciclice.

Scopul lucrării: Însuşirea instrucţiunilor limbajului.

Suport teoretic:

Instrucţiunea compusă este un bloc de instrucţiuni cu formatul:{declaraţii; instrucţiuni;}. La începutul blocului prin declaraţii se pot defini şi iniţializa date de diferite tipuri. Prin instrucţiuni se realizează prelucrarea datelor.

Instrucţiunea if este o instrucţiune de ramificare. Ea are două formate: incomplet şi complet. Formatul incomplete este: if (expresie) instrucţiune1.

La întâlnirea acestei instrucţiuni se evaluează expresia din paranteze. Dacă expresia are valoarea adevăr, adică o valoare diferită de 0, atunci se execută instrucţiune1 şi apoi se trece la instrucţiunea imediat următoare după instrucţiunea if. În caz contrar, se trece imediat la instrucţiunea următoare.

Deci forma generală a instrucţiunii if este: if (expresie) instrucţiune1; else instrucţiune2; Se evaluează expresia din paranteză şi în caz de adevăr se execută instrucţiune1, altfel se execută instrucţiune2. După aceasta se trece la instrucţiunea următoare după if. Instrucţiunile instrucţiune1 şi instrucţiune2 pot fi simple şi compuse.

Instrucţiunile if pot fi incluse una în alta.Instrucţiunea for este o instrucţiune de ciclu condiţionat şi are formatul: for(i1; i2; i3)

instrucţiune; Aici i1, i2, i3 sunt expresii: i1 este expresia de iniţializare a ciclului, i2 este expresia care determină condiţia de repetare a ciclului, i3 este expresia de reiniţializare a ciclului; instrucţiune este corpul ciclului şi poate fi o instrucţiune simplă sau compusă. Corpul ciclului sunt acele instrucţiuni de prelucrare a datelor care trebuie repetate. Şi corpul ciclului poate lipsi. În acest caz ciclul constă numai din antet şi instrucţiunea vidă: for(i1; i2; i3);

Instrucţiunea for se execută în felul următor: se efectuează operaţiile de iniţializare ale ciclului i1, apoi se evaluează expresia i2. Dacă i2 are o valoare diferită de 0, adică valoarea adevăr, atunci se execută instrucţiune – corpul ciclului. În caz contrar, când i2 are valoarea 0, adică valoarea fals, se termină execuţia ciclului for şi se trece la instrucţiunea următoare după ciclu. După execuţia corpului, ciclul se reiniţializează – se execută operaţiile definite de i3 şi se revine iarăşi la verificarea condiţiei de repetare a ciclului i2.

Instrucţiunea while este o instrucţiune de ciclul condiţionat şi are formatul: while(i1) instrucţiune; antetul ciclului este while(i1) şi conţine în paranteze expresia i1 care este condiţia de repetare a ciclului. Corpul ciclului este instrucţiune şi poate fi o instrucţiune simplă sau compusă. Ea conţine acele operaţii care trebuie repetate în ciclu. Corpul ciclului poate lipsi. Se evaluează i1 şi corpul ciclului se execută de atâtea ori de câte ori i1 are valoarea adevăr.

Instrucţiunea do-while se execută astfel: mai întâi se execută instrucţiune, adică corpul ciclului, apoi se evaluează i1, care este condiţia de repetare a ciclului. Dacă i1 este adevăr, atunci se repetă execuţia corpului ciclului. În caz contrar, adică dacă i1 este 0, atunci se termină execuţia ciclului şi se trece la instrucţiunea următoare după ciclu.

Instrucţiunea continue se foloseşte în corpul unui ciclu şi are formatul: continue; Instrucţiunea dată abandonează iteraţia curentă a ciclului şi trece la iteraţia următoare a lui.

Instrucţiunea break se foloseşte numai în corpul unui ciclu sau în instrucţiunea switch. La întâlnirea instrucţiunii break în corpul unui ciclu se termină execuţia ciclului şi se trece la instrucţiunea următoare după ciclu. La folosirea instrucţiunii break în instrucţiunea switch se iese din instrucţiunea switch şi se trece la instrucţiunea următoare după switch.

Instrucţiunea switch este o instrucţiune care realizează o alternativă din mai multe alternative posibile şi are formatul:

15

Page 16: FisierFinal

switch (expresie) {         case valoare1: instructiune1; break;

case valoare2: instructiune2; break;…

case valoaren: instructiunen; break; default: instructiune; } In limba engleza, switch înseamnă comutator. Conform acestei forme generale, după

cuvântul cheie  switch, există o expresie de tip  int sau compatibilă cu aceasta (deci poate fi şi de tip  char, byte sau  short, dar nu de tip long), a cărei valoare serveşte drept comutator. Se deschide apoi acolada corpului instrucţiunii, în care există mai multe cazuri. Fiecare caz începe prin cuvântul cheie case, urmat de o valoare de tip întreg, după care apar una sau mai multe instrucţiuni (simple sau compuse) şi opţional intrucţiunea break. După ce s-au epuizat toate cazurile, opţional se poate scrie cuvântul cheie  default urmat de una sau mai multe instrucţiuni şi se închide acolada corpului instrucţiunii switch.

Executarea instrucţiunii  switch decurge astfel: se evaluează mai întâi expresie şi se obţine o valoare, care serveşte drept comutator. Această valoare se compară, de sus în jos, cu fiecare din valorile indicate după cuvintele cheie  case, până când se găseşte prima  valoare care coincide cu cea a comutatorului. Dacă s-a găsit o astfel de valoare, se execută toate instrucţiunile care încep cu cazul respectiv şi se încheie la prima instrucţiune  break întâlnită sau, în lipsa acesteia, până la acoladă de închidere a corpului instrucţiunii  switch.  dacă însă nici unul din cazuri nu conţine valoarea potrivită a comutatorului, atunci se execută instrucţiunile care urmează după cuvântul cheie  default sau, în lipsa acestuia, nu se execută nimic.

Instrucţiunele case şi default se folosesc numai în instrucţiunea switch.Instrucţiunea goto este o instrucţiune de salt necondiţionat. Ea are formatul goto nume,

unde nume este numele unei etichete. Eticheta este un identificator (un nume) care se scrie în faţa unei instrucţiuni cu simbolul ‘:’ după el. De exemplu lab1: i++; Aici numele lab1 este o etichetă. La întâlnirea instrucţiunii goto lab1; se trece imediat la execuţia instrucţiunii cu eticheta lab1 în faţă, adică la instrucţiunea i++.

Instrucţiunea return se foloseşte pentru a reveni dintr-o funcţie. Ea are formatul return; sau return expresie; În primul caz, funcţia din care se revine nu returnează nici o valoare. Al doilea caz se foloseşte când funcţia returnează o valoare şi anume valoarea expresie defineşte valoarea de returnat. Tipul valorii pentru expresie trebuie să coincidă cu tipul indicat în antetul funcţiei respective pentru valoarea returnată. Instrucţiunea return poate fi scrisă în orice punct al corpului unei funcţii, însă nu este obligatorie. În corpul aceleaşi funcţii pot fi scrise mai multe instrucţiuni return.

Exemple de programe:

Exemplul 3.1. Este dat n întreg. Să se afle prima cifra a lui n (n=123, prima cifră este 1).#include<stdio.h>#include<conio.h>void main(){ int n,c; clrscr(); printf("n="); scanf("%d",&n); //cât n este mai mare ca 9 se face împărţirea lui n la 10, până se

ajunge la prima cifră while(n>9) n=n/10; printf("prima cifra este=%d",n); getch();}

Exemplul 3.2.Este dat n întreg. Să se numere din câte cifre este compus n (n=345, c=3).#include<stdio.h>

16

Page 17: FisierFinal

#include<conio.h>void main(){ int n,c; //c este un contor, iniţial are valoarea zero c=0; clrscr(); printf("n="); scanf("%d",&n);

//atât cât n este mai mare ca zero, n se împarte la zece şi c creşte while(n>0){ n=n/10; c=c+1; } printf("c=%d",c); getch();}

Exemplul 3.3. Date a, b două numere întregi. Să se afle cel mai mic multiplu comun al lor.#include<stdio.h>#include<conio.h>void main(){ int i,min,a,b,div; float mult; clrscr(); printf("a, b"); scanf("%d%d",&a,&b); if(a<b) min=a; else min=b; //mai întâi găsim minimul dintre a şi b //parcurgem ciclul până la minim for(i=1;i<=min;i++) //găsim cel mai mare divizor comun a lui a şi b if((a%i==0)&&(b%i==0)) div=i; //calculăm multiplu comun mult=(a*b)/(float)div; //float în faţa lui div-pentru conversie de tip printf("multiplu comun a 2 numere=%.2f", mult); getch();}

Exemplul 3.4. Să se calculeze expresia: .

#include<stdio.h>#include<conio.h>void main(){ int i,n; float produs; clrscr(); printf("n="); scanf("%d",&n); //notăm iniţial produsul cu valoarea 1 produs=1; for(i=1;i<n;i++) produs=produs*(1+(1/(float)(i*i))); printf("produs=%.2f",s); getch();}

Exemplul 3.5. Este dat numărul n . Să se verifice dacă n este număr prim sau nu(număr prim se împarte la 1 şi la el însăşi (1, 2, 3, 5, 7, 11 etc.)).

#include<stdio.h>#include<conio.h>void main(){ int i,n,prime; prime=1; clrscr(); printf("n=");

17

Page 18: FisierFinal

scanf("%d",&n); //parcurgem ciclul de la 2 până la jumătatea lui n for(i=2; i<n/2; i++) if(n%i==0) prime=0; //dacă n are divizori atunci if(prime==1) printf(“n este număr prim”); else printf(“n nu este număr prim”); getch();}

Exemplul 3.6. Folosind instrucţiunea case şi do while calculăm:a. Este dat numărul n să se verifice dacă este număr perfect(suma divizorilor este egală cu el însăşi 6=1+2+3);

b. Să se calculeze expresia: ;

c. Să se calculeze expresia: , , .

#include<stdio.h>#include<conio.h>#include<math.h>void main(){

int i,n,f,s1,s2,x,y,n1;float s=0,s3,e;char c;clrscr();s1=s2=0; s=0; x=y=1; f=1;printf("n=");scanf("%d",&n);do{

printf("\n1:se verifica daca este perfect");printf("\n2:sa se calculeze expresia din punctual b");printf("\n3:sa se calculeze suma din punctual c");printf("\n4:esirea\n");c=getch(); //aşteapta alegerea unei operaţiiswitch(c){ //c primeşte una din valorile (1- 4)

case '1':for(i=1; i<n; i++){// aflăm divizorii lui n şi calculăm suma lor

if(n%i==0) s1=s1+i;}if(s1==n) printf("numar perfect"); else printf("nu este numar perfect");break;case '2':for(i=1; i<n; i++) { f=f*i; //calculăm factorialul s=s+(pow(-1,i)*(i+1))/f; }printf("factorial=%d\tsuma=%f\n",f,s); break;case '3':printf("dati x"); scanf("%d",&x);e=0,0001; s3=1; n1=1; y=x;while(abs(y)>e)

{ n1=n1+1; s3=s3+y; y=y*(float)(x/n1);}

printf("\ns=%f\tn=%d\n",s3,n1);printf("\ny=%d\n",y); break; }}

while(c!='4'); //ciclul lucrează atât timp pân[ c va primi valoarea 4 getch();}

Exemplul 3.7. Să se afişeze toate numerele prime din intervalul [2;50].#include<stdio.h>

18

Page 19: FisierFinal

#include<conio.h>void main(){int i,j;int prim=0; //for(i=2; i<50; i++) {

for(j=2; j<i; j++){// dacă restul împărţirii nu e zero, atunci are loc instrucţiunea

//de continue, în caz contrar se trece la else if(i%j) continue; else { prim=1; break; //dacă s-a găsit un număr prim se iese din ciclu

} }

if(!prim) printf("%3d",i); prim=0;}getch();}

Probleme propuse spre rezolvare:

1. Este dat x număr întreg. Să se calculeze f(x):

a.

b.

c.

2. Programul citeşte valorile a, b, c de tip long, rezolvă ecuaţia ax2+bx+c=0 şi afişează rezultatul.

3. Programul citeşte un număr întreg din segmentul [1;7] şi afişează denumirea zilei din săptămână ce corespunde acestei cifre (1 – luni, 2 – marţi,…, 7 - duminică).

4. Un număr natural n se numeşte perfect daca este egal cu suma divizorilor săi naturali mai mici ca n. Sa se determine toate numerele perfecte până la un număr dat.

5. Pentru n şi x numere întregi date să se calculeze:

a. ; d. ; g. ;

b. ; e. ; h. ;

c. f. ; i.

.

6. Pentru n dat să se calculeze: , , , ,

7. Pentru ; n dat, să se

calculeze:

19

Page 20: FisierFinal

8. Pentru Sunt date u, v, să se calculeze:

9. Sa se afle toate numerele întregi pozitive formate din 3 cifre, egale cu media aritmetica a numerelor obţinute din fiecare din aceste numere în urma efectuării tuturor permutărilor (inclusiv cea identica) din cifrele sale.

10. Sa se scrie un program care să calculeze cel de-al n-lea număr al şirului lui Fibonacci (Astfel, fiecare număr Fibonacci este suma celor două numere Fibonacci anterioare, rezultând secvenţa 0, 1, 1, 2, 3, 5, 8, 13,...).

11. Sunt date a, b numere întregi. Să se determine toate numerele prime din intervalul [a, b].12. Pentru un număr n dat să se determine dacă n este număr polindrom (număr polindrom

6789876).13. Programul citeşte un număr pozitiv s cu cel mult două cifre după virgulă care exprimă o

sumă de bani în lei, determină şi afişează numărul minim de bancnote de 500, 200, 100, 50, 20, 10, 5,1 lei şi monede de 50, 25, 10, 5, 1 bani necesare pentru a exprima suma s. Folosiţi instrucţiunea do-while.

14. Sunt date a, b numere întregi. Să se afişeze toate numerele perfecte din intervalul [a,b].15. Pentru n întreg dat să se găsească toate perechile gemene mai mici ca n. Pereche gemene

sunt numerele prime cu diferenţa 2(5 şi 7, 11 şi 13, 29 şi 31 etc.). 16. Pentru n întreg dat. Să se găsească perechea maximă de numere gemene mai mici ca n.17. Scrieţi un program care determină numărul de zerouri în n! (n<=100). n!=1*2*3*…*(n-

1)*n. Numărul n este introdus de la tastatură. Exemplu: 12. Rezultat: 4.18. Din cifrele a două numere naturale de alcătuit cel mai mare număr, păstrând ordinea iniţială

a cifrelor din numerele date. De la tastatură se introduc două numere . Exemplu: 23 91662. Rezultat: 9231662.

19. Numerele de la 1 la N sunt aşezate în ordine crescătoare pe circumferinţa unui cerc astfel că N ajunge situate lângă 1. Începând cu numărul S se marchează numerele din K în K, în ordine crescătoare a lor, până când un număr este marcat de 2 ori. Câte numere au rămas ne marcate? Numerele N, S şi K se citesc de la tastatură. Să se afişeze la ecran numerele în ordinea de marcare şi numărul de valori, ce au rămas ne marcate. Exemplu: N=8, S=2, K=5. Rezultat: 2 7 4 1 6 3 8 5 2; 0.

20. Se citesc cele N cifre ale unui număr natural, N dat, în ordine descrescătoare a rangurilor. Pentru K dat, să se găsească cel mai mare număr care rămâne după ştergere a K cifre, păstrând ordinea dată a cifrelor (N, K <255). Exemplu: N=12; K=7; 682395892161. Rezultat: 99261.

Întrebări de control:1. Ce este o instrucţiune compusă?2. Care este formatul instrucţiunii if ? Explicaţi cum lucrează, daţi exemplu.3. Care este formatul ciclului for, care este antetul şi corpul ciclului? Explicaţi cum lucrează, daţi exemplu.4. Care este deosebirea dintre ciclurile for, while şi do-while? 5. Care este formatul instrucţiunii switch? Explicaţi cum lucrează această instrucţiune.6. Unde şi cum se folosesc instrucţiunile continue şi break? 7. De câte ori se vor executa ciclurile: for(;;); for(;;) continue; for (;;) break? Explicaţi.8. De câte ori se vor executa ciclurile: do {;} while (3.14); do {continue;} while(-1); do {break;} while(‘0’); do {continue;} while(‘0’); do {break;} while(‘1’); Explicaţi.9. Fie char h; h=getch(); puts(“ati introdus”); switch(h) {

default: puts(“greşit”); case ‘1’: printf(“%d\n”,1);case ‘2’: printf(“%d\n”,2);case ‘3’: printf(“%d\n”,3);

20

Page 21: FisierFinal

case ‘4’: printf(“%d\n”,4); }

Ce se extrage la ecran? Explicaţi.10. Fie long double w; printf(“\nw=”); while(scanf(“%lf”,&w)!=1) { clrscr();

printf(“Greşit! Repetaţi introducerea\n”); printf(“\nw=”);} De câte ori se va executa ciclul? Explicaţi.

Lucrare de laborator N4

Tema: Pointeri şi tablouri.

Scopul lucrării: obţinerea deprinderilor practice la utilizarea pointerilor, însuşiri aritmeticii pointerilor în limbajul C şi a legăturii dintre pointeri şi tablouri.

Suport teoretic:

Un pointer este o variabilă valorile căreia sunt adrese de memorie. Pe adresele-valori ale unui pointer se pot păstra date de un anumit tip. Acest tip se indică în declaraţia variabilei de tip pointer şi se numeşte tipul de bază al pointerului sau tipul spre care pointează pointerul.

Declaraţia de pointer are formatul: tip *id1, *id2,_, *idn, unde tip este un tip de date care arată ce tip de date se vor păstra pe adresele-valori ale variabilelor id1, id2,_,idn. De exemplu: int *pi, i; Aici i este o variabilă simplă de tip int, iar pi este un pointer ce indică spre tipul int, adică în pi se vor păstra adrese ale datelor de tip int. La fel char *c; c este pointer la un obiect de tipul char. Se pot declara şi tablouri de pointeri: char *s[80].

Alocarea memoriei pentru pointeri. Unui pointer i se alocă, de obicei, un cuvânt al calculatorului, adică 2 octeţi. Însă modificatorii near, far, huge pentru tipul pointer modifică modul de alocare a pointerilor în memorie. Modificatorii far şi huge alocă 2 cuvinte, adică 4 octeţi de memorie pentru pointeri, iar near sau lipsa oricărui modificator semnifică alocarea pointerului pe un cuvânt, adică pe 2 octeţi de memorie.

Operatori specifici pentru pointeri: * - se utilizează pentru accesul la conţinutul variabilei adresate; & - se utilizează pentru aflarea adresei variabilei. Pentru tipărirea adreselor se foloseşte specificatorul de format %p. Pentru a atribui pointerului pi adresa variabilei i scriem pi=&i. Dacă pi este un pointer, atunci *pi este data stocată pe adresa-valoare a lui pi. De exemplu, fie i=10 şi pi=&i. Atunci pi are ca valoare adresa lui i, iar *pi este chiar valoarea 10 a lui i. La declaraţie pointerii se pot iniţializa: float w, *y=&w; sau char *pc=”Informatica”; Aici pc este un pointer de tipul char * şi lui i se atribuie ca valoare adresa de început a şirului de caractere ”Informatica”, adică adresa primului caracter din şir.

Se pot declara pointeri de tipul void *, adică pointeri la care nu se indică tipul de bază. În acest caz nu se ştie în prealabil tipul datelor ce se vor păstra pe adresele-valori ale pointerului. De exemplu: int x=10, *pi; void *pv; Atribuirea pi=&x şi pv=pi sunt corecte. Atribuirea pi=pv nu este corectă. La atribuirea sau citirea datelor de pe adresele-valori ale unui pointer de tip void * trebuie explicit indicat tipul datelor respective, adică pi=(int*)pv.

Operaţii aritmetice cu pointeri: valorile a doi pointeri pot fi comparate folosind operatori relaţionali. Operaţia este folosită, de obicei, pentru pointerii care pointează spre elementele aceluiaşi tablou. Comparaţia unui pointer cu NULL – constantă specială definită în <stdio.h>, are rolul de a verifica dacă s-a făcut alocarea unei zone pointerului respectiv. Este definită adunarea (scăderea) unui scalar la un (dintr-un) pointer rezultatul fiind tot un

21

Page 22: FisierFinal

pointer şi diferenţa dintre doi pointeri, operaţiile având sens doar dacă pointerul păstrează adresa unui element dintr-un tablou. Fie p şi q doi pointeri la elemente ale aceluiaşi tablou. Expresia p+i indică elementul situat în vector cu i poziţii la dreapta faţă de p, iar expresia p-q are ca valoare numărul de elemente cuprinse între cele două adrese. Operaţia de incrementare (++) şi decrementare (--) pentru pointeri măreşte (micşorează) adresa-valoare a pointerului cu numărul de octeţi necesari pentru a păstra o valoare de tipul spre care pointează pointerul. De exemplu, dacă avem declarat int *p; atunci ++p, ca şi p++, măreşte valoarea lui p cu 2 octeţi, deoarece o valoare de tipul int este alocată pe 2 octeţi. Analogic, dacă avem declarat double *w; atunci w++, ca şi ++w, măreşte valoarea lui w cu 8, deoarece tipul double cere 8 octeţi.

Legătura dintre pointeri şi tablouri. Fie tab[n] un tablou unidimensional cu n elemente. Atunci numele tab este un pointer care are ca valoare adresa primului element al tabloului, adică are valoarea &tab[0]. Deci tab+1 este adresa elementului cu indicele 1, adică &tab[1], tab+2 este adresa elementului cu indicele 2, adică &tab[2] ş.a.m.d. Respectiv *(tab+0), adică *tab este elementul tab[0], *(tab+1) este elementul tab[1], *(tab+2) este elementul tab[2] ş.a.m.d.

Fie acum tab[m][n] un tablou bidimensional cu m linii şi n coloane. Atunci tab[0] este un pointer care are ca valoare adresa de început a liniei 0 a tabloului tab[m][n], adică &tab[0][0], tab[1] este un pointer care are ca valoare adresa de început a liniei 1 a tabloului tab[m][n], adică &tab[1][0] ş.a.m.d. Deci tab[0], tab[1],..., tab[m] este un tablou de pointeri. La rândul său, numele tab al tabloului tab[m][n] este un pointer ce pointează spre şirul de pointeri tab[0], tab[1], tab[2],..., adică pointerul tab are ca valoare adresa pointerului tab[0]. Din toate acestea rezultă că expresiile &tab[i][j], tab[i]+j, *tab+i*n+j sunt echivalente. La fel expresiile tab[i][j], *(tab[i]+j), *(*tab+i*n+j) sunt echivalente. Deci **tab este nu altceva decât elementul tab[0][0].

Exemple de programe:

Exemplul 4.1. Programul determină elementul maxim dintr-un şir numeric; sunt demonstrate diferite moduri de adresare la elementele unui tablou unidimensional.#include<conio.h>#include<stdio.h>void main(){ int x[]={10,20,30,40,50}, *px,i,r,t; clrscr(); px=x; r=*px; for (i=0;i<5;i++) {

t=*(px+i); if (r<t) r=x[i]; }

printf(”Elementul maxim al şirului x este %i”,r);}

Exemplul 4.2. Programul inversează un şir de caractere#include<conio.h>#include<string.h>#include<stdio.h>void main(){ char *s=”programare”,i,j,aux; clrscr(); puts(”Şirul iniţial:”); puts(s); for (i=0, j=strlen(s)-1; i<j;i++,j--) { aux=*(s+i); *(s+i)=*(s+j); *(s+j)=aux; } puts(”Şirul inversat:”);

22

Page 23: FisierFinal

puts(s); getch();}

Exemplul 4.3. Programul afişează doar numerele prime dintr-un tablou de numere întregi pozitive.#include<conio.h>#include<stdio.h>void main(){ unsigned a[]={10,7,9,40,5,7}, i=0,s=0,d,h; clrscr(); puts(”Şirul iniţial este:”); while ( i<6) printf(”%u\t”, *(a+i++)); while (s<6) {

d=0; for (h=1; h<=a[s];h++) if ( *(a+s)%h1==0) d++; if (d==2) printf(“%u\t”, *(a+s++)) ; } getch(); }

Exemplul 4.4. Programul determină caracterul de cod maxim într-un şir de caractere.#include<conio.h>#include<string.h>#include<stdio.h>void main(){ char *s=”programare C++”,i=-1,x; clrscr(); x=*s; for (;++i<strlen(s);) if (x<*(s+i)) x=*(s+i); puts(”Caracterul de cod maxim în şirul”); printf(”%s\neste %c”,s,x) ; getch();}

Exemplul 4.5. Programul ordonează crescător un şir de caractere.#include<conio.h>#include<stdio.h>void main(){ char x[]=”UNIVERSITATEA DE STAT A MOLDOVEI”; int n=strlen(x),i,j,aux; clrscr(); puts(”Şirul iniţial:”); puts(x); for (i=0; i<n-1; i++) for (j=i+1; j<n; j++) if (x[i]>x[j] )

{ aux=x[i]; x[i]=x[j]; x[j]=aux; } puts(”\nŞirul ordonat crescător:”); puts(s); getch();}

Exemplul 4.6. Programul formează din vectorul x de numere întregi un vector y de numere întregi, în care y[i] să fie restul împărţirii lui x[i] la suma cifrelor lui.#include<conio.h>#include<stdio.h>void main(){

23

Page 24: FisierFinal

unsigned x[]={123,17,439,5146,5667}, i=0,y[5],s; clrscr(); puts(”Şirul numeric iniţial este:”); while ( i<5) printf(”%u\t”, *(x+i++)); for (i=0; i<5; i++) {

s=0; while (x[i]>0) { s+=x[i]%10; x[i]=x[i]/10; } *(y+i)=s; } puts(“Şirul numeric format:”); i=0; while (i<5) printf(“%u\t”, *(y+i++)) ; } getch(); }

Exemplul 4.7. Programul afişează doar simbolurile cuprinse între simbolurile ( şi ). Se presupune că nu există mai multe paranteze.#include<conio.h>#include<stdio.h>void main(){ char *s=”abcd(1,2,3,4,5)xzy”; int k, *p, *q; clrscr(); puts(”Şirul iniţial:”); puts(s); p=strchr(s,’(’); q=strchr(s,’)’); k=p-s; j=q-s; for (i=k+1; i<j; i++) printf(“%c”,*(s+i));

getch();}

Exemplul 4.8. Programul afişează doar simbolurile cuprinse între simbolurile ( şi ). Se presupune că nu există mai multe paranteze. (Alt variant)#include<conio.h>#include<stdio.h>void main(){ char *s=”abcd(1,2,3,4,5)xzy”; int k, *p, *q; clrscr(); puts(”Şirul iniţial:”); puts(s); for (i=0; *(s+i++);) { if ( *(s+i)!=’(‘ ) continue; while ( *(s+ ++i)!=’)’ ) printf(“%c”,*(s+i)); } getch();

}

Exemplul 4.9. Programul determină şi afişează elementul maxim pe liniile unui tablou bidimensional. Sunt demonstrate diferite moduri de adresare la elementele tabloului.#include<conio.h>#include<stdio.h>void main(){ unsigned v[5][5],i,j,max,n,m;

24

Page 25: FisierFinal

puts(”Introdu numărul de linii şi de coloane:”); scanf(”%i%i”,&n,&m);

for (i=0;i<n;i++) for (j=0;j<m;j++) //accesul către elementele tabloului prin numele lui scanf(”%i”, *v+i*m+j); for (i=0;i<n;i++) { //accesul către elementele tabloului prin indicatorii v[0], v[1],… max=*(v[i]+j); for (j=0;j<m;j++) if ( max<v[i][j] ) max=v[i][j]; //acces la elemente tabloului prin indici printf(”Elementul maxim pe linia %i este %i\n”,i+1,max); } for (i=0; i<n*m;i++) printf(”%i\t”,*(*v+i)); // accesul către elementele tabloului prin v – indicator la indicatorul v[0]

}

Probleme propuse spre rezolvare:

1. Programul determină cel mai mic număr dintre elementele de indice par ale unui şir numeric.2. Programul transcrie toate elementele nule ale unui şir numeric la începutul tabelului, la sfârşit transcrie toate elementele ne nule, păstrând ordinea lor.3. Programul deplasează elementele unui şir numeric a[10] astfel încât a[i] să se deplaseze în a[i- 1], iar a[0] în a[9].4. Programul deplasează spre stânga un tablou a[10] cu k poziţii. Ultimele k poziţii se completează cu 0.5. Programul aruncă din textul dat toate cuvintele de lungime mai mare ca 6 simboluri. Se va afişa textul iniţial şi cel redactat.6. Programul afişează din şirul S l simboluri începând cu poziţia k .7. Programul realizează în tabloul a[10] cu numere sortate introducerea unui număr k astfel încât tabloul să rămână sortat.8. Programul realizează inversarea elementelor matricei pătrate de ordin n în raport cu diagonala secundară.11. Să se bordeze o matrice A (având m linii şi n coloane) cu linia m+1 şi coloana n+1, unde

A[m+1][j] să fie suma elementelor de pe coloana j (cu j de la 1 la n), iar A[i][n+1] să fie suma elementelor de pe linia i (cu i de la 1 la m).

12. Programul înmulţeşte un vector din n elemente cu o matrice numerică de dimensiunea m n.

Întrebări de control:

1. Ce este un pointer ?2. Câtă memorie se alocă unei variabile de tip pointer ?3. Cum se extrage valoarea unui pointer la ecran ? dar valoarea de pe adresa păstrată în variabila de tip pointer ?4. Fie int *p, *q, a=1, b=0; p=&a ; q=&b; if (*p<*q) *q=*p; else q=p; Ce va afişa printf(” %i %i %i %i”, a,b,*p,*q); ?

5. Care dintre expresiile următoare este eronată, ştiind că variabilele p, q şi a sunt declarate: int a, *p, **q; a) a=*q=*p b) p=&(**q) c) *q=&a d) *p*=*(*q)+a ?

6. Care este numărul de biţi necesari pentru memorarea tabloului declarat int a[20]; ?7. Dacă vectorul a este declarat char a[20]; atunci elementul al treilea este:a) a[3] b) *a[3] c) *(a+2) d) *(a+3) ?

8. Dacă vectorul a este declarat char a[20]; atunci elementul al treilea este: a) a[3] b) *a[3] c) *(a+2) d) *(a+3) ?

9. Ce este un pointer nul, ce reprezintă constanta NULL şi unde este definită ?

25

Page 26: FisierFinal

10. Fie char a=’a’, *pa; int x=10, *px; float y=2.8, *py; double z=12345.54321,

*pz; long double w=123456789.987654321, *pw ; pa=&a ; px=&x ; py=&y ;

pz=&z ; pw=&w ; Ce va afişa printf(“%c\t%d\t%f\t%lf\t%Lf\n”, *pa, *px,

*py, *pz, *pw) ;  ?13. Fie int x=2000, *p=&x, **q=&p, ***w=&q ; Ce va afişa printf(“%d %d %d

%d“, x, *p, **q, ***w) ;  ? 14. Fie int s[20]= {0,1,2,3,4,5}, *pi=s ; Ce va afişa printf(“%d %d %d %d %d %d“, *pi, *++pi, *++pi, *++pi, *++pi, *++pi) ;  ?

Lucrare de laborator N5

Tema: Prelucrarea şirurilor de caractere.

Scopul lucrării: Utilizarea funcţiilor standarde de prelucrare a şirurilor de caractere şi operaţii cu şiruri.

Suport teoretic:

Cele mai des întâlnite utilizări ale tablourilor unidimensionale în limbajul C sunt şirurile de caractere, deoarece în C nu este prevăzut tipul de date şir de caractere. Pentru memorarea şirurilor se utilizează tablouri cu tipul de bază char, care au pe ultima poziţie caracterul “\0”.

Pe lângă necesitatea de a defini un şir de caractere ca şi tablou de caractere, în prelucrarea şirurilor se utilizează deseori tipul pointer la caracter.

De exemplu: char sir[20]; // tablou de 20 de caracterechar *psir; // pointer la caractere.

Astfel, sir este o variabila de tipul tablou de caractere pentru care se rezervă un spaţiu de memorie de 20 de octeţi, în timp ce psir este un pointer la caracter care poate primi ca valoare adresa unui caracter (în particular, adresa primului element dintr-un şir de caractere). Trebuie reţinut că ori de câte ori se lucrează cu variabile şiruri de caractere într-un program, trebuie să existe fie o definiţie de forma celei prezentate pentru variabila sir, prin care se rezervă static (în timpul compilării), spaţiul de memorie necesar variabilei, fie să se aloce dinamic memoria necesară.

Funcţiile pentru prelucrarea şirurilor sunt declarate în fişierul antet string.h. Ele primesc adresele şirurilor prelucrate, prin intermediul parametrilor de tipul pointer la caracter.

Denumirea funcţiilor de prelucrare a şirurilor declarate în fişierul stdio.h

funcţia explicaţiechar * gets(char* s) Citeşte caracterele din intrarea standard până la întâlnirea

caracterului Enter, care nu se adaugă la şirul s; plasează '\0' la sfârşitul lui s; returnează adresa primului caracter din şir.

int puts(char* s) Tipăreşte şirul s, trece apoi la rând nou.printf("%s",s1) Tipăreşte şirul s1.

Denumirea funcţiilor de prelucrare a şirurilor declarate în fişierul string.hfuncţia explicaţie

int strncmp(char* s1, char* s2, int n) Compară şirurile s1 şi s2 spre care pointează pointerii s1, s2. Funcţia returnează 1 dacă s1>s2, valoarea -1 dacă s1<s2, şi valoarea 0 dacă s1=s2. Dar se compară şirurile

26

Page 27: FisierFinal

pentru cel mult n caractere.char *strcpy(char* s1, char* s2) Copie şirul sursă s2 în şirul destinaţie s1 şi returnează

adresa şirului destinaţie.char* strcat(char* s1, char* s2) Concatenarea şirurilor şi afişarea şirului rezultat.char* strchr(char s, char c) Poziţia primei apariţii a caracterului c în şirul s, respectiv

NULL dacă c nu este în s.strcspn(char* s1, char* s2) Afişează prima apariţie a caracterului care coincide în

ambele şiruri.char *strncpy(char* s1, char* s2, int n)

Copie maxim n caractere de la şirul sursă s2 în şirul destinaţie s1 şi returnează adresa şirului destinaţie.

char *strtok(char *s1, const char *s2); Desparte şirul s1 de şirul s2.int strlen(char* s1) Returnează lungimea şirului fără a număra caracterul de

sfârşit ‘\0’.strlwr(char* s1) Converteşte şirul din litere mari (A la Z) în litere mici (a

la z).strset(char* s1, char* s2) Caută prima intrare a şirului s2 în şirul s1.strrev(char* s) Inversează şirul.strrchr(char* s, int c) Verifică ultima intrare a simbolului c în şirul s.

Returnează pointerul spre ultimul simbol ce coincide cu c a şirului s. Dacă nu-l găseşte returnează NULL.

char*strpbrk(const char*s, const char*s1)

Căută în şirul s orice simbol din şirul s1 şi afişează pe acel care mai înaite se întâlneşte în şirul s.

strrupr(s) Converteşte şirul din litere mici în litere mari .isalpha(s) Verifică dacă s este literă.isdigit(c) Verifică dacă c – cifră.islower(s) Verifică dacă s este literă de la a la z.isspace(c) Verifică dacă c este spaţiu.zint atoi(const char* s) Converteşte şirul s într-o valoare întreagă.int atol(const char* s) Converteşte şirul s într-o valoare întreagă lungă.itoa(int n, char* s, int ) Converteşte un întreg în char.Double atof(char* s) Converteşte sirul s într-o valoare realăchar*gcvt(double v,int n, char*buf) Converteşte datele de tip double într-un şir de simboluri,

inclusiv simbol cu virgulă mobilă. Mai des se foloseşte la convertirea numerelor introduse ca şir de simboluri, şi efectuarea anumitor operaţii asupra lor.

Exemple de programe:

Exemplul 5.1. Este dat şirul s. Să se tipărească câte litere de a se întâlnesc in ultimul cuvânt din şir (de ex. Ana frate ada; rezulat: 2).#include<stdio.h>#include<conio.h>#include<string.h>void main(){ char s[256]; int i,j=0; clrscr(); gets(s); for(i=strlen(s)-1; s[i]!=' '; i--) //parcurgem şirul de la sfârşit if(s[i]=='a') j++; //dacă găsim litera a, contorul j va creşte printf(" Litere de a în ultimul cuvânt sunt: %d",j); getch();}

27

Page 28: FisierFinal

Exemplul 5.2. Fiecare caracter se înlocuieşte cu următorul caracter(de ex. abc se tipăreşte bcd) până la apăsarea tastei cifrei 9.#include<stdio.h>#include<conio.h>#include<string.h>void main(){ char g,c; int i,j,x,k; g=0; clrscr(); while(!g) { c=getchar(); // cât g=0, se citesc cu ecou caractere, până c!=9 if ( c == '9' ) {g = 1; continue;} // dacă c=’9’, atunci g=1 şi se trece la următorul pas putchar (c+1); // tipăreşte următorul caracter } getch();}

Exemplul 5.3. Este dat şirul d. Se concatenează şirurile şi se copie un şir în alt şir.#include <string.h>#include <stdio.h>#include <conio.h>void main(void){ char d[25]; char *blank = " ", *c = "C++", *t = "Turbo"; clrscr(); gets(d); strcat(d, blank); // la concatenare se păstrează textul din ambele şiruri strcpy(d, t); // şirul t se copie în d, şi textul din şirul d se şterge strcat(d, c); //se concatenează printf("%s\n", d); // se va afişa: TurboC++ getch();}

Exemplul 5.4. Este dat şirul s. Să se numere câte cuvinte are şirul.#include<stdio.h>#include<conio.h>#include<string.h>void main(){ char s[20]; int i,k; k=1; clrscr(); printf("sir:\n"); gets(s); for(i=1;i<strlen(s);i++) //şirul e parcurs din poziţia 1 până la sf.şirului { if((s[i-1]==' ')&&s[i]!=' ') // verificăm dacă este cuvânt k++; //contor ce numără cuvintele } printf(" %d",k); getch();}

Exemplul 5.5. Este dat şirul s. De despărţit fiecare propoziţie din rând nou. Propoziţia se termină cu punct.#include<stdio.h>#include<conio.h>#include<string.h>void main()

28

Page 29: FisierFinal

{ char s[256],*t; clrscr(); printf("sir:\n"); gets(s); t=strtok(s,"."); // atribuim lui t şirul s până la punct while(t!=NULL) //atât timp cât în t sunt propoziţii { printf("%s\n",t); //tipîrim din rand nou t=strtok(NULL,"."); } getch();}

Exemplul 5.6. Este dat un cuvânt s de maxim 20 caractere. Să se verifice dacă cuvântul introdus este polidrom (care se citeşte şi de la stânga şi de la dreapta la fel; de exemplu cojoc).#include<stdio.h>#include<conio.h>#include<string.h>#include<stdlib.h>void main(){ char s[20]; int i,k,l,h=1; clrscr(); printf("sir\n"); gets(s); k=strlen(s); l=k/2; for(i=0;i<l;i++) { if(h) if(s[i]==s[k-i-1]) h=1; else {printf("nu\n"); getch(); exit(0);} } printf("polidrom=%s",s); getch();}

Exemplul 5.7. Este dat şirul s. Să se tipărească cuvintele ce au lungimea mai mare decât 6 caractere.#include<stdio.h>#include<conio.h>#include<string.h>void main(){ char s[256]; int i,j,x; j=0;x=0; clrscr(); printf("sir\n"); gets(s); for(i=0;i<strlen(s);i++) { j++; if(s[i]==' ') { if(j>6) for(k=x;k<i;k++) s[k]=' '; j=0;x=1; }} printf("=%s",s); getch();}

Exemplul 5.8. Este dat şirul s. De tipărit şirul astfel încât, unde sunt mai mult de un spaţiu de considerat numai unul (De exemplu: azi plouă, rezultat: azi plouă). #include<stdio.h>

29

Page 30: FisierFinal

#include<conio.h>#include<string.h>void main(){ char s[256]; int i,j; clrscr(); printf("sir\n"); gets(s); for(i=0,j=0;i<strlen(s);i++) if((s[i]!=' ')||(s[i]==' ')&&(s[i+1]!=' ')) //se verifică dacă s[i] nu-i spaţiu sau s[i] este spaţiu şi următoarea poziţie nu-i

//spaţiu, atunci în şirul s[j], unde j creşte la fiecare simbol, se înscrie s[i] s[j++]=s[i]; s[j]='\0'; //ultimul caracter zero puts(s); //tipărim şirul getch();}

Exemplul 5.9. Să se tipărească poziţia caracterului ce se află în ambele şiruri.#include<conio.h>#include<stdio.h>#include<string.h>void main(){ char s[256]; int i,l; clrscr(); printf(“Şirul:”); gets(s); // de exemplu: abcdmh for(l=0;l<strlen(s);l++) i=strcspn(s,"nmn"); // atribuie poziţia primului caracter din şirul s printf("%d\t",i); //i=4 deoarece m se află pe poziţia 4 getch();}

Exemplul 5.10. Este dat şirul s şi subşirul căutat. Să se caute un subşir în şirul s. #include<conio.h>#include<stdio.h>#include<string.h>void main(){ char s[256],s1[256],*p; int i; clrscr(); printf("dati şirul s:"); //de exemplu: ada ion mihai gets(s); printf("dati subşirul căutat:"); //ion gets(s1); for(int l=0; l<strlen(s); l++) p=strstr(s,s1); printf("Subşirul căutat: %s\t",p); //ion getch();}

Exemplul 5.11. Este dat şirul s. Să se tipărească la ecran: şirul până la două puncte; şirul după două puncte.

#include<conio.h>#include<stdio.h>#include<stdlib.h>#include<string.h>void main(){ char s[256],*p; int i,j; i=j=0;

30

Page 31: FisierFinal

clrscr(); printf("dati şirul:"); gets(s); // de exemplu: asfsd:fdfh:hjklş; p=s; printf("\nşirul pâna la două puncte:"); while(p[i]!=':'){

putchar(p[i]); i++; } // afişarea şirului (asfsd) i++; j++; printf("\nsirul dupa doua puncte:\n"); for(i; i<=strlen(p); i++) putchar(p[i]); // fdfh:hjklş; getch();}

Exemplul 5.12. Este dat şirul s. Să se găsească cuvintele ce conţin litera s.#include <string.h>#include <stdio.h>#include <conio.h>void main(void){ char s[256]; char *ptr, c='s'; clrscr(); printf("daţi şirul:\n"); gets(s); ptr = strchr(s,c); if (ptr) printf("caracterul %c se află pe poziţia: %s\n", c, ptr); else printf("nu este aşa caracter\n"); getch();}

Exemplul 5.13. Este dat şirul s. Să se afişeze lungimea celui mai scurt cuvânt şi numărul de cuvinte.#include<stdio.h>#include<string.h>#include<conio.h>void main(){ char s[256],*t,*p; int k,min; k=0; clrscr(); printf("dati sirul:"); gets(s); t=s; t=strtok(s," "); // lui t se atribuie cuvintele (despărţite prin spaţiu) min=strlen(t); // notăm prin min lungimea şirului t while(t!=NULL) // verificăm atât timp cât avem cuvinte { printf("%s\n",t); //tipărim fiecare cuvânt din rand nou if(min>strlen(t)) //dacă se găseşte un cuvânt cu lungimea mai mică ca min min=strlen(t); //atunci min primeşte lungimea acelui cuvânt t=strtok(NULL," "); k++; //contorizează numărul de cuvinte } printf("\nnr de cuvinte:%d\nlungimea celui mai scurt cuvant:%d",k,min); getch();}

Exemplul 5.14. Folosind funcţia gcvt(), să se efectueze unele operaţii pentru convertirea şirului.#include<stdio.h>#include<string.h>#include<conio.h>

31

Page 32: FisierFinal

#include<stdlib.h>void main(){ char s[256]; double n; int k=4; n=2.897; gcvt(n, k. s); printf(“%s ”,s); // 2.897 // număr negativ n=-982.897; gcvt(n, k. s); printf(“%s ”,s); // -982.8 // număr în format ştiinţific n=0.897e3; gcvt(n, k. s); printf(“%s ”,s); // 8970}

Probleme propuse spre rezolvare:

1. Se citeşte un şir. Să se numere cuvintele care încep cu litera b.2. Să se afişeze toate poziţiile unui caracter intr-un şir dat. Caracterul se introduce de la tastatură(de exemplu: adelina; a are poziţia 0 şi 6).3. Se citeşte un şir de caractere care nu conţine caractere albe. Să se decidă dacă şirul este alcătuit exclusiv din caractere numerice.4. Să se determine numărul de litere mari şi mici dintr-un text dat.5. Se citeşte un şir ce conţine şi două puncte. Să se afişeze textul cuprins între două puncte ( Ex: ada:hjk:vbnv, şirul rezultat: hjk).6. Se citeşte un şir. Să se tipărească la ecran cuvântul cu lungimea mai mică.7. Se citeşte un şir. Să se tipărească la ecran caracterul de cod maxim şi simbolurile cu codurile cuprinse între [100, 235].8. Se citeşte un şir. Să se tipărească la ecran şirul dintre paranteze (Ex: asdf (ghdfhg ) fdhj,6g - ghdfhg).9. Se dă o listă de cuvinte separate prin spaţiu, lista se încheie prin două rânduri goale succesive (două enter-uri). Să se tipărească în ordine alfabetică toate polindroamele care apar în listă. Un polindrom este un cuvânt care este identic citit atât de la început spre sfârşit cât şi de la sfârşit spre început (Ex: cazac, elevele, cojoc).10. Se citeşte un text. Textul conţine cuvinte separate printr-un spaţiu. Dacă textul conţine ‘*’, atunci fiecare simbol ‘/’ ce precede ‘*’ să fie înlocuit cu ‘,’.11. Se citeşte un text. Textul conţine cuvinte separate printr-un spaţiu. Să se scrie, pe linii separate, fiecare cuvânt care apare în text urmat de un număr care va reprezenta de câte ori apare cuvântul în text. Să se determine cuvântul care apare de cele mai multe ori.12. Se citeşte un text. Textul conţine cuvinte separate printr-un spaţiu. Se va genera un nou text care va conţine cuvintele ordonate alfabetic.13. Se citeşte un text. Textul conţine cuvinte separate printr-un spaţiu. Să se determine numărul de apariţii al fiecărui caracter. Informaţia referitoare la un caracter se va afişa o singură dată.14. Se citeşte un text. Textul conţine cuvinte separate printr-un spaţiu. Se va genera un nou text care va conţine cuvintele în ordine inversă (asdf - fdsa).15. Să se sorteze alfabetic un şir de cuvinte (eventual, să se distingă literele mici de cele mari).16. Se dă un text de maxim 30 de caractere. Să se listeze toate cuvintele de două caractere din acest text.17. Se dau două texte. Să se stabilească o vocală comună celor două texte, care apare de cele mai puţine ori.18. Fie un şir de forma: cifră-literă, cifră literă …etc.(Ex : 2a4b5c). Să se genereze un astfel de şir: aabbbbccccc.

32

Page 33: FisierFinal

19. Se citeşte un şir de caractere alfanumerice. Considerăm că literele sunt separatorii numerelor. Afişaţi datele de tip numeric preluate în ordine din şirul citit. Numerele vor fi scrise câte unul pe o linie.Ex.in.txt out.txta23sc345ss5e 23

345 5

20. Se citeşte un text de la tastatură astfel încât cuvintele să fie separate printr-un singur spaţiu şi imediat după ultimul cuvânt se scrie punct. Textul va fi scris pe un singur rând:

a. Să se determine dacă textul are cuvinte distincte (se ignora diferenţa de cheie).b. Să se tipărească cuvintele cu lungimea mai mare ca 6.c. Să se determine dacă textul conţine cifre

21. Este dat un şir de caractere (lungimea şirului este <=100). De codificat acest şir în următorul mod: caracterele se plasează într-un pătrat de dimensiune minimă pe spirală, începând cu colţul din dreapta jos în direcţia acelor de ceasornic. Spaţiul se codifică prin *. Intrare: de la tastatură se va introduce şirul de caractere.Ieşire: se va afişa la ecran dimensiunea aleasă a pătratului şi textului codificat.Exemplu: Bună dimineaţa, Chişinău!Ieşire: 5 ineatminaaiş!u,dihC**anuB

i n e a tm i n a ai ş ! u ,d i h C ** a n u B

22. Se consideră două şiruri: a=a1…an şi b=b1…bm formate din n şi respectiv m litere. Asupra şirului a se pot face urătoarele operaţii.

Ştergere: S(i) – şterge litera de pe poziţia i. Inserare: I(j,c) – inserează litera c pe poziţia j. Modificare:M(i,c) – înlocuieşte litera de pe poziţia i cu c. Să se transforme şirul a în şirul b cu număr minim de astfel de operaţii. Exemplu: a= DANIELA, b=IOANA. Numărul minim de operaţii este 5 şi anume: M(1,1); I(2,O); S(5); S(6); S(5). Intrare: a şi b se citesc de la tastatură. Restricţii: m>0, n<80.

Întrebări de control:1. Ce returnează funcţiile: strlen(“ASEM”), strlen(“asem0”), strlen(“ASEM\N”),

strlen (“0”), strlen(“”)?2. Care va fi rezultatul returnat de funcţiile: strcat(“Limbajul C”, “++”),

strncat(“Cibernetica, ”,”Informatica Aplicată, Management, Matematica”, 21)?3. Ce afişează puts(strstr(“Informatica Aplicată”,”scop”));? Explicaţi.4. Ce returnează funcţiile: strcmp(“asem”,”ASEM”), stricmp(“ASEM”, “asem”),

strncmp(“Limbajul C”, “Limbajul C++”, 10), strnicmp(“INFORMATICA”, ”informatica”,1)?

5. Fie char *s=”Costel, Vicu şi Andrei merg la teatru”, *q=”Vicu”; puts(strstr(s,q)); Cine merge la teatru? Explicaţi.

6. #define L 15 char sir[L]; strcpy(sir,"123\0456");

printf("Şirul copiat este:/%s/ şi are lungimea:%d\n",sir, strlen(sir)); Ce se tipăreşte pe ecran?.

7. char s[]=”70000”;int i=atoi(s);long l=ato1(s);

33

Page 34: FisierFinal

printf(“%d\t%ld”,i,l); Explicaţi. Ce se tipăreşte la ecran?.8. char s[]=”asdfghjert”;

int i;

i=strcspn(s,”fnm”); Ce se tipăreşte la ecran, ce valoare primeşte variabila i?.9. char s1[]=”asdfghjert”;

char s2[]=”esa”; char *p;p=strpbrk(s1,s2);

printf((“%s”, p); Explicaţi. Ce se tipăreşte la ecran?.10. char s1[]=”asdfghjert”;

char *p; p=strrchr(s1,’j’);

printf((“%s”, p); Explicaţi. Ce se tipăreşte la ecran?.

Lucrare de laborator N6

Tema: Lucrul cu tablourile unidimensionale.

Scopul lucrării: obţinerea deprinderilor practice la utilizarea tablourilor unidimensionale şi operaţiile de prelucrare a lor.

Suport teoretic:

Definiţie: Masivele sunt structuri de date omogene cu un număr finit şi cunoscut de elemente, ce ocupă un spaţiu contiguu de memorie.

Un masiv este caracterizat de următoarele elemente: numele; tipul de date asociat; numărul de dimensiuni; numărul de elemente pentru fiecare dimensiune. Definiţie: Vectorii sunt masive unidimensionale. In C++ vectorii se declară folosind

sintaxa: tip nume[n] unde: tip – tipul de date folosit; poate fi unul din tipurile de bază (int, float, char, …) sau un tip

definit de utilizator (articole, obiecte) nume – numele prin care va fi referit vectorul n – numărul de elemente ale vectorului

Exemple de declaratii:// vector de 100 valori întregiint vanzari[100];

// vector de 15 valori realefloat temperaturi[15];

Memorarea vectorilor se face într-un spaţiu contiguu de memorie. Numele vectorului este de fapt un pointer către adresa primului element. Pentru o declaraţie de forma int v[5]; reprezentarea în memoria internă este:

v

v[0] v[4]v[3]v[2]v[1]

34

Page 35: FisierFinal

Dimensiunea totală a vectorului este calculată ca produs între numărul de elemente şi dimensiunea unui element.

Iniţializarea vectorului se poate face la declarare printr-o construcţie de forma:tip nume[]={lista_valori}.

Se observă că în acest caz nu este necesară precizarea numărului de elemente. Acesta va fi dedus automat de compilator din dimensiunea listei cu care se face initializarea. In cazul in care numărul de elemente precizat este mai mare decât numărul de elemente din listă se va realiza o initializare partiala a vectorului.

Exemple de initializări la declarare:

// iniţializare fără precizarea explicită a numărului maxim de elementeint v1[] = {1, 2, 3, 4, 5};// iniţializare completă cu precizarea numărului maxim de elementeint v2[3] = {17, 19, 23};// iniţializare parţialăint v3[5] = {7, 6, 5};

Accesul la elementele vectorului se face direct; compilatorul calculează adresa elementului pe baza indexului şi a dimensiunii unui element. Numerotarea elementelor se face incepând cu zero. Pentru un vector v cu n elemente referirea elementelor se face folosind v[0], v[1], v[2], …, v[n-1].

Operaţii de bază: Citirea de la tastatură ;printf("daţi nr de elemente:");scanf("%d",&nrelem);for (i = 0; i < nrelem; i++) { printf("vector[%d]=",i); scanf("%d",&vector[i]); }

Afişarea pe monitor;for (i = 0; i < nrelem; i++) printf("%3d",vector[i]);

Căutarea elementului după valoare ;// parcurgem vectorulfor (i = 0; i < nrelem; i++)if (vector[i] == valoare)

{ f=1;// notăm că am găsit valoarea căutatăprintf("elementul cautat %d e pe pozitia: d:",vector[i],i);}// element negăsit

if (f==0) printf("elementul cautat nu este in vector: ");

Inserarea elementului; // se presupune că dimensiunea maximă a vectorului // este cel putin egala cu nrElemente + 1int pozitia;printf("dati pozita pe care vreti sa inserati:");scanf("%d",&pozitia);printf("dati valoarea pentru inserare:");

scanf("%d",&valoare);for (i = 0; i < nrelem; i++)

if (pozitia == nrelem)// inserare la sfarsitul vectoruluivector[nrelem] = valoare;

else // inserare în interiorul vectorului {

// se deplasează la dreapta a elementele aflate după poziţia de inserare for (int i = nrelem; i > pozitia; i--)

35

Page 36: FisierFinal

vector[i] = vector[i-1];// şi se inserează elementul

vector[pozitia] = valoare; }

printf("Dupa inserare:\n");for (i = 0; i < nrelem+1; i++) printf("%3d",vector[i]);

Ştergerea elementului; // deplasăm la stanga elementele aflate după poziţia de stergere printf("dati pozita pe care vreti să o stergeţi:");

scanf("%d",&pozitia);for (i = pozitia; i < nrelem; i++)

vector[i] = vector[i+1];printf("Dupa stergere:\n");for (i = 0; i < nrelem; i++) printf("%3d",vector[i]);

Exemple de programe:

Exemplul 6.1. Dat un tablou de 10 elemente. Programul determină suma elementelor de pe poziţiile pare.#include<stdio.h>#include<conio.h>void main(){ int a[10], i, s; s=0; printf(“Introducem elementele vectorului:\n”); for(i=0; i<10; i++){

printf(“a[%d]=”, i); scanf(“%d”, &a[i]); }

for(i=0; i<10; i++) if(i%2==0) s=s+a[i]; // se verifică dacă poziţia elementului este pară printf(“\nSuma elementelor de pe poziţiile pare este=%d”, s);}

Exemplul 6.2. Se dă un tablou de n elemente, toate elementele sunt diferite. Să se afişeze pe primele locuri elementele egale cu zero, apoi restul elementelor păstrând ordinea lor( Ex.: 1 2 0 4 0 – 0 0 1 2 4 ).#include<stdio.h>#include<conio.h>void main(){ int a[100], n, i, j, x[100]; clrscr(); printf("\ndimensiunea vectorului:"); scanf("%d",&n); for(i=0; i<n; i++) { printf("a[%d]=", i); scanf("%d", &a[i]); } j=0; for(i=0; i<n; i++) if(a[i]==0) { j++; x[j-1]=a[i]; } // se verifică dacă elementul este zero, atunci j creşte şi înscriem în x for(i=0; i<n; i++) if(a[i]!=0) { j++; x[j-1]=a[i]; } printf("vectorul final\n"); for(i=0; i<n; i++) printf("%d%c", x[i],';');

36

Page 37: FisierFinal

getch();}

Exemplul 6.3. Se dă un tablou de n elemente. Să se deplasare la stânga cu x poziţii şi pozitiile eliberate se înlocuiesc cu zero ( Ex.: 1 2 3 4 5 6; x=2; 3 4 5 6 0 0 ).#include<stdio.h>#include<conio.h>void main(){ int a[100], n, i, j, x; clrscr(); printf("\ndimensiunea vectorului:"); scanf("%d", &n); printf("\nnumărul de poziţii de deplasare:"); scanf("%d", &x); printf("\nIntrodu elementele:\n"); for(i=0; i<n; i++) { printf("a[%d]=", i); scanf("%d", &a[i]); } for(i=0; i<x; i++) { for(j=0; j<n; j++) a[j]=a[j+1]; // se face deplasarea la stânga a[j-1]=0; // şi înscrierea lui zero pe poziţiile eliberate } printf("vectorul final\n"); for(i=0; i<n; i++) printf("%3d", a[i]); getch();}

Exemplul 6.4. Se dă un tablou de n elemente. Să se găsească elementul maxim din acest tablou.#include<stdio.h>#include<conio.h>void main(){ int a[100], n, i, j, max; clrscr(); printf("\ndimensiunea vectorului:"); scanf("%d", &n); printf("\nIntrodu elementele:\n"); for(i=0; i<n; i++) { printf("a[%d]=", i); scanf("%d", &a[i]); } max=a[0]; //iniţial elementul maxim este elementul de pe poziţia zero for(i=0; i<n; i++) if (a[i]>max) max=a[i]; // găsim elementul maxim printf("%3d", max); getch();}

Exemplul 6.5. Sunt daţi doi vectori de aceeaşi dimensiune a şi b. Să se găsească: poziţiile pentru care elementele din vectorul a sunt mai mari ca elementele din vectorul

b; poziţiile pentru care elementele din vectorul a sunt egale cu elementele din vectorul b

#include<stdio.h>#include<conio.h>#include<alloc.h>void main(){ int k,*a, n, i, j,*b, l;

37

Page 38: FisierFinal

clrscr(); printf("\ndimensiunea vectorului:"); scanf("%d", &n);/* se alocă memorie pentru vectorul a: dimensiunea vectorului se înmulţeşte cu dimensiunea tipului int(2 octeţi) */ a=(int*)malloc(n*sizeof(int)); b=(int*)malloc(n*sizeof(int)); // se alocă memorie pentru vectorul b printf("elementele vectorului a:\n"); for(i=0; i<n; i++) { printf("a[%d]=", i); scanf("%d", a+i); } printf("elementele vectorului b:\n"); for(i=0; i<n; i++) { printf("\nb[%d]=", i); scanf("%d", b+i); } printf("a:"); for(i=0; i<n; i++) printf("%3d", a[i]); printf("\nb:"); for(i=0; i<n; i++) printf("%3d", b[i]); k=0; printf("\npoziţiile pentru care elementele din vectorul a sunt mai mari ca din b\n"); for(i=0; i<n; i++)/* dacă măcar un element din a este mai mare ca un element din b, atunci k păstrează poziţia elementului mai mare */ if(*(a+i)>*(b+i)) { k=i; printf("%3d", k);

} l=0; printf("\npoziţiile elementele corespunzătoare primului vector egale cu elementele din al doilea vector\n"); for(i=0; i<n; i++) if(*(a+i) ==*(b+i)) { l=i; // dacă elemental sunt egale, atunci l păstrează poziţia elementelor egale printf("%3d", l);

} free(a); // se eliberează memoria alocată vectorului a free(b); // se eliberează memoria alocată vectorului b getch();}

Exemplul 6.6. Se dă un tablou de n elemente. Să se găsească cel mai mic element pozitiv#include<stdio.h>#include<conio.h>#include<alloc.h>void main(){ int k,*a, n, i, min; clrscr(); printf("\ndimen vec:"); scanf("%d", &n); a=(int*)malloc(n*sizeof(int)); printf("elementele vectorului a:\n"); for(i=0; i<n; i++) { printf("a[%d]=", i); scanf("%d", a+i); }

38

Page 39: FisierFinal

printf("a:"); for(i=0; i<n; i++) printf("%3d", a[i]); min=a[0]; k=0; printf("\n"); for(i=0; i<n; i++) if((*(a+i)<0)&&*(a+i)<min) { min=*(a+i); k=i;} printf("pozitia elementului negativ %d are minimul %d", k, min); free(a); getch();}

Exemplul 6.7. Se dă un tablou de n elemente. Să se sorteze descrescător folosind metoda bulelor (adică se compară primul cu al doilea, 2 cu 3,etc. Ex: 6 2 4 3 1 5;

prima parcugere: 2 4 3 1 5 6; a doua parcurgere: 2 3 1 4 5 6; a treia parcurgere: 2 1 3 4 5 6; a patra parcurgere: 1 2 3 4 5 6;

#include<stdio.h>#include<conio.h>#include<alloc.h> //biblioteca pentru funcţia maloccvoid main(){ int k,*a, n, i, aux, j; clrscr(); printf("\ndimen vec:"); scanf("%d", &n); a=(int*)malloc(n*sizeof(int)); printf("elementele vectorului a:\n"); for(i=0; i<n; i++) { printf("a[%d]=", i); scanf("%d", a+i); } printf("a:"); for(i=0; i<n; i++) printf("%3d", *(a+i)); printf("\n"); for(i=0; i<n-1; i++) //se parcurge de la 0 până la n-1 for(j=i+1; j<n; j++) // se parcurge de la i+1 până la n { if(*(a+i) <*(a+j)) //comparăm elementele {

aux=*(a+i); // păstrăm elemntul (a[0])*(a+i)=*(a+j); // se inversează (a[0]=a[1])*(a+j)=aux; // (a[1]= a[0]) şi etc.}

} printf("vectorul sortate\n"); for(i=0; i<n; i++) printf("%3d", *(a+i)); free(a); getch();}

Exemplul 6.8. Este dat vectorul a de lungimea n. Să se mişte ciclic la drapta cu x poziţii.#include<stdio.h>#include<conio.h>void main(){ int a[100], n, i, j, x, k; clrscr(); printf("\ndimen vec:");

39

Page 40: FisierFinal

scanf("%d", &n); printf("\nnumarul de pozitii de deplasare:"); scanf("%d", &x); printf("\nIntrodu numarul de elemente:\n"); for(i=0; i<n; i++) { printf("a[%d]=", i); scanf("%d", &a[i]); } for(i=0; i<x; i++) { k=a[n-1]; for(j=n-1;j>=0;j--) a[j]=a[j-1]; a[0]=k; } printf("şirul final\n"); for(i=0; i<n; i++) printf("%3d", a[i]); getch();}

Exemplul 6.9. Este dat vectorul a de lungimea n. Să se schimbe cu locurile elementul maximal cu cel minimal.#include<stdio.h>#include<conio.h>void main(){ int a[10], n, i, j, max, min, k; clrscr(); printf("\ndimen vec:"); scanf("%d", &n); for(i=0; i<n; i++) { printf("a[%d]=", i); scanf("%d", &a[i]); } printf("\nsirul initial\n\n"); for(i=0; i<n; i++) printf("%d ", a[i]); max=min=a[0]; for(i=0;i<n;i++) if(a[i]<min) {min=a[i]; k=i;} for(i=0; i<n; i++)

if(a[i]>max){max=a[i]; j=i;}a[k]=a[j];a[j]=min;

printf("\nşirul final\n\n"); for(i=0;i<n;i++) printf("%d ",a[i]); getch();}

Probleme propuse spre rezolvare:

1. Se dă un tablou de 10 elemente. Să se determine suma elementelor pare.2. Se dă un tablou de 10 elemente. Să se determine câte elementelor pare şi câte impare sunt.3. Se dă un tablou de n elemente. Să se determine produsul elementelor divizibile la 3.4. Se dă un tablou de n elemente. Să se tipărească elementele care se repetă cel mai des. Dacă

sunt mai multe de acelaşi fel, atunci să se indice unul din ele.5. Se dă un vector din n elemente. Să găsească poziţia ultimului element pozitiv.

40

Page 41: FisierFinal

6. Se dă un tablou de 10 elemente nici un element nu este nul. Să se determine de câte ori se schimbă semnul numerelor scrise în tablou (trebuie verificate câte două, ca să le vedem semnul mai bine le înmulţim).

7. Se dă un tablou de 10 elemente întregi pozitive formate din 2 cifre(10 - 99). Să se determine câte elemente sunt distincte (elementul se numără numai odată).

8. Se dă un tablou de 10 elemente. Să se determine de câte ori se întâlneşte elementul maxim în tablou.

9. Se dă un vector de n elemente. Să construiască un nou vector ce conţine aceleaş elemente ca tabloul iniţial cu condiţia că toate elementele negative preced pe cele pozitive.

10. Se dă un tablou de n elemente, toate elementele sunt diferite. Să se afişeze pe primele locuri elementele diferite de zero, apoi elementele egale cu zero păstrând ordinea lor (Ex:

1 2 0 4 0 –1 2 4 0 0).11. Se dă un tablou de n elemente. Să se deplaseze ciclic la stânga cu x poziţii (Ex: 1 2 3 4 5 ;

x=3 4 5 1 2 3).12. Se dă tablou a de n elemente. Să se alcătuiască algoritmul de numărare a elementelor

maxime şi minime din tablouul a de n.13. Se dă tablou a de n elemente. Să se construiască un nou vector de lungimea n, pentru care

elementul i este media aritmetică ale primelor i elemente din vectorul iniţial.14. Sunt daţi doi vectori de lungimea n cu elementele în ordine descrescătoare. Să se

construiască un alt vector de lungimea n+n elemente, în ordine crescătoare şi conţine elementele vectorilor iniţiali.

15. Se dă tabloul a de n elemente. Au fost introduse meciurile cu participarea echipei ZIMBRU. Elementele tabloului sunt egale cu zero (ZIMBRU a suferit înfrângere), 1 (meciul s-a terminat la egalitate) cu 2 (învingătoare). Să se stabilească în câte meciuri echipa a suferit înfrângere, în câte a câştigat şi în câte a fost la egalitate.

16. În tabloul t[31] a fost înscrisă temperatura zilnică a lunii ianuarie. Să se numere în câte zile a fost înregistrată temperatura sub zero grade şi în câte mai sus de zero grade. Să se stabilească numărul de zile z, în care a fost înregistrată o temperatură mai mică decât temperatura medie a lunii şi numărul de zile z1 în care temperatura a depăşit mărimea medie.

17. Se dă un vector din n elemente. Să se determine numărul elementelor pentru care elementele precedente sunt mai mari.

18. Statu-Palmă-Barbă-Cot a îngropat patru comori în vârfurile unui dreptunghi, scriindu-şi coordonatele comorilor pe un pergament. În timpul unei lupte cu Făt-Frumos pergamentul s-a pierdut. Din fericire, Statu-Palmă-Barbă-Cot a memorat coordonatele a trei puncte în care se află comorile. Scrieţi un program, care va determina coordonatele celei de a patra comori. Punctele în care au fost îngropate comorile au coordonate întregi (x1,y1), |x1|<100, |y1|<100. Coordonatele a trei vârfuri ale dreptunghiului se introduc de la tastatură în ordinea (x1,y1), ( x2,y2), ( x3,y3). Coordonatele celui de a patra vârf se afişează la ecran în ordinea (x4,y4). Exemplu: 1 1 5 1 1 7. Rezultat: 5 7.

19. Se dau N(N+1)/2 numere întregi strict pozitive, mai mici sau egale ca 10000. Să se aşeze aceste numere, dacă este posibil, într-o piramidă cu următoarele proprietăţi:piramida are N nivele, pe fiecare nivel 1 sunt 1 numere;fiecare număr din piramidă, în afară de cele de pe ultimul nivel, este egal cu suma celor două numere pe care “se sprijină”.Exemplu: 1 1 2 3 3 4 5 8 9 17Rezultat: 17

8 9 3 5 4 1 2 3 1.20. Se dă tabloul a de n elemente, unde este introdusă informaţia despre îndeplinirea planului

de producere a strungurilor de către 10 uzine de profil ce aparţin ministerului respectiv. Valorile .a[i] (i=0,..,n) au următoarea semnificaţie:

41

Page 42: FisierFinal

a[i]>0 numărul de strunguri produs supraplan de către uzină cu numărul de ordine i;

a[i]=0 arată că uzina a produs atât cât prevede planul; a[i]<0 indică câte strunguri nu ajung pentru a îndeplini planul.

Să se compună algoritmul de numărare a uzinelor ce au îndeplinit planul sau au depăşit. Să se stabilească dacă ministerul respectiv a îndeplinit planul, răspunsul da sau nu. Să se calculeze cu cât n-au realizat planul unele uzine (a[i]<0).

Întrebări de control:1. Ce înseamnă tablou. Cum se defineşte?2. Poate tabloul(vectorul) include diferite tipuri. Dacă da sau nu explicaţi. Daţi exemplu.3. int i, a[100], k=0;

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

if(a[i]<0) k=k*i; printf(“k=%d”,k); Ce se tipăreşte la ecran? Explicaţi. 4. Ce se tipăreşte? Explicaţi.

int i, a[100], k=0; for(i=0; i<6; i++)if(a[i]%2==1) k++; printf(“k=%d”,k);

5. Câtă memorie se alocă pentru un vector de lungimea n şi de tipul: int, double, char, float. ?6. Când se folosesc funcţile free() şi malloc(), şi ce fac ele? În care fişier se includ ele?7. Ce se tipăreşte? Explicaţi.

int i, a[100], k=1; for(i=0; i<6; i++)if(a[i]!=0) k=k*a[i];else k=0; printf(“k=%d”,k);

8. Sunt daţi doi vectori. Cum se face înscrierea ambilor vectori în al treilea vector? Şi ce dimensiune va avea al treilea vector?

42

Page 43: FisierFinal

Lucrare de laborator N7

Tema: Lucrul cu tablourile bidimensionale.

Scopul lucrării: obţinerea deprinderilor practice la utilizarea tablourilor bidimensionale şi operaţiile de prelucrare a lor.

Suport teoretic: Matricele sunt masive unidimensionale. Sintaxa de declarare este: tip nume[m][n] unde: tip – tipul de data folosit; poate fi unul din tipurile de baza (int, float, char, …) sau un tip

definit de utilizator (articole, obiecte); nume – numele prin care va fi referita matricea; n – numarul de linii din matrice; m – numarul de coloane din matrice.

Exemple de declaratii:

// matrice de intregi cu 10 linii si 10 coloane int vanzari[10][10];

// vector de valori realefloat temperature[3][15];

Memorarea matricelor se face, ca şi în cazul vectorilor, într-un spaţiu continuu de memorie. Numele matricei un pointer către adresa primului element. Elementele matricei sunt stocate în memorie linie după linie.

Pentru o declaraţie de forma float m[2][3] reprezentarea în memoria interna este: m

m[0][0] m[1][2]m[1][1]m[1][0]m[0][2]m[0][1]

Dimensiunea totală a matricei este calculată ca produs între numărul de linii, numărul de coloane şi dimensiunea unui element.

Iniţializarea matricei se poate face la declarare printr-o construcţie de forma:tip nume[][n]={{lista_valori1}, {lista_valori2}, …, {lista_valorim}}.

Se observă că în acest caz nu este necesară precizarea numărului de elemente asociat primei dimensiuni. Acesta va fi dedus automat de compilator din dimensiunea listei cu care se face initializarea. În cazul în care numărul de linii precizat este mai mare decât numărul de elemente din listă se va realiza o iniţializare parţială a matricei.

Exemple de iniţializări la declarare:

// iniţializare fără precizarea explicită a numărului de liniiint m1[][2] = {{1, 2}, {3, 4}, {5, 6}};

// iniţializare completă cu precizarea numărului de linii şi coloaneint m2[2][3] = {{17, 19, 23}, {29, 31, 37}};// iniţializare parţialăint m3[2][5] = {{7, 6}, {5}};

Accesul la elementele matricei se face direct; compilatorul calculează adresa elementului pe baza liniei, a coloanei, a numărului de elemente pe linie şi a dimensiunii unui element. Formula folosită este:

43

Page 44: FisierFinal

adr(m[i][j]) = adr(m[0][0]) + (i * nr_max_elemente_linie + j) * dim_element.

Numerotarea liniilor şi a coloanelor se face începând cu zero.

Exemple de accesare elemente:

// citeste al doilea element de pe a doua linie din matriceint a = m2[1][1];// modifica primul elementm2[0][0] = 7;

Transmiterea ca parametri se face ca şi in cazul vectorilor prin numele masivului. Problema care apare în cazul matricelor este aceea că numărul de coloane trebuie fixat pentru a permite calcularea de către compilator a adresei elementelor. În cazul în care se doreşte lucrul cu matrice oarecare, transmiterea se va face prin pointeri iar adresa elementelor se va calcula dupa formula prezentată anterior. În acest caz va trebui trimisă ca parametru atât dimensiunea maximă a matricei cât şi dimensiunea minimă a acesteia.

In practică apar cazuri în care matricele au anumite caracteristici care permit o stocare mai eficienta decât cea standard. Exemple de asemenea matrice sunt: matricele diagonale, matricele simetrice.

Matricele diagonale sunt matrice pătratice de dimensiune n care conţin elemente nenule numai pe diagonala principală:

7 0 00 2 00 0 11

In acest caz memorarea se va face folosind un vector de dimensiune n care va memora elementele de pe diagonala principala.

Exemplu de utilizare:

// declarare si initializareint matDiag[3] = {7, 2, 11};// citire valoareint val1 = CitireValoare(matDiag, 3, 1, 2);// scriere valoare (1, 1);ScriereValoare(matDiag, 3, 1, 1, 5);

Matricele simetrice sunt matrice patratice in care corespondente de sub şi de peste diagonala principala sunt egale (adica m[i][j] = m[j][i] pentru oricare i si j). În acest caz se va folosi un vector care va conţine numai elementele de peste şi de pe diagonala principală.Matricea

1 2 3 42 5 6 73 4 8 97 8 9 10

va fi liniarizata sub forma:

1 2 3 4 5 6 7 8 9 10

Calculul pozitiei elementului i,j dintr-o matrice de dimensiune n se face dupa formula:

jii

nijinijinnnp

2

)1()...21()(...)2()1(

pentru j <= i. Daca j > i, atunci se interschimbă i cu j.Funcţia de acces la elemente este:int& Valoare(int* matrice, int n, int i, int j)

44

Page 45: FisierFinal

{// interschimbăm elementele daca este cazulif (j > i){

int t = j;j = i;i = t;

}// calculam pozitiaint pozitia = i*n + (i*(i-1))/2 + j;return matrice[pozitia];

}

Exemplu de utilizare:// declarare si initializareint matSim[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};// citire valoareint val1 = Valoare(matSim, 4, 1, 2);// scriere valoare (1, 1);

Valoare(matSim, 4, 1, 1) = 7;Aceeaşi tehnica se poate aplica şi în cazul matricelor triunghiulare.

Matricele rare sunt matrice care au majoritatea elementelor nule (mai mult doua treimi). În acest caz este mai eficient să memorăm matricea sub forma a trei vactori care să conţină linia, coloana şi valoarea pentru elementele nenule.Pentru matricea:

0 0 0 00 0 0 230 7 0 00 0 0 0

vom avea vectorii:Linii: 1 2Coloane: 3 1Valori: 23 7

Alternativ, putem stoca elementele intr-un singur vector de articole care să conţină linia, coloana şi valoarea pentru fiecare element nenul.

Exemple de programe:

Exemplu 7.1. Este dată matricea de dimensiunea n*m. Să se afişeze câte elementele sunt pare pe fiecare linie.#include<stdio.h>#include<conio.h>#include<malloc.h>void main(){ int i,j,n,m,a[5][5],pare; clrscr(); printf("\nintroduceti numărul de linii"); scanf("%d",&n); printf("\nintroduceţi numărul de coloane"); scanf("%d",&m); printf("\nintroduceţi elementele matricei:\n"); for(i=0;i<n;i++) for(j=0;j<m;j++) { printf("a[%d][%d]=",i,j); scanf("%d",&a[i][j]); }

45

Page 46: FisierFinal

printf("\nAfişăm elementele matricei:\n"); for(i=0;i<n;i++) { for(j=0;j<n;j++) printf("%3d",a[i][j]); printf("\n"); } printf("\nAfisam cate elementele sunt pare si impare pe fiecare nie:\n"); for(i=0;i<n;i++) { pare=0; // notam prin k numărul de elemente pare for(j=0;j<n;j++) if(a[i][j]%2==0) //daca se împarte la 2 si restul este zero pare++; printf("%3d",pare);

} getch();}

Exemplul 7.2. Este dată matricea de dimensiunea n*n. Să se calculeze produsul unui vector de dimensiunea n cu matricea de dimensiunea n*n, Rezultatul va fi un vector de dimensiunea n.#include<stdio.h>#include<conio.h>#include<malloc.h>void main(){ int i,j,n,m,a[10][10],k=0,s,c[10],b[10]; clrscr(); printf("\nintroduceti numarul de linii"); scanf("%d",&n); printf("\nintroduceţi elementele matricei:\n"); for(i=0;i<n;i++) for(j=0;j<n;j++) { printf("a[%d][%d]=",i,j); scanf("%d",&a[i][j]); } printf("\nintroduceţi elementele vectorului:\n"); for(i=0;i<n;i++) { printf("b[%d]=",i); scanf("%d",&b[i]); } printf("\nprodusul unui vector cu o matrice:\n"); for(j=0;j<n;j++) { s=0; for(i=0;i<n;i++) s=s+b[i]*a[i][j]; c[k]=s; k++; } for(i=0;i<n;i++) printf("%3d",c[i]); getch();}

Exemplul 7.3. Este dată matricea de dimensiunea n*m. Să se afişeze maximul pe fiecare coloană dintre elementele pozitive. #include<stdio.h>#include<conio.h>#include<malloc.h>void main(){ int i,j,n,m,*a,max;

46

Page 47: FisierFinal

clrscr(); printf("\nintroduceţi numarul de linii"); scanf("%d",&n); printf("\nintroduceţi numarul de coloane"); scanf("%d",&m); a=(int*)malloc(n*m*sizeof(int)); // alocăm memorie printf("\nintroduceţi elementele matricei:\n"); for(i=0;i<n;i++) for(j=0;j<m;j++) { printf("a[%d][%d]=",i,j); scanf("%d",a+i*m+j); } printf("\nAfişăm elementele matricei:\n"); for(i=0;i<n;i++) { for(j=0;j<n;j++) printf("%3d",*(a+i*m+j)); printf("\n"); } printf("\nAfişăm maximul pe fiecare coloană:\n"); for(j=0;j<m;j++) { // notăm prin max primul element din fiecare coloană max=*(a+0*m+j); for(i=0;i<n;i++) // verificăm dacă elementul este mai mare ca zero if dacă este mai mare decât max if(*(a+i*m+j)>0 && *(a+i*m+j)>max) max=*(a+i*m+j); printf("%3d",max); } free(a); // eliberăm memoria ocupată getch();}

Exemplul 7.4. Este dată matricea de dimensiunea n*m. Să se calculeze suma elementelor mai sus de diagonala principală şi suma elementelor mai jos de diagonala principală.#include<stdio.h>#include<conio.h>#include<malloc.h>void main(){ int i,j,n,m,*a,sum=0,suma=0; clrscr(); printf("\n introduceţi numărul de linii"); scanf("%d",&n); a=(int*)malloc(n*n*sizeof(int)); printf("\n introduceţi elementele matricei:\n"); for(i=0;i<n;i++) for(j=0;j<n;j++) { printf("a[%d][%d]=",i,j); scanf("%d",a+i*n+j); } printf("\nAfişăm elementele matricei:\n"); for(i=0;i<n;i++) { for(j=0;j<n;j++) printf("%3d",*(a+i*n+j)); printf("\n"); } printf("\nAfisam suma elementelor mai sus de diagonala principală:\n"); for(i=0;i<n;i++) for(j=0;j<n;j++)

47

Page 48: FisierFinal

if(i<j) suma=suma+*(a+i*n+j); printf("%3d",suma); printf("\nAfisam suma elementelor mai jos de diagonala principala:\n"); for(i=0;i<n;i++) for(j=0;j<n;j++) if(i>j) sum=sum+*(a+i*n+j); printf("%3d",sum); free(a); getch();}

Probleme propuse spre rezolvare:1. Se dă un vector numeric de n elemente şi o matrice numerică de dimensiunea m*n. Să se

înmulţească matricea cu vectorul.2. Să se determine poziţia şi elementul maxim dintre elementele maxime de pe fiecare linie a

unei matrice de dimensiunea m*n.3. Să se afişeze toate elementele pare din matricea dată m*n.4. Este dată matricea n*n. Să se afişeze numărul elementelor negative de pe diagonala

secundară. Şi numărul elementelor pozitive de pe diagonala principală.5. Este dată matricea m*n. Să se afişeze numărul elementelor negative de pe fiecare linie. Şi

numărul elementelor pozitive de pe fiecare coloană.6. Determinaţi de câte ori se întâlneşte elementul minimal în matricea de dimensiunea m*n şi

afişaţi poziţiile unde se găseşte.7. Dintr-o matrice dată M, să se listeze valorile tuturor punctelor şa şi poziţia lor. M[i, j] este

considerat punct şa dacă este minim pe linia i şi maxim pe coloana j.8. Să se elimene dintr-o matrice A (cu m linii şi n coloane) linia 1 şi coloana k şi să se listeze

matricea rămasă. (Nu se va folosi o altă matrice).9. Să se afişeze matricea A (cu m linii şi n coloane) cu linia m+1 şi coloana n+1, unde

A[m+1, j] să fie suma elementelor de pe coloana j, cu j de la 1 la m, iar A[i, n+1] să fie suma elementelor de pe linia i, cu i de la 1 la n.

10. Se dă o fotografie specificată printr-o matrice pătratică, care conţine 0 şi 1 (0 pentru punctele albe, 1 pentru punctele negre). Se consideră fonul alb, obiectele negre. Iar dacă două puncte negre sunt vecine pe linie, coloană sau diagonală, atunci aparţin aceluiaşi obiect. Să se numere câte obiecte distincte apar în fotografie. Exemplu: 1 0 1 0

1 0 1 00 0 1 00 1 0 1. Rezultat: 2.

11. Se numeşte pătrat magic pătratul N*N, în care sunt înscrise numerele 1,2, .., N2 astfel încât suma numerelor fiecărei linii este egală cu suma elementelor fiecărei coloane şi, în plus, cu suma elementelor situate pe cele două diagonale ale pătratului. Scrieţi un program, care construieşte pătratul magic pentru N dat (2<N<=25).

Exemplu: 3Rezultat: 4 3 8 9 5 1 2 7 6.

12. Se consideră o matrice pătratică de dimensiune N*N (N<=50), ale cărei elemente sunt cifre de la 0 la 9. Să se afişeze toate elementele situate de asupra diagonalei principale (inclusiv pe diagonală) sub forma unui triunghi, ca în exemplul de mai jos. Datele se citesc de la tastatură.

13. Se dă matricea A[N, N] de numere întregi (N<=10). De parcurs matricea în urătoarea ordine: primul se va afişa A[N, 1] A[1, N].

14. Să se verifice dacă o matrice A(3,3) de tip întreg, este sau nu o matrice simetrică.

48

Page 49: FisierFinal

15. Se consideră un grup format din N2 (N<50) copii de înălţimi diferite. Se cere să se aşeze în spirală copiii în ordinea crescătoare a înălţimilor. Copilul cu înălţimea cea mai mică va fi plasat în centrul spiralei.

Exemplu: 3 1.80 1.90 1.75 1.65 1.70 1.55 1.68 1.78 1.95.

Rezultat: 1.95 1.90 1.80 1.65 1.55 1.78 1.68 1.70 1.75.

Întrebări de control:

1. Cum se defineşte o matrice ?2. Câte feluri de matrice cunoaşteţi ?3. Poate matricea include diferite tipuri. Dacă da sau nu explicaţi. Daţi exemplu.4. int i, j, b[3][3];

for(i=0; i++<3;)for(j=0;j<3;j++) { b[i][j]=8>>(i+j)%3; printf((“%4d”,*(*(b+i)+j));}

printf(“\n”); Ce se tipăreşte la ecran? Explicaţi. 5. Ce înseamnă matrice simetrică? Explicaţi.6. Care este funcţia de alocare a memoriei într-o matrice. Explicaţi cum vom aloca memorie

pentru matricea *a de dimensiunea n*m.7. Ce se tipăreşte la ecran? Explicaţi. for(i=0;i<n;i++) for(j=0;j<n;j++) { printf("a[%d][%d]=",i,j); scanf("%d",a+i*n+j); }

49

Page 50: FisierFinal

Lucrare de laborator N8

Tema: Subprograme.

Scopul lucrării: Definirea subprogramelor-utilizator, apelarea şi aplicarea lor.

Suport teoretic:

Subprogramele sînt unităţi de program care: au un algoritm propriu, pot fi proiectate independent, pot fi scrise independent, pot fi compilate independent, nu se pot executa independent ci numai în cadrul unui program (apel).

Avantajele utilizării lor: evitarea scrierii repetate a aceluiaşi set de instrucţiuni, creşterea eficienţei, prin reutilizarea subprogramelor (biblioteci de subprograme).

Programele se pot descompune în subprobleme (module), adică în grupe de acţiuni care se pot repeta de un număr de ori şi care se execută numai în funcţie de anumite condiţii. Acest lucru determină existenţa unui modul principal pentru prelucrările principale şi pentru activarea “subordonaţilor”. Când se apelează un subprogram, executarea continuă cu prima instrucţiune din respectivul subprogram. Când se termină executarea instrucţiunilor din subprogram, se continuă cu instrucţiunea următoare apelului, din blocul apelant.

Subprogramele in limbajul C++ se numesc funcţii.Subprogramele pot fi:

standard (predefinite) sau nestandard (utilizator)

Exemple de funcţii sdandard utilizate frecvent: Funcţii de i/o: gets (), fgets (), puts (), scanf (), printf (), getch (), getchar (), fscanf (), … Funcţii de lucru cu şiruri de caractere: strlen (), strcat (), strchr (), strcmp (), atoi (), … Funcţii matematice: exp(), log(), sin(), cos(), ceil(), floor(), pow(), sqrt(), abs(), …

Ce trebuie să ştim despre funcţii? cum le putem defini, cum să le apelăm, cum să stabilim legătura dintre funcţie şi programul apelant.

Definiţia conţine antetul funcţiei şi corpul acesteia. Nu este admisă definirea unei funcţii în corpul altei funcţii.

Sintaxa antetului: tip_rezultat nume (lista parametrilor formali);

Aici tip_rezultat poate fi : un tip standard, o adresă a unui tip definit anterior, o structură de tip articol. Dacă este omis se consideră ca fiind tipul int. sau

void nume (lista parametrilor formali)Dacă are tipul void , apelul la funcţie se face dintr-o linie de program aparte. În celelalte cazuri poate fi parte componentă a unor expresii.

Lista parametrilor formali este o listă separată prin virgule de nume de variabile şi tipurile asociate lor, care primesc valorile argumentelor atunci când este apelată funcţia. O funcţie poate să nu aibă parametri. Totuşi, parantezele sunt necesare, chiar dacă nu există parametri. Toţi parametrii funcţiei trebuie declaraţi individual, fiecare conţinând atât tipul cît şi

50

Page 51: FisierFinal

numele. Ei sînt creaţi la intrarea în funcţie şi distruşi la ieşirea din ea. Parametrilor formali li se pot aplica atribuiri sau folosiţi în expresii. Aceste variabile îndeplinesc sarcina de primire a valorilor argumentelor transmise funcţiei.

Corpul funcţiei este un bloc, care implementează algoritmul de calcul folosit de către funcţie. În corpul funcţiei apar (în orice ordine) declaraţii pentru variabilele locale şi instrucţiuni. Dacă funcţia întoarce o valoare, se foloseşte instrucţiunea return valoare. La execuţie, la întâlnirea acestei instrucţiuni, se revine în funcţia apelantă.

Sfera de influenţă a funcţiilor. Fiecare funcţie este un bloc de cod discret. Nici o instrucţiune din altă funcţie nu poate avea acces la el decât printr-un apel al funcţiei. De exemplu nu putem folosi goto pentru a sări în mijlocul altei funcţii. Codul şi datele definite într-o funcţie nu pot să interacţioneze cu codul sau cu datele definite în alta, deoarece cele două funcţii au diferite sfere de influenţă. Variabilele definite într-o funcţie se numesc variabile locale. Clasa de memorare este segmentul de stivă. Ele sînt vizibile doar la nivelul blocului în care au fost declarate. Durata de viaţă este egală cu durata execuţiei blocului respectiv. Adică variabilele locale nu-şi păstrează valoarea între apelările funcţiei. Excepţie este atunci când variabila se declară cu specificatorul de clasă de memorie static.

Variabilele globale se declară în afara oricărei funcţii şi pot fi utilizate de toate funcţiile care urmează declaraţiei respective. La declarare acestea sînt iniţializate automat cu 0. Ele au alocat spaţiu în tot timpul execuţiei programului. Sunt utile atunci când mai multe funcţii ale aceluiaşi program folosesc aceleaşi date.

Observaţie: în C++ toate funcţiile au acelaşi nivel de influenţă. Asta înseamnă că nu pot fi definite într-o funcţie alte funcţii.

Funcţia se utilizează prin apelare la ea. Apelul funcţiei este o construcţie urmată de punct şi virgulă, numită instrucţiune de apel, de forma:

nume_funcţie (lista_parametrilor_efectivi);Parametrii efectivi trebuie să corespundă cu cei formali ca ordine şi tip. La apel, se atribuie

parametrilor formali valorile parametrilor efectivi, după care se execută instrucţiunile din corpul funcţiei. La revenirea din funcţie, controlul este redat funcţiei apelante, şi execuţia continuă cu instrucţiunea următoare instrucţiunii de apel, din funcţia apelantă. O altă posibilitate de a apela o funcţie este aceea în care apelul funcţiei constituie operandul unei expresii (apelul funcţiei intervine intr-o expresie). Acest lucru este posibil doar în cazul în care funcţia returnează o valoare, folosită în calculul expresiei(doar pentru funcţiile cu tip). La întâlnirea instrucţiunii return, după atribuirea valorii, execuţia funcţiei se încheie şi se revine la funcţia care a apelat-o. În absenţa instrucţiunii return, execuţia funcţiei se încheie după execuţia ultimei instrucţiuni. În acest caz nu se întoarce nici o valoare.

Parametrii declaraţi în antetul unei funcţii sunt numiţi formali, pentru a sublinia faptul că ei nu reprezintă valori concrete, ci numai ţin locul acestora pentru a putea exprima procesul de calcul realizat prin funcţie. Ei se concretizează la execuţie prin apelurile funcţiei.

Parametrii folosiţi la apelul unei funcţii sunt parametri reali, efectivi, concreţi, actuali iar valorile lor vor fi atribuite parametrilor formali, la execuţie. Utilizarea parametrilor formali la implementarea funcţiilor şi atribuirea de valori concrete pentru ei, la execuţie, reprezintă un prim nivel de abstractizare în programare. Acest mod de programare se numeşte programare procedurală şi realizează un proces de abstractizare prin parametri.

Funcţiile comunică prin argumente: ele primesc ca parametri (argumente) datele de intrare, efectuează prelucrările descrise în corpul funcţiei asupra acestora şi pot returna o valoare (rezultatul, datele de ieşire). Transmiterea parametrilor se poate realiza:

prin valoare. Această metodă copiază valoarea unui argument într-un parametru formal al subprogramului. În acest caz modificările efectuate asupra parametrului nu au efect asupra argumentului;

51

Page 52: FisierFinal

prin referinţă (adresă). Prin această metodă în parametru se copiază adresa unui argument. Aceasta înseamnă că modificările efectuate asupra parametrului afectează argumentul. Se utilizează dacă e necesar a transmite în programul apelant mai mult decît o valoare. Cu puţine excepţii, C++ foloseşte apelarea funcţiilor prin valoare. Cînd o matrice este folosită ca un argument al unei funcţii, acesteia îi este pasată adresa matricei. Astfel, codul funcţiei operează asupra conţinutului efectiv al matricei şi poate să-l modifice.

Funcţiile pot fi descrise în cadrul aceluiaşi fişier, sau în fişiere diferite, care sunt testate şi compilate separat, asamblarea lor realizându-se cu ajutorul linkeditorului de legături.

Funcţii recursive se folosesc la programarea proceselor de calcul recursive. Recursivitatea este procesul de definire a unui lucru prin el însuşi. Se spune despre o funcţie că este recursivă, dacă o instrucţiune din corpul ei apelează chiar acea funcţie. Funcţia de calcul al factorialului e un exemplu simplu de funcţie recursivă. În limbajul C funcţia recursivă fact(n) poate fi realizată astfel:

double fact(int n) { if(n==0) return 1.0; else return n*fact(n-1); }

Exemple de programe:

Exemplul 8.1. Funcţia afisare afişează 65 de simboluri ‘*’ consecutive.#include<stdio.h>#define NAME “Vasilache Andrei”#define ADDRESS “Cogalniceanu, 65”#define LIM 40void afisare(void); // prototipul funcţieivoid main(){ afisare(); //apelul funcţiei printf(„\t%s\t”,NAME); printf(“%s\n”,ADDRESS); afisare(); // al doilea apel al funcţiei}void afisare(){ int n; for(n=1; n<=LIM; n++) putchar(‘*’); putchar(‘\n’);}

În urma execuţiei programului vom avea afişat p ecran: **************************************** Vasilache Andrei Cogalniceanu,65 ****************************************

Exemplul 8.2. Programul efectuează acelaşi lucru; dar funcţia are doi parametri : un caracter şi un întreg.#include<stdio.h>#define NAME “Vasilache Andrei”#define ADDRESS “Cogalniceanu, 65”#define LIM 65#define SPACE “ “void show_n_char(char ch, int n); // prototipul funcţieivoid main(){ int spaces; show_n_char(’*’,LIM); // apelul funcţiei putchar(’\n’);

52

Page 53: FisierFinal

show_n_char(SPACE,20); printf(”%s”,NAME); spaces=(60-strlen(ADDRESS))/2; show_n_char(SPACE, spaces); printf(“%s\n”,ADDRESS); show_n_char(’*’,LIM); // al doilea apel al funcţiei} void show_n_char(char ch,int n) { int i; for(i=1; i<=n; i++) putchar(ch); }

Exemplul 8.3. Programul înmulţeşte două valori întregi, utilizând o funcţie.#include<stdio.h>int prod(int a, int b) { return a*b; }void main(){ int x,y,z; x=10; y=20; z=prod(x,y); // funcţia e atribuită – folosită într-o expresie printf(“%i”, prod(x,y)); // funcţia nu e atribuită, dar e folosită prod(x,y); // valoarea returnată se pierde}

Exemplul 8.4. Programul calculează factorialul pentru numerele din intervalul 0 – 170, utilizând o funcţie.#include<stdio.h>#include<stdlib.h>double fact(int n); // prototipul funcţieivoid main(){ for (int m=0;m<171;m++) {printf(“m=%d \t m!=%g \n”,m, fact(m)); if((m+1)%23==0) // sau if(wherex()==23) { puts(“actionati o tasta”); getch(); } }double fact(int n){ double f; int i; if(n<0 || n>170) return -1.0; for(i=2, f=1.0; i<=n; i++) f*=i; return f; }

Exemplul 8.5. Funcţia calculează cel mai mare divizor comun a două numere întregi fără semn.unsigned dc(unsigned a, unsigned b){ unsigned c, d=1; if (a==0||b==0) return a>b?a:b; else for(c=2;c<=(a<b?a:b);c++) if(a%c==0 && b%c==0) d=c; return d;}

Exemplul 8.6. Programul citeşte două numere întregi fără semn şi calculează cel mai mic multiplu comun al lor. Este folosită funcţia din exemplul precedent care a fost salvată în fişierul “d:\bc\director\ex8_5.cpp”#include<stdio.h>#include<conio.h>#include” d:\\bc\\director\\ex8_5.cpp”void main(){ unsigned a, b, c; clrscr();

53

Page 54: FisierFinal

puts(“introdu doua numere fara semn:”); scanf(“%u%u”,&a,&b); c=dc(a,b); printf(“cmmmc(a,b)=%u”,a*b/c); getch();}

Exemplul 8.7. Să se determine o rădăcină a ecuaţiei 6cos(x)+8sin(x)=0 pe segmentul [2,4] cu precizia eps=0.00017 prin metoda bisecţiei.#include<stdio.h>#include<conio.h>#include<math.h>#define eps 0.0001float f( float x){ return 6*cos(x)+8*sin(x);}void main(){ clrscr(); float a=2.0, b=4.0; float ya,yc; double c; int n=0; lab1: c=(a+b)/2.0; ya=f(a); yc=f(c); n++; if ((c-a)<=eps){

printf("%7.4f-radacina aproximativa,n=%d",c,n);goto end; }

if(n>=100) { printf ("convergenta slaba, n=%d",n); goto end; }

if((ya*yc)<0){ b=c; goto lab1; } else { a=c; goto lab1; } end: getch(); }

Exemplul 8.8. Funcţia schimbă cu locurile simbolul cu cod maxim cu simbolul cu cod minim într-un şir de caractere#include<stdio.h>#include<conio.h>void fct(char *s);void main() { int i; char *sir; puts(“Input string:”); gets(sir); fct(s); puts(s); } void fct(char *s) { int i = 0, max = *s, min = *s, pmin = 0, pmax = 0; char ch; for ( ; s[i]; i++) { if (s[i]>max) { max = s[i]; pmax = i; } if (s[i]<min) { min = s[i]; pmin = i; } } ch=*(s+pmax); *(s+pmax)=*(s+pmin); *(s+pmin)=ch; }

Exemplul 8.9. Programul prelucrează un şir numeric. Se utilizează o funcţie de citire a elementelor şi o funcţie ce returnează numărul de elemente pare negative din şir.#include<stdio.h>#include<conio.h>// prototipul functiei de citire a elementelor in masivvoid citire(int s[], int n); // prototipul functiei de numarare a elementelor pare negativeint numar(int s[], int n); void main()

54

Page 55: FisierFinal

{ int i, m[10], dim; puts(”dimensiunea sirului numeric:”); scanf(”%i”,&dim); citire(m,dim); printf(”sint %i numere pare negative”, numar(m,dim));}void citire(int s[], int n) { puts(”Elementele masivului:”); for(int i=0; i<n; i++) scanf(”%i”,&s[i]); }int numar(int s[], int n) { int i, c=0; for(i=0; i<n; i++) if(s[i]<0 && s[i]%2==0) c++; return c; }

Exemplul 8.10. Programul afişează elementul maxim de pe liniile unei matrice. Se utilizează o funcţie care primeşte drept argumenţi un pointer la matrice şi numărul liniei.#include<stdio.h>#include<stdlib.h>int n, m; // variabile globale, acestea fiind dimensiunea matricei// prototipul functiei de determinare a elementului maxim pe linia kint max(int *p, int k); void main(){ int *p, i, j, z; puts(”dimensiunea matricei:”); scanf(”%i%i”,&n, &m); //alocare dinamică de memorie pentru matrice p = (int*)malloc(n*m*sizeof(int)); for(i=0; i<n; i++) { for(j = 0; j < m; j++) { *(p+i*m+j)= random(11); // generare aleatoare a elementelor matricei printf(” %i ”, *(p+i*m+j)); } printf(”\n”); } for( i = 0; i < n; i++) { // funcţia primeşte ca argumenţi pointerul la matrice şi numărul liniei z = max(p,i); printf(„Maximum pe linia %i - %i\n”, i+1, z); }}int max(int *p, int k){ int M, x; M=*(p+k*m+0); for( x = 0; x < m; x++) if ( M < *(p+k*m+x) ) M = *(p+k*m+x); return M; }

Exemplul 8.11. Programul sumează componentele unui şir numeric. Se utilizează o funcţie recursivă#include<stdio.h>#include<conio.h>int suma(int v[], int n); // prototipul functiei recursivevoid main(){ int i, a[10], dim; puts(”dimensiunea sirului numeric:”); scanf(”%i”,&dim); for(i = 0; i < dim; i++) scanf(“%i”,&a[i]);

55

Page 56: FisierFinal

printf(”suma elementelor - %i”, suma(a,dim-1)); getch();}int suma(int v[], int n){ if(n == 1) return 0; else return (v[n-1] + suma(v,n-1); }

Exemplul 8.12. Funcţia cu număr variabil de parametri sumează numere întregi.#include<stdio.h>#include<conio.h>int suma(int m,...); // prototipul funcţiei cu număr variabil de parametrivoid main(){ printf(”suma elementelor - %i”, suma(2,6,4)); printf(”suma elementelor - %i”, suma(6,1,2,3,4,5,6)); getch(); }int suma(int m,...){ int *p=&m, t=0; for(; m; m--) t += *(++p); return t; }

Probleme propuse spre rezolvare:

1. Să se realizeze un program care conţine o funcţie ce citeşte elementele unui vector de dimensiunea n cu valori întregi şi o funcţie ce returnează câte elemente impare pozitive sunt.

2. Să se realizeze un program care conţine o funcţie ce citeşte elementele unui vector de dimensiunea n cu valori întregi şi o funcţie ce returnează produsul elementelor pare pozitive.

3. Să se realizeze un program care conţine o funcţie ce citeşte elementele unui vector de dimensiunea n cu valori reale şi o funcţie ce returnează indicele celui mai mare element.

4. Să se realizeze o funcţie care primeşte un simbol ca parametru şi returnează numărul lui de ordine dacă-i literă şi -1 în caz contrar. (De ex.: şi ‘c’ şi ‘C’ sunt litere cu numărul de ordine 3).

5. Să se realizeze o funcţie care primeşte un şir de simboluri ca parametru şi returnează 1 dacă şirul e palindromic (se citeşte la fel din ambele direcţii) şi 0 în caz contrar.

6. Să se realizeze un program care conţine o funcţie ce citeşte elementele unui vector de dimensiunea n cu valori întregi şi o funcţie ce returnează lungimea celui mai lung subşir nedescrescător din acest tablou.

7. Programul calculează suma pătratelor numerelor din segmentul [m,n]. Se foloseşte o funcţie recursivă pentru a calcula suma.

8. Programul determină cel mai mic număr dintr-un şir numeric. Se foloseşte o funcţie recursivă.9. Programul afişează cuvintele cu lungimea mai mare decât 6 simboluri dintr-un şir de

caractere, care este pasat unei funcţii. 10. Date numerele reale s, t. De obţinut y = f( t, -2s, 1.47 ) + f( 2.2, t, s-t ), unde

11. Date numerele reale a, b, c. De calculat .

Întrebări de control:

1. O funcţie este total caracterizată de : ...2. Dacă funcţia f are următorul prototip: tip f(lista parametrilor), atunci tip poate fi:

i. vector

56

Page 57: FisierFinal

ii. structurăiii. întreg, real sau caracteriv. pointer spre un tip definit anteriorv. tablou bidimensional

3. Cum se numesc parametrii folosiţi la definiţia unui subprogram?4. O funcţie întoarce obligatoriu o valoare?5. O funcţie trebuie să conţină obligatoriu parametri?6. Ce tipuri de subprograme cunoaşteţi?7. Ce trebuie să ştim despre funcţii? 8. Ce prezintă antetul funcţiei?9. Ce metode de transmitere a argumenţilor în funcţii cunoaşteţi?10. Ce este o funcţie recursivă?11. Funcţiile trebuie definite şi descrise obligator în acelaşi fişier cu programul apelant?12. Ce va tipări funcţia?int a=1;void f() { int b=1, c=1; printf(”a=%i b=%i c=%i\n”, a++, b++, c++); }void main() { while(a<4) f(); }

13. Ce va tipări funcţia? int fun(int n, int a, int b) { int z=1, i; for (i=1; i<n; i++) z=z+a*b; return z; } void main() { int x=5, y=6, j=1; while (j<6) { printf(”%i %i \n”, j, fun(j,x,y)); j++; } } 14. Ce se va afişa în urma rulării programului?: f(int a, int &b, int c) { a=++b; c=a+=2; return a+b+c/3; } void main() { int a, b, c; a=b=c=1; printf(”a=%i b=%i c=%i f=%i”, a, b, c, f(a,b,c)); }

15. Ce valori va returna funcţia f() apelată în programul principal? int f(const char *s) { int n=0; for( ; *s++ != ’\0’; n++ ); return n; } void main() { printf( “%s”, f(“informatica”); }

57

Page 58: FisierFinal

Lucrare de laborator N9

Tema: Tipuri de date definite de utilizator, redenumirea tipurilor.

Scopul lucrării: Definirea şi utilizarea unui tip nou de date: structuri, reuniuni, enumerări, câmpuri de biţi; însuşirea modalităţii de redenumire a tipurilor.

Suport teoretic:

Un mod de grupare al datelor este tabloul. Tabloul este un set ordonat de date de acelaşi tip. Un alt mod de grupare al datelor este structura. Structura reuneşte date de diferite tipuri, dar care se află într-o legătură logică. Obiectele ce fac parte din structură se numesc câmpuri sau membrii structurii. La definirea şi utilizarea structurilor e necesar a cunoaşte trei lucruri: 1) definirea structurii; 2) declararea variabilei, care corespunde acestui tip; 3) asigurarea accesului la componentele variabilei-structură.

O declaraţie de structură are forma:

struct nume { lista de declaraţii } nume1, nume2,…, numen;

Aici nume defineşte un tip nou de date, iar nume1, nume2,..., numen sunt structuri, adică variabile de tipul nume; lista de declaraţii declară componentele structurii de tip nume. Exemplu de definire: struct { char title[20]; int year; float value; };. Structura dată are 3 câmpuri. In unul se păstrează denumirea cărţii, în altul – anul ediţiei, în al treilea – preţul. Tipului structură i se poate asocia un nume generic, care poate fi indicat în forma: typedef struct { char title[20]; int year; float value; } book ;. Specificatorul typedef este executat de către compilator, nu de către preprocesor ca #define. În continuare numele generic book poate fi utilizat la definirea noilor structuri. Există şi altă modalitate de asociere a numelui generic tipului structura: struct book { char title[20]; int year; float value; };. Această modalitate este necesară la definirea structurilor recursive deoarece typedef nu este suficient: struct node{ int date; node* next; };. Structura S nu poate conţine membri de tipul S, dar poate conţine membri ce pointează către S. Observaţie: când definiţi o structură, definiţi nu o variabilă, ci un tip compus de variabile. Nu va exista nici o variabilă până nu veţi declara una de acest tip.

Declararea variabilelor de tip structură se poate face odată cu definirea ei: struct { char title[20]; int year; float value; } date1, mas[10];. În C++ dacă a fost deja declarată o structură, putem declara variabile de acest tip folosind doar numele ei generic, fără a preceda cu cuvântul cheie struct. De exemplu având declararea struct book { char title[20]; int year; float value; }; putem declara book date2, date3[10]. Când este declarată o variabilă de tip structură compilatorul de C/C++ alocă automat suficientă memorie pentru toate elementele ei. Lungimea zonei de memorie rezervată pentru variabila de tip struct rezultă din însumarea lungimilor câmpurilor. Aceasta nu poate depăşi 65520 octeţi (ca orice variabilă de tip structurat). Pentru o structură îşi dovedeşte utilitatea operatorul sizeof, care asigură determinarea lungimii zonei de memorie asociate unei variabile sau unui tip de date.

Accesul la membrii stucturii se face în două moduri: global sau pe componente. Referirea globală este permisă numai în operaţia de atribuire, cu condiţia ca ambele variabile (sursă şi destinaţie) să aibă acelaşi tip. Referirea pe componente (prin numele lor) este o reflectare a faptului că articolul este o structură cu acces direct. Referirea câmpurilor unei structuri se face prin calificare, folosind operatorul. (punct). De exemplu: dacă declarăm book libry, identificatorul libry.value indică la membrul value al structurii libry. Identificatorul libry.value

58

Page 59: FisierFinal

este variabilă de tipul float şi se utilizează asemănător variabilelor de acest tip, ca de exemplu: scanf(“ %f ”,&libry.value). Dacă sunt declarate două variabile a şi b de acelaşi tip structură putem efectua atribuirea a=b. Nu se admite atribuirea între variabile de tip structură care aparţin şabloanelor diferite, fie şi foarte asemănătoare.

Se pot declara pointeri către structuri. Există două întrebuinţări ale pointerilor pentru structuri : generarea unei apelări de funcţii prin referinţă şi crearea listelor înlănţuite. De exemplu : struct bal { float bilanţ; char nume[80]; } pers, *pstr;. Atunci pstr=&pers; plasează adresa structurii pers în pstr. Pentru a avea acces la membrii structurii folosind acest pstr se utilizează operatorul ->: pstr->bilanţ , pstr->nume[0].

Un alt mod de grupare a datelor este reuniunea. Diferenţa este doar aceea că se substituie cuvântul struct prin cuvântul union. Declararea tipului reuniune se realizează astfel: union nume_tip { tip_cimp1 cimp1; tip_cimp2 cimp2; ...; tip_cimpn cimpn;};Spre deosebire de o structură lungimea zonei de memorie rezervate pentru o variabilă de tip reuniune va fi egală cu maximul dintre lungimile câmpurilor componente. Gestiunea conţinutului respectivei zone de memorie va trebui realizată de către programator.

Referirea la elementele unei reuniuni se face ca şi la structuri.

Exemplu de declarare de reuniune: union a { int x; long y; double z; char z[5]; } p, r[6], *t;

Aici s-au declarat reuniunea p de tipul a, tabloul de reuniuni r ce constă din 6 elemente şi fiecare element este o reuniune de tipul a, un pointer t ce pointează spre acelaşi tip a. Pentru fiecare reuniune declarată se vor aloca câte 8 octeţi, deoarece tipul double necesită 8 octeţi – numărul maxim.

Un alt tip definit de utilizator este tipul enumerare. Acest tip permite folosirea numelor sugestive pentru valori numerice.

O declaraţie de tip enumerare are forma:

enum nume_generic { nume0, nume1, …, numen} listă_variabile;

Aici nume_generic este numele tipului enumerare nou declarat, nume0, nume1,..., numen sunt numele sugestive care se vor folosi în continuare în locul valorilor numerice 0, 1, ..., n şi anume: nume0 substituie valoarea 0, nume1 substituie valoarea 1, ..., numen substituie valoarea n. Iar listă_variabile sunt declarate variabile de tipul nume_generic, adică variabile de acest tip enumerare. Aceste variabile sunt similare cu variabilele de tip int. De exemplu definim enum season { win,spr,sum,aut } s; Atunci printf(“%d %d”, spr,sum) va afişa 1 2.

La declaraţia tipului enumerare se pot impune şi alte valori pentru numele sugestive. De exemplu, dacă vom folosi construcţia numei=si în loc de numei în lista numelor sugestive, atunci aceasta va impune pentru numele sugestiv numei valoarea si. Respectiv numei+1 va avea valoarea si+1. Dacă definim în felul următor enumerarea de mai sus enum seazon { win=1,spr,sum,aut } s; Atunci printf(“%d %d”, spr,sum) va afişa 2 3.

Limbajul de programare C permite accesul la unul sau mai mulţi biţi din octet. Una din metodele de prelucrare pe biţi este organizarea unui tip nou – tipul câmpuri de biţi. Aceştia sunt

59

Page 60: FisierFinal

structuri speciale în care se definesc numărul de biţi ocupaţi de fiecare element. O declaraţie pentru un tip câmpuri de biţi are forma:

struct nume { tip nume_cimp1 : lungime_cimp ; tip nume_cimp2 : lungime_cimp ; ……………………………………… tip nume_cimpn : lungime_cimp ; } n1, n2,..., nm;

Aici tip poate fi unsigned, int, signed, char, unsigned char, iar lungime_cimp este lungimea câmpului în biţi şi nu poate depăşi doi octeţi. Numele câmpului poate lipsi, atunci el defineşte o zonă de biţi ne utilizată din octetul respectiv. Lungimea câmpului poate fi 0, atunci câmpul următor se alocă în octetul următor. Biţii se alocă începând de la biţii de ordin inferior ai octetului spre cei de ordin superior. Dacă un câmp nu încape în octetul curent, el se alocă în octetul următor.

Referirea la câmpurile de biţi se face ca şi în cazul structurilor obişnuite. Exemplu de declarare a tipului câmpuri de biţi:

struct BITFIELDS { unsigned a : 2; int b : 4; unsigned c : 1; unsigned : 3; int d : 2 ; } x;

Aici este declarată variabila x de tipul câmpuri de biţi. Această declarare ne asigură următoarea amplasare:

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0ne utilizaţi d ne utilizaţi c b a

Dacă câmpul d ar fi avut lungimea mai mare decât 6 ar fi fost amplasat automat în următorul octet. Pentru a regla în mod forţat acest lucru se foloseşte, după cum s-a spus mai sus, lungimea 0 a unui câmp.

În structuri pot fi utilizaţi în comun atât componente obişnuite cât şi câmpuri de biţi. De exemplu: struct angajat { char nume[20]; float plata; unsigned active : 1; // activ sau întrerupt

unsigned impozit : 3; } ; defineşte o înregistrare despre salariat care foloseşte doar un octet pentru a păstra două informaţii: statutul angajatului şi impozitul. Variabilele de tip câmpuri de biţi au şi restricţii: 1) nu putem obţine adresa unui câmp de biţi; 2) nu pot fi introduse în tablouri.

C admite o facilitate numită typedef pentru a crea nume pentru noi tipuri de date. O astfel de declaraţie de tip are forma:

typedef nume_tip_vechi nume_tip_nou;

De exemplu declaraţia: typedef int LENGTH; face numele LENGTH sinonim pentru "int". Tipul LENGTH poate fi utilizat în declaraţii exact la fel ca int: LENGTH len, maxlen; LENGTH *lengths[];

Similar, declararea: typedef char* STRING;face ca STRING sa fie sinonim cu char* sau pointerul unui caracter, care poate fi utilizat în declaraţii ca: STRING p, lineptr[LINES] ;

60

Page 61: FisierFinal

Exemple de programe:

Exemplul 9.1. Programul simplifică o fracţie raţională. Simplificarea se face prin împărţirea numărătorului şi numitorului la cel mai mare divizor comun al lor.#include<conio.h>#include<stdio.h>void main(){// câmpul n reprezintă numărătorul, m - numitorul typedef struct { long unsigned n; long unsigned m; } Rational; Rational s; long unsigned k, cmmdc=1, h; clrscr(); puts(“Introduceţi o fracţie raţională”); scanf (“%lu%lu”,&s.n,&s.m) ; puts(“Aţi introdus fracţia: “); printf(“%lu/%lu\n”,s.n,s.m); h=s.n < s.m ? s.n : s.m; // h este minimul dintre numărător şi numitor for(k=1;k<h/2;k++) if(s.m%k==0 && s.n%k==0) cmmdc=k; s.n=s.n/cmmdc; s.m=s.m/cmmdc; puts(“Fracţia simplificată este:”); printf(“%lu/%lu”,s.n,s.m); getch();}

Exemplul 9.2. Programul declară o structură carte care conţine 3 elemente. Primul element conţine numele autorului, al doilea – denumirea cărţii, al treilea – preţul. Sunt prelucrate informaţiile despre câteva cărţi.#include<conio.h>#include<stdio.h>#define maxc 100struct carte { char nume[20]; char titlu[40]; float pret; }void main(){ carte bibl[maxc]; // tablou de cărţi int i, c=0; puts(“Dati titlul cărţii. Pentru sfârşit acţionaţi [enter] la început de linie“); while ( c<maxc && gets(bibl[c].titlu) !=NULL && bibl[c].titlu[0] !=’ \0 ’ ) { puts(“Autor:”); gets(bibl[c].nume); puts(“Preţul:”); scanf(“%f”, &bibl[c++].pret); fflush(stdin); // golirea intrării puts(“Introduceţi titlul următoarei cărţi:”); } puts(“Iată lista cărţilor”); for (i=0;i<c;i++) printf(“%s, %s : $%.2f\n”,bibl[i].titlu, bibl[i].nume, bibl[i].pret);}

Exemplul 9.3. Se dă o listă de persoane şi punctajele obţinute de acestea la un concurs. Programul ordonează descrescător persoanele în funcţie de punctaj şi afişează lista ordonată.#include<conio.h>#include<stdio.h>#define max 20struct persoana { char nume[max]; int punctaj ; } ;int Citeste ( persoana p[]){ int i,n;

61

Page 62: FisierFinal

printf(“Daţi numărul de persoane: “); scanf(“%d”,&n); for (i=0; i<n; i++) {fflush ( stdin ); printf ( “Daţi numele persoanei nr. %d: “, i+1); gets( p[i].nume ); p[i].nume[max]=’\0’ ; printf ( “Daţi punctajul lui %s: “, p[i].nume ); scanf ( “%d“, &p[i].punctaj ) ; fflush ( stdin ) ; } return n;}void Schimba ( persoana *a, persoana *b){ persoana aux; aux=*a; *a=*b; *b=aux;} int Ordoneaza ( persoana p[], int n){ int i, j, ord=1 ; for ( i=0 ;i<n-1 ;i++) if ( p[i].punctaj<p[i+1].punctaj ) ord=0 ; if ( !ord ) { for ( i=0; i<n-1; i++ ) for ( j=i+1; j<n; j++) if ( p[i].punctaj<p[j].punctaj ) Schimba ( &p[i], &p[j] ); } return ( !ord );}void Afiseaza ( persoana *x, int n ) { int i; for ( i=0; i<n; i++ ) printf ( “%d. %20s -> %4d. \n “, i+1, x[i].nume, x[i].punctaj ); } void main(){ persoana x[max]; // şirul persoanelor int n; clrscr(); puts ( “Ordonare personae dupa punctaj” ); if (( n = Citeste(x))==0 ) puts ( “Nu exista persoane.” ); else { if ( Ordoneaza (x,n) puts ( “Am ordonat persoanele” ); else printf ( “Persoanele erau deja ordonate\n” ); Afiseaza(x,n); } getch();}

Exemplul 9.4. Programul exemplifică folosirea reuniunilor pentru citirea şi afişarea datelor despre mai multe persoane de ambele sexe.#include<conio.h>#include<stdio.h>#include<stdlib.n>union partener { char sotie[20]; char sot[20]; } ; struct persoana { char nume[20]; char sex; int virsta; union partener p; } ;void Citeste ( int nr_p, persoana *x ){ int vs; char sx; printf ( “Se citesc datele persoanei a %d-a:\n”, nr_p ); fflush ( stdin ); puts ( “Numele:” ); gets ( x->nume );

62

Page 63: FisierFinal

puts ( “Virsta:” ); scanf ( “%d”, &vs ); x->virsta=vs; fflush ( stdin ); puts ( “Sexul:” ); scanf ( “%c”, &sx ); x->sex=sx; fflush ( stdin ); if ( x->sex==’F’ || x->sex==’f’ ) { puts ( “Dati numele sotului:” ); gets ( x->p.sot ); } else { puts ( “Dati numele sotiei:” ); gets ( x->p.sotie ); }}void Scrie ( int nr_p, persoana x ){ if ( wherey ()==20 ) { puts ( “Apasati o tasta” ); getch(); } printf ( “Datele persoanei a %d-a:\n”, nr_p ); printf ( Numele: %s Virsta: %d Sexul: %c “, x.nume, x.virsta, x.sex ); if ( x.sex==’F’ || x.sex==’f’ ) printf ( “Numele sotului: %s\n”, x.p.sot ); else printf ( “Numele sotiei: %s\n”, x.p.sotie );}void main(){ clrscr(); persoana om[20]; int i,n; puts ( “Dati numarul de personae:” ); scanf ( “%d”, &n ); for ( i=0; i<n; i++) Citeste ( i+1, &om[i] ); for ( i=0; i<n; i++ ) Scrie ( i+1, om[i] ); getch();}

Exemplul 9.5. Programul afişează codul binar ASCII al simbolului introdus de la tastatură.#include<stdio.h>#include<conio.h>

struct byte { int b1:1; int b2:1; int b3:1; int b4:1; int b5:1; int b6:1; int b7:1; int b8:1; } ;

union bits { char ch; byte bit;} b;

void decode ( bits b );void main(){ do { b.ch=getche(); printf ( ":" ); decode ( b ); } while ( b.ch!='q' );}void decode ( bits u ){ if ( u.bit.b8 ) printf ( "1" ); else printf ( "0" ); if (u.bit.b7 ) printf ( "1" ); else printf ( "0" ); if ( u.bit.b6 ) printf ( "1" ); else printf ( "0" ); if ( u.bit.b5 ) printf ( "1" ); else printf ( "0" ); if ( u.bit.b4 ) printf ( "1" ); else printf ( "0" ); if ( u.bit.b3 ) printf ( "1" ); else printf ( "0" ); if ( u.bit.b2 ) printf ( "1" ); else printf ( "0" ); if ( u.bit.b1 ) printf ( "1" ); else printf ( "0" ); printf ( "\n" );

63

Page 64: FisierFinal

}

Exemplul 9.6. Programul exemplifică folosirea enumerărilor.#include<stdio.h>#include<conio.h>enum spectrum { red, orange, yellow, green, blue, violet } ;void main(){ enum spectrum color; puts ( “Introduceti culoarea ( pentru ieşire – tastaţi q )” ); while ( ( scanf (“%d”, &color)) == 1 ) { switch ( color ) { case red : puts ( “Trandafirii sunt rosii” ); break; case orange : puts ( “Macii sunt orange” ); break; case yellow : puts ( “Florile florii soarelui sunt galbene” ); break; case green : puts ( “Iarba este verde” ); break; case blue : puts ( “Clopoţeii sunt albaştri” ); break; case violet : puts ( “Toporasii sunt violeti” ); break; default : printf ( “Nu cunosc nimic de culoarea data.\n” ); } puts ( “Urmatoarea culoare “); }}

Exemplul 9.7. Programul declară un tablou de structuri student cu elementele: nume – numele studentului, tabloul note[5] – pentru a păstra notele, med – pentru păstrarea notei medii. Se utilizează funcţiile de introducere a datelor despre fiecare student, de calculare a notei medii fiecărui student şi atribuirii ei variabilei med, de afişare a listei studenţilor.#include<stdio.h>#include<conio.h>#include<stdlib.h>struct student { char nume[10];

int note[5]; float med; };void initiere (student * s, int n);void calcul (student * s, int n);void afisare (student * s, int n);void main(){

int n; clrscr(); student *m; puts (“Daţi numărul de studenţi:”); scanf (“%d”, &n); m=(student*)malloc(n*sizeof(student)); initiere (m,n); calcul (m,n); afisare (m,n); getch ();}void initiere (student * s, int n){ int i, j, q; for ( i=0; i<n; i++ ){ fflush ( stdin ); printf ( "nume %i: ", i+1 ); gets ((s+i)->nume); for ( j=0; j<5; j++ ) { printf ( "nota %i: ",j+1); scanf ( "%i",&q ); (s+i)->note[j]=q;

} }

}void calcul ( student* s, int n){ int i,j; float f; for (i=0; i<n; i++ )

64

Page 65: FisierFinal

{ f=0.0; for ( j=0; j<5; j++ ) f+=(s+i)->note[j]; (s+i)->med=f/5.0; } }void afisare ( student *s, int n){ puts (" NUME | MEDIA "); for ( int i=0; i<n; i++ ) printf ( "%-10s|%7.1f\n",(s+i)->nume, (s+i)->med );}

Probleme propuse spre rezolvare:

1. Programul realizează operaţii cu fracţii raţionale ( introducere, extragere, atribuire, inversare, adunare, scădere, înmulţire, împărţire ).

2. Programul realizează admiterea la un liceu şi permite: iniţializarea vectorului de înregistrări de tip elev; adăugarea unui elev în vector; înlocuirea unui elev cu alt elev; inserarea unui elev pe o anumită poziţie în vector; eliminarea din vector a unui elev având un anumit nume; căutarea unui elev după nume; calcularea mediilor; listarea alfabetică a elevilor; listarea elevilor în ordinea descrescătoare a mediilor.

3. Programul administrează un parc de automobile. Informaţiile relative la un automobil sunt: numărul de locuri, marca, tipul de carburant, numărul de înmatriculare. Programul permite intrarea unei maşini, ieşirea unei maşini, înlocuirea unei maşini cu alta de acelaşi model (având alt număr de înmatriculare).

4. Programul invită utilizatorul să introducă ziua, luna (denumirea prescurtată), anul şi afişează numărul zilelor ce s-au scurs de la începutul anului până la ziua introdusă.

5. Fiind date două fracţii p şi q programul afişează forma ireductibilă a fracţiilor p+q, p-q, p/q, p*q, punând în evidenţă numărătorul şi numitorul acestora.

6. Programul determină de câte ori o persoană născută în anul A>1900, luna L, ziua z, având vârsta v şi-a aniversat ziua de naştere în aceeaşi zi a săptămânii cu cea în care s-a născut.

7. Programul calculează valoarea unei expresii raţionale.8. Programul determină denumirea zilei după o dată calendaristică presupusă corectă. Folosiţi

tipul union.

Întrebări de control:

1. Ce este un tip definit de utilizator ? Care sunt aceste tipuri şi necesitatea lor ? 2. Ce este o structură ? Care este deosebirea dintre o structură şi un tablou ?3. Cum se declară o structură ? Cum se face referirea la componentele unei structuri ? 4. Cum se alocă memorie unei structuri ?5. Definiţi o structură care să conţină denumirea prescurtată a lunii până la trei simboluri,

numărul de zile a lunii şi numărul de ordine al lunii.6. Definişi un tablou din 12 structuri ca în punctul 5 şi efectuaţi iniţializarea lui pentru un an

bisect.7. Condiţia ca două puncte distincte A şi B ( de tip structură) să aparţină aceleiaşi axe de

coordonate este:a) A.x==0 && B.x==0 && A.y==0 && B.y==0 b) ( A.x==0 || B.x==0 ) && ( A.y==0 || B.y==0)

65

Page 66: FisierFinal

c) A.x==0 && B.x==0 || A.y==0 && B.y==0d) A.x==0 || B.x==0 && A.y==0 || B.y==0

8. Este dat un fragment de program: struct name { char first[20]; char last[20]; } ; struct bem { int limbs; name title; char type[30]; } ; bem *pb; bem deb = { 6, { “Bernazel”, “Gwolkapwolk” }, “Arcturan” };

A) Ce va afişa: printf(“%d\n”, deb.limbs); printf(“%s\n”, pb->type); printf(“%s\n”, pb->type + 2) ?

B) Cum poate fi accesat „Gwolkapwolk” ( în două moduri ).9. Ce este o reuniune ? Care este deosebirea dintre o structură şi o reuniune ?10. Cum se alocă memoria pentru o reuniune ?11. Ce reprezintă tipul câmpuri de biţi ?12. Cum se face referirea la câmpuri de biţi ?13. Ce tip poate avea un câmp de biţi ?14. Care este lungimea maximă a unui câmp de biţi ?15. Ce semnifică lipsa numelui unui câmp de biţi în declaraţia tipului câmp de biţi ?16. Fie următoarea declarare :

struct cimp { unsigned a : 3; int b : 2; unsigned c : 4; unsigned d : 1; int e : 2 ; } x;

Ce amplasare ne asigură această declarare ?17. Ce reprezintă tipul enumerare ? Cum se declară tipul enumerare ?18. Cum se alocă memoria pentru datele de tip enumerare ?19. Care valori implicite substituie numele sugestive din declaraţia unui tip enumerare ? 20. Cum se pot impune alte valori decât cele implicite pentru numele sugestive din declaraţia unui tip enumerare ?21. Ce tip au valorile numelor sugestive din declaraţia unui tip enumerare ?22. Ce operaţii pot fi efectuate cu datele de tip enumerare ?23. Ce reprezintă specificatorul typedef ? 24. Care-i deosebirea dintre typedef şi #define ?

66

Page 67: FisierFinal

Lucrare de laborator N10Tema: Prelucrarea fişierelor.

Scopul lucrării: Crearea, actualizarea, modificarea şi utilizarea fişierelor în probleme de prelucrare a datelor.

Suport teoretic:

Un fişier este o colecţie de date omogene, stocate pe un suport extern şi identificată printr-un nume. Datele fişierului se mai numesc elemente, componente, înregistrări, articole.

Fişierele se păstrează pe diferite dispozitive externe. Folosirea fişierelor permite păstrarea informaţiei de orice natură pentru un timp îndelungat, transferarea datelor de pe un purtător informaţional pe altul, citirea şi afişarea datelor în caz de necesitate. În C, C++ tratarea fişierelor se face la două nivele:

1. inferior: se realizează cu sprijinul direct al sistemului de operare, asemănător celui din UNIX, denumit şi neformatat sau unbuffered;

2. superior: se realizează cu mijloacele sistemului de programare C, C++ cu utilizarea tipului structurat de date FILE denumit şi sistem de fişiere de tip buffer sau formatat

Vom deosebi un fişier de date de pe un dispozitiv extern şi un fişier de date din program (din memoria operativă a calculatorului). Un fişier de date de pe un dispozitiv extern îl vom numi fişier fizic, iar un fişier de date din program îl vom numi flux (stream) de date sau fişier logic. Există două tipuri de fluxuri: text şi binar.

Un flux text este o succesiune de caractere şi este format din linii. Fiecare linie se termină cu un caracter newline. La scrierea unui flux text pe un dispozitiv extern, în flux pot interveni unele schimbări impuse de dispozitivul concret. Deci, e posibil să nu existe o corespondenţă biunivocă între caracterele fluxului citit sau scris şi caracterele fişierului respectiv de pe dispozitivul extern.

Un flux binar este o secvenţă de octeţi din memorie cu o corespondenţă biunivocă faţă de octeţii de pe dispozitivul extern respectiv. Aici la scriere şi la citire nu intervin schimbări.

Fişierele nu sunt toate la fel. De exemplu, dintr-un fişier putem extrage înregistrarea a cincea sau modifica înregistrarea a zecea. Acestea sunt fişiere cu acces direct (aleatoriu). Dar într-un fişier legat cu imprimanta sau alt port informaţia poate fi transmisă doar consecutiv în aceeaşi ordine ca în stream. Acestea sunt fişiere cu acces secvenţial. Asta e deosebirea între stream şi fişier: toate stream-urile sunt la fel, dar fişierele nu.

În timpul intrării datelor în program dintr-un fişier de pe disc, are loc copierea lor în memoria operativă a calculatorului, iar informaţia din fişier ce se află pe discul rigid rămâne neschimbată pe parcursul executării programului. La ieşirea datelor din program pe disc, în fişier sunt înscrise datele ce se păstrau până în acel moment în memoria operativă.

Înscrierea sau citirea informaţiei din fişier este efectuată cu ajutorul indicatorului de poziţie, care stă pe începutul fişierului la deschiderea acestuia. Pe măsură ce fiecare caracter este citit sau scris în fişier indicatorul de poziţie este incrementat, asigurând parcurgerea fişierului. Cînd programul începe execuţia, se deschid automat cinci stream-uri: stdin (standard input), stdout (standard output), stderr (standard error). În plus BC++ deschide stream-ul stdprn şi stdaux, asociate printerului şi portului consecutiv. Aceste stream-uri la fel se închid automat.

Prelucrarea fişierelor presupune un şir de operaţii specifice: crearea, deschiderea, citirea, închiderea, actualizarea, ştergerea unui fişier, adăugarea de noi înregistrări, poziţionarea într-un fişier ş.a. Aceste operaţii pot fi realizate prin funcţii speciale de prelucrare a fişierelor. Aceste funcţii au prototipul lor în fişierul <stdio.h> şi numele unei astfel de funcţii începe cu litera f. Fişierul antet <stdio.h> mai defineşte şi următoarele tipuri: size_t, fpos_t şi FILE. Tipul size_t ca şi fpos_t este o varietate de întreg fără semn. <stdio.h> defineşte mai multe funcţii macro:NULL, EOF, FOPEN_MAX, SEEK_SET, SEEK_END, SEEK_CUR. Funcţia macro NULL defineşte un pointer nul. EOF este definită drept -1 şi este valoarea returnată când o funcţie de intrare

67

Page 68: FisierFinal

încearcă să citească peste sfârşitul fişierului. FOPEN_MAX defineşte o valoare întreagă ce reprezintă numărul maximal de fişiere ce pot fi deschise simultan. Celelalte sunt folosite cu funcţia fseek(), care face accesul aleator dintr-un fişier. Pentru a citi sau scrie fişiere, e necesar a declara în program o variabilă pointer de tip FILE. Sintaxa de declarare a unui indicator de fişier este următoarea:

FILE *file_pointer;Pointerul este pentru fişier legătura cu fluxul de input/output. Un pointer pentru fişier este

un pointer către informaţiile care definesc diferite lucruri despre fişier, cum ar fi: numele, starea şi poziţia curentă a fişierului.

Deschiderea unui fişier se realizează cu ajutorul funcţiei fopen(), care are următoarea sintaxă:

FILE *fopen(const char *calea, const char *mod);unde calea este un pointer spre un şir de caractere ce conţine calea spre fişierul respectiv, iar mod este un pointer spre un şir de caractere ce indică modul de acces la fişier. Funcţia returnează un pointer spre tipul FILE sau pointerul nul în caz de eroare. Sunt posibile următoarele moduri de acces la un fişier:

1. r – deschiderea unui fişier text pentru citire;2. w - deschiderea unui fişier text pentru scriere;3. a - deschiderea unui fişier text pentru a adăuga înregistrări la sfârşitul fişierului;4. r+ - deschiderea unui fişier text pentru citire şi scriere;5. w+ - crearea unui fişier text pentru citire şi scriere;6. a+ - deschiderea unui fişier text pentru adăugarea înregistrărilor la sfârşitul fişierului sau

crearea unui fişier text pentru citire şi scriere;7. rb - deschiderea unui fişier binar pentru citire;8. wb - deschiderea unui fişier binar pentru scriere;9. ab - deschiderea unui fişier binar pentru a adăuga înregistrări la sfârşitul fişierului;10. r+b - deschiderea unui fişier binar pentru citire şi scriere;11. w+b - crearea unui fişier binar pentru citire şi scriere;12. a+b - deschiderea unui fişier binar pentru adăugarea înregistrărilor la sfârşitul fişierului

sau crearea unui fişier binar pentru citire şi scriere.Deschiderea cu modul “w” sau “a” a unui fişier inexistent duce la crearea lui.Deschiderea cu modul “w” a unui fişier existent duce la ştergerea lui şi crearea unui fişier

nou.Deschiderea cu modul “a” a unui fişier existent permite adăugarea înregistrărilor la

sfârşitul fişierului.Deschiderea cu modul “r” a unui fişier inexistent duce la eroare.Deschiderea cu modul de citire şi scriere a unui fişier inexistent duce la crearea lui.Deschiderea cu modul de citire şi scriere a unui fişier existent nu şterge fişierul.

De exemplu, pentru a crea un fişier nou cu nume info.txt se va folosi sintaxa: FILE *fisier; fisier=fopen(“info.txt”,”w”).

În unele cazuri apare situaţia când sistemul operaţional nu poate deschide fişierul indicat în funcţia fopen(). Aceasta poate fi condiţionat de lipsa spaţiului pe discul rigid, sau de faptul că fişierul indicat pur şi simplu nu există. În cazul încercării folosirii fişierului ce nu poate fi deschis, programul va fi stopat în urma unei greşeli de execuţie. Pentru a evita stoparea avariată a programului poate fi controlată starea de deschidere a fişierului cu ajutorul instrucţiunii condiţionate if, care va opri programul în caz de eşec. Condiţia pentru evitarea ieşirii avariate din program are următoarea sintaxă:

if ( fisier=fopen(“info.txt”,”w”))==NULL) { puts(“fişierul nu poate fi deschis”);

68

Page 69: FisierFinal

exit(1); }

Închiderea unui fişier, care a fost deschis cu fopen(), se face cu funcţia fclose() care are prototipul int fclose(FILE *fp ); aici fp este un pointer spre tipul FILE, returnat de funcţia fopen(). Funcţia returnează 0, dacă a reuşit închiderea fişierului, şi -1, în caz de eroare. Funcţia înscrie datele rămase în fluxul de date în fişier şi apoi închide fişierul, adică rupe legătura dintre fluxul de date şi fişier. Închiderea corectă a fişierului se va face:

if ( fclose(fisier)!=0) puts(”eroare la închiderea fişierului”);Mai mult ca atât, închiderea fişierului eliberează indicatorul şi după aceasta el poate fi

utilizat pentru accesul la alt fişier sau pentru îndeplinirea altor operaţii cu fişierul. De menţionat faptul, că după înscrierea datelor, fişierul trebuie închis şi numai după aceasta deschis pentru citire, astfel având acces respectiv la datele din fişier.

Scrierea unui caracter într-un fişier se face cu funcţia putc() (vezi şi funcţia fputc()), care are prototipul int putc(int ch, FILE *fp); aici fp este pointerul spre tipul FILE, returnat de funcţia fopen() la deschiderea fişierului, iar ch este caracterul care se înscrie în fişier. Funcţia returnează codul caracterului scris în fişier sau EOF (adică -1) în caz de eroare.

Citirea unui caracter dintr-un fişier se face cu funcţia getc() (vezi şi funcţia fgetc()), care are prototipul int getc(FILE *fp); aici fp este pointerul spre tipul FILE, returnat de funcţia fopen() la deschiderea fişierului.

Funcţia returnează codul caracterului citit din fişier sau EOF, adică valoarea -1, dacă s-a ajuns la sfârşitul fişierului.

Funcţia feof() determină momentul când a fost atins sfârşitul fişierului. Ea are prototipul int feof(FILE *fp);

Funcţia returnează o valoare diferită de zero, dacă a fost atins sfârşitul fişierului si 0 în caz contrar.

Funcţia fgets() cu prototipul char *fgets( char *s, int n, FILE *fp); citeşte un şir de caractere din fişierul specificat de pointerul fp, pînă cînd se ajunge la un caracter newline sau au fost citite n-1 caractere; pointerul s indică spre zona de memorie unde se păstrează şirul de caractere citit din fişier; citirea din fişier se întrerupe sau la citirea caracterului newline sau după citirea a n-1 caractere. În zona indicată de s se scrie ‘\n’, dacă el a fost citit din fişier, apoi se scrie caracterul NUL (‘\0’).

Funcţia returnează valoarea pointerului s sau pointerul NUL, în caz de EOF.

Funcţia fputs() cu prototipul int fputs (const char *s, FILE *fp); efectuează înscrierea şirului specificat de pointerul s în fişierul specificat de pointerul fp sau imprimarea lor pe hârtie fără înserarea caracterului sfîrşit de linie. Pentru ca fiecare şir înscris în aşa mod în fişier să înceapă din rînd nou, este necesară înserarea manuală a simbolului sfîrşit de linie.

Funcţia returnează codul ultimului caracter scris în fişier sau EOF, în caz de eroare.

Funcţia rewind() cu prototipul void rewind(FILE *fp); poziţionează indicatorul de poziţie al fişierului la începutul fişierului. Funcţia nu returnează nici o valoare.

Funcţia ferror() cu prototipul int ferror(FILE *fp); determină dacă o anumită operaţie cu fişiere a generat o eroare. Funcţia returnează o valoare diferită de zero, dacă a survenit vre-o eroare, şi 0, dacă n-a fost nici o eroare.

Funcţiile pentru prelucrarea caracterelor şi şirurilor au destinaţia de înscriere/citire din fişier numai a informaţiei textuale. În caz, când e necesar de înscris în fişier date ce conţin valori numerice este folosită funcţia fprintf() cu următoarea sintaxă

int fprintf (FILE *fp, const char *format, data); unde fp este indicatorul la fişierul în care se realizează înscrierea, format este şirul de control al formatului datelor înscrise şi data

69

Page 70: FisierFinal

este lista variabilelor sau valorilor ce trebuie înscrise în fişier. Ea se comportă ca şi funcţia printf(), cu deosebirea că scrie datele în fişierul fp.

Funcţia returnează numărul de caractere (octeţi) efectiv scrise în fişier. Dacă survine o eroare până la prima scriere, funcţia returnează o valoare negativă.

Funcţia fscanf() cu prototipul int fscanf (FILE *fp, const char *format, data); citeşte din fişierul indicat de pointerul *fp date sub controlul unor formate. Ea se comportă ca şi funcţia scanf(), cu deosebirea că citeşte datele din fişierul fp.

Funcţia returnează numărul de argumente cărora li s-au atribuit efectiv valori. Dacă a apărut o eroare până la prima atribuire, atunci funcţia returnează EOF, adică valoarea -1.

Funcţia fflush() cu prototipul int fflush(FILE *fp); şterge conţinutul unui flux de ieşire. Ea scrie datele din flux în fişier, apoi şterge conţinutul acestui flux. Dacă fp este pointerul NUL, atunci se sterg toate fluxurile asociate cu fişierele deschise pentru scriere.

Fucţia returnează valoarea zero în caz de succes, şi -1, în caz de eroare.

Funcţia fwrite() cu prototipul unsigned fwrite (void *bufer, unsigned dim, unsigned n, FILE *fp); scrie în fişierul indicat de pointerul *fp n obiecte (blocuri) de dimensiunea dim octeţi fiecare. Datele se iau din zona de memorie indicată de pointerul bufer. Indicatorul de poziţie al fişierului se măreşte cu numărul de caractere (octeţi) scrise. Pentru determinarea mărimii dim se foloseşte funcţia sizeof(dim). Dacă vom deschide fişierul cu ajutorul unui redactor de texte obişnuit vom observa în el un conţinut neînţeles. În realitate informaţia (sau mai bine zis înregistrările) ce se află în acest fişier este înţeleasă de compilator şi poate fi citită cu funcţia fread().

Funcţia returnează numărul de obiecte (blocuri) efectiv scrise, care poate fi şi mai mic decât numărul solicitat n.

Funcţia fread() cu prototipul unsigned fread (void *bufer, unsigned dim, unsigned n, FILE *fp); citeşte n obiecte (blocuri), fiecare având dim octeţi, din fişierul indicat de pointerul *fp. Datele se plasează în tabloul indicat de pointerul bufer. Indicatorul de poziţie al fişierului se măreşte cu numărul de octeţi citiţi.

Funcţia returnează numărul de blocuri efectiv citite, care poate fi mai mic decât numărul solicitat n.

Funcţia fseek() cu prototipul int fseek(FILE *fp, long depl, int origine); deplasează indicatorul de poziţie al fişierului. Funcţia lucrează la nivel de octeţi. Parametrul depl arată numărul de octeţi peste care se va deplasa indicatorul fişierului, iar parametrul origine arată de unde începe numărarea acestor octeţi. Parametrul origine poate avea una din următoarele valori: SEEK_SET, care are valoarea 0 şi semnifică numărarea de la începutul fişierului; SEEK_CUR, care are valoarea 1 şi semnifică numărarea de la poziţia curentă înainte; SEEK_END, care are valoarea -1 şi semnifică numărarea de la sfârşitul fişierului înapoi.

Funcţia returnează valoarea 0, dacă operaţia de poziţionare a reuşit, şi o valoare diferită de zero, în caz de eroare.

Funcţia ftell() cu prototipul long ftell(FILE *fp); returnează poziţia curentă a indicatorului de fişier. Funcţia determină poziţia indicatorului de fişier şi returnează numărul de octeţi parcurşi de la începutul fişierului. Primul octet este sub numărul 0. Valoarea returnată reprezintă octetul curent, nu înregistrarea curentă şi poate fi utilizată de funcţia fseek().

Funcţia returnează valoarea indicatorului de poziţie al fişierului, dacă operaţia de poziţionare a reuşit, şi valoarea -1, în caz de eroare.

Exemple de programe:

70

Page 71: FisierFinal

Exemplul 10.1. Programul copiază intrarea standard la ieşirea standard, adică citeşte câte un caracter din fişierul stdin şi îl scrie în fişierul stdout. Citirea se întrerupe la întâlnirea caracterului EOF (adică la acţionarea tastelor Ctrl + Z).#include<conio.h>#include<stdio.h>void main(){ char c; clrscr(); while ( ( c=getc(stdin))!=-1) // EOF e definit în fişierul stdio.h ca -1 putc(c, stdout); getch();}

Exemplul 10.2. Programul citeşte caractere de la claviatură şi le scrie în fişierul cu numele file01 pe disc până la citiea caracterului EOF.#include<conio.h>#include<stdio.h>void main(){ FILE *fp; char c; clrscr(); fp = fopen(”file01”,”w”); while ( ( c=getc(stdin))!=EOF) putc(c, fp); fclose(fp); getch();}

Exemplul 10.3. Programul demonstrează utilizarea fluxului de citire/scriere pentru citirea din fişier şi contorizarea simbolurilor citite.#include<conio.h>#include<stdio.h>void main(){ FILE *fp; char S[20]; long count=0; int ch; clrscr(); gets(S); // se aşteaptă introducerea numelui fişierului // deschiderea fişierului pentru citire şi if ( ( fp = fopen(”S”, ”r”) ) == NULL) { // verificarea execuţiei deschiderii lui printf(„Nu se deschide fişierul %s\n”,S); exit(1); } // se citesc simboluri din fişier până la EOF while ( ( c = getc(fp)) != EOF) { putc(ch,stdout); // sau putchar(ch); se tipăresc la ecran simbolurile citite count++; } fclose(fp); printf(”Fişierul %s conţine %ld simboluri\n”, S, count); getch();}

Exemplul 10.4. Programul citeşte câte un caracter de la intrarea standard şi îl adaugă la sfârşitul fişierului creat în exemplul 10.2.#include<conio.h>#include<stdio.h>void main(){ FILE *fp; char c; clrscr(); fp = fopen(”file01”,”a”); while ( ( c=getc(fp)) != -1) putc(c, fp); fclose(fp); getch(); }

71

Page 72: FisierFinal

Exemplul 10.5. Programul citeşte de la intrarea standard un şir de numere întregi, scrie cu fprintf() numerele pare într-un fişier binar şi numerele impare în alt fişier binar, apoi citeşte cu fscanf() fişierele şi le afişează la ecran.#include<conio.h>#include<stdio.h>void main(){ FILE *fp1, *fp2; int n; clrscr(); fp1 = fopen(”fpar”,”wb”); fp2 = fopen(”fimpar”,”wb”); while ( 1 ) // se introduc numere da la tastatură { if ( scanf( ”%d”, &n )!=1) break; // până se întroduce un simbol (n%2==0) ? fprintf( fp1, ”%4d”, n) : fpintf( fp2, ”%4d”, n); } fclose( fp1 ); fclose( fp2 ); fp1 = fopen(”fpar”,”rb”); fp2 = fopen(”fimpar”,”rb”); puts(”Fişierul cu numere pare:\n\n”); while ( fscanf( fp1, ”%4d”, &n)==1) printf( ”%d\t”,n); puts(”\nFişierul cu numere impare:\n\n”); while ( fscanf( fp2, ”%4d”, &n)==1) printf( ”%d\t”,n); fclose(fp1); fclose(fp2); getch();}

Exemplul 10.6. Programul citeşte de la intrarea standard un şir de numere întregi, scrie cu fprintf() numerele pare într-un fişier text şi numerele impare în alt fişier text, apoi citeşte cu fscanf() fişierele şi le afişează la ecran.#include<conio.h>#include<stdio.h>void main(){ FILE *fp1, *fp2; int n; clrscr(); fp1 = fopen(”gpar”,”w+”); fp2 = fopen(”gimpar”,”w+”); while ( 1 ) { if ( scanf( ”%d”, &n )!=1) break; // citire de la tastatură (n%2==0) ? fprintf( fp1, ”%d”, n) : fpintf( fp2, ”%d”, n); } // scriere în fişiere fclose( fp1 ); fclose( fp2 ); // indicatorul de poziţie al fişierelor este readus la începutul lor rewind( fp1 ); rewind( fp2 ); puts(”Fişierul cu numere pare:\n\n”); while ( fscanf( fp1, ”%d”, &n)==1) printf( ”%d\t”,n); // citire din fişier şi afişare la ecran puts(”\nFişierul cu numere impare:\n\n”); while ( fscanf( fp2, ”%d”, &n)==1) printf( ”%d\t”,n); // citire din fişier şi afişare la ecran fclose(fp1); fclose(fp2); getch();}

Exemplul 10.7. Programul citeşte câte un cuvânt de la intrarea standard şi îl adaugă într-un fişier.#include<conio.h>#include<stdio.h>#define max 40void main(){ FILE *fp; char words[max]; clrscr(); // deschiderea fişierului pentru adăugare şi if ( ( fp = fopen(”wordy”, ”a+”) ) == NULL) { printf(„Nu se deschide fişierul\n”); exit(1); }

72

Page 73: FisierFinal

puts( “Introdu cuvântul următor; acţionează Enter la începutul cuvântului pentru întrerupere”); // se citesc cuvinte de la tastatură while ( ( gets(words)) != NULL) && words[0] != ‘\0’) fprintf ( fp, ”%s”, words ); // se înscriu cuvintele în fişier puts(”Conţinutul fişierului”); rewind( fp ); while ( fscanf( fp, ”%s”, words ) == 1 ) puts(words); if (fclose( fp ) != 0 ) fprintf( stderr, ”Eroare la închiderea fişierului”);}

Exemplul 10.8. Programul demonstrează utilizarea funcţiilor de citire/scriere fgets() şi fputs().#include<conio.h>#include<stdio.h>#define max 20void main(){ char line[max]; clrscr(); while ( fgets(line, max, stdin) != NULL) && line[0] != ‘\n’) fputs ( line, stdout ); }

Funcţia gets() citeşte şirul pînă la simbolul ‘\n’;Funcţia fgets() citeşte şirul inclusiv şi simbolul ‘\n’;Funcţia puts() adaugă simbolul ‘\n’ la ieşire;Funcţia fputs() nu adaugă simbolul ‘\n’ la ieşire. În legătură cu aceasta fgets() se utilizează în pereche cu fputs(), dar nu cu puts(). În aşa

caz un simbol de linie nouă s-ar preface la ieşire în două simboluri de linie nouă.Exemplul 10.9. Programul creează fişierul binar Bursa şi scrie în el articole ce conţin:

grupa, numele şi prenumele studentului, nota medie obţinută la sesiune şi mărimea bursei. Datele se citesc de la intrarea standard. După introducerea ultimului articol se tastează EOF (<Ctrl+Z>).#include<conio.h>#include<stdio.h>void main(){ struct { char grupa[8], nume[15], pren[15]; float media; int bursa; } student; clrscr(); FILE *fp; float p; fp = fopen(”Bursa”, ”wb”); while ( scanf(”%s”, student.grupa) != -1) { scanf(”%s”,student.nume); scanf(”%s”,student.pren); scanf(”%f”,&p); student.media=p; scanf(”%i”,&student.bursa); fprintf( fp, ”%-7s%-15s%-15s%.2f%4d\n”,student.grupa, student.nume,

student.pren, student.media, student.bursa); } fclose(fp); getch();}

Exemplul 10.10. Programul caută în fişierul binar Bursa, creat în exemplul 10.9 studenţii cu nota medie maximă şi afişează informaţia despre aceşti studenţi la ecran.#include<conio.h>#include<stdio.h>void main(){

73

Page 74: FisierFinal

struct { char grupa[8], nume[15], pren[15]; float media; int bursa; } student; clrscr(); FILE *fp; float nm=0; fp = fopen(”Bursa”, ”rb”); while ( !feof(fp)) { fscanf( fp, ”%-7s%-15s%-15s%.2f%4d\n”,student.grupa, student.nume, student.pren, student.media, student.bursa); if ( nm < student.media ) nm=student.media; } rewinf(fp); while ( !feof(fp)) { fscanf( fp, ”%-7s%-15s%-15s%.2f%4d\n”,student.grupa, student.nume, student.pren, student.media, student.bursa); if ( nm == student.media ) { printf(”%-7s”,student.grupa); printf(”%-15s”,student.nume); printf(”%-15s”,student.pren); printf(”%.2f”, student.media); printf(”%4i\n”,student.bursa); } } fclose(fp); getch();}

Exemplul 10.11. Programul creează fişierul binar Bursa şi scrie în el articole ce conţin: grupa, numele şi prenumele studentului, nota medie obţinută la sesiune şi mărimea bursei. Datele se citesc de la intrarea standard. Se utilizează fwrite(). Pentru citirea din fişier se utilizează fread().#include<conio.h>#include<stdio.h>void main(){ struct { char grupa[8], nume[15], pren[15]; float media; int bursa; } student; clrscr(); FILE *fp; float p; fp = fopen(”Bursa”, ”w+b”); // fişier deschis pentru scriere şi citire while ( scanf(”%s”, student.grupa) != -1) { scanf(”%s”,student.nume); scanf(”%s”,student.pren); scanf(”%f”,&p); student.media=p; scanf(”%i”,&student.bursa); fwrite( &student, sizeof student, 1, fp ); } fclose(fp); rewinf(fp); while ( !feof(fp)) { fread( &student, sizeof student, 1, fp ); printf(”%-7s”,student.grupa); printf(”%-15s”,student.nume); printf(”%-15s”,student.pren); printf(”%.2f”, student.media); printf(”%4i\n”,student.bursa); } fclose(fp); getch(); }

74

Page 75: FisierFinal

Exemplul 10.12. Programul înscrie într-un fişier elementele unui tablou. Apoi demonstrează accesul aleator la înregistrările sale.#include <stdio.h>#include <conio.h>#include<stdlib.h>#define ARSIZE 100void main(){ clrscr(); float numbers[ARSIZE], value; const char *file="numbers.dat"; int i; long pos; FILE *fp; // creaza tabloul de numere tip float for ( i=0; i < ARSIZE; i++) { numbers[i] = 100.0 * i + 1.0/( i + 1); printf("%f ",numbers[i]); } if ( ( fp = fopen( file, "wb")) == NULL ) { puts("Eroare la deschidere"); exit(1); } // inscrie in fisier tabloul de dimensiunea ARSIZE fwrite( numbers, sizeof( float ), ARSIZE, fp); fclose( fp); if ( ( fp = fopen(file, "rb"))==NULL) { puts("Eroare la deschidere"); exit(1); } // citeste din fisier inregistrarile selectate de utilizator printf( "\nintroduceti un numar din diapazonul 0 - %i.\n", ARSIZE - 1); scanf("%i", &i); while ( i >= 0 && i < ARSIZE) { pos = ( long ) i * sizeof( float ); //gaseste deplasamentul fseek( fp, pos, SEEK_SET ); // efectuează deplasarea în cadrul fişierului // efectuează citirea din fişier a unei înregistrări fread(&value, sizeof( float), 1, fp); printf("Valoarea = %f\n", value); printf("Urmatorul indice"); puts("pentru iesire indicati un indice ce nu apartine diapazonului"); scanf("%i",&i); } fclose( fp); getch();}

Probleme propuse spre rezolvare:

1. Programul copie un fişier text iniţial (numele căruia se citeşte de la tastatură) în altul final (numele căruia la fel se citeşte de la tastatură) doar cu majuscule.

2. Creaţi un program ce deschide două fişiere, numele cărora se introduc de la tastatură. Apoi afişează o linie din primul fişier, o linie din al doilea fişier, o linie din primul fişier, o linie din al doilea fişier s.a.m.d. până la ultima linie din fişierul cu cele mai multe linii.

3. Creaţi un fişier text şi scrieţi în el numele, prenumele şi numărul de telefon ale colegilor de grupă. Apoi afişaţi pe monitor informaţia înscrisă în fişier.

75

Page 76: FisierFinal

4. Creaţi un fişier text şi scrieţi în el numele, prenumele, numărul de telefon şi data naşterii ale colegilor de grupă. Folosiţi informaţia din fişierul creat cu programul pentru sarcina 3. Apoi afişaţi pe monitor informaţia înscrisă în fişier.

5. Programul citeşte de la intrarea standard un şir de numere întregi, scrie numerele pare într-un fişier binar şi numerele impare în alt fişier binar, apoi le afişează la ecran.

6. Se consideră fişierul text IN1.TXT şi IN2.TXT. Fiecare din aceste fişiere conţine câte un şir de numere reale, ordonate crescător. Scrieţi un program care comasează aceste fişiere în fişierul OUT.TXT. Numerele vor fi scrise în fişier în ordine crescătoare.

7. Se consideră fişierul IN.TXT care conţine n numere separate prin spaţiu ce reprezintă elementele unui tablou. Scrieţi un program care calculează recursiv suma valorilor elementelor tabloului.

8. Se consideră fişierul IN.TXT care conţine pe fiecare linie câte o pereche de cuvinte, separate prin spaţiu. Primul cuvânt din fiecare pereche este în limba engleză, al doilea – în limba română. Scrieţi un program care aranjează aceste perechi în ordinea lexicografică a cuvintelor din limba engleză.

9. Fişierul IN.TXT conţine 3*n numere reale (n triplete). Scrieţi un program care modifică fişierul astfel: fiecare al doilea element din triplete consecutive se înlocuieşte cu media aritmetică a vecinilor săi.

10. Fişierul text ELEVI.IN conţine datele referitoare la examene a cel mult 200 concurenţi. Datele despre fiecare concurent sînt numele, prenumele şi media obţinută la examene. Scrieţi un program care scrie în fişierul ELEVI.OUT lista elevilor admişi ( care au media nu mai mică decât 5) ordonată descrescător după medii.

11. Se numesc numere “bine ordonate” acele care au cifrele în ordine strict crescătoare sau strict descrescătoare. Scrieţi un program care citeşte dintr-un fişier numere de 4 cifre şi crează alt fişier unde înscrie numerele “bine ordonate”.

12. Fişierul text BAC.TXT conţine numele, prenumele, clasa şi media obţinută la bacalaureat ale fiecărui elev. Clasele sunt 12A, 12B, 12C. Scrieţi un program care afişează media obţinută pentru fiecare clasă (se consideră numai elevii care au media mai mare ca 5).

Întrebări de control:

1. Ce este un fişier de date?2. Ce este un flux de date?3. Care este legătura dintre un fişier de date şi un flux de date?4. Ce este un flux text?5. Ce este un flux binar?6. Care este deosebirea dintre un flux text şi un flux binar?7. Cum se asociază un flux de date la un fişier de date?8. Ce este un fişier cu acces secvenţial la date?9. Ce este un fişier cu acces direct la date?10. Care dintre următoarele afirmaţii este adevărată?

a.într-un fişier text se pot scrie numai litere,b. nu se poate şterge o linie dintr-un fişier text,c.fişierele text permit numai acces secvenţial,d. fişierele text nu pot fi modificate.

11. Ce se întâmplă la deschiderea cu modul ”w” sau ”a” a unui fişier inexistent?12. Ce se întâmplă la deschiderea cu modul ”w” a unui fişier existent?13. Ce se întâmplă la deschiderea cu modul ”a” a unui fişier existent?14. Ce se întâmplă la deschiderea cu modul ”r” a unui fişier inexistent?15. Ce se întâmplă la deschiderea cu modul de citire şi scriere a unui fişier inexistent?16. Ce se întâmplă la deschiderea cu modul de citire şi scriere a unui fişier existent?17. Care moduri de deschidere a unui fişier duc la ştergerea lui?

76

Page 77: FisierFinal

18. Funcţia fseek(nume_p, nr, origine) a.precizează poziţia indicatorului de fişierb. deplasează indicatorul de poziţie cu nr octeţi faţă de poziţia curentăc.deplasează indicatorul de poziţie cu nr octeţi faţă de începutul de fişierd. deplasează indicatorul de poziţie cu nr octeţi faţă de origine.

19. Funcţia void rewind(FILE *f);a.şterge conţinutul fişierului b. mută indicatorul de fişier la începutul săuc.reciteşte conţinutul fişieruluid. marchează sfârşitul de fişier.

20. Secvenţa:FILE *f;f = fopen ( “a.txt”, ”r” );fseek ( f, 0L, SEEK_END );long l = ftell ( f );

a) calculează în l lungimea fişieruluib) calculează în l numărul de liniic) calculează în l numărul de caractere diferite de cele albed) este eronată

21. Cînd se închide un fişier?a.la apelul funcţiei closeb. la apelul funcţiei freopenc.la terminarea blocului în care a fost declaratd. la apelul funcţiei fclose

22. Care sunt pointerii predefiniţi spre fişierele I/O standard?23. Secvenţa

FILE *f = fopen ( “a.txt”, “w”);int n; scanf ( “%i”, &n);while ( n ) { if ( !feof ( f )) fprintf(f,“%i”,n ); scanf (“%i”,&n); } fclose ( f );

a.scrie un număr în fişierb. scrie în fişier numerele introduse până la 0,c.afişează numerele nenule din fişier,d. verifică dacă un număr se găseşte în fişier.

77

Page 78: FisierFinal

Bibliografie1. Herbert Shildt. C manual complet. Editura Teora, Bucure;ti, 19982. Liviu Negrescu. C şi C++ pentru începători. Editura Microinformatica, Cluj-Napoca, 1995.3. Vasile Petrovici, Florin Goicea. Programarea în limbajul C. Editura Tehnică. Bucureşti, 1993.4. Ana Întuneric, Cristina Sichim. Informatică. Editura Polirom, Bucureşti, 2003.5. Bogdan Pătruţ. Aplicaţii în C şi C++. Editura Teora, Bucureşti, 1998.6. Стивен Прата. Язык программирования С. DiaSoft, 2002.7. С. М. Перетятку, С. А. Тутунару. Сборник задач по информатике. Кишинэу, 1999

78