Sunteți pe pagina 1din 7

Universitatea “Politehnica” din Bucureşti

Facultatea de Electronică, TelecomunicaŃii şi


Tehnologia InformaŃiei
Cuprins

7.1. FuncŃii
Programarea Calculatoarelor
7.2. Recursivitate
(limbajul C)

Curs 7 – FuncŃii şi Recursivitate

Ş.l. Bogdan IONESCU


Prof. Dragoş BURILEANU
Prof. Claudius DAN

2
2010-2011 Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 1/36

Definirea funcŃiilor

> Pentru rezolvarea unor probleme complexe de calcul,


acestea trebuie descompuse în sub-probleme mai simple.
 “divide et impera” ar spune romanii.
7.1. FuncŃii
> Descompunerea fizică a codului în porŃiuni, ce realizează
anumite sub-probleme de calcul, se face cu ajutorul funcŃiilor.
 modulare program (fiecare modul se ocupă de
anumite operaŃii).

> Pe lângă structurarea programului, funcŃia are avantajul de a


fi scrisă o singură dată, dar folosită de câte ori este nevoie,
evitând astfel rescrierea codului aferent de fiecare dată.

Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 2/36 Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 3/36

Subprograme – funcŃii (continuare) Definirea funcŃiilor (continuare)


> Ce înseamnă o funcŃie ? > Astfel, în limbajul C, funcŃiile îşi păstrează sensul
matematic:
> Din punct de vedere matematic:
corpul funcŃiei Formă generală:
valoarea (calculul realizat) <tip_dată> <nume>(<var1>,...,<varN>)
returnată {
f(x,y) = sin(x*y) <secvenŃă instrucŃiuni 1>;
<secvenŃă instrucŃiuni 2>;
...
numele argumente <secvenŃă instrucŃiuni M>;
funcŃiei funcŃie (variabile) [return <expresie>;]
} [ ] = opŃional

> Din punct de vedere al programării în C, funcŃia îşi • <tip_dată>: reprezintă tipul datelor returnate de funcŃie,
păstrează sensul matematic (programare funcŃională). AtenŃie: o funcŃie nu poate returna decât o singură valoare.
5 6
Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 4/36 Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 5/36
Definirea funcŃiilor <tip_dată> <nume>(<var1>,...,<varN>) Definirea funcŃiilor <tip_dată> <nume>(<var1>,...,<varN>)
{ {
(continuare) <secvenŃă instrucŃiuni 1>; (continuare) <secvenŃă instrucŃiuni 1>;
<secvenŃă instrucŃiuni 2>; <secvenŃă instrucŃiuni 2>;
• <tip_dată>: dacă funcŃia > ObservaŃie: o funcŃie chiar
... ...
nu returnează nici o valoare <secvenŃă instrucŃiuni M>; dacă nu primeşte variabile, <secvenŃă instrucŃiuni M>;
atunci se specifică tipul [return <expresie>;] aceasta poate interacŃiona [return <expresie>;]
} }
void  procedură. cu programul pe baza
• <nume>: reprezintă identificatorul funcŃiei pe baza căruia variabilelor globale din program (vizibile pentru orice funcŃie)
aceasta va fi apelată pe parcursul rulării programului.  de evitat, deoarece funcŃia nu mai este independentă
• (var1,...,varN): reprezintă variabilele de intrare, pe care le de program, portabilitatea într-un alt program fiind redusă.
primeşte funcŃia din programul, sau sub-programul în care este
apelată. Este posibil ca funcŃia să nu primească date de intrare, • { secvenŃe instrucŃiuni }: corpul funcŃiei (ceea ce se execută)
caz în care lista este vidă: <nume>(), sau se poate folosi este specificat între “{” şi “}”. Acesta poate fi văzut, el însuşi ca
tipul void: <nume>(void). un program.
7
Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 6/36 Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 7/36

Definirea funcŃiilor <tip_dată> <nume>(<var1>,...,<varN>) Definirea funcŃiilor (continuare)


