Sunteți pe pagina 1din 30

Curs 6

Programarea Calculatoarelor si Limbaje de


Programare
- limbajul C -

Conf. Dr. Ioana FIRASTRAU


Sef lucr. Dr. Dana E. GHITA
Drd. Cristian MUSUROI

1
2
Definirea funcţiilor

 Pentru rezolvarea unor probleme complexe de calcul, acestea trebuie


descompuse în sub-probleme mai simple.

 Descompunerea fizică a codului în portiuni, ce realizează anumite sub-probleme


de calcul, se face cu ajutorul functiilor.

 Modulare program (fiecare modul se ocupă de anumite operatii).

 Pe lângă structurarea programului, functia 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ă.

3
 Ce înseamnă o functie ?

 Din punct de vedere matematic:

f:AB
corpul
valoarea functiei
returnata
f(x,y) f(x,y) = sin(x*y)

numele Argumentele/parametrii
functiei functiei
(f) (x si y)

Din punct de vedere al programării în C, functia îsi păstrează sensul matematic


(programare functională).
4
Definirea functiilor :

Forma generala:

tip_dată nume ( tip_arg1 arg1, ..., tip_angN argN )


{
secventa de instructiuni;
[return expresie;]
}

• nume reprezintă identificatorul functiei pe baza căruia aceasta va fi apelată pe


parcursul rulării programului.
• tip_dată reprezintă tipul datelor returnate de functie

ATENTIE: • o functie nu poate returna decât o singură valoare


• dacă functia nu returnează nici o valoare atunci se specifică tipul
void  procedură

5
tip_dată nume ( tip_arg1 arg1, ..., tip_angN argN )
{
secventa de instructiuni;
[return expresie;]
}

• arg1, ..., argN reprezintă variabilele de intrare, avand tipurile tip_arg1, …, tip_angN,
pe care le primeste functia din programul sau sub-programul în care este apelată.

ATENTIE : 1) Este posibil ca functia să nu primească date de intrare, caz în care lista
este vidă.
tip_data nume () sau se poate folosi tipul void tip_data nume(void)

2) Atât la definirea, cât si la apelul functiilor, parantezele () urmează


întotdeauna numele functiilor, chiar dacă acestea nu au parametri.

Observatie: o functie chiar dacă nu primeste variabile, aceasta poate interactiona


cu programul pe baza variabilelor globale din program (vizibile pentru orice functie)
 de evitat, deoarece functia nu mai este independentă de program,
portabilitatea într-un alt program fiind redusă

6
tip_dată nume ( tip_arg1 arg1, ..., tip_angN argN )
{
secventa de instructiuni;
[return expresie;]
}

• { secventa de instructiuni; }: corpul functiei (ceea ce se execută) este specificat


între “{” si “}”.
!Acesta poate fi văzut, el însusi ca un program.

• return expresie : comanda return este folosită pentru a returna valoarea dorită.

Efect : functia se încheie în momentul în care se execută comanda return,


iar expresia specificată este returnată ca dată de iesire a functiei.

Obsevatii: 1) dacă aceasta nu corespunde tipului specificat (tip_dată), se face


conversie la acesta, dacă nu este posibilă, atunci eroare.
2) folosirea functiei return este optională chiar dacă s-a specificat că
functia trebuie să returneze ceva (warning).
3) orice comanda situata dupa return este ignorata.

7
Exemplu de definire functie:
- am definit functia adunare care
int adunare(int a, int b) primeste două numere întregi si
{ returnează un număr întreg
int r;
r=a+b;
return r; - calculează suma în variabila r
} si returnează valoarea lui r.

Mai eficient:

int adunare(int a, int b)


{ - functia return poate primi o
return a+b; expresie si nu neapărat o singură
} variabilă.

8
Apelarea functiilor:
dupa ce a fost definita o functie poate sa fie apelata in main sau in alta functie.

#include <stdio.h> Observatie: Parametri formali/parametri efectivi

int adunare(int a, int b) Se foloseste denumirea de :


{ • parametri formali pentru identificatorii din lista
int r; de argumente din definitia functiei (a si b);
r=a+b; • parametri efectivi (constantele, variabilele,
return r; expresiile) din lista unui apel al functiei (valorile lui
} x si y)

