Sunteți pe pagina 1din 10

Programul din fig. 5.

11 ilustreaz toate cele 3 tehnici de transmitere a


parametrilor prezentate mai sus.
#include <iostream.h>
#include <iomanip.h>
void apel_prin_valoare(int a,int b, int c)
{
a=3; b=2; c=1;
}
void apel_prin_pointer_referinta(int * a,int * b, int * c)
{
* a=3; * b=2; * c=1;
}
void apel_prin_referinta(int & a,int & b, int & c)
{
a=1; b=2; c=3;
}
void main(void) {
int a=1, b=2, c=3;
int &a_alias=a;
int &b_alias=b;
int &c_alias=c;
apel_prin_valoare(a,b,c);
cout<<"prin valoare:"<<a<<" "<<b<<" "<<c<<endl;
apel_prin_pointer_referinta(& a,& b, & c);
cout<<"prin pointer:"<<a<<" "<<b<<" "<<c<<endl;
apel_prin_referinta( a_alias, b_alias, c_alias);
cout<<"prin referinta:"<<a<<" "<<b<<" "<<c<<endl;
}
Fig. 5.11
Dup execuie se obine rezultatul:

Atunci cnd se lucreaz cu referine, trebuie respectate urmtoarele reguli:


1. Dup iniializare, programul nu poate modifica valoarea referinei.
2. Tipul referinei i tipul variabilei trebuie s fie acelai.

85

3. Nu se poate crea un pointer la o referin.


4. Nu se poate compara valoarea a dou referine s-ar compara de fapt
valorile variabilelor refereniate.
5. Nu se poate incrementa, decrementa sau modifica valoarea referin
operaiile se vor aplica valorii variabilelor refereniate.
5.7. Specificatori de clas de memorie
Atunci cnd se declar o variabil, naintea tipului su se poate preciza i
un specificator de clas de memorie. Sintaxa general utilizat pentru
declararea unei liste de variabile este:
[specificator_de_clas_de_memorie] specificator_de_tip lista_de_variabile
Specificatorul de clas de memorie specific clasa de memorie creia i
aparin variabilele din lista de variabile i poate fi: auto, extern, static i register.
1. Variabilele declarate cu ajutorul specificatorului de clas de memorie auto
sunt variabile automate. O astfel de variabil va fi local unei funcii sau unui
bloc, adic este vizibil numai n cadrul funciei sau blocului respectiv. Dac
pentru o variabil declarat ntr-o funcie sau ntr-un bloc nu s-a fcut nici o
declarare de clas de memorie, atunci aceasta se consider implicit auto.
2. Variabilele locale declarate explicit folosind cuvntul cheie extern sunt tot
variabile globale. Dac programul utilizatorului este compus din mai multe
fiiere surs, atunci variabilele externe se declar ca globale ntr-un singur
fiier surs i ca externe n celelalte fiiere surs.
Cuvntul cheie extern anun compilatorul c variabila respectiv a fost
declarat extern (n afara fiierului surs curent) de un alt program.
n exemplul din fig. 5.12 se utilizeaz un proiect format din dou fisiere
surs. n functia main din fisierul sursa 1 se apeleaz funciile f i g. f
modific valorile variabilelor i,a,b, care sunt declarate ca i variabile globale
n fisierul sursa 1. Modificarea acestora este resimit i de functia g, pentru
c i, a i b sunt declarate cu specificatorul de clas extern n fisierul sursa 2.
La rndul su, atunci cnd este apelat, g modific aceste variabile,
modificarea respectiv resimindu-se n funcia main.
3. Variabilele statice sunt declarate cu specificatorul de clas static. O astfel
de variabil i pstreaz valoarea pe parcursul executrii programului.
Atunci cnd se declar o variabil ca static ntr-o funcie, la primul apel,

86

Fisier sursa 1

Fisier sursa 2