{
(continuare) <secvenŃă instrucŃiuni 1>; Exemplu de funcŃie:
• return <expresie>: <secvenŃă instrucŃiuni 2>; int adunare((int a, int b) -am definit funcŃia adunare care
... primeşte două numere întregi şi
funcŃia return este folosită <secvenŃă instrucŃiuni M>;
{
int r; returnează un număr întreg,
pentru a returna valoarea [return <expresie>;]
} r=a+b;
dorită. -calculează suma în variabila r
return r;
şi returnează valoarea lui r.
> Efect: funcŃia se încheie în momentul în care se execută }
comanda return, iar <expresia> specificată este returnată ca
> Cum se poate rescrie funcŃia mai eficient ???
dată de ieşire a funcŃiei.
 dacă aceasta nu corespunde tipului specificat (<tip_dată>), Optimizare:
conversie la acesta, dacă nu este posibilă, atunci eroare. int adunare((int a, int b)
{ -funcŃia return poate primi o
> ObservaŃie: folosirea funcŃiei return este opŃională chiar dacă return a+b; expresie şi nu neapărat o singură
s-a specificat că funcŃia trebuie să returneze ceva (warning). } variabilă.
9 10
Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 8/36 Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 9/36

Definirea funcŃiilor (continuare) Definirea funcŃiilor (continuare)


> Unde se definesc funcŃiile. > Unde se definesc funcŃiile (continuare).
Formă generală program: Formă generală program:
comenzi de comenzi de
#include<stdio.h> preprocesare #include<stdio.h> preprocesare
... ...
Varianta 1: funcŃiile pot fi definite int adunare((int a, int b);
b)
int adunare((int a, int b)
{ înaintea funcŃiei main, acestea int main()
{ programul
return a+b; fiind scrise integral.
} … principal (main)
}
int main() int adunare((int a, int b) Varianta 2: funcŃiile pot fi
{ programul { anunŃate înaintea funcŃiei main,
… principal (main) return a+b; (prototip), acestea fiind descrise
} }
integral după funcŃia main.
11 12
Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 10/36 Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 11/36
Definirea funcŃiilor (continuare) Definirea funcŃiilor (continuare)
> Unde se definesc funcŃiile (continuare). > Unde se definesc funcŃiile (continuare).
Exemplu: -am definit funcŃia factorial care Altă variantă: -am anunŃat funcŃia şi am
calculează factorialul unui număr #include<stdio.h> specificat prototipul acesteia.
#include<stdio.h>
întreg n şi returnează această #include<stdlib.h>
#include<stdlib.h>
valoare sub forma unui double ? double factorial(int n); -corpul funcŃiei este detaliat după
double factorial(int n)
int main()
{ programul principal.
int i; double fact=n;
-funcŃiile se apelează în mod {
identic cu modul de apelare al printf(“20!=%lf”, factorial(20) );
for (i=n-1; i>0; i--)
}
fact=fact*i; funcŃiilor disponibile în C. -în cazul în care funcŃiile nu sunt
return fact; double factorial(int n)
{
evidente (complexe), iar
} factorial(20)  int i; double fact=n; conceperea lor necesită un timp
int main() -n=20, for (i=n-1; i>0; i--) semnificativ, putem scrie mai
{
-se efectuează calculele, fact=fact*i; întâi programul principal, ca şi
printf(“20!=%lf”, factorial(20) );
-factorial(20) devine val. return fact; cum funcŃiile există deja.
}
specificată de return. }

13 14
Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 12/36 Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 13/36

Definirea funcŃiilor (continuare) Definirea funcŃiilor (continuare)


> Vizibilitatea variabilelor în cadrul funcŃiilor > Vizibilitatea variabilelor în cadrul funcŃiilor
• variabilele declarate în corpul unei funcŃii sunt valabile doar • variabilele declarate în afara programului principal main(),
în acesta, şi doar pe parcursul execuŃiei funcŃiei respective. în secŃiunea de variabile globale, sunt vizibile peste tot în
program: în funcŃia main(), în toate funcŃiile definite, etc.
Exemplu: -variabila i este o variabilă locală
double factorial(int n) a funcŃiei factorial ce va fi Exemplu: -variabila offset este definită
{ alocată în memorie doar când #include<stdio.h> după comenzile de preprocesare,
int i; double fact=n; funcŃia este apelată. int offset=3;
for (i=n-1; i>0; i--)
dar înaintea definirii funcŃiilor
float produs(float a, float b) programului,
fact=fact*i;
- variabila i şi fact nu există în {
return fact;
} cadrul celorlalte funcŃii, inclusiv
return a*b+offset; -aceasta este astfel vizibilă atât
} în procedura produs cât şi în
int main() main(). int main()
{ main.
{
printf(“%d, %lf”, i, factorial(20) );
eroare! printf(“%d, %f”, offset, produs(5,6) ); >3, 5*6+3=33
}
}
15 16
Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 14/36 Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 15/36

Definirea funcŃiilor (continuare) Definirea funcŃiilor (continuare)


> Vizibilitatea variabilelor în cadrul funcŃiilor > Vizibilitatea variabilelor în cadrul funcŃiilor
Exemplu: -ce valoare va returna funcŃia
-variabila offset este definită Exemplu: produs ???
#include<stdio.h>
float produs(float a, float b)
după definirea procedurii
produs, ce se întâmplă ??? #include<stdio.h> >3, 30+4=34.00
{ float produs(float a, float b)
return a*b+offset; -în funcŃie, variabila offset este
eroare! {
}
int offset=3;
int offset
offset=4; definită local şi are valoarea 4.
variabila offset este vizibilă de offset
return a*b+offset;
int main() aici în jos. } -în main(), variabila offset este
{ int offset
offset=3; cea definită global, cea din
printf(“%d, %f”, offset, produs(5,6) ); funcŃie neexistând decât în
} int main() interiorul fcŃ. produs (execuŃie).
{
> Principiu: o declaraŃie de variabile sau de funcŃii este vizibilă printf(“%d, %f”, offset,
offset produs(5,6) );
pentru toate funcŃiile ce sunt definite după aceasta. }

17 18
Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 16/36 Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 17/36
Definirea funcŃiilor (continuare) Definirea funcŃiilor (continuare)
> Vizibilitatea variabilelor în cadrul funcŃiilor
EnunŃ: să se realizeze o funcŃie care permite
Exemplu: -ce valoare va returna funcŃia P afişarea pe ecran a unei matrice pătratice de numere
produs ???
#include<stdio.h> întregi. Matricea se va afişa pe linii şi coloane.
>3, 2*3+4=10.00, 3
int offset=3;
offset
program principal
float produs(float a, float b) main()
-cu toate că variabila offset Variabile de intrare/lucru:
{
int offset=4;
offset este definită global şi este int M[100][100]; definiŃie funcŃie
offset
return a*b+offset; vizibilă şi în funcŃia produs, int dim; AfisareM()
} redefinirea ei local, duce la int i, j;
int main() ignorarea variabilei globale . void AfisareM(int dim, int M[100][100]);
{
offset produs(2,3), offset );
printf(“%d, %f, %d”, offset, Variabile de ieşire:
} nu

19 20
Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 18/36 Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 19/36

Definirea funcŃiilor (continuare) Definirea funcŃiilor (continuare)

#include<stdio.h> int main()


#include<stdlib.h> {
/* procedura este definita inaintea funcŃiei main */
int M[100][100], i, j, dim;
void AfisareM(int dim, int M[100][100])
{ printf("dim="); scanf("%d",&dim);
int i,j; for (i=0; i<dim; i++)
printf("\n"); for (j=0; j<dim; j++)
for (i=0; i<dim; i++) // parcurgere linii { -în felul acesta funcŃia
{ printf("M[%d][%d]=",i,j); AfisareM poate fi folosită ori
for (j=0; j<dim; j++) // parcurgere elemente de pe scanf("%d",&M[i][j]); de câte ori avem nevoie să
printf("%8d",M[i][j]); // coloane } afişăm pe ecran o matrice
printf("\n"); pătratică.
} AfisareM(dim, M);
} }

21 22
Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 20/36 Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 21/36

FuncŃii recursive
> Recursivitatea unei funcŃii în programare, reprezintă
procesul prin care funcŃia se autoapelează.
> Pentru ca procesul să nu se repete la infinit, autoapelarea
7.2. Recursivitate se încheie de regulă pe baza unei condiŃii de oprire.
Efectul Droste: Sierpinski triangle:
etc.

23 24
Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 22/36 Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 23/36
FuncŃii recursive (continuare) FuncŃii recursive (continuare)
> Astfel, un obiect sau un fenomen se defineşte în mod > O funcŃie recursivă trebuie să fie bine formată:
recursiv dacă în definiŃia sa există o referire la el însuşi. - o funcŃie nu se poate defini doar în funcŃie de sine
Exemple: însăşi,
definirea numerelor întregi: definirea funcŃiei factorial: exemplu: f(n) =2+f(n)  greşit, se execută la ∞

0∈N  1 dacă n = 0 - o funcŃie recursivă se poate folosi numai de noŃiuni deja


n!= 
dacă i∈N atunci i+1∈N n ⋅ (n − 1)! dacă n > 0 definite anterior,
exemplu: f(n)=f(n+1)-2  greşit (valoare inexistentă f(n+1)),
definirea şirului Fibonacci:
0, 1, 1, 2, 3, 5, 8, 13, 21, ... - orice şir de apeluri de funcŃii recursive trebuie să se
 0 dacă n = 0 oprească (nu va genera un calcul infinit).

fib(n) =  1 dacă n = 1 exemplu: f(0)=1, f(n)=f(n-1)+3, 
 fib(n − 1) + fib(n − 2) dacă n > 1 f(3)=f(2)+3=f(1)+3+3=f(0)+3+3+3=1+3+3+3=10

25 26
Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 24/36 Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 25/36

FuncŃii recursive (continuare)


FuncŃii recursive (continuare)
> În general distingem:
Exemplu: funcŃia factorial
- funcŃia primeşte valoarea n şi
- un caz de bază: pentru care funcŃia este definită direct, int Factorial(int n) returnează valoarea calculată a
de exemplu: f(0)=1 { factorialului.
if (n==0) - condiŃia de oprire a recursivităŃii:
- un pas inductiv (recursivitatea propriu-zisă): funcŃia return 1; dacă n a ajuns la valoarea 0, se
este definită folosind aceeaşi funcŃie, dar pe un caz mai else returnează 1 (0!)
simplu, de exemplu: f(n+1)=f(n)*PI return n*Factorial(n-1);
} - pasul inductiv: relaŃia de calcul
> În limbajul C crearea de funcŃii recursive nu necesită o recursiv ce depinde de valorile
de rang inferior ale funcŃiei:
anumită sintaxă sau folosirea unui anumit cuvânt cheie,
Factorial(n-1), Factorial(n-2) …
aceasta reiese automat din modul de definire al funcŃiei.

27
Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 26/36 Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 27/36

FuncŃii recursive (continuare) int Factorial(int n) FuncŃii recursive (continuare)


{
Modul de execuŃie if (n==0) Exemplu: o funcŃie recursivă care numără de la a la b în sens
return 1; crescător, şi invers.
int main() else - funcŃia primeşte valoarea a şi
{ return n*Factorial(n-1); respectiv b şi nu returnează nimic
printf(“%d”, Factorial(2) ); } void printnum(int a, int b) (rezultatul este afişat pe ecran)
} {
printf("%d ",a);
- se afişează valoarea lui a şi apoi
Factorial(2) Factorial(1) Factorial(0) if (a<b)
se apelează recursiv funcŃia pentru a
printnum(a+1,b);
n=2 n=1 n=0 afişa în ordine crescătoare valorile.
2==0 Fals 1==0 Fals 0==0 Adevărat printf("%d ",a);
return 2*Factorial(2-1) return 1*Factorial(1-1) return 1 } - profită de închiderea în sens
invers a procedurilor lansate
iteraŃia 1 iteraŃia 2 iteraŃia 3
pentru diverse valori ale lui a
> FuncŃia returnează valoarea: 2 * 1 * 1 pentru afişarea în ordine inversă.
30
Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 28/36 Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 29/36
FuncŃii recursive (continuare) void printnum(int a, int b) FuncŃii recursive (continuare)
{
Se dă o imagine binară (valori 0 şi 1) sub forma unei
Mod de execuŃie: printf("%d ",a); P
if (a<b) matrice bidimensionale. În aceasta, obiectele sunt
int main()
printnum(a+1,b); reprezentate cu valori de 1, iar fundalul cu valori de 0.
{
printf("%d ",a); Să se realizeze o funcŃie recursivă care permite calculul
printnum(2,4); }
} suprafeŃei unui obiect (metoda “flood fill”).

Exemplu: 0 0 0 1 obiect de suprafaŃă 1


printnum(2,4) printnum(3,4) printnum(4,4)
suprafaŃă ~ număr valori de 1
printf("%d ",2); printf("%d ",3); printf("%d ",4);
0 1 0 0 obiect = mulŃime de valori
if (2<4) if (3<4) if (4<4) Fals
printf("%d ",2); printf("%d ",3); printf("%d ",4);
1 1 1 0 de 1 vecine (conexe).

iteraŃia 1 iteraŃia 2 iteraŃia 3 0 0 1 1


31 32
Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 30/36 Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 31/36

FuncŃii recursive (continuare) FuncŃii recursive (continuare)


0 1
Problemă obiecte (continuare) Problemă obiecte (continuare)
Strategie: “flood fill”
> Pentru a determina care valori de 1 sunt vecine, şi astfel
aparŃin obiectului curent, se va folosi conectivitatea cu 4 vecini: int matrice[20][20];
int dim;
int suprafata; (var.globală)
4 connectivity câte obiecte sunt
1 0 0 1 în imagine ?
V
0 1 0 0 void SuprafataObiect(int matrice[20][20], int dim, int x, int y)
V V V
V
1 1 1 0 nu returnează primeşte matricea primeşte dim (x,y) indică
nimic,suprafaŃa pentru a verifica pentru a nu ieşi poziŃia curentă
0 0 1 1 este stocată valorile din matrice la analizată din
global calcul matrice

33 34
Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 32/36 Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 33/36

FuncŃii recursive (continuare) FuncŃii recursive (continuare)


Problemă obiecte (continuare) int Suprafata;
Problemă obiecte (continuare) …
void SuprafataObiect(int matrice[20][20], int dim, int x, int y) int main()
{
Mod de execuŃie:
condiŃie de oprire: {
if ((matrice[x][y]==0) || (matrice[x][y]==-1)) return;
(x,y) fundal sau 0 0 0 0 int dim, matrice[20][20];
suprafata++; matrice[x][y]=-1; …
if (x+1<dim) (x,y) a fost deja 0 1 0 0 Suprafata=0;
if (matrice[x+1][y]==1) luat în calcul (-1) SuprafataObiect(matrice, dim, 1,1);
SuprafataObiect(matrice, dim, x+1,y); 1 1 1 0 }
if (y+1<dim) (x,y) este luat în
if (matrice[x][y+1]==1) calcul la suprafaŃă 0 0 1 0
SuprafataObiect(matrice, dim, x,y+1); şi apoi marcat,
if (x-1>=0) x=1, y=1 x=2, y=1 x=2, y=2 x=3, y=2 x=2, y=0
if (matrice[x-1][y]==1) vecin Sud Suprafata=1 Suprafata=2 Suprafata=3 Suprafata=4 Suprafata=5
SuprafataObiect(matrice, dim, x-1,y); lansare Sud lansare Sud lansare Sud lansare Sud lansare Sud
if (y-1>=0) vecin Est lansare Est lansare Est lansare Est lansare Est lansare Est
if (matrice[x][y-1]==1) lansare Nord lansare Nord lansare Nord lansare Nord lansare Nord
vecin Nord lansare Vest lansare Vest lansare Vest lansare Vest lansare Vest
SuprafataObiect(matrice, dim, x,y-1);
} vecin Vest
35 36
Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 34/36 Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 35/36
Sfârşitul Cursului 7

37
Curs Programarea Calculatoarelor, Ş.l. Bogdan IONESCU, 2010-2011 36/36

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