int main( )
{ sau
int x, y, suma=0; int main( )
{
printf(“Dati doua valori care se aduna”); int x, y;
scanf(“%d %d”, &x, &y);
printf(“Dati doua valori care se aduna”);
suma= adunare(x, y); scanf(“%d %d”, &x, &y);

printf(“Suma este %d”, suma); printf(“Suma este %d”, adunare(x, y) );


} } 9
Exemplu de functie de tip void:

#include <stdio.h>

void salut(void) Buna ziua!


{
printf (“Buna ziua!\n”);
}

int main(){
salut(); Apelarea unei unei functii de tip void

}
Buna ziua!
int main(){
Buna ziua!
salut(); salut(); salut(); Buna ziua!

10
Unde se definesc functiile?
Formă generală program:
Varianta 1: Varianta 2:

#include <stdio.h> comenzi de #include <stdio.h>


preprocesare
int adunare(int a, int b) int adunare(int a, int b);
{ 1: functiile pot fi definite
return a+b; înaintea functiei main() int main()
} { …
adunare (2, 5);
programul
int main() }
principal (main)
{
… int adunare(int a, int b)
adunare (2,5); 2: functiile pot fi definite {
…. dupa functia main() return a+b;
} }
Functiile sunt scrise integral Functiile sunt anuntate înaintea functiei
main (prototip), acestea fiind descrise
integral după functia main.
Obsevatie: Nu este admisă definirea unei functii în blocul altei functii si nu sunt
premise salturi cu instructiunea goto în afara functiei. 11
Exemple de functii:
1) Sa se scrie un program care calculeaza aria unui cerc folosind o functie,
denumita arie.

#include <stdio.h>
#include <math.h>
#define PI 3.1415926535897932384626433832795 Varianta 1
float arie(float r)
{ Definitia unei functii:
float a; Am definit functia arie care calculează aria unui
a = PI*pow(r, 2); cerc cunoscand raza cercului si returnează această
valoare sub forma unui float.
return a;
}
int main( ){
float raza, a;
printf("Dati valoarea razei: ");
scanf("%f", &raza);
Apelul functiei:
a = arie(raza); Am apelat functia arie cu parametrul efectiv raza, a
carui valoare am citit-o de la tastatura.
printf("Aria este %f", a);
}
2) Sa se scrie un program care calculeaza aria unui dreptunghi folosind o functie,
denumita arie.

#include <stdio.h> Varianta 2


#include <math.h>
float arie(float L, float l ); Am anunƫat functia si am specificat prototipul
acesteia.
int main( )
{
float L, l, a;
printf("Dati valorile lungimii (L) si latimii (l) ale dreptunghiului");
scanf("%f%f", &L, &l);
a = arie(L, l); Am apelat functia in programul pricipal (main).
printf("Aria este %f", a);
}

float arie(float L, float l )


{
float a; Am definit functia si i-am detaliat corpul dupa programul
a = L*l; pricipal (main).
return a;
} 11
3
3) Sa se scrie o functie care calculeaza factorialul unui numar intreg.
#include <stdio.h>
Varianta 1

double factorial(int n)
{
int i; Definitia unei functii:
double fact=n; Am definit functia factorial care calculează
for (i=n-1; i>0; i--) factorialul unui număr întreg n si returnează
fact=fact*i; această valoare sub forma unui double.
return fact;
}

int main()
{ Apelarea unei functii:
printf(“20!=%lf”, factorial(20) ); Functiile se apelează în mod identic cu modul
} de apelare al functiilor disponibile în C.
Executia functiei factorial(20):
double f; - n=20
f= factorial(20); - se efectuează calculele
printf(“20!=%lf”, f); - factorial(20) devine valoarea specificată de
return.
14
Altă variantă:

#include <stdio.h> Varianta 2


#include <stdlib.h>

double factorial(int n); Am anunƫat functia si am specificat


prototipul acesteia.
int main()
{
printf(“20!=%lf”, factorial(20) ); Am apelat functia.
}

double factorial(int n)
{
Am definit functia, detaliind corpul acesteia după
int i; double fact=n;
programul principal.
for (i=n-1; i>0; i--)
fact=fact*i;
return fact;
}

15
Observatii: Variabile globale
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
int offset=3;
double factorial(int n)
{ float produs(float a, float b)
int i; {
double fact=n; return a*b+offset;
for (i=n-1; i>0; i--) }
fact=fact*i; int main()
return fact; {
} printf(“%d, %f”, offset, produs(5,6) );
int main() }
{
printf(“%d %lf”, i, factorial(20) ); -variabila offset este definită după comenzile
} de preprocesare, dar înaintea definirii functiilor
programului
eroare
Observatie: variabilele declarate în corpul unei Observatie: variabilele declarate în afara
functii sunt valabile doar în acesta, si doar pe programului principal main(), s.n. variabile
parcursul executiei functiei respective. globale, sunt vizibile peste tot în program: în
functia main(), în toate functiile, etc.

