Sunteți pe pagina 1din 79

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
Cuprins

Introducere.......................................................................................................................................2
Lucrare de laborator N1...................................................................................................................4
Lucrare de laborator N2...................................................................................................................9
Lucrare de laborator N3.................................................................................................................15
Lucrare de laborator N4.................................................................................................................21
Lucrare de laborator N5.................................................................................................................26
Lucrare de laborator N6.................................................................................................................34
Lucrare de laborator N7.................................................................................................................43
Lucrare de laborator N8.................................................................................................................50
Lucrare de laborator N9.................................................................................................................59
Lucrare de laborator N10...............................................................................................................68

Bibliografie...............................................................................................................................................................7
8

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

2
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 № ore


1. Funcţii de intrare/ieşire, tipuri de bază. 6-8
2. Operatori, operanzi, expresii şi funcţii matematice în limbajul C. 4-6
3. Instrucţiuni ciclice. 6-8
4. Pointeri şi tablouri. 6-8
5. Prelucrarea şirurilor de caractere. 4-6
6. Lucrul cu tablourile unidimensionale. 4-6
7. Lucrul cu tablourile bidimensionale. 4-6
8. Subprograme. 6-8
9. Tipuri de date definite de utilizator, redenumirea tipurilor. 6-8
10. 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
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
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 date
întregi

reale

simple caracter

enumerativ

logic
statice
masiv

ş ir

structurate mulţime

articol
dinamice fişier

5
Tipuri simple de date
G
Grupa
rupa Lungim
Lungime e
Tipul
Tipul Dom
omeniu
eniu de
de valori
valori
de d at ă
dat ă ((octe
octe ţţi ))
[signed] char 1 -128..127 ( -27..2 7-1)
unsigned char 1 0..255 (0..2 8-1)

Întreg unsigned [ int ] 2 0..65535


[short] [ int ] 2 -32768..32767
unsigned long 4 0..2 32 -1

long [ int ] 4 -231 ..2 31 -1


float 4 3.4*10 -38 ..3.4*10 38

Real double 8 1.7*10 -308 .. 1.7*10 308

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

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
}
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.456f
void 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 apel
printf("al doilea apel:%d\n",getch());
getch(); // primul apel
a=getch(); // al doilea apel
printf("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
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.
x −y
9. Sunt date numere întregi x şi y. Să se obţină: 1 + xy
.
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
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 π / 180 , unde constanta π = 3.14 .

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
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
calculează valoarea funcţiei sinus de unghiul x
double sin(double x);
exprimat în radiani.
double sqrt(double x); radicalul lui x
double tan(double x); tangenta lui x
calculează valoarea polinomului
double poly(x, n, c[])
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

Tabela 2.3: Codurile ASCII.

10
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();
}
Exemplul 2.2. Este dat un număr întreg. Programul verifică dacă numărul introdus este
pozitiv, negativ sau zero.
#include <stdio.h>

11
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;
clrscr();
printf("n=");
scanf("%d",&n);
n=n%10;

12
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.
sin 2 cx13 + dx 22 − cd
6. Sunt date c,d. Să se calculeze: + tg (cx13 + dx 22 x1 ) , unde x1-
(cx + dx − x1 ) + 3.14
3
1
2
2
2

rădăcina mare, iar x2 - rădăcina mică a ecuaţiei x 2 −3 x − cd = 0 .


7. Sunt date a, b. Să se calculeze s:
2a( a + 2b + a 2 + 4ab ) b
a. s = − ;
a + (a + 4ab )( a + 4b + a + 4ab )
2 2
b − 2 +1 / b
−1 2
+1) a 3b −3 −1 a 3b −3 + 1
b. s = (ab / ;
ab −1 − a −1b a 2b −2 + ab −1 +1 ab −1 + a −1b −1
a + a 3 / 4b1 / 2 + a1 / 4b 3 / 2 + b 2 4 3 b (a1 / 2 − b) −1 / 3 4
c. s = ( ( a ) + b ) + −1 / 4 1 / 4 ) /( a + b ) −1 ;
a + 2a b + b
1/ 2 1/ 4 1/ 2
a (a − b )
3
b 4 − a 3 + a 2 3 b − ba 2b + 2 b 2 − 9
d. s = ( b 2 + a 3 b + a 2 ) +
3
;
ba −1 + a − a 4b −1 − a 2 2b − 2 b 2 − 9
(a 2 b b − 6a 5 / 3b5 / 4 + 12 ab 2 a − 8ab 3 / 4 ) 2 / 3
e. s = .
ab 3 a − 4ab −3 / 4 + 4a 2 / 3 b

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


x −1 − 3 y
a= −( x +3 )
a. x 2 y 2 , b = x ( arctgz + e );
1+ +
2 4
3 + e y −1 ( y − x) 2 y −x
3

