Sunteți pe pagina 1din 12

SUBPROGRAME

PREZENTARE TEORETICĂ

1. INTRODUCERE
Subprogramele sunt părţi ale unui program, identificabile prin nume, care se pot
activa la cerere prin intermediul acestor nume. Prezenţa subprogramelor implică
funcţionarea în strânsă legătură a două noţiuni: definiţia unui subprogram şi apelul
unui subprogram. Definiţia unui subprogram reprezintă de fapt descrierea unui
proces de calcul cu ajutorul variabilelor virtuale (parametri formali) iar apelul unui
subprogram nu este altceva decât execuţia procesului de calcul pentru cazuri
concrete (cu ajutorul parametrilor reali, (efectivi, actuali) ).

Structura unui subprogram C++


Un subprogram (funcţie) are o definiţie şi atâtea apeluri câte sunt necesare.

Definiţia unei funcţii are forma generală:

tip_returnat nume_funcţie (lista parametrilor formali)


{
instrucţiune; // corpul funcţiei
}
Reprezintă tipul rezultatului calculat şi returnat de funcţie
şi poate fi: int, char, char*, long, float, void, etc.

În cazul în care tipul rezultatului este diferit de void, corpul


Tip_returnat funcţiei trebuie să conţină cel puţin o instrucţiune return.

Înstrucţiunea return va specifica valoarea calculată şi


returnată de funcţie care trebuie să fie de acelaşi tip ca şi
tip_returnat.

Reprezintă numele dat funcţiei de către cel ce o defineşte,


Nume_funcţie pentru a o putea apela.
Reprezintă o listă de declaraţii de variabile separate prin
Lista_parametrilor_for
virgulă. Această listă poate să fie şi vidă.
mali

Este o instrucţiune vidă, simplă sau compusă.


Instrucţiune

APELUL UNEI FUNCŢII . REVENIREA DINTR-O FUNCŢIE


Apelul unei funcţii care întorc valori prin intermediul parametrilor are forma generală:

nume_funcţie (lista parametrilor efectivi);

unde:

● parametru efectiv = parametru actual = parametru real = parametru de apel


● lista parametrilor efectivi = poate fi vidă, poate fi o expresie sau mai multe despărţite
prin virgulă

Efectul instructiunii de apel este:

● crearea tabelei de parametrii actuali;


● crearea variabilelor locale funcției;
● executarea corpului de instrucțiuni al functiei;
● desființarea tabelei de parametrii și a variabilelor locale;
● revenirea la instrucțiunea următoare din program

O funcţie care returnează o valoare poate fi apelată fie printr-o instrucţiune de apel simplă
(cazul funcţiilor care nu returnează valori) şi în plus poate fi apelată ca operand al unei
expresii. În cazul în care funcţia se apelează printr-o instrucţiune de apel simplă, rezultatul
funcţiei se pierde.

Când funcţia se apelează ca operand, valoarea returnată va fi utilizată în expresie.


La apelul unei funcţii, valorile parametrilor efectivi se atribuie parametrilor formali
corespunzători. În cazul în care unul din tipul unui parametru efectiv diferă de tipul
parametrului formal corespunzător, parametrul efectiv va fi convertit spre parametru formal
(dacă este posibil, altfel compilatorul generează eroare).
În momentul în care se întâlneşte un apel de funcţie, controlul execuţiei programul este
transferat primei instrucţiuni din funcţie, urmând a se executa secvenţial instrucţiunile
funcţiei.
Revenirea dintr-o funcţie se face în unul din următoarele cazuri:

● după execuţia ultimei instrucţiuni din corpul funcţiei


● la întâlnirea unei instrucţiuni return

Instrucţiunea return are formatele:

● return ;
● return expresie ;

Exemplul 3.1 Exemplul 3.2

#include<iostream> #include<iostream>
using namespace std; using namespace std;
void f1 (int k)
void f1 () {
{ for (int i=1; i<=k ; i++)
cout << "abc"; cout << "abc"<< " ";
} }
int main () int main ()
{ {
f1(); f1(5);
} }

Se va afisa:abc Se va afişa:abc abc abc abc abc

Funcţia nu returnează o valoare


Funcţia nu returnează o
Funcţia are un parametru formal de tip int
valoare
Apelul funcţiei este o instrucţiune de apel simplă şi
Funcția nu are parametri
se face cu ajutorul unui parametru actual care este
Apelul funcţiei este o
de acelaşi tip cu tipul parametrului formal
instrucţiune de apel simplă
corespunzător

