Sunteți pe pagina 1din 47

Subprograme definite de utilizator

- Proceduri şi funcţii: declarare şi apel


- Parametri formali şi parametri efectivi
- parametri transmişi prin valoare
- Parametri transmişi prin referinţă
- Variabile globale şi variabile locale, domeniu de vizibilitate
- Proiectarea modulară a rezolvării unei probleme
Proceduri şi funcţii: declarare şi apel

 Funcţia reprezintă o unitate de sine stătătoare a unui


programului C, prin intermediul căreia se descrie un subalgoritm
de rezolvare a unei subprobleme.
 Programele C permit o traducere a descrierilor algoritmice bazate
pe subalgoritmi prin posibilitatea definirii unor funcţii utilizator
care tratează aspecte parţiale ale rezolvării.
 Un program C poate conţine funcţia principală main dar şi alte
funcţii definite de către programator sau apelul funcţiilor
predefinite din bibliotecile standard.
 Avantajele folosirii functiilor utilizator
Proceduri şi funcţii: declarare şi apel

SINTAXA DEFINIRE FUNCTIE

<tip>NumeFuncţie (<tip1><arg1>,…,<tipn><argn>)
{
<instrucţiuni de declarare de tip a variabilelor locale>
……………
<instrucţiuni>
}
CORPUL FUNCŢIEI cuprinde între acolade { ...} partea de declarare a variabilele locale funcţiei
respective şi partea de prelucrare a datelor: secvenţă de instrucţiuni prin care se prelucrează
variabilele locale sau altele cu caracter global.
În ANTETUL unei funcţii este precizat tipul de dată pe care îl returnează <tip>. Acesta poate
fi void, caz în care funcţia nu returnează nimic.
Parantezele rotunde (….) ce urmează numelui funcţiei delimitează lista argumentelor
funcţiei.. Fiecărui argument îi este precizat tipul şi numele sub care este referit în cadrul funcţiei
curente.
Parametri formali şi parametri efectivi

 Prototipul funcţiei: este format de antetul funcţiei din


care poate să lipsească numele parametrilor formali:
<tip>NumeFuncţie(<tip1>,…,<tipn>) ;
//declararea unei funcţii
 Utilitatea declararii functiilor
Parametri formali şi parametri efectivi

 La definirea unei funcţii, argumentele


precizate în antetul acesteia se numesc
parametri formali.
 La apelul funcţiei, parametrii formali sunt
înlocuiţi de parametri actuali.
Apelul funcțiilor

 Apelul unei funcţii se face prin construcţia:

[ var= ] NumeFuncţie (pa1, pa2, … , pan);


Funcţie fără tip şi fără parametrii

 Există posibilitatea definirii de către utilizator a unor funcţii care nu


returnează nimic şi lista parametriolor acestora este vidă:

void NumeFuncţie ()
{
… //corpul functiei
}

 Apelul funcţiei se face printr-o construcţie de forma:

NumeFuncţie();
Funcţie fără tip şi fără parametrii

 Exemplu:
Se defineşte o funcţie Cifre care tipăreşte cifrele arabe. Funcţia va fi apelată în funcţia main.

#include <stdio.h>

void Cifre()
{
int i; //declaraţie de variabilă locală
for(i=0;i<=9;i++) printf(“%d”,i);
}

void main(void)
{
Cifre(); //apelul functiei Cifre
}
Funcţie fără tip şi fără parametrii

void main()
void suma()
{int a,b;
{char op;
cin>>a; cin>>b; op=getch(); //cin>>op;
cout<<(a+b); switch case (op)
} {
void produs() case ‘+’:suma();break;
{int a,b; case ‘*’ produs();break;
cin>>a; cin>>b;
case ‘*’ diferenta();break;
cout<<(a*b);
default: cout<<“nu este operatie”;
}
void diferenta() }
{int a,b; }//main
cin>>a; cin>>b;
cout<<(a-b);
}
Funcţii cu tip
 Dacă unei funcţii îi este precizat tipul (diferit de void) acest lucru
