De ce contează?
Te duci la copiator cu o foaie pe care scrie 5. Apeși butonul, iei copia și mâzgălești pe ea: tai 5-ul și scrii 10. Copia arată acum 10 — dar foaia ta originală, lăsată pe birou, are tot 5. Nimic din ce faci pe copie nu atinge originalul. Transmiterea unui parametru prin valoare funcționează exact așa: funcția primește o fotocopie a argumentului tău și se joacă pe ea, nu pe original.
Ce este
Când chemi o funcție și îi dai un argument, C++ copiază valoarea acelui argument într-un parametru nou, local funcției. Funcția lucrează de aici încolo doar pe această copie. Când funcția se termină, copia dispare, iar variabila din apelant rămâne neatinsă.
Asta înseamnă transmiterea prin valoare: parametrul și argumentul sunt două variabile diferite, care doar pornesc cu aceeași valoare. Sunt depozitate în locuri diferite din memorie. A modifica una nu o atinge pe cealaltă.
De ce e util? Pentru că funcția devine sigură de folosit: oricât s-ar agita pe parametrii ei, nu-ți poate strica din greșeală variabilele. O chemi liniștit, știind că datele tale rămân exact cum le-ai lăsat.
Reține o singură propoziție: argumentul este COPIAT în parametru. Parametrul e o variabilă nouă, cu propria ei adresă în memorie. De aceea modificările dinăuntrul funcției nu urcă înapoi la apelant — nu există nicio legătură fizică între cele două.
Cum arată
Hai să urmărim ce se întâmplă pas cu pas. Avem o funcție care vrea să dubleze un număr, dar îl primește prin valoare:
void dubleaza(int x) {
x = x * 2; // modific COPIA, nu originalul
}În main avem o variabilă n = 5 și apelăm dubleaza(n). Privește cele două variabile ca pe două celule separate de memorie: n (originalul, în main) și x (copia, în funcție).
Pasul 1 — înainte de apel. Există doar n. Copia x nu există încă.
5 | |
| main | n |
original |
Pasul 2 — la apel, valoarea se copiază. C++ creează parametrul x și îi pune valoarea lui n. Acum sunt două celule, ambele cu 5.
5 | 5 |
n | x |
original | copie |
Pasul 3 — în interiorul funcției. x = x * 2 schimbă doar celula x. Celula n nici nu știe că s-a întâmplat ceva.
5 | 10 |
n | x |
neatins | modificat |
Pasul 4 — după ce funcția se termină. Copia x dispare cu totul. Rămâne doar n, cu valoarea pe care a avut-o de la început.
5 | |
| main | n |
tot-5 |
Observă declicul: dublarea s-a întâmplat „pe bune", dar pe copie. Pentru că nu am întors nimic și nu am lucrat pe original, efortul s-a evaporat odată cu funcția.
Implementare C++
Programul de mai jos dovedește totul: tipărește valoarea înainte și după apel, și vei vedea că nu se schimbă.
#include <iostream>
using namespace std;
// x este transmis PRIN VALOARE: e o copie a argumentului
void dubleaza(int x) {
x = x * 2; // modific doar copia locala
cout << " in functie, x = " << x << "\n"; // afiseaza 10
}
int main() {
int n = 5;
cout << "inainte: n = " << n << "\n"; // 5
dubleaza(n); // trimit o COPIE a lui n
cout << "dupa: n = " << n << "\n"; // tot 5, nu 10
return 0;
}Rezultatul afișat:
inainte: n = 5
in functie, x = 10
dupa: n = 5x chiar a devenit 10 înăuntru — dar n a rămas 5. Dacă voiai ca main să afle rezultatul, aveai două variante: ori returnezi valoarea (int dubleaza(int x) { return x * 2; } și apoi n = dubleaza(n);), ori transmiți prin referință (altă lecție).
Greșeli frecvente
Te aștepți ca funcția să modifice variabila din apelant. Scrii dubleaza(n) și crezi că n devine 10. Nu devine: ai trimis o copie. Dacă vrei rezultatul înapoi în main, fie îl returnezi (n = dubleaza(n);), fie folosești transmiterea prin referință. Niciodată nu te baza pe efecte magice asupra unui parametru prin valoare.
Trimiți structuri sau vectori mari prin valoare. Pentru un int, copia e gratuită. Dar dacă transmiți prin valoare un obiect mare (un string lung, un vector cu un milion de elemente), C++ copiază tot la fiecare apel — lent și risipitor de memorie. La concurs asta te poate costa timp prețios. Soluția obișnuită: transmite astfel de date prin referință (eventual const, dacă nu vrei să le modifici).
Dacă tocmai ți-ai dat seama că ai nevoie ca funcția să schimbe chiar variabila din apelant, ai nimerit fix motivul pentru care există transmiterea prin referință. O studiezi în lecția următoare — acolo parametrul nu mai e o copie, ci un alias către originalul tău.