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
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
- 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
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
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
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
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
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
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
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
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
- 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
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
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
- 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
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
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
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
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
/* 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
Top Related