spune că funcţia returnează codului apelant o valoare de acest
tip. În caz contrar, funcţia nu returnează valoare.

 Tipul funcţiei reprezintă tipul de dată al valorii pe care o


returnează.

 Instrucţiunea return, folosită în cadrul funcţiei cu tip definite, are


sintaxa:
return <expresie>;
şi are rolul de a reveni în programul apelant şi de a returna o valoare
de tipul precizat în antetul functiei.
Funcţii cu tip
Apelul functiilor cu tip

Funcţia poate fi apelată (in corpul apelant) printr-o instrucţiune de


asignare:
ValoareReturnată= NumeFuncţie();

//membrul stâng al instrucţiunii este o variabilă de tipul returnat de funcţie


Funcţii cu tip
Varianta 1 Varianta compacta
Exemplu: Programul C conţine o funcţie CitireValoare,
care citeşte o valoare numerică întreagă de la tastatură
şi returnează această valoare funcţiei main apelantă, pe
care aceasta o va afişa pe ecran.

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


int CitesteValoare() int CitesteValoare()
{ {
int numar; //declaraţie de variabilă locală int numar; //declaraţie de variabilă locală
scanf(“%d”,&numar); scanf(“%d”,&numar);
return numar; return numar;
} }

void main(void)
{ void main(void) //varianta compacta
int valoare; {
valoare=CitesteValoare();//apel printf(“valoarea este: %d”, CitesteValoare());
printf(“valoarea este: %d”, valoare); }
}
Funcţii parametrizate
 Funcţiile cu parametri corespund acelor subalgoritmi care
prelucrează date de intrare
 Intrările funcţiei sunt descrise prin lista parametrilor formali ce
conţine nume generice ale datelor prelucrate în corpul funcţiilor.
 Parametrii efectivi/actuali sunt transmişi la apelul funcţiilor,
aceştia înlocuind corespunzător parametrii generici specificaţi.
 În limbajul C transmiterea parametrilor actuali funcţiilor apelate se
face prin valoare: înţelegând prin aceasta că valorile curente ale
parametrilor actuali sunt atribuite parametrilor generici ai
funcţiilor.
Funcţii parametrizate
Exemplu:
int minim(int a, int b)
{ return ( (a>b)?a:b) }
//apelul din functia main
int nr1,nr2, min;
nr1=7; nr2=6;
min=minim(nr1,nr2); // la apel a va primi valoarea 7 şi b – valoarea 6
min=minim(nr2,nr1); // la apel a va primi valoarea 6 şi b – valoarea 7
Parametri transmişi prin valoare

Fie funcţia:
tip NumeFuncţie(tip1 pf1, tip2 pf2, … , tipn pfn)
{…};
La apelul:
NumeFuncţie(pa1, pa2, … , pan);
se vor transmite prin valoare parametrii actuali şi fiecare parametru
formal din antetul funcţiei este înlocuit cu valoarea parametrului
actual. Dacă parametrul actual este o expresie, aceasta este initial
evaluată la o valoare care ulterior este copiată în parametrul formal
corespunzător.
Observaţie: modificările aduse parametrilor formali în cadrul
funcţiei apelate nu afectează valorile parametrilor actuali !!!
Parametri transmişi prin valoare

Definitie functie:
tip NumeFunctie (tip1 pf1, tip2 pf2, … , tipn pfn)
{...instructiuni...};
Apel functie:
NumeFunctie ( pa1, pa2, … , pan);

Observaţie: numarul parametrilor actuali (de la apel) trebuie sa


coincida cu numarul parametrilor formali (de la definire)!!!
Parametri transmişi prin valoare

#include <stdio.h>
void putere(int n) //ridică la pătrat valoarea n şi afişează rezultatul
{
n=n*n;
printf(“ valoarea lui n in functie este %d”,n); //n este 25
}
void main(void)
{
int n=5;
printf(“ valoarea lui n inainte de apel este %d”,n); // efectul: valoarea lui n inainte de apel este 5
putere(n); // efectul: valoarea lui n in functie este 25
printf(“ valoarea lui n dupa de apel este %d”,n); //efectul: valoarea lui n dupa de apel este 5
// (!nu s-a modificat parametrul actual)
}
Parametri transmişi prin adresă

 În multe situaţii este necesar ca efectul operaţiilor din corpul unei


