Transmiterea parametrilor
Prin valoare și prin referință: care face copie și care nu, cum returnezi mai multe rezultate, și cum se transmit vectorii.
Prin valoare
Implicit, un parametru primește o copie a argumentului. Ce se întâmplă cu el în funcție nu iese afară.
void strica(int x) {
x = 100;
}
int main() {
int a = 5;
strica(a);
cout << a; // 5, nu 100
}x este o variabilă nouă, care doar pornește cu valoarea lui a. După aceea nu mai are nicio legătură cu ea.
De aceea poți scrie liniștit funcții care distrug parametrul:
int sumaCifrelor(int n) {
int s = 0;
while (n > 0) { s += n % 10; n /= 10; }
return s;
}Bucla golește n, dar numărul din main rămâne intact, pentru că se golește doar copia.
Prin referință
Cu & în antet, parametrul devine un alt nume pentru aceeași variabilă. Modificările se văd afară.
void dubleaza(int &x) {
x = x * 2;
}
int main() {
int a = 5;
dubleaza(a);
cout << a; // 10
}Exemplul clasic este interschimbarea:
void interschimba(int &a, int &b) {
int aux = a;
a = b;
b = aux;
}Fără &, funcția ar interschimba două copii, iar originalele ar rămâne neschimbate. Compilatorul nu îți dă niciun avertisment pentru greșeala asta.
Când folosești care
Prin valoare, când funcția doar citește parametrul sau când vrei să lucrezi pe el fără să strici originalul. Este cazul obișnuit.
Prin referință, în două situații:
- Funcția trebuie să modifice argumentul.
- Funcția trebuie să întoarcă mai multe rezultate.
Cazul al doilea îl luăm pe larg, pentru că return întoarce o singură valoare.
Mai multe rezultate
Un subprogram care primește un vector și returnează prin doi parametri valoarea minimă și cea maximă.
void minmax(int v[], int n, int &mic, int &mare) {
mic = v[1];
mare = v[1];
for (int i = 2; i <= n; i++) {
if (v[i] < mic) mic = v[i];
if (v[i] > mare) mare = v[i];
}
}
int main() {
int a, b;
minmax(v, n, a, b);
cout << a << " " << b;
}Funcția este void, deci nu returnează nimic prin return. Rezultatele ies prin cei doi parametri cu &.
Enunțurile de bac formulează asta explicit: „…returnează prin parametrul p …". Când vezi „prin parametrul", trebuie &.
Vectorii
Un vector transmis ca parametru nu se copiază niciodată. Funcția primește doar adresa lui, deci lucrează pe vectorul original, chiar și fără &.
void aduna1(int v[], int n) {
for (int i = 1; i <= n; i++)
v[i]++; // modifică vectorul din main
}Pare ciudat, pentru că la int se întâmplă exact invers. Motivul e practic: copierea unui vector de un milion de elemente la fiecare apel ar costa enorm, așa că limbajul nu o face.
Asta are câteva urmări:
Nu poți strica vectorul „în siguranță". Dacă funcția nu are voie să-l modifice, trebuie să ai tu grijă de asta.
Dimensiunea trebuie transmisă separat. Funcția nu are de unde ști câte elemente sunt. De aceea antetul este mereu (int v[], int n).
Nu poți returna un vector cu return. Rezultatul se pune tot într-un parametru vector.
Matricele se transmit la fel, dar cu a doua dimensiune scrisă explicit:
void prelucreaza(int a[][101], int n, int m) { ... }Domeniul de vizibilitate
O variabilă declarată în afara tuturor funcțiilor este globală: o văd toate.
int n;
int v[1001];
void citeste() {
cin >> n;
for (int i = 1; i <= n; i++) cin >> v[i];
}E comod, dar are un preț. Din antet nu se mai vede ce folosește funcția. Iar două funcții care modifică aceeași variabilă globală își pot strica una alteia datele, în feluri greu de urmărit.
Pentru vectori mari, declararea globală este justificată, din motivul de memorie discutat la tablouri. În rest, transmite datele prin parametri.
La bac, dacă enunțul dă antetul, folosește exact acei parametri. Un subprogram care ia datele din variabile globale în loc de parametri nu respectă cerința.
Un exemplu complet
Subprogramul elimina primește un vector v cu n elemente și o valoare x, și elimină din vector toate aparițiile lui x. Noul număr de elemente se returnează prin n.
void elimina(int v[], int &n, int x) {
int k = 0;
for (int i = 1; i <= n; i++)
if (v[i] != x)
v[++k] = v[i];
n = k;
}Antetul folosește trei feluri de transmitere:
v: vector, deci implicit modificabil.&n: referință, pentru că se schimbă și schimbarea trebuie să se vadă afară.x: valoare, pentru că doar se citește.
De reținut
- Prin valoare = copie. Modificările nu ies din funcție.
- Prin referință (
&) = același obiect. Modificările se văd afară. - Folosește
&când modifici argumentul sau când ai mai multe rezultate. - Vectorii se transmit fără copiere, deci sunt mereu modificabili. Dimensiunea se dă separat.
- „Returnează prin parametrul …" din enunț înseamnă
&.