b. a = , ;
1 + x 2 y − tgz b =1 + y − x + 2
+
3
x
a=y+ z
c. y2 +
x2 , b = (1 + tg 2 ) ;
2
y + x3 / 3
y x 2 x5
d. a = ln ( y − x )( x − , b = x − + ;
z + x2 / 4 3! 5!
x + y /( x 2 + 4) 1 + cos( y − 2)
e. a = (1 + y ) − x −2 , b= 4 ;
e + 1 /( x + 4)
2
x / 2 + sin 2 z
2 cos( x − π / 6) z2
f. a = , b = 1 + ;
1 / 2 + sin 2 y 3 + z2 / 5
1 + sin ( x + y )
2
1
g. a = 2 + x − 2 x /(1 + x 2 y 2 ) + x , b = cos 2 ( arctg ) ;
z

13
x+y x−y

( y + 2 xy )( 2 y + 4 x y )
3 2 3 2 −1
x− y x + y y − xy + x
h. a = ( − (2 x ) −1 / 3 ) −6 , b =
3
y − 3 2x x− y x+ y 2 xy
+
x+y x−y
;

Î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
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
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>
#include<conio.h>

16
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();
}
1 1 1 1
Exemplul 3.4. Să se calculeze expresia: produs = (1 + 2
)(1 + 2 )(1 + 2 )...( 1 + 2 ) .
1 2 3 n
#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=");
scanf("%d",&n);

17
//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);
n
Să se calculeze expresia: ∑−1 (i +1) / i! ;
i
b.
i =1

x 2 x3 xn
c. Să se calculeze expresia: s = 1 + x + + + + , e = 0.0001 , x / n! >e .
2! 3! n!
#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ţii
switch(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>
#include<conio.h>

18
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):


 x 2 , daca − 2 ≤ x < 2,
a. f ( x) = 
4, in caz contrar;
 x 2 + 4 x + 5, x ≤ 2,

b. f ( x) =  1
 x + 4 x + 5 , in ca z contrar;
2

 0, x ≤ 0,

c. f ( x) =  x − x,
2
0 < x ≤ 1,
 x 2 − sin πx 2 , in caz contrar .

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:
n
x i n
( −1)i (i +1) n
( −1)i ( i −1) / 2
a. ∑i =1 i!
; d. ∑
i =1 i!
; g. ∑
i =1 i!
;
n n 2 i +x
1 sin( ix ) n
1 x 
b. ∑ (
i =1 i!
+ x ) ; e. ∏
i =1
(1 +
i!
) ; h. ∑ 
i =1 i!( x + i )!  2 
 ;
n
x + cos( ix ) n
(1 − x )i +1 +1 ( −1)[lg 1] ( −1)[lg 2 ] (−1)[lg n]
c. ∑i =1 2 i f. ∏
i =1 (( i −1)!+1)
2 ; i.
1
+
2
+ ... +
n
.
n
xi
6. Pentru n dat să se calculeze: ∑ , x1 = y1 = 1 , xi = 0,3 xi −1 , yi = xi −1 + yi −1 ,
i =1 1 + yi
i = 2,3,...
7. Pentru a1 = b1 =1; ak = 3bk −1 + 2ak −1; bk = 2ak −1 + bk −1; k = 2,3,... ; n dat, să se
n
2k
calculeze: ∑ .
k =1 (1 + ak + bk ) k!
2 2

Pentru a1 = u; b1 = v; ak = 2bk −1 + ak −1; bk = 2ak −1 + bk −1 , k = 2,3,... Sunt date


2
8.
u, v, să se calculeze:

19
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);
case ‘4’: printf(“%d\n”,4);
}
Ce se extrage la ecran? Explicaţi.
20
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
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

21
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:”);
puts(s);
getch();
}

22
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()
{
unsigned x[]={123,17,439,5146,5667}, i=0,y[5],s;
clrscr();
puts(”Şirul numeric iniţial este:”);

23
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;
puts(”Introdu numărul de linii şi de coloane:”);
scanf(”%i%i”,&n,&m);
for (i=0;i<n;i++)

24
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ă ?
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 ;

25
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 caractere
char *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ţie
char * 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.h
funcţ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
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.
26
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 Copie maxim n caractere de la şirul sursă s2 în şirul
n) 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 Căută în şirul s orice simbol din şirul s1 şi afişează pe
char*s1) 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.z
int 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();
}
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>

27
#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()
{
char s[256],*t;
clrscr();
printf("sir:\n");

28
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>
#include<conio.h>
#include<string.h>
void main()
{

29
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;
clrscr();
printf("dati şirul:");
gets(s); // de exemplu: asfsd:fdfh:hjklş;
p=s;

30
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>
#include<stdlib.h>
void main()
{
char s[256];

31
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.
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.txt
32
a23sc345ss5e 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 t
m i n a a
i ş ! 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);
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;

33
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 întregi
int vanzari[100];

// vector de 15 valori reale


float 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[1] v[2] v[3] v[4]

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}.

34
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 elemente
int v1[] = {1, 2, 3, 4, 5};
// iniţializare completă cu precizarea numărului maxim de elemente
int 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 vectorul
for (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 + 1
int 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 vectorului
vector[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--)
vector[i] = vector[i-1];
// şi se inserează elementul
vector[pozitia] = valoare;
}
printf("Dupa inserare:\n");

35
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],';');
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 ).