funcţii apelate asupra parametrilor de intrare să fie vizibil şi în
corpul apelant.
 În exemplul anterior efectul dorit este acela ca variabila n după
apel să păstreze rezultatul ridicării la pătrat. Transmiterea prin
valoare nu permite acest lucru. În schimb, transmiterea prin
adresă realizată prin intermediul variabilelor de tip pointer
asigură modificarea valorilor parametrilor actuali.
 Pentru a înţelege mecanismul transmiterii parametrilor prin
adresă în limbajul C, vom defini în continuare noţiunea de
pointer.
Variabile Pointer

Pointer = variabilă care are ca valori adrese de memorie.


Sintaxa de declarare a unei variabile pointer:
tip * p; // variabilă pointer spre tip
Prin această declaraţie s-a introdus o variabilă ale cărei valoare este adresa
unei zone de memorie ce poate reţine o dată de tipul tip.

Fie x o variabilă simplă de tipul tip:


tip x;
şi p un pointer (variabilă de tip pointer) care are ca valoare adresa variabilei
x.

Pentru a face o atribuire unei variabile de tip pointer p se foloseşte construcţia:


p=&x; // semnificaţia: lui p i se atribuie adresa variabilei x.
Variabila Pointer

Prin construcţia &x ne referim la adresa variabilei x.


Prin construcţia *p ne referim la valoarea variabilei x.

Operatorul * se numeşte operator de indirectare
Operatorul & se numeşte operator adresă
Expresia *&x are aceiaşi semnificaţie cu expresia x.
Variabila Pointer
2
int x; 3

int *p; x nedefinit

p=&x;

p ff02
x=2;

*p=3;
Transmiterea parametrilor prin adresă
folosind pointeri

Transmiterea prin adresă se realizează prin variabile de tip pointer


şi ne asigură de modificarea valorii parametrilor actuali.
Transmiterea prin prin adresa este realizată astfel:

1. Parametrii formali ai funcţiei se declară ca fiind de tip pointer;


