Programare - Curs 3

31
3 CURS Sumar Pointeri. Funcţii definite de utilizator Declararea variabilelor pointer. Tipul pointer (adresă) Tipul pointer Aritmetica pointerilor Alocare de memorie dinamică Funcţii definite de utilizator Prezentarea funcţiilor Transmiterea parametrilor Variabile locale şi variabile globale Probleme propuse spre rezolvare individuală Declararea variabilelor pointeri. Tipul pointer (adresă) Aşa cum am mai spus, o variabilă este numele unei locaţii de memorie, care este aptă de a păstra o valoare de un anumit tip (fiecare variabilă are două atribute importante: valoarea sa curentă şi adresa de memorie). Programul descris, în urma compilării, face referinţă la fiecare locaţie de memorie prin utilizarea unei adrese unice. Pointerul este o variabilă care conţine o adresă, adresa unică a unei locaţii de memorie, cea la care am făcut referire anterior. Cu alte cuvinte, prin pointer se înţelege o variabilă care reţine adrese ale altor variabile de un anumit tip specificat. Pointerul este o adresă la o locaţie de memorie. Dereferenţierea unui pointer este este procesul de accesare a valorii la o anumită locaţie de memorie. Pentru

description

Pointeri. Funcţii definite de utilizator Declararea variabilelor pointer. Tipul pointer (adresă) Tipul pointer Aritmetica pointerilor Alocare de memorie dinamică Funcţii definite de utilizator Prezentarea funcţiilor Transmiterea parametrilor Variabile locale şi variabile globale Probleme propuse spre rezolvare individuală

Transcript of Programare - Curs 3

Page 1: Programare - Curs 3

3CURS

Sumar

Pointeri. Funcţii

definite de utilizator

Declararea variabilelor pointer. Tipul pointer (adresă)

Tipul pointer Aritmetica pointerilor Alocare de memorie dinamică

Funcţii definite de utilizator Prezentarea funcţiilor Transmiterea parametrilor Variabile locale şi variabile globale

Probleme propuse spre rezolvare individuală

Declararea variabilelor pointeri. Tipul pointer (adresă)

Aşa cum am mai spus, o variabilă este numele unei locaţii de memorie, care este

aptă de a păstra o valoare de un anumit tip (fiecare variabilă are două atribute importante:

valoarea sa curentă şi adresa de memorie). Programul descris, în urma compilării, face

referinţă la fiecare locaţie de memorie prin utilizarea unei adrese unice. Pointerul este o

variabilă care conţine o adresă, adresa unică a unei locaţii de memorie, cea la care am

făcut referire anterior.

Cu alte cuvinte, prin pointer se înţelege o variabilă care reţine adrese ale altor

variabile de un anumit tip specificat. Pointerul este o adresă la o locaţie de memorie.

Dereferenţierea unui pointer este este procesul de accesare a valorii la

o anumită locaţie de memorie. Pentru a dereferenţia valoarea unui pointer, se va utiliza

operatorul de redirectare (sau, dereferenţiere) - asteriscul ( * ).

1

Page 2: Programare - Curs 3

1. Tipul pointer

Variabilele pointer intră în alcătuirea tipului pointer sau tipului adresă. Acesta

se scrie sub forma tip*, la care se ataşează numele dorit al pointerilor.

De exemplu, declararea unei variabile pointer spre tipul întreg se face prin

următoarea declaraţie:

int a; //a este o variabilă întreagă

int * b ; /*nu are importanţă plasarea caracterului ‘*’ int*

b; int *b; int*b;*/

//se poate construi că:

b=&a;

În acest caz transferul se face între adrese, adică cu alte cuvinte, adresa locaţiei a devine adresa

b, făcându-se şi preluarea valorilor reţinute la acestea.

După caz, dacă se doreşte doar transfer între valori, se poate opta pentru declaraţia de mai

jos:

a=*b; //respectiv *b=a;(o expresie atât L-value cât şi R-value)

