Un parametru în programare este un argument acceptat de o funcție. Termenul „argument” implică ce anume a fost transmis și cărei funcție anume, iar parametrul - în ce calitate a primit funcția aplicată. Adică, codul de apelare transmite argumentul unui parametru care este definit într-un membru al specificației funcției.
Este important să distingem:
Exemplu în limbajul C :
// Descrierea funcției. int a - parametru formal, numele parametrului poate fi absent. int funcția mea ( int a ); // Definiția funcției. int b - parametru formal, numele parametrului poate să nu se potrivească cu cel specificat la declararea funcției. int funcția mea ( int b ) { returnează 0 ; } int main () { int c = 0 ; funcția mea ( c ); // Apel de funcție. c este parametrul real. returnează 0 ; }Semantica utilizării parametrilor formali și actuali se numește strategie de evaluare . O anumită strategie de evaluare dictează când trebuie evaluate argumentele unei funcții (metodă, operație, relație) și ce valori trebuie transmise. Există destul de multe strategii de calcul diferite.
Notă - utilizarea termenului „ transmitere a parametrilor ”, comună în comunitatea de programare imperativă , nu este tocmai corectă pentru multe limbaje de programare - de exemplu, în cazul unui apel de necesitate , folosit în limbajul Haskell , parametrul poate fi folosit în corpul funcției, dar niciodată trecut pentru toate cazurile apelului său și chiar exclus complet din codul mașină rezultat.
Strategiile de evaluare cele mai frecvent menționate sunt apelul după valoare și apelul prin referință , dar utilizarea efectivă a acestor termeni nu este întotdeauna adecvată. De exemplu, în comunitatea limbajului Java se spune „ Java folosește apelul după valoare, unde „valoarea” este o referință la obiect ”, iar în comunitatea limbajului Ruby se spune „ Ruby folosește apelul prin referință ”, dar în realitate ambele limbi folosiți strategia de apel prin referință .apel prin partajare ) [3] [4] . Multe limbaje, cum ar fi C , nu au un mecanism de apel prin referință, dar permit ca unul să fie simulat în semantica apel după valoare prin tipuri de referință , în special pointeri . În acest din urmă caz, în comunitățile de astfel de limbi, se spune adesea „ limba susține două strategii de evaluare ”, precum și „ apel cu indicator ” sau „ apel cu adresă ”.
În practică, modelul de calcul al multor limbaje industriale ( Java , C# ) este redus la o strategie „ call-at-mention/pass-by-reference ”. Unele limbi mai vechi, în special limbaje nesigure , cum ar fi C++ , combină mai multe modele de apelare diferite, inclusiv cele exotice, cum ar fi apelul prin referință la constantă . Din punct de vedere istoric, apelul după valoare și apelul după nume se întorc la Algol-60 , creat la sfârșitul anilor 1950 . Numai limbaje funcționale pure , cum ar fi Clean și Haskell , folosesc call - by - need , care este adesea identificat (care, de asemenea, nu este complet corect) cu evaluare leneșă .
Trecerea unui parametru prin referință înseamnă că nu valoarea în sine este copiată , ci adresa variabilei originale (ca și în cazul trecerii unui parametru cu adresă), totuși, sintaxa este utilizată astfel încât programatorul să nu fie nevoit să folosească operațiune de dereferință și se poate ocupa direct de valoarea stocată la această adresă (ca în cazul trecerii parametrului după valoare).
Trecerea prin referință evită copierea tuturor informațiilor care descriu starea obiectului (care poate fi semnificativ mai mare decât sizeof(int)) și este necesară pentru constructorul de copiere .
Dacă o funcție returnează o valoare prin referință (de exemplu, sub forma „return *this;”), atunci apelul ei poate fi folosit în stânga operatorului de atribuire (vezi și L-expression ).
Dacă trecerea prin referință este folosită tocmai ca mijloc de creștere a performanței, dar modificarea parametrului este nedorită, puteți utiliza trecerea prin referință a unui obiect constant.
Exemplu în C++ : #include <iostream> folosind namespace std ; // a folosi cout void f ( int x ) { // trecerea unui parametru prin valoarea cout << x ; x = 1 _ cout << x ; } void g ( int * x ) { // trecerea unui parametru la adresa cout << * x ; * x = 2 ; cout << * x ; } void h ( int & x ) { // trecerea unui parametru prin referință cout << x ; x = 3 ; cout << x ; } void i ( const int & x ) { // trecerea unui parametru imuabil prin referința cout << x ; x = 4 ; // Eroare din cauza căreia codul nu va fi compilat cout << x ; } int main () { int x = 0 ; cout << x ; f ( x ); cout << x << " " ; g ( & x ); cout << x << " " ; h ( x ); cout << x << " " ; i ( x ); cout << x ; returnează 0 ; }Astfel, ne-am aștepta ca programul exemplu să imprime (dacă linia eronată este comentată) „0010 022 233 333”.
Unele limbi (sau dialectele lor) nu acceptă trecerea prin referință, în timp ce altele, dimpotrivă, transmit parametrii exclusiv prin referință, ceea ce creează riscul de a schimba din neatenție contextul funcției de apelare.
Limbajul Fortran presupune trecerea parametrilor exclusiv prin referință:
Exemplu Fortran :Program:
PARAMILOR PROGRAMULUI IMPLICIT NIMIC INTEGER A , B , C A = 7,0 B = 9,0 C = 0,0 100 FORMAT ( 'A =' , I2 , ', B =' , I2 , ', C =' , I3 ) SCRIE ( * , 100 ) A , B , C Apelează MUL ( A , B , C ) SCRIE ( * , 100 ) A , B , C TERMINAT PROGRAMUL SUBRUTINĂ MUL ( A , B , C ) INTEGER A , B , C C = A * B END SUBRUTINĂSe va imprima:
A=7, B=9, C=0 A=7, B=9, C=63