Exemplul 3.3 Exemplul 3.4


#include<iostream>
using namespace std;
int prim (int x)
{ #include<iostream>
int nrdiv; using namespace std;
nrdiv=0; int prim (int x)
for (int i=2; i<=x/2; i++) {int i;
if (x%i==0) for ( i=2; i<=x/2; i++)
nrdiv++; if (x%i==0)
if (nrdiv==0) return 0;
return 1; return 1;
else }
return 0; int main ()
} {int N;
int main () cout << "N="; cin >> N;
{ if (prim(N))
int N; cout << "PRIM";
cout << "N="; cin >> N; else
if (prim(N)) cout << "NU E PRIM";
cout << "PRIM"; }
else
cout << "NU E PRIM";
}

În cazul în care se întâlneşte un divizor a lui x se


execută instrucţiunea return 0. Astfel apelul
Funcţia returnează o valoare de tip
funcţiei se încheie.
int Funcţia are un parametru formal
Dacă x este număr prim, instrucţiunea return 0 nu
de tip int Rezultatul funcţiei este este
se execută niciodată şi în acest caz, după
utilizat în cadrul unei expresii.
terminarea execuţiei instrucţiunii for, se execută
instrucţiunea return 1 (care determină încheierea
execuţiei funcţiei).

OBS: În cazul în care tipul returnat de funcţie lipseşte din definiţia funcţiei, acesta este
implicit int şi nu void.

Exemplul 3.5 Exemplul 3.6 Exemplul 3.7


#include<iostream>
#include #include
using namespace std;
using namespace std; using namespace std;
p( ) void p( )
p( )
{ {
{
return 25; cout << "void";
cout << " abcd";
} }
}
int main () int main ()
int main ()
{ {
{
cout << p( ); cout << p();
cout << p();
} }
}

Compilatorul generează
eroare deoarece o
funcție cu tipul returnat
Compilatorul generează Compilatorul generează
void
eroare deoarece lipsește eroare deoarece lipsește
nu se poate apela în
tipul returnat de funcție tipul returnat de funcție
cadrul unei funcții, în
cazul de fata cout

#include #include
using namespace std; using namespace std;
int p( ) void p( )
{ {
return 25; cout << "abcd";
} }
int main () int main ()
{ {
cout << p( ); p();
} }

Se afişează 25 Se afişează abcd

PROTOTIPUL UNEI FUNCŢII


Pentru a apela o funcţie, aceasta trebuie inițial definită. Astfel apelul unei funcţii trebuie
precedat de definiţia funcţiei respective.
O a doua posibilitate de apelare a funcţiei constă în scrierea prototipului funcţiei înainte ca
acesta să fie apelată.
Prototipul funcţiei conţine informaţii asemănătoare cu cele din antetul funcţiei. Pot lipsi
numele parametrilor formali (contează doar tipul şi ordinea acestora), în plus acesta este
urmat de “;”.
Exemplul 4.1.
# include
using namespace std;

int max (int, int);


PROTOTIPUL FUNCȚIEI
int main ()
{
APELUL FUNCŢIEI
cout << max(10, 20);
}
DEFINIŢIA FUNCŢIEI
antetul funcţiei
int max (int a, int b)
{
corpul functiei
if (a>b)
return a;
else
return b;
}

Variabile locale şi variabile globale

Funcţia main
În C++ funcţia main determină prima instrucţiune pe care o va executa programul. Aceasta
este unica diferenţă dintre main şi celelalte funcţii. Din acest motiv se poate spune că “orice
se poate face în main se poate face şi în celelalte funcţii”.

Variabile locale
La fel cum se declară variabilele în cadrul funcţiei main, la fel se pot declara variabile si în
cadrul celorlalte funcţii. Aceste variabile se numesc locale şi sunt accesibile doar în funcţia în
care au fost declarate.
In cadrul unei funcţii se pot apela şi alte funcţii, cu condiția ca acestea sa fi fost definite
înaintea eventualului apel sau este prezent un prototip de funcţie înaintea funcţiei apelate

Variabile globale
Variabilele globale sunt declarate în afara oricărei funcţii şi sunt vizibile (pot fi utilizate) în
tot programul (în programul principal şi în subprograme) din momentul declarării lor.

Exemplul 5.2 Exemplul 5.3


Exemplul 5.1
1. include
1. include

using namespace std; 1. include