tip NumeFuncţie(tip1 *p1, tip2 *p2, … , tipn *pn)
{…};
2. La apel, argumentele funcţiei sunt adresele parametrilor actuali;
NumeFuncţie(&p1, &p2, … , &pn)
(exceptie in cazul in care variabilele sunt de tip pointer)
Transmiterea parametrilor prin adresă
folosind pointeri - exemplu
#include <stdio.h>
void putere(int *p) //ridică la pătrat valoarea n şi afişează rezultatul
{
*p=*p* *p;//ridică la pătrat valoarea referită de p: *p
printf(“ valoarea lui n in functie este %d”,*p); //n este 25
}
void main(void)
{
int n=5;
printf(“ valoarea lui n inainte de apel este %d”,n); // efectul: valoarea lui n inainte de apel este
5
putere(&n); // efectul: valoarea lui n in functie este 25
printf(“ valoarea lui n dupa de apel este %d”,n); //efectul: valoarea lui n dupa de apel este 25
///(!s-a modificat parametrul actual) }
Transmiterea parametrilor prin adresa

 Probleme …
Variabile referintă (C++)

Referința= variabilă ALIAS pentru alta variabila. (porecla)


sinonimie
Sintaxa de declarare a unei variabile referinta:
tip & ref =var; // variabilă referinta la tip
//referintele trebuie INITIALIZATE
Referintele sunt nume diferite pentru aceiasi locatie de memorie
Fie x o variabilă simplă de tipul tip:
tip x;
şi ref o referinta (variabilă de tip referinta la tip).

Pentru a face o atribuire unei variabile de tip referinta ref se foloseşte


construcţia:
tip &ref=x;
Referintă versus pointer

 referintele sunt initializate la declaratie


 referinta nu poate fi modificata pentru a referi o alta zona de
memorie (
 intr-un program C++ valid nu exista referinte nule!
 Tipul referinta este specific C++

 Implicit transmiterea parametrilor se face prin valoare


 Transmiterea parametrilor prin adresa
 Folosind pointeri
 Folosind referinte
Exemplu:

 Transmiterea parametrilor prin adresa:


 Cu pointeri
 Cu referinte
Exemplu
Cu pointeri Cu referinte
void fa_zero(int *a) void fa_zero(int &a)
{ *a=0;} { a=0;}

void main() void main()


{ {
int a; int a;
a=1; a=1;
cout<<“inainte de functie:”<<a; cout<<“inainte de functie:”<<a;
fa_zero(&a); fa_zero(a);
cout<<“dupa apel functie:”<<a; cout<<“dupa apel functie:”<<a;
} }
Exercitii
 Interschimbarea a doua variabile
 Calcularea ariei si perimetrului unui triunghi
 Ridicarea la putere a unui nr.
Variabile globale şi variabile locale

 Variabilele locale se declară în cadrul funcţiilor


şi se numesc locale deoarece numele şi
valorile lor sunt cunoscute doar în cadrul
funcţiei respective (local).
 Variabilele globale sunt acele variabile care
se declară înaintea oricăror declaraţii de
funcţii, iar numele, valorile şi existenţa lor este
cunoscuta în întregul program.
Domeniu de vizibilitate

Domeniul de vizibilitate reprezinta spatiul –


cuantificat ca textul sursa in care variabila poate
fi accesata.
Domeniul de vizibilitate incepe de la declararea
variabilei si se incheie la terminarea blocului
care contine declaratia respectiva.

OBS: Domeniul de vizibilitate al unei variabile globale poate fi intrerupt de


domeniul de vizibilitate a unei variabile locale cu acelasi NUME! (exemplu…)
OBS: operatorul scope resolution ::
Durata de viata a unei variabile
 Programul:
 Codul (instructiunile)
 Zona de date
 (variabile globale – statice, alocate la compilare
 Durata de viata – intreg programul
 Zona de stiva
 variabile locale, temporare – auto, alocate la executia blocului/functiei
 Durata de viata – coincide cu timpul de executie a functiei (exceptie
variabilele locale static - isi pastreaza valoarea intre apeluri succesive ale
aceleiasi functii)
 Zona heap (variabile dinamice)
 Variabile dinamice - controlate de programator (gestiunea memoriei in
timpul executiei)
Proiectarea modulară a rezolvării unei
probleme
 Modulul este o unitate structurala de sine statatoare:
program, subprogram (functie), unitate de program:
fisier sursa, clasa(mai multe functii grupate in acelasi
fisier, clasa –in programarea orientata obiect)
 Proiectarea modulara:
 Top - down
 Bottom -up
Recursivitate

- Prezentare generală
- Proceduri şi funcţii recursive
- Probleme
Recursivitate
Recursivitatea se obţine prin instrucţiunea de apel a unei funcţii în
corpul definirii funcţiei respective:

<tip>NumeFuncţie(<tip1><arg1>,…,<tipn><argn>)
{
<instrucţiuni de declarare de tip a variabilelor locale>
……………
<instrucţiuni>
……………
NumeFuncţie(pa1, pa2, … , pan); //auto apelul funcţiei
……………
}
Recursivitate
 La fiecare apel al funcţiei recursive, pe stiva programului sunt
depuse noul set de variabile locale (parametri). Chiar dacă
variabile locale au acelaşi nume cu cele existente înainte de
apelarea funcţiei, valorile lor sunt distincte, şi nu există conflicte
de nume. Practic, ultimele variabile create sunt luate în
considerare în operaţiile conţinute de funcţie!
Recursivitate – exercitiu 1
 Problemă 1: Să se calculeze P(n)=n! printr-o funcţie recursivă.

 Analiza problemei: Pornind de la observaţia că produsul


P(n)=1*2*…(n-1)*n
se mai poate formula ca:
P(n)=P(n-1) * n,
vom defini o funcţie factorial care tratează problema determinării lui
P(k) pe baza formulei anterioare, presupunând că P(k-1) este
calculabil după acelaşi procedeu. P(k-1)=P(k-2)*(k-1).
Recursivitate – exercitiu 1
 Funcţia autoapelantă trebuie să conţină o condiţie de terminare
a recursivităţii. În problema calculului n!, condiţia de terminare a
recursivităţii se deduce din observaţia că 1! are valoarea 1, ceea
ce nu mai necesită un calcul suplimentar.

 Apelul iniţial al funcţiei factorial se va face pentru parametrul


actual n- reprezentând data de intrare a programului.
 Funcţia returnează la ieşirea din apel rezultatul dorit n!.
Recursivitate – exercitiu 1
int factorial(int k)
{
if (k>1) //testarea conditiei de terminare a recursivitatii
return (k*factorial(k-1));
else
return 1;
}
… //apelul functiei
int p;
p=factorial(n);
Executie pas cu pas
 Considerăm n=3
 La apelul iniţial factorial(n) se transmite valoarea 3
parametrului formal k şi se predă controlul funcţiei apelate
 Din condiţia adevărată 3>=1 rezultă amânarea revenirii din
funcţie şi un nou apel factorial(2); la ieşirea din primul apel
se va return 3*factorial(2).
 Apelul factorial(2) va produce transmiterea valorii 2 la
parametrul formal k şi predarea controlului funcţiei apelate
pentru valoarea curentă a parametrului
 Condiţia adevărată 2>=1 produce o nouă apelare
factorial(1) cu amânarea revenirii din apelul curent; la
ieşirea din acest al doilea apel se va return 2*factorial(1) .
 Apelul factorial(1) va produce transmiterea valorii 1 la
parametrul formal k şi predarea controlului funcţiei apelate
pentru valoarea curentă a parametrului
 Din condiţia falsă 1>1 rezultă că la ieşirea din acest apel se
va return 1 şi funcţia nu se mai apelează.
 Revenirea din ultimul apel este urmată de revenirile în
cascadă din apelurile precedente în ordinea inversă, ceea
ce conduce la rezultatul 3*2*1 = 6.
Exercitiu 2
Problema 2: Se cere determinarea celui de-al n-lea
termen din şirul lui Fibonacci.
Analiza problemei:
Se cunoaşte că:
primii doi termeni ai şirului sunt 0,1:
Fibonacci(0)=0
Fibonacci(1)=1
oricare termen este format prin însumarea celor doi
termeni precedenţi:
Fibonacci(k)=Fibonacci(k-1)+ Fibonacci(k-2)
Exercitiu 2- rezolvare
int Fibonacci(int k)
{
if (k<=1)
return k;
else
return Fibonacci(k-2) + Fibonacci(k-1); //două autoapeluri
}
Exercitiu 3
Problema 3. Determinarea celui mai mare divizor comun
a două numere a şi b. (prin funcţie recursivă)
Analiza problemei:
cmmdc(a,b) poate fi: a, dacă b = 0
cmmdc(b, a mod b), dacă b≠0

Obs: Prin a mod b se înţelege restul împărţirii întregi a


lui a la b
Exercitiu 3 - rezolvare
int cmmdc(int m, int n)
{
if(n==0)
return m;
return
cmmdc(n,m%n); //autoapel
}
Exercitiu 4
 Suma primelor n numere naturale
 S(n)=n+S(n-1)
Exercitiu 5
 Suma cifrelor unui numar natural n

int SUMA(int n)
{ if(n==0) //testarea conditiei de terminare a recursivitatii
return 0;
else
return (SUMA(n/10)+n%10);
//obs: n/10 – impartirea intreaga!!!
}
void main()
{ int n;
cin>>n;
SUMA(n);
}
Exercitiu 6 – recursivitate
(Divide et impera)
Maximul dintr-un vector (global) int main( )
int TAB[10],n;
{
int maxim(int st, int dr) cout<<”n=”;
{ cin>>n;
int a, b, m;
for (int i=1; i<=n; i++)
if (st==dr) return TAB[i];
else {
{ cout<<”TAB[“<<i<<”]=”;
median = (i+j)/2;
cin>>TAB[i];
max1 = maxim(st, median);
max2 = maxim(median+1, dr);
}
if (max1>max2) return max1; cout<<”max=”<<max(1,n);
else return max2; return 0;
}
}
}

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