Documente Academic
Documente Profesional
Documente Cultură
Programarea în limbajul C
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
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:
3
Lucrare de laborator N1
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)
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();
}
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:
8
Lucrare de laborator N2
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 .
9
double cos(double x); cosinus de x
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();
}
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:
14
Lucrare de laborator N3
Suport teoretic:
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
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
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
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].
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.
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.
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]
}
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
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.
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();
}
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:
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
Suport teoretic:
Exemple de declaratii:
// vector de 100 valori întregi
int vanzari[100];
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.
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:
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();
}
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
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:
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.
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();
}
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:
49
Lucrare de laborator N8
Tema: Subprograme.
Suport teoretic:
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.
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.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;
}
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
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ă.
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.
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.
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.
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:
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:
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:
61
Exemple de programe:
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 );
}
Î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.
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.
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.
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.
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,
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:
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