În acest caz, practic se lucrează cu două locaţii de memorie, una cu numele a, iar alta ce are

adresa de memorie b, la ambele locaţii fiind memorată aceeaşi valoare.

2. Aritmetica pointerilor

Cum spuneam, un pointer este o adresă care indică spre o anumită valoare de un

anumit tip de memorie. Mai simplu, un pointer este o valoare care indică o anumită

locaţie de memorie. Dacă se adaugă valoarea 1 unui pointer, pointerul va indica

următoarea locaţie de memorie. Dacă se adaugă valoare 3 unui pointer, pointerul va

indica locaţia de memorie care este cu trei locaţii după adresa curentă.

Însă, aritmetica pointerilor nu este atât de simplă precum se crede. De exemplu, să

presupunem că un pointer conţine adresa 12f0. Dacă se adună valoare 1 la pointer,

aşteptarea este ca rezultatul să fie 12f1. Adresa rezultată, însă, depinde de tipul

pointerului, şi anume:

- dacă se adaugă 1 la o variabilă pointer de tip char (care conţine 12f0), adresa

rezultată este 12f1;

2

Page 3: Programare - Curs 3

- dacă se adună 1 la un pointer de tip int (care cere doi octeţi de memorie), adresa

rezultată este 12f2;

- dacă se adaugă 1 la un pointer de tip float (care cere patru octeţi), adresa rezultată

este 12f4.

Atunci când se efectuează operaţii aritmetice cu pointeri, trebuie ţinut cont de tipul

pointerilor. În plus, faţă de adunarea de valori la pointeri, programele create pot scădea

valori sau pot scădea doi pointeri.

3. Alocare de memorie dinamică

Dacă spaţiul de memorie este insuficient, adică dacă la anumite adrese se incearcă

memorarea unor date mai mari de doi octeţi (reprezentând 16 biţi pentru pointeri de tipul

far, cum se cheamă cei folosiţi până acum) se poate opta ptr. alocarea dinamică a

memoriei. Acest lucru se poate obţine folosind funcţia de bibliotecă bibliotecă malloc,

respectiv free pentru dealocare, ambele găsindu-se în stdlib.h şi alloc.h.

Funcţiile de alocare, respectiv, dealocare, au antetele:

- funcţia de alocare dinamică:

#include<stdlib.h> void *malloc(size_t nr_octeti);

unde, size_t este un tip determinat pentru alocare de memorie, iar, nr_octeti

specifică numărul de octeţi care se doresc pentru alocare dinamică a respectivei variabile.

Dacă funcţia malloc reuşeşte alocarea intervalului de octeţi, ea va returna un pointer la

începutul intervalului, void*. Dacă apare o eroare, funcţia malloc va returna NULL.

- funcţia de dealocare dinamică:

#include<stdlib.h> void free(void* ptr);

unde, ptr este un pointer la începutul intervalului de memorie care se doreşte a fi eliberată.

O variabilă astfel declarată poartă numele de variabilă dinamică, iar, zona de

declarare poartă numele de zona Heap.

3

Page 4: Programare - Curs 3

Exemplul 1. Exemplificare în declararea şi folosirea variabilelor pointer.

a) Transferul se va face între adrese ale locaţiilor de memorie, cu reţinere simultană şi a

valorilor reţinute la acestea.

#include<stdio.h>

void main() { int a=1; /* a este o locatie de memorie pentru elemente de tip int pe

doi octeti, pe care am initializat-o cu valoarea 1 */

int* b; /* b este o variabila pointer spre tipul int, adica capabila a retine adrese ale altor variabile de tipul specificat */

b=&a; /* in adresa b retinem adresa locatiei de memorie (adica, a variabilei) a, deci, cu alte cuvinte, b devine adresa locatiei de memorie a */

printf("Val a= %d\tVal b= %d\n",a,*b); printf("Adr a= %p\tAdr b= %p\n",&a,b); }

Programul anterior va afişa următoarele:

b) Transferul se va face doar între valori reţinute la anumite locaţii de memorie.

#include<stdio.h>

void main() { int a=1; /* a este o locatie de memorie pentru elemente de tip int pe

doi octeti, pe care am initializat-o cu valoarea 1 */

int* b; /* b este o variabila pointer spre tipul int, adica capabila a retine adrese ale altor variabile de tipul specificat */

*b=a; /* trasnferul se face intre valori, si nu intre adrese; cu alte cuvinte, valorii retinute la adresa b ii atribuim valoarea retinuta in a */

printf("Val a= %d\tVal b= %d\n",a,*b); printf("Adr a= %p\tAdr b= %p\n",&a,b); }

Programul va afişa:

4

Page 5: Programare - Curs 3

Observaţie: După cum se vede în primul caz vor coincide atât cele două valori, cât şi cele

două adrese, pe când în varianta a doua vor coincide doar valorile reţinute.

Exemplul 2. Transmiterea informaţiilor prin intermediul adreselor.

Să se scrie rutine C care interschimbă două valori întregi, folosind în descrierea

programelor variabile pointer.

a) Interschimbarea se va face între adrese ale locaţiilor de memorie, elementul auxiliar

interschimbării fiind tot o adresă.

#include<stdio.h>

void main() { int *a,*b,*c;

printf("a= "); scanf("%d",a); printf("b= "); scanf("%d",b);

printf("\nInainte de interschimbare:\n"); printf("\tval a= %d\tval b= %d\n",*a,*b); printf("\tadr a= %p\tadr b= %p\n",a,b);

//interschimbarea c=a; a=b; b=c;

printf("\nDupa interschimbare:\n"); printf("\tval a= %d\tval b= %d\n",*a,*b);

printf("\tadr a= %p\tadr b= %p\n",a,b); }

Pentru a fiind 2, iar b fiind 3, programul va afişa:

5

Page 6: Programare - Curs 3

Din rezultatul de mai sus că prin interschimbare în exemplul anterior, cele două

variabile îşi vor interschimba atât adresele locaţiilor, cât şi valorile reţinute la respectivele

locaţii.

b) Interschimbarea se va face între adresele locaţiilor de memorie, elementul auxiliar

interschimbării nefiind o adresă (un pointer).

#include<stdio.h>

void main() { int *a,*b,c;

printf("a= "); scanf("%d",a); printf("b= "); scanf("%d",b);

printf("\nInainte de interschimbare:\n"); printf("\tval a= %d\tval b= %d\n",*a,*b); printf("\tadr a= %p\tadr b= %p\n",a,b);

c=*a; /* transfer intre valori, ptr ca expresia &c=a; nu ar fi fost valida, nefiind o expresie L-value */

a=b; b=&c;

printf("\nDupa interschimbare:\n"); printf("\tval a= %d\tval b= %d\n",*a,*b);

printf("\tadr a= %p\tadr b= %p\n",a,b); }

Pentru a fiind 2, iar b fiind 3, programul va afişa:

unde, se poate observa ca doar valorile se interschimbă, adresele nu, doar în sensul b spre

a.

c) Interschimbarea se va face între valorile reţinute la locaţiile de memorie ale

respectivelor adrese, elementul auxiliar interschimbării fiind o adresă (un pointer).

#include<stdio.h>

6

Page 7: Programare - Curs 3

void main() { int *a,*b,*c;

printf("a= "); scanf("%d",a); printf("b= "); scanf("%d",b);

printf("\nInainte de interschimbare:\n"); printf("\tval a= %d\tval b= %d\n",*a,*b); printf("\tadr a= %p\tadr b= %p\n",a,b);

*c=*a; *a=*b; *b=*c;

printf("\nDupa interschimbare:\n"); printf("\tval a= %d\tval b= %d\n",*a,*b);

printf("\tadr a= %p\tadr b= %p\n",a,b); }

Rezultatul va fi:

unde, se poate observa că doar valorile se interschimbă, adresele rămân aceleaşi.

d) Interschimbarea se va face între valorile reţinute la locaţiile de memorie ale

respectivelor adrese, elementul auxiliar interschimbării nefiind o adresă (un pointer).

#include<stdio.h>

void main() { int *a,*b,c;

printf("a= "); scanf("%d",a); printf("b= "); scanf("%d",b);

printf("\nInainte de interschimbare:\n"); printf("\tval a= %d\tval b= %d\n",*a,*b); printf("\tadr a= %p\tadr b= %p\n",a,b);

c=*a; *a=*b; *b=c;

7

Page 8: Programare - Curs 3

printf("\nDupa interschimbare:\n"); printf("\tval a= %d\tval b= %d\n",*a,*b);

printf("\tadr a= %p\tadr b= %p\n",a,b); }

Pentru a fiind dat 2, iar b fiind dat 3, rezultatul va fi:

unde, se poate observa că doar valorile se interschimbă, adresele rămân aceleaşi.

Exemplul 3. Aritmetica pointerilor.

a) Să se scrie o rutină în C pentru exemplificarea aritmeticii în cazul pointerilor,

exemplificare pe cazurile operaţiilor de incrementare/decrementare, respectiv,

adunare/scădere de valori.

#include<stdio.h>

void main() { int a[]={10,20,30,40,50}; /* am declarat un sir de elemente de tip

int pe care l-am initializat cu valorile aflate in multime */

int* b; //b este pointer spre tipul int

b=a; /* in adresa b retinem sirul a; transferul se face asa,deoarece a este o adresa prin numele sau, adresa primului element din sir */

for(int i=1;i<=5;i++) {

printf("%d\n",*b); /* b-ul prin transfer fiind adresa primului element, rezultatul acestei expresii va fi prima valoare din sir, adica, 10 */

b++; //se face trecerea pe elementul urmator din sir}

//ne vom intoarce cu pointerul de cursor al sirului in prima pozitie b-=5; //se mai putea scrie si b=b-5;

printf("primul element al sirului: %d\n",*b);

/* ne pastram pozitia de pointare in sir, dar vrem sa afisam elementul

8

Page 9: Programare - Curs 3

al treilea al sirului */ printf("al treilea element al sirului: %d",*(b+2));

}

Programul va afişa:

b) Se va reface exemplul anterior, astfel încât prelucrarea să se facă asupra unui şir de

caractere prin prelucrare pe subşiruri ale acestuia.

#include<stdio.h>

void main() { char a[]="ABCDE"; //sirul a retine un sir de caractere, in numar de 5 char* b;

b=a;

for(int i=1;i<=5;i++) {

printf("%s\n",b); /* un şir este o adresă, iar, mesajul acesta vaafisa subsirul incepand cu prima pozitie, adica "ABCDE" */

b++;}

b-=5;

printf("subsirul incepand cu prima pozitie: %s\n",b); printf("subsirul incepand cu a treia pozitie: %s",b+2);

}

Programul de mai sus va afişa:

9

Page 10: Programare - Curs 3

Exemplul 4. Memoria ocupată de o variabilă pointer de un anumit tip determinat.

Să vedem care este spaţiul ocupat de o variabilă a unui tip pointer spre un tip oarecare din cele

standard predefinite.

#include<stdio.h>

void main() {

printf("Spatiul ocupat in octeti de catre:\n"); printf("\tun pointer spre tipul <char>: %d\n",sizeof(char*)); printf("\tun pointer spre tipul <int>: %d\n",sizeof(int*)); printf("\tun pointer spre tipul <float>: %d\n",sizeof(float*)); printf("\tun pointer spre tipul <double>: %d\n",sizeof(double*));

}

Rezultatul afişat va fi:

Exemplul 5. Alocarea memorie dinamice în lucrul cu variabile pointer.

Alegând una dintre cele 4 variante de program descrise mai sus în exemplul 2 să se