#include<iostream.h>
extern int i;
int i;
extern float a,b;
float a,b;
void g(){
//declarare prototip functie f
{
void f();
i*=100;//i=100*30=3000
void main(void){
a*=100;//a=50.25*100=5025
i=10;
b*=100;//b=49.75*100=4975
a=20.25;
}
b=79.75;
//se afiseaza i=10,a=20.25,b=79.75
cout<<i=<<i<<,a=<<a<<,b=<<b;
f();
//se afiseaza i=30,a=50.25,b=49.75
cout<<i=<<i<<,a=<<a<<,b=<<b;
// se va apela functia g din fisierul sursa 2
g();
//se afiseaza i=3000,a=5025.0,b=4975.0
cout<<i=<<i<<,a=<<a<<,b=<<b;
}
//descrierea functiei f
void f()
{
i+=20;
a+=i;
b-=i;}
Fig. 5.12
compilatorul va iniializa variabila cu valoarea pe care o indicm. La un nou
apel ulterior al aceleiai funcii, nu se mai face iar iniializarea. Iniializarea
unei variabile statice este diferit de celelalte iniializri de variabile pe care
le execut de obicei compilatorul n cadrul funciilor.
Variabilele statice pot fi interne sau externe.
a) Variabilele statice interne sunt locale funciilor, dar spre deosebire de cele
declarate cu auto i pstreaz valoarea pe parcursul executrii programului.
Aceste variabile sunt importante n definirea funciilor de sine-stttoare
atunci cnd se dorete pstrarea valorii lor ntre dou apelri. Un exemplu de
astfel de funcii este cel al funciilor utilizate la generarea seriilor de numere
87

care calculeaz o valoare plecnd de la valoarea precedent. O alt soluie


care se poate adopta pentru pstrarea valorii anterioare const n utilizarea
unei variabile globale, care ar trebui s fie declarat de fiecarea dat. n plus,
trebuie avut grij ca aceasta s nu interfereze cu alte variabile globale deja
amplasate n alte fiiere surs.
n exemplul din fig. 5.13 se genereaz seria aritmetic cu n numere
ntregi care are primul termen 10. Raia seriei i numrul de termeni sunt
furnizai ca i date de intrare.
b) Variabilele statice
#include<iostream.h>
externe se declar n
int serie(int q) {
static int termen_serie=10;
afara oricrei funcii
termen_serie+=q;
(sunt
deci
variabile
return (termen_serie);}
globate),
dar
sunt
recunoscute doar de ctre
void main(void){
toate funciile care fac
int ratia,n,i;
cout<<dati numarul de termeni<<endl;
parte din acelai fiier
cin>>n;
surs.
Dac
un
cout<<dati ratia<<endl;
programator dorete ca
cin>>ratia;
anumite variabile globale
for(i=1;i<=n;i++)
dintr-un anumit fiier s
cout<<serie(ratia)<<endl;
}
nu poat fi accesate de
Fig. 5.13
funcii din afara acestuia
(din alte fiiere), trebuie
s declare aceste variabile utiliznd specificatorul de clas static.
4. Variabilele registru sunt declarate cu specificatorul de clas register.
Aceste variabile sunt locale funciilor i blocurilor i i pierd valorile la
ieirea din funcii sau blocuri. Iniial specificatorul de clas register cere
compilatorului s pstreze valoarea variabilei de tip register ntr-un registru
al procesorului n loc de a o stoca n memoria intern (aa cum procedeaz n
mod obinuit). Acest lucru determin ca operaiile aplicate asupra unei
variabile de acest tip s se desfoare cu o vitez mult mai mare n raport cu
o variabil normal. ntr-un program, numrul permis de variabile register
care beneficiaz de optimizarea vitezei este determinat att de mediul de
programare ct i de varianta de implementare a compilatorului.

88

5.8. Funcii recursive