using namespace std;
int N;
int N;
void f1() using namespace std;
void f1()
{ int N;
{
int x=5; void f1(int p)
int x=5;
N=10; {
cout << endl << x;
cout << endl< int x=p;
P=2;
cout << endl << x; cout << x;
}
} }
int P=9;
int main () int main ()
int main ()
{ {
{f1();
N=4; f1(77);
cout << x;
cout << N; }
P=7;
f1();
}
}

N este variabilă globală si


Se afişează 77
poate fi accesată în cadrul Compilatorul generează eroare
oricărei funcţii. deoarece
N este variabilă globală.
Poate fi accesată în
x este variabilă locală, ● funcţia main încearcă să
acceseze variabila locala x cadrul oricărei funcţii.
vizibilă doar în cadrul
care este vizibilă doar în x este variabilă locală.
funcţiei f1()
funcţia f1(). Poate fi accesată doar în
● variabila P este accesată cadrul funcţiei f1()
Se va afişa: în f1() înainte de a fi p este parametru formal.
4 declarată. Poate fi accesat doar în
10
f1().
5

Regula de omonimie
În cazul în care există o variabilă locală care are acelaşi nume cu o variabilă globală,
aceste două variabile se numesc variabile omonime.
Variabilele locale sunt prioritare (ascund) variabilele globale omonime.

Exemplul 5.4
# include
<iostream>

using namespace
std;
int N=10; Variabila N este definită atât ca variabilă globală cât şi ca
void f1() variabilă locală în f1().
{ Se va afisa: 2 10
int N=2; Funcţia f1() acţionează asupra variabilei locale N.
cout << N<<" "; Funcţia main() acţionează supra variabilei globale N.
}
int main ()
{
f1();
cout << N;
}

Întrebare. Cum gestionează compilatorul cele două variabile omonime ?


Răspuns:
Variabilelor globale li se rezervă spaţiu de memorie la începutul execuţiei programului, într-o
zonă de memorie numită “zonă de date”. Acest spaţiu va fi ocupat până la încheierea
execuţiei programului.

Variabilelor locale li se rezervă spaţiu într-o zonă specială de memorie numită “stiva”. La
încheierea execuţiei subprogramului, conţinutul stivei este eliberat. Din acest motiv,
variabilele locale sunt vizibile doar în interiorul subprogramului în care au fost declarate.

Parametrii formali şi parametrii actuali


Parametrii formali apar în antetul subprogramului şi sunt utilizaţi de subprogram pentru
descrierea abstractă a unui proces de calcul .
Parametrii actuali apar în instrucţiunea de apelare a unui subprogram şi sunt folosiţi la
execuţia unui proces de calcul pentru valori concrete.
Parametrii formali nu sunt variabile. O variabilă este caracterizată de nume, tip, şi adresă.
Legarea unui parametru formal la o adresă se realizează în timpul execuţiei instrucţiunii de
apelare a subprogramului.

Apel prin valoare şi apel prin referinţă


Există două tipuri de apel al subprogramelor:

● Apel prin valoare


● Apel prin referinţă
Apel prin valoare – se transmite o copie a parametrului actual.
Valorile transmise la apelul unui subprogram sunt memorate în stivă. Datorită faptului că,
după terminarea execuţiei unui subprogram, stiva este eliberată, în cazul apelului prin valoare
parametrul actual nu se modifică (se operează asupra unei copii a parametrului efectiv)
Parametrii transmiși prin valoare se pot modifica în corpul funcției dar după
terminarea apelului funcției au aceasi valoare pe care au avut-o înainte de apel.
Se utilizează atunci când dorim ca subprogramul să lucreze cu acea valoare, dar să nu poată
modifica parametrul efectiv corespunzător din blocul apelator.

Se pot transmite prin valoare:


a)Valorile reţinute de variabile. În acest caz parametrii efectivi trebuie să fie numele
variabilelor.

Exemplu:
#include
void test(int n) {
n++;
cout << n << endl; // tipăreşte n=8
}
void main() {
int n = 7;
test(n);
cout << n << endl; // tipăreşte n=7
}