16
Observatii: Variabile globale
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
int offset=3;
double factorial(int n)
{ float produs(float a, float b)
int i; {
double fact=n; return a*b+offset;
for (i=n-1; i>0; i--) } 3, 33
fact=fact*i; int main()
return fact; {
} printf(“%d, %f”, offset, produs(5,6) );
int main() }
{
printf(“%d %lf”, i, factorial(20) ); -variabila offset este definită după comenzile
} de preprocesare, dar înaintea definirii functiilor
programului
eroare
Observatie: variabilele declarate în corpul unei Observatie: variabilele declarate în afara
functii sunt valabile doar în acesta, si doar pe programului principal main(), s.n. variabile
parcursul executiei functiei respective. globale, sunt vizibile peste tot în program: în
functia main(), în toate functiile, etc.

17
Vizibilitatea variabilelor în cadrul functiilor

#include <stdio.h>

float produs(float a, float b)


{
return a*b+offset; - variabila offset este definită
} după definirea functiei
produs, ce se întâmplă ???
int offset=3;

int main() eroare!


{
printf(“%d, %f”, offset, produs(5,6) );
} - variabila offset este vizibilă de
la definitie în jos.

Principiu: o declaratie de variabile sau de functii este vizibilă


pentru TOATE functiile ce sunt definite DUPA aceasta.

18
#include <stdio.h> ce valoare va returna functia produs ???

float produs(float a, float b) 3, 34.00


{
int offset=4;
return a*b+offset;
} -în functie, variabila offset este
definită local si are valoarea 4.
int offset=3;

int main()
-în main( ), variabila offset este
{
printf(“%d, %f”, offset, produs(5,6) ); cea definită global, cea din
functie neexistând decât în
}
interiorul fct. produs (executie).

19
#include <stdio.h>
ce valoare va returna functia produs???
int offset=3;
3, 10.00, 3
float produs(float a, float b)
{
int offset=4;
3, 2*3+4=10.00, 3
return a*b+offset;
} !!! cu toate că variabila offset,
este definită global si este
vizibilă si în functia produs,
int main() redefinirea ei local duce la
{ ignorarea variabilei globale.
printf(“%d, %f, %d”, offset, produs(2,3), offset );
}

20
Exemplu de utilizare a unei functii:
Sã se întocmeascã un program în care se definesc urmãtoarele funcţii:
- functie de afişare a divizorilor unui întreg;
- funcţie care returneazã c.m.m.d.c. a doi întregi preluaţi ca parametri;
- funcţie care returneazã c.m.m.m.c. a doi întregi preluaţi ca parametri.
În funcţia main se citesc doi întregi de la tastaturã pentru care se vor afişa
divizorii, c.m.m.d.c, c.m.m.m.c.

functie afisare divizori functie calcul c.m.m.d.c


#include <stdio.h> int cmmdc(int n1, int n2)
{
void af_div( int nr) int min, div=1, i;
{
int i; min = n1<n2?n1:n2; // minimul dintre valorile n1 si n2
for ( i=2; i<=nr/2; i++)
if ( nr%i==0 ) for ( i=2; i<=min/2; i++)
printf("%d ", i); {
} if ( !(n1%i) && !(n2%i) )
div = i;
}
return div;
if ( !(nr%i) ) }
21
functie calcul c.m.m.m.c
int cmmmc(int n1, int n2)
{
return n1*n2/cmmdc(n1, n2);
}

functie afisare optiuni


void meniu(void)
{
printf("\n\n-------------------------- MENIU ----------------------------\n\n");
printf("\n1. Afisarea divizorilor primului intreg introdus.");
printf("\n2. Afisarea divizorilor celui de al doilea intreg introdus.");
printf("\n3. Afisarea cmmdc pentru cei doi intregi introdusi.");
printf("\n4. Afisarea cmmmc pentru cei doi intregi.");
printf("\n5. Iesire din program.");
}