O funcie recursiv este o funcie care se apeleaz pe sine nsi pentru a
efectua o anumit operaie, iar procesul n care o funcie se apeleaz pe sine
nsi se numete recursivitate.
Recursivitatea prezint urmtoarele avantaje:
- codul recursiv este mai compact i adesea mai uor de scris i de neles
dect echivalentul su recursiv;
- recursivitatea este mai
#include<iostream.h>
convenabil n mod special
int factorial(int val){
pentru
operaii
asupra
if (val==1) return (1);
structurilor de date definite
else return (val*factorial(val-1));}
recursiv, cum sunt listele,
void main(void){
arborii, etc.
int i;
n exemplul din fig. 5.14
for(i=1;i<=5;i++)
este definit o funcie factorial,
cout<<factorial de
care calculeaz factorialul
<<i<<=<<factorial(i)<<endl;}
numrului ntreg furnizat ca
Fig. 5.14
parametru. Apoi, n funcia
main , se apeleaz factorial ntr-un ciclul for pentru a afia factorialul
primelor 5 numere naturale. Se observ ca funcia factorial returneaz un
rezultat care se bazeaz pe propriul ei rezultat.
n fig. 5.15 se descrie lanul de apelri recursive i de returnri de valori
n cazul apelului factorial(3).
O funcie recursiv este oarecum asemntoare cu o structur ciclic,
deoarece trebuie precizat o condiie de ncheiere. Dac nu se face aceast
precizare, funcia nu se sfrete niciodat. n acest exemplu, condiia de
ncheiere este factorial(1) care, prin definiie, este 1.
Dac funcia se apeleaz pe sine nsi pentru a ndeplini o sarcin,
funcia execut un proces recursiv direct .
Forma mai dificil a recursivitii, recursivitatea indirect, are loc atunci
cnd o funcie (s o notm cu A) apeleaz o alt funcie (s o notm cu B), care
la rndul su o apeleaz pe A. Acest tip de recursivitate poate conduce la
realizarea unui cod dificil de neles, aa c de obicei trebuie evitat utilizarea sa.
Funciile recursive sunt lente, pentru c la fiecare apel se introduce n
program o suprasarcin de apel. De aceea se recomand pe ct posibil

89