Parametrul n este transmis prin valoare. În funcţia main() acest parametru este
iniţializat cu valoarea 7. Când apelăm funcţia test(), se rezervă spaţiu pe stivă, spaţiu
care are numele parametrului formal (în acest caz, tot n) şi care este iniţializat cu
valoarea memorată de variabila n a programului principal. Altfel spus, pe stivă se
copie valoarea parametrului efectiv de apel. În funcţie, variabila n (care este locală
acestei funcţii) este incrementată şi devine 8, valoare care va fi tipărită. La ieşirea
din funcţie, variabila n din stivă se pierde, adică nu mai are spaţiu alocat, prin urmare
valoarea 8 este pierdută. În main() se tipăreşte valoarea variabilei n (locală acesteia)
care are valoarea 7.
Se observă că, în momentul apelului funcţiei test(), pe stivă sunt alocate două
variabile cu acelaşi nume n. Prima variabilă este variabila locală funcţiei main() care
se salvează pe stivă în momentul apelului pentru a putea reface contextul funcţiei
main() după încheierea apelului. A doua variabilă este parametrul formal tip valoare
n, vizibil numai în funcţia test() şi iniţializat în momentul apelului cu valoarea 7.
Indiferent ce valori primeşte acest n în corpul funcţiei test(), după încheierea
execuţiei acestei funcţii, spaţiul său este de alocat din stivă, adică variabila
respectivă este distrusă. Din acest motiv, după execuţia funcţiei test(), conţinutul
stivei este cel din dreapta. Se reface contextul din care s-a lansat apelul funcţiei
test(), adică se recuperează din stivă valoarea variabilei locale n=7 şi adresa de
revenire, adică adresa instrucţiunii cout.
b)Expresii. În acest caz, parametrii efectivi sunt expresii, care pot conţine şi funcţii şi
care mai întâi se evaluează. Exemplu:

#include
#include

void test(int n) {
cout << n << endl;
}

void main() {
test(5); // se va tipări 5
test(7 + (int)sqrt(45)); // se va tipări 13
}

În funcţie se creează o variabilă numită n, reţinută pe stivă, care la primul apel va


primi valoarea 5 şi la al doilea apel valoarea 13.

La ieşirea din funcţie conţinutul acestei variabile se pierde.

Transmiterea parametrilor prin valoare

se utilizează când nu dorim ca subprogramul apelat să poată modifica parametrii


efectivi de apel. Acesta este modul implicit de transmitere a parametrilor în limbajul
C. Dacă nu ar exista decât transmiterea prin valoare, ar fi imposibil să modificăm
valoarea anumitor valori care sunt declarate în blocul apelator.

Apel prin referinţă - se transmite adresa parametrului actual.

În cazul apelului prin referinţă, subprogramul, cunoscând adresa parametrului actual,


acţionează direct asupra locaţiei de memorie indicată de aceasta, modificând valoarea
parametrului actual.
Parametrii transmisi prin referinta se folosesc pentru transmiterea de rezultate in
afara functiei. Ei se pot modifica in corpul functiei dar dupa terminarea apelului
functiei au valoarea pe care au primit-o in timpul apelului functiei.
În C++, implicit, apelul se face prin valoare. Pentru a specifica un apel prin referinţă,
în lista parametrilor formali, numele parametrului formal va trebui precedat de
simbolul &
#include
#include
using namespace #include
using namespace
std; using namespace std;
std;
int a,b; int a,b;
int a,b;
void afis(int &a, int void afis(int &m, int n)
void afis(int a, int b)
&b) {
{
{ m=m+1;
a=a+1;
a=a+1; n=n+4;
b=b+4;
b=b+4; cout< }
cout< }
cout< }
int main()
int main()
int main() {
{
{ a=1;
a=1;
a=1; b=2;
b=2;
b=2; cout < afis(a,b);
afis(a,b);
afis(a,b); cout < }
cout < }
cout < }

Se va afisa:
1 2 (rezultatul inaintea
apelului functiei afis)
2 6 (rezultatul apelului functiei
afis)
Se va afisa: Se va afisa: 2 2 (rezultatul de dupa apelul
2 6 (rezultatul 2 6 (rezultatul functiei afis: variabila a isi
apelului functiei afis) apelului functiei afis) pastreaza
1 2 (rezultatul de 2 6 (rezultatul de valoarea dupa apel fiind
dupa apelul functiei dupa apelul functiei parametru transmis prin
afis) afis) referinta pe cand
variabila b revine la valoarea
pe care o avea inainte de apel
fiind
parametru transmis prin
valoare)

Exemplul 7.1
1. include

using namespace std;


void schimba_valoare (int x, int y)
{
int z=x;
x = y;
y = z;
}
void schimba_referinta (int &a, int &b)
{
int aux=a;
a=b;
b=aux;
}
int main ()
{
int M=1, N=5;
schimba_valoare(M,N);
cout << "M="<schimba_referinta(M,N);
cout << "M="<}

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