22
int main()
{
int nr1, nr2, optiune;

printf("nr1= ");
scanf("%d", &nr1);
printf("nr2= ");
scanf("%d", &nr2);

do
{ meniu();
printf("\n\nIntrodu optiunea: ");
scanf("%d", &optiune);

switch(optiune)
{
case 1: printf("\nDivizorii numarului %d sunt: ", nr1);
af_div(nr1);
break;
case 2: printf("\nDivizorii numarului %d sunt: ", nr2);
af_div(nr2);
break;
23
case 3: printf("\nCMMDC = %d ", cmmdc(nr1,nr2) );
break;
case 4: printf("\nCMMMC = %d ", cmmmc(nr1,nr2) );
break;
case 5: printf("\nSfarsit de program !\n");
break;
default: printf("\nOptiunea dumneavoastra este gresita !");
} //end switch
}
while ( optiune != 5 ); //sfarsit do while

return 0;

} //sfarsit main

Observatie: S-ar putea ca la introducerea valorilor pentru variabilele nr1 si nr2 (slide 23) sa
se aleaga valori irelevante (valori negative, 0 sau 1). Prin urmare, la citirea de la tastatura
se poate verifica daca ceea ce s-a introdus este corect sau nu. Daca valoarea introdusa nu
este corecta (este <=1), se solicita din nou introducerea unei valori. Acest lucru se poate
face astfel (slide 25):
24
int main() do
{ {
int nr1, nr2, optiune; printf("nr1= ");
scanf("%d", &nr1);
printf("nr1= "); }
se
scanf("%d", &nr1); while (nr1<=1); // verificam daca valoarea citita este >1
printf("nr2= "); inlocuieste
scanf("%d", &nr2); cu do
{
printf("nr2= ");
scanf("%d", &nr2);
}
while (nr2<=1); // verificam daca valoarea citita este >1
do
{ meniu();
printf("\n\nIntrodu optiunea: ");
scanf("%d", &optiune);

switch(optiune)
{
case 1: printf("\nDivizorii numarului %d sunt: ", nr1);
af_div(nr1);
break;
25
// continuarea programului ca inainte
Recursivitate

Recursivitatea unei functii în programare, reprezintă procesul prin care functia


se autoapelează.

Pentru ca procesul să nu se repete la infinit, autoapelarea se încheie de


regulă pe baza unei conditii de oprire.

Astfel, un obiect sau un fenomen se defineste în mod recursiv dacă în


definitia sa există o referire la el însusi.

1, daca n  0
n!  
 n   n  1 !

26
O functie recursivă trebuie să fie bine formată:

- o functie nu se poate defini doar în functie de sine însăsi,

exemplu: f(n) =2+f(n)  gresit, se execută la ∞

- o functe recursivă se poate folosi numai de notiuni deja definite


anterior

exemplu: f(n)=f(n+1)-2  gresit (valoare inexistentă f(n+1))

- orice sir de apeluri de functii recursive trebuie să se oprească (nu va


genera un calcul infinit).

exemplu: f(0)=1,
f(n)=f(n-1)+3,

f(3)=f(2)+3=f(1)+3+3=f(0)+3+3+3=1+3+3+3=10

27
În general distingem:

- un caz de bază: pentru care functia este definită direct,


de exemplu: f(0)=1

- un pas inductiv (recursivitatea propriu-zisă): functia este definită


folosind aceeasi functie, dar pe un caz mai simplu,
de exemplu: f(n+1)=f(n)*PI

În limbajul C crearea de functii recursive nu necesită o anumită sintaxă sau


folosirea unui anumit cuvânt cheie, aceasta reiese automat din modul de
definire al functiei.

- functia primeste valoarea n si returnează


int Factorial(int n)
valoarea calculată a factorialului.
{
if (n==0) - conditia de oprire a recursivitătii: dacă n a
return 1; ajuns la valoarea 0, se returnează 1 (0!)
else
return n*Factorial(n-1); - pasul inductiv: relatia de calcul recursiv
} ce depinde de valorile de rang inferior ale
functiei: Factorial(n-1), Factorial(n-2) …

28
#include <stdio.h>

int Factorial(int n); anuntarea fct Factorial

int main() {
int nr;

printf("nr= "); functia principala


scanf("%d", &nr);

printf(“Factorialul este %d”, Factorial(nr) );

} apelul fct Factorial

int Factorial(int n)
{
if (n==0)
return 1; descrierea complete a fucntiei
else
return n*Factorial(n-1);
}

29
TEMA

Elaborati si testati programele care sunt prezentate in acest curs.

30

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