Transmiterea parametrilor
Când apelăm o funcție cu parametri, valorile sunt trimise funcției. Dar cum ajung acolo și ce se întâmplă cu ele? Există două moduri fundamental diferite.
Transmiterea prin valoare
Implicit, în C++, parametrii sunt transmiși prin valoare. Asta înseamnă că funcția primește o copie a valorii.
#include <iostream>
using namespace std;
void mareste(int x) {
x = x + 10;
cout << "In functie: " << x << endl;
}
int main()
{
int a = 5;
mareste(a);
cout << "In main: " << a << endl;
return 0;
}Output:
In functie: 15
In main: 5Ce s-a întâmplat?
adinmainare valoarea5.- La apelul
mareste(a), se creează o copie numităxcu valoarea5. - Funcția modifică copia
xla15. - Dar
adinmainrămâne neschimbat la5.
main: a = 5 ──copie──> functie: x = 5
a = 5 x = 15 (doar copia s-a schimbat)
Transmiterea prin referință
Dacă vrem ca funcția să modifice variabila
originală, folosim referință - punem
& după tipul parametrului.
#include <iostream>
using namespace std;
void mareste(int &x) {
x = x + 10;
cout << "In functie: " << x << endl;
}
int main()
{
int a = 5;
mareste(a);
cout << "In main: " << a << endl;
return 0;
}Output:
In functie: 15
In main: 15Ce s-a schimbat?
- Parametrul
int &xînseamnă:xeste o referință la variabila originală. - Nu se face copie.
xșiasunt același lucru - același loc în memorie. - Modificarea lui
xmodifică directa.
main: a = 5 ──referinta──> functie: x = a (acelasi loc)
a = 15 x = 15
Comparație directă
| Prin valoare | Prin referință | |
|---|---|---|
| Sintaxă | void f(int x) |
void f(int &x) |
| Ce primește | Copie | Referință la original |
| Modifică originalul? | NU | DA |
| Când folosim | Când nu vrem să modificăm | Când vrem să modificăm |
Exemplu clasic: interschimbarea a două variabile
Varianta greșită (prin valoare)
void interschimba(int a, int b) {
int aux = a;
a = b;
b = aux;
}
int main()
{
int x = 3, y = 7;
interschimba(x, y);
cout << x << " " << y; // 3 7 - NU s-au schimbat!
return 0;
}Funcția interschimbă copiile, nu originalele.
Varianta corectă (prin referință)
void interschimba(int &a, int &b) {
int aux = a;
a = b;
b = aux;
}
int main()
{
int x = 3, y = 7;
interschimba(x, y);
cout << x << " " << y; // 7 3 - Corect!
return 0;
}Output:
7 3Când folosim fiecare?
Prin valoare - când funcția doar citește datele
bool estePar(int n) { // doar verificăm, nu modificăm
return n % 2 == 0;
}
int patrat(int x) { // calculăm, nu modificăm
return x * x;
}Prin referință - când funcția trebuie să modifice datele
void citeste(int &n) { // citim valoarea și o punem în n
fin >> n;
}
void sorteaza(int v[], int n) { // sortăm vectorul (vectorii se transmit automat prin referință)
// ...
}Vectorii se transmit prin referință automat
Când transmitem un vector la o funcție, nu se face
copie - funcția lucrează direct pe vectorul original.
Nu trebuie &.
#include <iostream>
using namespace std;
void dubleaza(int v[], int n) {
for (int i = 1; i <= n; i++)
v[i] = v[i] * 2;
}
int v[101];
int main()
{
int n = 5;
v[1] = 3; v[2] = 7; v[3] = 2; v[4] = 9; v[5] = 4;
dubleaza(v, n);
for (int i = 1; i <= n; i++)
cout << v[i] << " ";
return 0;
}Output:
6 14 4 18 8Vectorul s-a modificat direct - fără &.
De ce? Numele unui vector este de fapt un
pointer (adresa primului element). Când transmitem
v, transmitem adresa - deci funcția lucrează pe
aceleași date.
Parametri multipli - combinații
Putem combina parametri prin valoare și prin referință în aceeași funcție:
void calcul(int a, int b, int &suma, int &produs) {
suma = a + b;
produs = a * b;
}
int main()
{
int s, p;
calcul(3, 5, s, p);
cout << "Suma: " << s << endl;
cout << "Produs: " << p << endl;
return 0;
}Output:
Suma: 8
Produs: 15a și b sunt prin valoare (doar le
citim), suma și produs sunt prin
referință (le modificăm).
Exemplu complet: CMMDC ca funcție
#include <fstream>
using namespace std;
ifstream fin("date.in");
ofstream fout("date.out");
int cmmdc(int a, int b) {
while (b != 0) {
int r = a % b;
a = b;
b = r;
}
return a;
}
int main()
{
int a, b;
fin >> a >> b;
fout << cmmdc(a, b);
return 0;
}Aici a și b sunt prin valoare -
funcția le modifică intern (în buclă), dar originalele din
main rămân intacte. Exact ce vrem.
Greșeli frecvente
1. Uitarea lui
& când vrem să modificăm
void citeste(int n) { // GREȘIT - n e copie
fin >> n; // citim în copie, originalul rămâne neschimbat
}Trebuie void citeste(int &n).
2. Folosirea
& când nu e nevoie
bool estePrim(int &n) { // INUTIL - nu modificăm nDacă nu modificăm parametrul, nu punem &. E
mai clar și mai sigur.
3. Transmiterea unei constante prin referință
void f(int &x) { x = 10; }
f(5); // EROARE! Nu putem modifica constanta 5Prin referință se poate transmite doar o variabilă, nu o valoare constantă.
4. Confuzia cu vectorii
void f(int &v[], int n) { // GREȘIT - vectorii nu au nevoie de &
void f(int v[], int n) { // CORECTCe să reții
- Prin valoare (
int x): funcția primește o copie. Originalul nu se modifică. - Prin referință (
int &x): funcția lucrează direct pe original. Modificările se păstrează. - Vectorii se transmit automat prin referință
(fără
&). - Folosim referință pentru: interschimbare, citire, funcții cu mai multe rezultate.
- Folosim valoare pentru: calcule, verificări, funcții care doar citesc datele.