evitarea utilizrii recursivitii. Orice funcie care poate fi scris ntr-o form
recursiv poate fi de asemenea scris ntr-o structur ciclic. n exemplu din
fig. 5.16 se prezint rezolvarea problemei din fig. 5.14, dar fr a utiliza
recursivitatea.
5.9. Funcii cu valori implicite pentru parametri
Principala diferen dintre parametrii funciilor din C i respectiv din
C++ const n faptul c C++
#include<iostream.h>
permite programelor s
int factorial(int val){
utilizeze valori implicite
int rezultat=1;
pentru
parametri. Dac
int contor;
programul invoc o funcie
for(contor=2;contor<=val;contor++)
rezultat*=contor;
fr specificarea unuia sau
return (rezultat);}
mai
multor
parametri,
programul va utiliza valorile
void main(void){
implicite.
De
exemplu
int i;
programul din fig. 5.17
for(i=1;i<=5;i++)
cout<<"factorial de
utilizeaz
funcia
"<<i<<"="<<factorial(i)<<endl;}
arata_valori pentru a afia 3
parametri. Dac utilizatorul
Fig. 5.16
invoc funcia cu mai puin

90

#include<iostream.h>
void arata_valori(int unu=1,int doi=2, int trei=3)
{
cout<<unu<<' '<<doi<<' '<<trei<<endl;
}
void main(){
arata_valori(1,2,3);
arata_valori(100,200);
arata_valori(1000);
arata_valori();
}
Fig. 5.17

de 3 parametri,
programul
utilizeaz valorile
implicite 1,2 i 3.
Dup execuie se
afieaz:
123
100 200 3
1000 2 3
123

5.10.Funcii care accept un numr variabil de parametri


Se pot utiliza macroinstruciunile va_arg, va_end i respectiv va_start
(definite n fiierul antet stdarg.h) pentru a crea funcii utilizator cu un numr
variabil de parametri. n esen macroinstruciunile extrag parametrii unul
cte unul din stiv pn cnd programul ajunge la ultimul parametru. Atunci
cnd se folosesc aceste macroinstruciuni trebuie cunoscut cu exactitate tipul
fiecrui parametru.
n exemplul din fig. 5.18 se creeaz funcia add_val care adun toate
valorile ntregi transmise funciei de ctre funcia apelant. Funcia accept
un numr variabil de parametri. Valoarea 0 din apelul funciei indic ultimul
parametru (care nu afecteaz suma).
Dup execuie programul afieaz:
suma lui 3 este 3
suma lui 3+5 este 8
suma lui 3+5 +8 este 16
Funcia add_val folosete macroinstruciunea va_start pentru a atribui
unui pointer (argument_ptr) adresa primului parametru din stiv. Apoi,
funcia folosete macroinstruciunea va_arg pentru a obine valorile una cte
una. Macroinstruciunea va_arg returneaz o valoare de tipul specificat i
incrementeaz argument_ptr, astfel nct s indice urmtorul argument. Cnd
argument_ptr ntlnete terminatorul 0, funcia folosete va_end pentru a
atribui lui argument_ptr o valoare care previne folosirea ulterioar a acestui
pointer (pn cnd va_start l reiniializeaz).

91

#include<stdio.h>
#include<stdarg.h>
int ad_val(int val,...)
{ va_list argument_ptr ;
int rezultat=0;
if(val!=0)
{
rezultat+=val;
va_start(argument_ptr,val);
while((val=va_arg(argument_ptr,int))!=0)
rezultat+=val;
va_end(argument_ptr);
}
return(rezultat);
}
void main(void){
printf("suma lui 3 este %d \n",ad_val(3,0));
printf("suma lui 3 +5 este %d \n",ad_val(3,5,0));
printf("suma lui 3 +5+8 este %d \n",ad_val(3,5,8,0));}
Fig. 5.18
5.11.Funcii cu un numr variabil de parametri de tipuri multiple
Programul din fig. 5.19 modific funcia add_val pentru ca aceasta s
poat accepta valori de toate tipurile. n acest scop se folosesc descriptori de
format. Analizndu-se aceti descriptori se determin tipul variabilei
transmise ca parametru.
n cele ce urmeaz se prezint alte dou exemple de definire/utilizare a
funciilor definite de utilizator.
Exemplul 1
n exemplul din fig. 5.20 se prezint un program n care se calculeaz i
afieaz suma, diferena i produsul a dou numere reale, furnizate sub form
de date de intrare de ctre utilizator. Se utilizeaz o funcie f care returneaz
suma. Diferena i produsul sunt transmise ctre funcia care o apeleaz pe f
deoarece n lista de parametri formali ai lui f se utilizeaz doi parametri
transmii prin adres: xy va memora produsul iar x_y memoreaz diferena.

92

#include<stdio.h>
#include<stdarg.h>
double ad_val(char *sir,...)
{
va_list marcator ;
double rezultat=0.0;
va_start(marcator, sir); //marcheaza primul argum. supl.
while(*sir)
{
if(*sir=='%') //se sare peste daca nu e specif. form.
{
switch(*(++sir))
{
case 'd':rezultat+=va_arg(marcator, int);
break;
case 'f':rezultat+=va_arg(marcator, double);
break;
}
}
sir++;
}
va_end(marcator);
return(rezultat);
}
void main(void){
double rezultat;
printf("rezultat %f \n",ad_val("%f",1.1));
printf("rezultat %f \n",ad_val("%f %f",1.1, 2.2));
printf("rezultat %f \n",ad_val("%f %f %f",1.1, 2.2,3.3));}
Fig. 5.19
Exemplul 2
Se dau numerele naturale n i k ( n k ). S se determine C k n .
C k n = n! /((n k )!*k!) .
Se va folosi o funcie definit de utilizator pentru calculul unui produs
factorial (fig. 5.21).
n acest exemplu s-a artat i cum se poate face validarea datelor introduse

93

de utilizator. Astfel, dac se dau valori greite, se reia citirea datelor.


#include<iostream.h>
float f(float x, float y, float *xy, float *x_y){
*xy=x*y;
*x_y=x-y;
return(x+y);}
void main(void){
float a,b,s,d,p;
cout<<"a="<<endl;cin>>a;
cout<<"b="<<endl;cin>>b;
s=f(a,b,&p,&d);
cout<<"suma="<<s<<",dif.="<<d<<",prod="<<p;}
Fig. 5.20

#include<iostream.h>
int fact(int val){
int rezultat=1;
int contor;
for(contor=2;contor<=val;contor++)
rezultat*=contor;
return (rezultat);}
void main(void){
int n,k,combinari;
do
{cout<<"n=";
cin>>n; cout<<"k=";cin>>k;
}
while((k>n) || (k<1) || (n<1));
combinari=fact(n)/fact(n-k)/fact(k);
cout<<"comb. de "<<n<<"luate cate "<<k<<"="<<combinari;
}
Fig. 5.21

94

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