Quelle est la différence entre le passage par référence vs passage par valeur?
Quelle est la différence entre
- un paramètre passé par référence
- un paramètre passé par valeur?
Pourriez-vous me donner quelques exemples, s'il vous plaît?
- Connexes: Comment passer des objets à des fonctions en C++?
- Si vous ne savez pas ce qu'est une adresse ou la valeur est de voir ici
Vous devez vous connecter pour publier un commentaire.
D'abord et avant tout, le "passage par valeur vs passez par référence" distinction telle que définie dans la CS de la théorie est aujourd'hui obsolète parce que la technique initialement définie comme "passage par référence" a depuis perdu la faveur et il est rarement utilisé aujourd'hui.1
Nouveaux langages2 ont tendance à utiliser un autre (mais similaire) paire de techniques pour obtenir les mêmes effets (voir ci-dessous) qui est la principale source de confusion.
Une source secondaire de confusion est le fait que dans "passage par référence", "référence" a un sens plus étroit que le terme général de "référence" (parce que l'expression antérieur).
Maintenant, l'authentique définition est:
Lorsqu'un paramètre est passé par référence, l'appelant et l'appelé utiliser la même variable pour le paramètre. Si le destinataire de l'appel modifie le paramètre variable, l'effet est visible à l'appelant de la variable.
Lorsqu'un paramètre est passé par valeur, l'appelant et l'appelant ont deux variables indépendantes avec la même valeur. Si le destinataire de l'appel modifie le paramètre variable, l'effet n'est pas visible à l'appelant.
Choses à noter dans cette définition sont:
"Variable" signifie ici l'appelant (local ou global) de la variable elle-même -- c'est à dire si je passe une variable locale par référence, et de confier à elle, je vais changer l'appelant de la variable elle-même, pas par exemple ce qu'il indique si c'est un pointeur.
Le sens de "référence" dans le "passage par référence". La différence avec la générale de "référence" à terme est que cette "référence" est temporaire et implicite. Ce que le destinataire de l'appel, fondamentalement, est une "variable" qui est en quelque sorte "le même" que celui d'origine. Comment plus précisément cet effet est obtenu n'est pas pertinent (par exemple, la langue peut aussi exposer les détails de l'implémentation -- les adresses, les pointeurs, déréférencement-tout cela est sans importance; si l'effet net est présent, il est passé par référence).
Maintenant, en langues modernes, les variables ont tendance à être de "référence" types de (un autre concept inventé plus tard le "passage par référence" et inspirée par elle), c'est à dire l'objet réel les données sont stockées séparément quelque part (généralement sur le tas), et seuls les "références" sont toujours détenus dans des variables et passés en paramètres.3
Passer un tel renvoi relève de passer par valeur parce que la valeur d'une variable est techniquement la référence elle-même, pas la visée de l'objet. Cependant, l'effet net sur le programme peut être le même que le passage par valeur ou par référence:
Comme vous pouvez le voir, cette paire de techniques est presque le même que dans la définition, avec un niveau d'indirection: il suffit de remplacer "variable" avec "objet référencé".
Il n'y a pas de nom, ce qui conduit à tordus explications comme "appel par valeur où la valeur est une référence". En 1975, Barbara Liskov suggéré le terme "appel-par-objet de partage" (ou parfois simplement "call-by-partage"), bien qu'il ne sera jamais pris. En outre, aucune de ces expressions, qui établit un parallèle avec le couple originel. Pas étonnant que les anciens termes fini par être réutilisés en l'absense de quelque chose de mieux, menant à la confusion.4
NOTE: Pendant longtemps, cette réponse disait:
C'est surtout corriger sauf le sens plus étroit de "référence", étant à la fois temporaire et implicite (il n'est pas nécessaire, mais le fait d'être explicite et/ou persistants sont des fonctionnalités supplémentaires, pas une partie de la passé par référence sémantique, comme expliqué ci-dessus). De plus près l'analogie serait de vous donner une copie d'un document vs vous invite à travailler sur l'original.
1Sauf si vous êtes à la programmation en Fortran ou en Visual Basic, il n'est pas le comportement par défaut, et dans la plupart des langues modernes de l'utilisation, de la vraie call-by-reference n'est même pas possible.
2Une bonne quantité de anciennes de le soutenir, trop
3Dans plusieurs langues modernes, tous les types sont des types référence. Cette approche a été lancé par le langage CLU en 1975 et a depuis été adopté par de nombreuses autres langues, y compris Python et Ruby. Et beaucoup d'autres langues utilisent une approche hybride, où certains types sont des "types de valeur" et d'autres "types de référence" -- parmi eux, C#, Java et JavaScript.
4Il n'y a rien de mal avec recyclage d'un côté ancien terme en soi,, mais on doit en quelque sorte faire clairement quel sens est utilisé à chaque fois. Ne pas le faire, c'est exactement ce qui continue de causer de la confusion.
C'est une façon de savoir comment passer des arguments aux fonctions. Le passage par référence signifie que les fonctions dites "du paramètre sera le même que les appelants' argument passé (pas la valeur, mais l'identité de la variable elle-même). Le passage par valeur signifie que les fonctions dites "du paramètre sera une copie de l'appelant' argument passé. La valeur sera la même, mais l'identité de la variable est différente. Ainsi, toute modification d'un paramètre se fait par la fonction appelée, dans un cas, les modifications de l'argument passé et dans l'autre cas il suffit de modifier la valeur du paramètre dans la fonction appelée (qui n'est qu'une copie). Dans un rapide dépêchez-vous:
ref
utilisé à l'appelant et l'appelé de la fonction). Jon Skeet a également une belle explication de ce ici.Codes
Depuis ma langue est le C++, je vais utiliser ici
Et un exemple en Java ne fera pas de mal:
Wikipedia
http://en.wikipedia.org/wiki/Pass_by_reference#Call_by_value
http://en.wikipedia.org/wiki/Pass_by_reference#Call_by_reference
Ce mec assez bien clous:
http://javadude.com/articles/passbyvalue.htm
Beaucoup de réponses ici (et en particulier les plus hautement upvoted réponse) sont en fait incorrect, car ils ne comprennent pas ce que "l'appel par référence" signifie vraiment. Voici ma tentative de mettre les questions de droit.
TL;DR
En termes plus simples:
En termes métaphoriques:
Ce que "l'appel par valeur" et "appel par la référence" ne pas dire
Noter que ces deux concepts sont totalement indépendants et orthogonal à partir de la notion de types de référence (qui en Java, tous les types qui sont des sous-types de
Object
, et en C# tous lesclass
types), ou le concept de types de pointeur comme en C (qui sont sémantiquement équivalents de Java "types de référence", simplement avec une syntaxe différente).La notion de type de référence correspond à l'URL: il est à la fois lui-même un morceau de l'information, et c'est un référence (un pointeur, si vous voulez) à d'autres informations. Vous pouvez avoir plusieurs copies d'une URL dans différents endroits, et ils ne changent pas ce site, ils ont tous un lien, si le site est mise à jour chaque URL copie sera toujours conduire à la mise à jour de l'information. À l'inverse, la modification de l'URL dans un seul endroit, de ne pas affecter de toute autre copie écrite de l'URL.
Remarque que le C++ a une notion de "références" (par exemple,
int&
) qui est pas comme Java et C#"types de référence", mais est comme "appeler par référence". Java et C#"types de référence", et tous types de Python, sont comme ce que C et C++ appel "les types pointeur" (par exemple,int*
).OK, voici la plus longue et la plus formelle explication.
Terminologie
Pour commencer, je tiens à souligner certaines des choses importantes de la terminologie, pour aider à clarifier ma réponse et de nous assurer que nous mettons tout en se référant à la même idée lorsque nous utilisons des mots. (Dans la pratique, je crois que la grande majorité de la confusion à propos de sujets tels que les tiges de l'utilisation des mots dans les façons de ne pas communiquer pleinement le sens qui était prévu.)
Pour commencer, voici un exemple, dans certains C-comme la langue d'une déclaration de fonction:
Et voici un exemple de l'appel de cette fonction:
À l'aide de cet exemple, je veux définir un certain nombre de choses importantes de la terminologie:
foo
est un fonction déclaré sur la ligne 1 (Java insiste sur la prise de toutes les fonctions méthodes, mais le concept est le même, sans perte de généralité; C et C++ de faire une distinction entre la déclaration et la définition que je ne vais pas ici)param
est un paramètre formel àfoo
, a également déclaré sur la ligne 1arg
est un variable, plus précisément une variable locale de la fonctionbar
, déclaré et initialisé sur la ligne 2arg
est aussi un argument à un invocation defoo
sur la ligne 3Il y a deux très importants ensembles de concepts à distinguer ici. La première est valeur contre variable:
bar
fonction ci-dessus, après la ligneint arg = 1;
, l'expressionarg
a la valeur1
.final
ou C#'sreadonly
) ou profondément immuables (par exemple à l'aide de C++deconst
).Autre paire de concepts afin de les distinguer est paramètre contre argument:
Appel par valeur
Dans appel par valeur, la fonction, les paramètres formels sont des variables qui sont nouvellement créé pour l'appel à la fonction, et qui sont initialisés avec la valeurs de leurs arguments.
Cela fonctionne exactement de la même manière que tous les autres types de variables sont initialisées avec des valeurs. Par exemple:
Ici
arg
etanother_variable
sont complètement indépendantes les variables, leurs valeurs peuvent évoluer indépendamment les uns des autres. Cependant, au point oùanother_variable
est déclaré, il est initialisé à contenir la même valeur quearg
détient -- qui est1
.Car ils sont des variables indépendantes, les changements de
another_variable
n'affectent pasarg
:C'est exactement la même que la relation entre
arg
etparam
dans notre exemple ci-dessus, qui je le répète ici pour la symétrie:C'est exactement comme si nous avions écrit le code de cette façon:
Qui est, la définition des caractéristiques de ce appel par valeur signifie que le destinataire de l'appel (
foo
dans ce cas) reçoit valeurs comme arguments, mais dispose de son propre variables pour ces valeurs à partir des variables de l'appelant (bar
dans ce cas).Pour en revenir à ma métaphore ci-dessus, si je suis
bar
et vous êtesfoo
, quand je vous appelle, je vous remettre un morceau de papier avec un valeur écrit sur elle. Vous appelez ce morceau de papierparam
. Cette valeur est un copie de la valeur que j'ai écrit dans mon portable (mon variables locales) dans une variable, j'appellearg
.(En aparté: en fonction du matériel et du système d'exploitation, il existe différents conventions d'appel sur la façon dont vous appelez une fonction à partir d'un autre. La convention d'appel est comme nous de décider si j'écris la valeur sur un morceau de mon papier et puis à la main pour vous, ou si vous avez un morceau de papier que j'écris, ou si je l'écris sur le mur en face de nous deux. C'est un sujet intéressant, mais bien au-delà de la portée de cette déjà longue réponse.)
Appel par référence
Dans appel par référence, la fonction, les paramètres formels sont tout simplement de nouveaux noms pour les mêmes variables que l'appelant fournitures comme arguments.
Pour en revenir à notre exemple ci-dessus, c'est équivalent à:
Depuis
param
est juste un autre nom pourarg
-- qui est, ils sont la même variable, les changements deparam
sont reflétées dansarg
. C'est le moyen fondamental dans l'appel par référence diffère de l'appel par valeur.Très peu d'appui aux langues d'appel par référence, mais le C++ pouvez le faire comme ceci:
Dans ce cas,
param
n'avez pas la même valeur commearg
, il fait estarg
(juste un nom différent) et doncbar
peut observer quearg
a été incrémenté.Noter que c'est pas la façon dont Java, JavaScript, C, Objective-C, Python, ou presque n'importe quel autre langage populaire travaille aujourd'hui. Cela signifie que ces langues sont pas appel par référence, ils sont en appel par valeur.
Addendum: appel par le partage d'objets
Si ce que vous avez est appel par valeur, mais la valeur réelle est un type de référence ou pointeur de type, puis la "valeur" lui-même n'est pas très intéressant (par exemple, en C c'est juste un entier d'une plate-forme spécifique à la taille) -- ce qui est intéressant, c'est ce que la valeur points de.
Si ce que ce type de référence (qui est, pointeur) est mutable alors un effet intéressant est possible: vous pouvez modifier le pointu de valeur, et le visiteur peut observer les changements de la pointe-de valeur, même si l'appelant ne peut pas observer les changements pour le pointeur lui-même.
À emprunter de l'analogie de l'URL de nouveau, le fait que je vous ai donné un copie de l'URL d'un site web n'est pas particulièrement intéressant si la chose que nous avons à la fois des soins sur le site internet, pas l'URL. Le fait que vous griffonner sur votre copie de l'URL n'a pas d'incidence sur ma copie de l'URL n'est pas une chose que nous nous soucions (et, en fait, dans des langages comme Java et Python "URL", ou le type de référence valeur, ne peuvent pas être modifiées à tout, que la chose pointé par il le peut).
Barbara Liskov, quand elle a inventé le CLU langage de programmation (qui avait ces sémantique), rendu compte que les termes "appel par valeur" et "appel par la référence" n'étaient pas particulièrement utile pour décrire la sémantique de cette nouvelle langue. Donc, elle a inventé un nouveau terme: appel par le partage d'objets.
Lors de la discussion de langues qui sont techniquement appel par valeur, mais où les types les plus courants sont la référence ou les types pointeur (qui est: presque tous les impératif, orienté objet, ou multi-paradigme langage de programmation), je trouve que c'est beaucoup moins compliqué pour simplement éviter de parler de appel par valeur ou appel par référence. Bâton de appel par le partage d'objets (ou simplement appel par objet) et personne ne sera confus. 🙂
The first is value versus variable.
The other important pair of concepts to distinguish is parameter versus argument:
Avant de le comprendre, les 2 termes, vous DOIT comprendre la suite. Chaque objet, a 2 choses qui peuvent faire qu'il faut distinguer.
Donc, si vous dites
employee.name = "John"
sais qu'il y a 2 choses à propos de
name
. Sa valeur est"John"
et aussi de son emplacement dans la mémoire qui est certain nombre hexadécimal peut-être comme ceci:0x7fd5d258dd00
.En fonction de la langue de l'architecture ou de la type (class, struct, etc.) de votre objet, vous serait soit le transfert de
"John"
ou0x7fd5d258dd00
Passant
"John"
est connu comme le passage par valeur.En passant
0x7fd5d258dd00
est connu comme le passage par référence. N'importe qui qui est pointant vers le présent de la mémoire de l'emplacement d'avoir accès à la valeur de"John"
.Pour en savoir plus, je vous recommande de lire sur un déréférencement d'un pointeur et aussi pourquoi choisir struct (valeur type) au cours de la classe (type de référence)
Voici un exemple:
y
a déjà été fixé à 2 par la ligne précédente. Pourquoi serait-il revenir à 0?La façon la plus simple pour obtenir ce qui est sur un fichier Excel. Par exemple, disons que vous avez deux numéros, 5 et 2 dans les cellules A1 et B1 en conséquence, et que vous voulez trouver leur somme dans une troisième cellule, disons A2.
Vous pouvez le faire de deux façons.
Soit par passant leurs valeurs à la cellule A2 en tapant = 5 + 2 dans cette cellule. Dans ce cas, si les valeurs des cellules A1 ou B1 changement, la somme A2 reste le même.
Ou par en passant de la “références” des cellules A1 et B1 à la cellule A2 en tapant = A1 + B1. Dans ce cas, si les valeurs des cellules A1 ou B1 changement, la somme A2 trop de changements.
En passant par ref vous êtes essentiellement en passant un pointeur vers la variable. Le passage par valeur, vous transmettez une copie de la variable. En utilisation de base, cela signifie passer par ref changements de la variable considérée être l'appel de la méthode et le passage par valeur ils l'habitude.
Passage par valeur envoie une COPIE des données stockées dans la variable que vous spécifiez, passage par référence envoie un lien direct à la variable elle-même. Donc, si vous passer une variable par référence, puis de changer la variable à l'intérieur du bloc, vous avez passé en, la variable d'origine sera changé. Si vous devez simplement passer par valeur, la variable d'origine ne pourra pas être modifié par le bloc, vous avez passé en, mais vous obtiendrez une copie de ce qu'elle contenait, au moment de l'appel.
Passage par valeur - La fonction copie de la variable et travaille avec une copie(donc ça ne change rien dans la variable d'origine)
Passer par référence - La fonction utilise la variable d'origine, si vous modifiez la variable dans la fonction, les changements dans la variable d'origine trop.
Exemple(à copier et à utiliser/essayer vous-même et voir) :
Keep it simple, jette un coup d'oeil. Les murs de texte peut être une mauvaise habitude.
Un principale différence entre eux est que la valeur des variables de type de stocker des valeurs, de sorte que la spécification d'une valeur de variable de type dans un appel de méthode en transmet une copie de la valeur de la variable à la méthode. De référence des variables de type de stocker des références à des objets, de sorte que la spécification d'une référence de type de variable comme argument passe à la méthode une copie de la référence qui se rapporte à l'objet. Même si la référence elle-même est passé par valeur, la méthode peut toujours utiliser la référence qu'il reçoit d'interagir avec et de modifier éventuellement—l'objet d'origine. De même, lors du retour de l'information à partir d'une méthode par l'intermédiaire d'une instruction de retour, la méthode renvoie une copie de la valeur stockée dans une variable de type ou une copie de la référence stockée dans la variable de type. Lorsqu'une référence est retourné, l'appel de méthode ne peut utiliser que la référence à interagir avec l'objet référencé. Donc, en effet, les objets sont toujours passés par référence.
En c#, pour passer une variable par référence si la méthode appelée pouvez modifier la variable, C# fournit les mots-clés ref et à l'extérieur. Appliquer le mot-clé ref pour une déclaration de paramètre vous permet de passer une variable par référence à une méthode—la méthode appelée sera en mesure de modifier la variable d'origine en l'appelant. Le mot-clé ref est utilisé pour les variables qui ont déjà été initialisé dans la méthode appelante. Normalement, lorsqu'un appel de méthode contient une variable non initialisée comme argument, le compilateur génère une erreur. Précédant un paramètre avec le mot-clé out crée un paramètre de sortie. Cela indique au compilateur que l'argument sera passé dans la méthode appelée par la référence et que la méthode appelée sera attribuer une valeur à la variable d'origine en l'appelant. Si la méthode ne permet pas d'attribuer une valeur pour le paramètre de sortie dans chaque chemin d'exécution, le compilateur génère une erreur. Cela empêche également le compilateur de générer un message d'erreur pour une variable non initialisée est passé comme argument à une méthode. Une méthode peut retourner qu'une seule valeur à son appelant par l'intermédiaire d'une instruction de retour, mais peut retourner plusieurs valeurs, par la spécification de sortie multiples (ref et/ou sortie) des paramètres.
voir c# de discussion et des exemples ici texte du lien
Exemples:
const &
est généralement meilleure. Vous ne supportez pas la construction et la destruction de la peine. Si la référence n'est pas const votre interface est en suggérant qu'il va changer le passé dans les données.En bref, Passé par valeur est CE que c'est et passé par référence est là OÙ il est.
Si votre valeur est VAR1 = "Heureux les Gars!", vous ne verrez que les "Heureux les Gars!". Si VAR1 modifications "Heureux Gal!", vous ne savez pas qui. Si il est passé par référence, et VAR1 changements, vous aurez.
passer par la valeur, c'est comment passer de la valeur d'une fonction en faisant usage d'arguments. dans le passage par valeur, on copie les données stockées dans la variable que nous spécifier et il est plus lent que le passage par référence bcse t
il les données sont copiées . de nous faire des changements dans les données copiées les données d'origine n'est pas affectée. nd en passer par refernce ou de passer par l'adresse de nous envoyer le lien direct de la variable elle-même . ou en passant le pointeur sur une variable. il est plus rapide bcse moins de temps est consommé
Si vous ne voulez pas modifier la valeur de la variable d'origine après le passage dans une fonction, la fonction devrait être construit avec une "passage par valeur" paramètre.
Alors que la fonction aura SEULEMENT la valeur, mais pas l'adresse de la variable. Sans la variable de l'adresse, le code à l'intérieur de la fonction ne peut pas changer la valeur de la variable comme on le voit de l'extérieur de la fonction.
Mais si vous voulez donner à la fonction de la possibilité de changer la valeur de la variable que vu de l'extérieur, vous devez utiliser passer par référence. Comme la valeur et l'adresse (de référence) sont transmises et disponible à l'intérieur de la fonction.
Voici un exemple qui illustre les différences entre passage par valeur du pointeur de la valeur de référence:
Le “passage par référence à la” méthode a une limitation importante. Si un paramètre est déclaré passé par référence (si elle est précédée par l' & signe) correspondant paramètre réel doit être une variable.
Un paramètre réel se référant à “des passé par valeur” paramètre formel peut être une expression en général, de sorte qu'il est permis d'utiliser non seulement une variable, mais aussi un littéral ou même une invocation de la fonction du résultat.
La fonction n'est pas en mesure de placer une valeur dans autre chose qu'une variable. Il ne peut pas affecter une nouvelle valeur à un littéral ou la force d'une expression de changer son résultat.
PS: Vous pouvez aussi vérifier Dylan Beattie réponse dans le thread courant qui l'explique en mots simples.