realizeze un program care interschimbă două valori reale folosind variabile pointer.

#include<stdio.h> #include<stdlib.h> //sau, #include<alloc.h>

void main() { double *a,*b,*c;

/* vom crea variabile dinamice, adica variabila ce isi vor pastra memoria extinsa intr-o zona, numita zona HEAP */

a=(double*)malloc(sizeof(double)); /* in zona HEAP am rezervat spatiu suficient pentru memorarea unei variabile de tipul double */ printf("a= ");

scanf("%lf",a);

b=(double*)malloc(sizeof(double)); printf("b= "); scanf("%lf",b);

c=a; /* pentru c nu este nevoie sa alocam memorie dinamica, pentruca c primeste prin transfer de la a */

a=b; b=c;

printf("dupa interschimbare: a= %.2lf\tb= %.2lf",*a,*b);

/* desi in acest caz nu este necesar, pentru ca o variabila dinamica

10

Page 11: Programare - Curs 3

nu mai este viabila la sfarsitul executiei functiei, totusi noi putem opta pentru dealocare explicita pentru variabilele create dinamic */

free(a); free(b); }

Programul de mai sus va afişa pentru două valori arbitrar alese, următoarele:

Funcţii definite de utilizator

1. Prezentarea funcţiilor

Ştiam până acum că un program C este o succesiune de funcţii, din care una este cea

principală în rulare, şi anume funcţia main. Pe măsură ce programele create vor deveni

mai mari şi mai complexe, munca programatorului se va putea simplifica şi se va putea

îmbunătăţii claritatea programelor, prin fragmentarea acestora în părţi mai mici, numite

funcţii. Deci, funcţiile pot fi cele principale în rulare (ex.: main), cele predefinite în limbaj

(ex.: printf), sau cele dezvoltate de către programator.

Dacă toate instrucţiunile ar fi plasate în cadrul funcţiei main, programul ar deveni foarte

lung şi greu de înţeles. Pe măsură ce dimensiunea programelor şi complexitatea lor creşte,

creşte şi posibilitatea apariţiei erorilor. Dacă programul va fi fragmentat în părţi mai mici,

mai uşor de manevrat, erorile ar putea fi evitate. O funcţie este o colecţie de instrucţiuni

care execută o anumită sarcină.

Forma generală a unei funcţii este:

tip_rezultat nume_functie (lista_parametri_formali)

{

//corpul functiei cu declaratiile de variabile locale [return

expresie;]

}

- Tipul rezultat poate să fie tipul void, unul din tipurile predefinite, un tip definit de

utilizator, un tip pointer sau un tip structură.

11

Page 12: Programare - Curs 3

- Un parametru este o informaţie pe care programul o transmite funcţiei. Lista

parametrilor formali este de forma:

tip1 param1 , tip2 param2 , tip3 param3 , …, tipn paramn

Există posibilitatea ca lista parametrilor formali să fie vidă.

- Ieşirea dintr-o funcţie se poate face cu return, care dacă este însoţit de o expresie

întoarce o anumită valoare la funcţiile a căror tip rezultat este diferit de cel vid.

Orice funcţie declarată are trei zone: zona declarativă sau antetul funcţiei sau

prototipul funcţiei, zona definitivă sau corpul funcţiei şi zona de apel. În multe din cazuri zona

declarativă se confundă cu cea definitivă.

Antetul (prototipul) unei funcţii are următorul format:

tip_rezultat nume_functie (tip1, tip2, tip3, …, tipn);

plasându-se în program înaintea etapei de descriere a funcţiei.

O funcţie se apelează prin numele său, care după caz, dacă întoarce un rezultat se poate

atribui unei variabile de tipul specificat în rezultat. În zona de apel linia de parametri se

cheamă linie de parametri actuali, care trebuie să coincidă în număr, tip şi aşezare cu cei

formali.

2. Transmiterea parametrilor

Transmiterea parametrilor prin intermediul funcţiilor se poate face prin valori sau prin