36
#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;
clrscr();
printf("\ndimensiunea vectorului:");
scanf("%d", &n);

37
/* 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);
}
printf("a:");
for(i=0; i<n; i++)
printf("%3d", a[i]);

38
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 malocc
void 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:");
scanf("%d", &n);
printf("\nnumarul de pozitii de deplasare:");
scanf("%d", &x);

39
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
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 17
Rezultat: 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
• 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
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 reale


float 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[0][1] m[0][2] m[1][0] m[1][1] m[1][2]

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 linii


int m1[][2] = {{1, 2}, {3, 4}, {5, 6}};
// iniţializare completă cu precizarea numărului de linii şi coloane
int 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
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 matrice


int a = m2[1][1];
// modifica primul element
m2[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 0
0 2 0
0 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 initializare
int matDiag[3] = {7, 2, 11};
// citire valoare
int 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 4
2 5 6 7
3 4 8 9
7 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:
i ⋅ (i − 1)
p = (n − 1) + (n − 2) + ... + (n − i ) + j = i ⋅ n − (1 + 2 + ... + i ) + j = i ⋅ n − + j
2 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
{
// interschimbăm elementele daca este cazul
if (j > i)
{
int t = j;
j = i;
i = t;
}
// calculam pozitia
int pozitia = i*n + (i*(i-1))/2 + j;
return matrice[pozitia];
}

Exemplu de utilizare:
// declarare si initializare
int matSim[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// citire valoare
int 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 0
0 0 0 23
0 7 0 0
0 0 0 0
vom avea vectorii:
Linii: 1 2
Coloane: 3 1
Valori: 2 7
3

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);

45
scanf("%d",&a[i][j]);
}
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()

46
{
int i,j,n,m,*a,max;
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");

47
for(i=0;i<n;i++)
for(j=0;j<n;j++)
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
1010
0010
0 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: 3
Rezultat: 4 3 8
951
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
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
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ă

50
parametri. Toţi parametrii funcţiei trebuie declaraţi individual, fiecare conţinând atât tipul cît şi
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:

51
 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;
 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 40
void afisare(void); // prototipul funcţiei
void 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ţiei
void main()

52
{
int spaces;
show_n_char(’*’,LIM); // apelul funcţiei
putchar(’\n’);
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ţiei
void 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”

53
void main()
{
unsigned a, b, c;
clrscr();
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.0001
float 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 masiv

54
void citire(int s[], int n);
// prototipul functiei de numarare a elementelor pare negative
int numar(int s[], int n);
void main()
{
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 k
int 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 recursive
void main()
{

55
int i, a[10], dim;
puts(”dimensiunea sirului numeric:”); scanf(”%i”,&dim);
for(i = 0; i < dim; i++)
scanf(“%i”,&a[i]);
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 parametri
void 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
2a − b − sin c
f ( a , b, c ) =
5+ | c |
max( a, a + b) + max( a, b + c )
11. Date numerele reale a, b, c. De calculat y = .
1 + max( a + bc ,1.15 )
Întrebări de control:

56
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
ii. structură
iii. întreg, real sau caracter
iv. pointer spre un tip definit anterior
v. 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
58
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

59
libry.value 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

60
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 0
ne 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] ;

61
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 100
struct 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 20
struct persoana { char nume[max];
int punctaj ; } ;
int Citeste ( persoana p[])
{
int i,n;

62
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 );

63
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" );

64
}
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++ )

65
{ 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:

66
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)
c) A.x==0 && B.x==0 || A.y==0 && B.y==0
d) 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 ?

67
Lucrare de laborator N10
Tema: 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

68
ş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
î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

69
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”);
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.

70
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
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

71
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:

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()

72
{
FILE *fp; char c;
clrscr();
fp = fopen(”file01”,”a”);
while ( ( c=getc(fp)) != -1)
putc(c, fp);
fclose(fp);
getch(); }
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 40

73
void 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); }
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 20
void 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);

74
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()
{
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))
{

75
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(); }

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 100
void 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:

76
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.
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.

77
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?
18. Funcţia fseek(nume_p, nr, origine)
a.precizează poziţia indicatorului de fişier
b. 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şier
d. 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ău
c.reciteşte conţinutul fişierului
d. 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şierului
b) calculează în l numărul de linii
c) calculează în l numărul de caractere diferite de cele albe
d) este eronată
21. Cînd se închide un fişier?
a.la apelul funcţiei close
b. la apelul funcţiei freopen
c.la terminarea blocului în care a fost declarat
d. 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şier
b. 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.

78
Bibliografie
1. Herbert Shildt. C manual complet. Editura Teora, Bucure;ti, 1998
2. 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

79

S-ar putea să vă placă și