adrese.

În cazul apelului prin valoare, compilatorul va da funcţiei o copie a valorii

parametrului. Folosind apelul prin valoare, orice modificare a parametrului va exista

numai în interiorul funcţiei apelate. La sfârşitul execuţiei funcţiei, valoarea variabilelor care i-

au fost transmise rămâne nemodificată în funcţia apelantă.

De exemplu, programul de mai jos (exemplul 6, varianta a) transmite trei

parametri (variabilele a, b şi c) funcţiei modifică, care va afişa valorile, le va adăuga 10 şi apoi

va afişa rezultatul. După execuţia funcţiei, programul va afişa valorile variabilelor. Deoarece

se foloseşte apelul prin valoare, funcţia nu modifică valorile variabilelor în cadrul funcţiei

apelante, după cum se vede în rezultatul de mai jos.

Când se transmit parametrii către o funcţie, compilatorul de C/C++ plasează

valorile corespunzătoare într-o stivă. În exemplul nostru de mai jos, în cazul variabilelor

12

Page 13: Programare - Curs 3

a, b şi c stiva conţine valorile 1, 2 şi 3. Când funcţia schimbă valoarea unui parametru,

modifică valoarea din stivă asociată acestuia.

Când se încheie execuţia funcţiei, compilatorul descarcă valorile din stivă şi nu mai

sunt luate în considerare modificările pe care funcţia le-a efectuat în locaţiile stivei. Funcţia nu

face niciodată referire la locaţiile de memorie care conţin valorile variabilelor, astfel că

modificările parametrilor primiţi în urma unui apel prin valoare nu vor mai exista după

încheierea execuţiei funcţiei.

Exemplul 6.

Transferul parametrilor prin valoare, respectiv, prin adresă în cazul funcţiilor propriu descrise.

a) Transferul parametrilor prin valoare.

#include<stdio.h>

void modifica(int x, int y, int z) {

printf("Valori initiale in functie: %d %d %d\n",x,y,z); x+=10; y+=10; z+=10; printf("Valori finale in functie: %d %d %d\n",x,y,z);

}

void main() { int a=1,b=2,c=3; printf("Valori initiale in program: %d %d %d\n",a,b,c); modifica(a,b,c); printf("Valori finale in program: %d %d %d\n",a,b,c);

}

Programul de mai sus va afişa:

În multe din cazuri funcţiile create vor avea ca scop modificarea valorile

variabilelor transmise prin parametri. În cazul funcţiilor care modifică valorile

13

Page 14: Programare - Curs 3

parametrilor în program, la sfârşitul execuţiei lor, tehnica folosită va trebui să fie cea a

apelului prin adresă.

Diferenţa între apelul prin valoare şi cel prin adresă este că, folosind apelul prin

valoare, funcţia primeşte o copie a valorii unui parametru, pe când, în cazul apelului prin

adresă, funcţia primeşte adresa de memorie a variabilei. De aceea, funcţiile ce transmit

parametri prin adresă pot să modifice valoarea păstrată într-o locaţie de memorie (adică,

valoarea variabilei), iar modificarea rămâne şi după terminarea execuţiei funcţiei. Pentru

a utiliza apelul prin adresă, programul creat trebuie să folosească pointeri.

b) Transferul parametrilor prin adresă.

#include<stdio.h>

void modifica(int* x, int* y, int* z) {

printf("Valori initiale in functie: %d %d %d\n",*x,*y,*z); *x+=10; *y+=10; *z+=10; printf("Valori finale in functie: %d %d %d\n",*x,*y,*z);

}

void main() { int a=1,b=2,c=3; printf("Valori initiale in program: %d %d %d\n",a,b,c); modifica(&a,&b,&c); printf("Valori finale in program: %d %d %d\n",a,b,c);

}

Programul anterior va afişa:

3. Declararea variabilelor

Din punctul de vedere al declarării variabilelor acestea se împart în două categorii:

- variabile locale - sunt variabilele primite ca parametru sau declarate în corpul unei

funcţii, fiind viabile din momentul declarării şi până la sfârşitul execuţiei funcţiei.

Zona de memorie a acestora poartă numele de segment stivă;

14

Page 15: Programare - Curs 3

- variabile globale - sunt variabile cu vizibilitate într-un întreg program, din momentul

declarării şi până la sfârşitul execuţiei acestuia. Zona de memorie a acestora poartă

numele de segment de date.

Atunci când situaţia o cere se poate apela la zona extinsă de memorare, numită zona

Heap, prin folosirea variabilelor dinamice.

În sintetizarea celor de mai sus, propunem următorul tabel:

Tip variabilă Clasă de memorare Vizibilitate şi durată de viaţă. CaracteristiciVariabile globale segmentul de date - în cazul declaraţiilor înaintea tuturor funcţiilor acestea

sunt vizibile în întreg programul fişier - statică - o variabilă globală este automat iniţializată cu 0 la declarare

Variabile locale segmentul de stivă - vizibilitate locală, adică la nivel de subprogramVariabile dinamice zona Heap - dinamică, determinată de utilizator

Exemplul 7.

Se va scrie un program care va realiza interschimbarea conţinutului a două variabile ce pot

reţine valori reale. Programul va defini funcţii de citire şi afişare pentru un număr real,

precum şi o funcţie proprie pentru interschimbarea conţinutului variabilelor, cu rămânerea

rezultatului şi în afara execuţiei funcţiei.

#include<stdio.h>

//citirea unei variabile reale void citire(float* x, char c) {

printf("dati valoarea %c: ",c); scanf("%f",x);

}

//afisarea continutului unei variabile reale void afisare(float x, char c) {

printf("valoarea din %c este: %.2f\n",c,x);}

//functie de interschimbare a continutului unor doua variabile reale void interschimba(float* x, float* y) {

float z; //interschimbarea se va face intre valori retinute la adrese z=*x; *x=*y;*y=z;

}

15

Page 16: Programare - Curs 3

void main() {

float a,b;

citire(&a,'a'); citire(&b,'b');

printf("\nINITIAL:\n");

afisare(a,'a'); afisare(b,'b');

printf("\nDUPA INTERSCHIMBARE:\n");

interschimba(&a,&b);

afisare(a,'a'); afisare(b,'b');

}

Programul anterior va afişa, pentru două valori arbitrar alese, următoarele:

Observaţii:

1. În cazul interschimbării se cere transferul parametrilor prin adresă, dat fiind faptul

că doar această posibilitate permite programului modificarea valorilor transmise

din funcţie prin intermediul parametrilor.

2. În programul de mai sus nu am folosit alocare dinamică, precum într-un caz

anterior, deoarece prin declaraţia float a,b s-a rezervat spaţiu suficient pe stivă

pentru cele două variabile.

Exemplul 8. Ce se întâmplă, în cazul aplicaţiei anterioare, dacă variabilele sunt declarate global?

a) declarate de un tip standard definit.

#include<stdio.h>

16

Page 17: Programare - Curs 3

float a,b;

//functie de citire a celor doua variabile void citire() { printf("dati a: ");

scanf("%f",&a); printf("dati b: "); scanf("%f",&b); }

//functie de afisare void afisare() { printf("valorile sunt: a=%.2f, b=%.2f\n",a,b);

}

//functie de interschimbarevoid interschimba(){float c;c=a;a=b;b=c;

}

void main(){citire();afisare();

printf("\n");

interschimba(); afisare();

}

//functie cu transfer a parametrilor prin adresa

Pentru două valori arbitrar alese, programul va afişa:

b) declarate de tip pointer spre un tip real.

#include<stdio.h> #include<stdlib.h>

float*a,*b;

void alocare() { a=(float*)malloc(sizeof(float));

17

Page 18: Programare - Curs 3

b=(float*)malloc(sizeof(float));}

void citire() { alocare(); printf("dati a: "); scanf("%f",a); printf("dati b: "); scanf("%f",b);

}

void afisare() { printf("valorile sunt: a=%.2f, b=%.2f\n",*a,*b);

}

void interschimba() { float c; c=*a; *a=*b;

*b=c; }

void main() { citire(); afisare(); printf("\n");

interschimba(); afisare();

}

Exemplul 9.

Să se urmărească programul de mai jos:

#include<stdio.h>

int a,b;

int f(int m,int n) {

m=n+b; n+=1; return n+b+m;

}

void main() {

a=6; b=5; printf("%d %d ",a,b); printf("%d ",f(a,b));

18

Page 19: Programare - Curs 3

printf("%d %d ",a,b);}

Ce valori afiseaza programul? R: 6 5 21 6 5Ce valori s-ar afisa, daca antetul functiei ar fi: int f(int *m,int *n) ?

R: 6 5 22 10 6

Exemplul 10.

Se cere a se scrie funcţii ce vor calcula suma cifrelor unui numar întreg si inversul sau. Funcţiile se vor scrie cu prototip (zona declarativă diferenţiată de cea definitivă).

#include<stdio.h>

//in acest caz rezultatul se va transmite prin tipul rezultat int s_c(int); //suma cifrelor unui nr. intreg

//in acest caz rezultatul se va transmite prin linia de parametri void n_i(int, int*); //inversul unui nr. intreg

void main() { int n, suma_cifrelor=0, nr_invers=0; printf("dati n: "); scanf("%d",&n);

suma_cifrelor=s_c(n); printf("\nSuma cifrelor sale este: %d",suma_cifrelor);

n_i(n,&nr_invers); printf("\nInversul sau este: %d",nr_invers);

}

/* suma cifrelor unui numar intreg: Presupunem nr. dorit ca fiind 523 ptr. care sa calculam suma cifrelor 523 : 10 = 52 rest 3 Suma cifrelor intermediara: 0+3=3 52 : 10 = 5 rest 2 Suma cifrelor intermediara: 3+2=5 5 : 10 = 0 rest 5 Suma cifrelor finala: 5+5=10 */

int s_c(int n) { int sc; while (n) {

sc=sc+n%10; n/=10;

} return sc;

}

19

Page 20: Programare - Curs 3

/* inversul unui numar intreg: Presupunem nr. dorit ca fiind 523 ptr. care dorim sa-i aflam inversul 523 : 10 = 52 rest 3 Numarul invers intermediar: 0*10+3=3 52 : 10 = 5 rest 2 Numarul invers intermediar: 3*10+2=32 5 : 10 = 0 rest 5 Numarul invers final: 32*10+5=325 */

void n_i(int n, int* ni) {

while (n) { *ni=*ni*10+n%10; n/=10;

} }

Probleme propuse

1. Să se rescrie, cu eventuale modificări aplicaţiile prezente în setul de aplicaţii

rezolvate.

2. Folosind o funcţie să se realizeze un program care calculează următoarea

expresie:

(1+ ½ + 1/3+ ¼ +…+1/n)n , unde n este un întreg dat de la tastatură.

3. Să se realizeze un program care calculeaya prin intermediul a două funcţii

cmmdc-ul şi cmmmc-ul a duă numere date de la tastatură.

4. Să se realizeze adunarea şi înmulţirea a două numere reale folosind variabile de

tipul pointer.

5. Scrieţi o funcţie care primeşte ca parametru lungimea laturii unui pătrat şi

returnează aria sa şi o funcţie care returnează diagonala.

6. Scrieţi o funcţie care primeşte 3 parametri de tip real, cu semnificaţia de lungimi

pentru 3 segmente. Funcţia va returna 1, dacă cele trei segmente pot forma un

triunghi şi 0, în caz contrar.

7. Scrieţi o funcţie care returnează ultima cifră a unui număr natural. De exemplu,

dacă numărul este 234, funcţia va returna 4.

20