Está en la página 1de 10

¿Cuándo se utiliza «paso por referencia» y cuándo «paso por valor»?

Página 1 de 10

Blog de tecnologías de la información

Antología Curiosidades Series Acerca de nosotros

marzo 7, 2017 General

¿Cuándo se utiliza «paso por referencia» y cuándo


«paso por valor»?
Publicado por Diego Vizcarra

¿Qué entendemos por “pasar una variable”? Básicamente es entregarle a una función, al momento de ser llamada, alguna
variable ya existente. Si queremos que una función acepte valores externos a ella, es necesario que en su declaración
coloquemos parámetros. Los parámetros serán los contenedores donde habremos de colocar las variables con las que
nuestra función realizará su trabajo.

Comencemos a tratar este tema utilizando un poco de código escrito en Java. Varias han sido las ocasiones donde nos
han dicho que los objetos que se mandan a una función o método se pasan por referencia; si esto fuera cierto, ¿podría
alguien explicar por qué el siguiente ejemplo no realiza el cambio de nombre que queremos?

mhtml:file://C:\Users\Rafael\Downloads\¿Cuándo se utiliza «paso por referencia» y c... 10/12/2019


¿Cuándo se utiliza «paso por referencia» y cuándo «paso por valor»? Página 2 de 10

1. public class PasoDeVariable {


2. public static void main(String[] args) {
3. Persona vecino = new Persona("Hugo");
4. System.out.println("-> " + vecino.nombre);
5.
6. cambiarNombre(vecino);
7. System.out.println("-> " + vecino.nombre);
8. }
9.
10. public static void cambiarNombre(Persona p) {
11. p = new Persona("Miguel");
12. }
13. }
14.
15. class Persona {
16. public String nombre;
17. public Persona(String nombre) {
18. this.nombre = nombre;
19. }
20. }
21.
22. // SALIDA
23. // -> Hugo
24. // -> Hugo

En el mundo de la programación existen dos formas muy famosas de pasar variables a alguna función: una se conoce
como paso por valor y la otra es conocida como paso por referencia. De acuerdo a nuestras clases, la primera forma
nos dice que nuestra función recibirá una copia de la variable que pasemos y, cualquier modificación que realicemos, solo
afectará a dicha copia. Por otro lado, en la segunda forma se nos lleva a entregar prácticamente la variable original, es
decir, si realizamos algún cambio en el parámetro de nuestra función, esto equivaldría a estar actuando directamente
sobre la variable original.

Aquí se representa gráficamente lo que hasta el


momento sabemos de ambas formas.

Lo anteriormente dicho luce muy bien y tal parece que no debería existir razón alguna para que nos lleguemos a
confundir pero… ¿es así de sencillo? Si lo fuera, ¿por qué siguen ocurriendo confusiones respecto a ambos términos? ¿Por
qué el “paso por referencia” en lenguajes como Java pareciera no estar funcionando? Es momento de otorgar respuestas.
Para lograrlo, habrá que volver a definir algunos conceptos.

Definamos las referencias

El paso por referencia es el término que más controversia genera en el mundo de la computación; por tanto, si
queremos utilizar adecuadamente dicha sentencia habrá que definir primero la palabra: referencia.

mhtml:file://C:\Users\Rafael\Downloads\¿Cuándo se utiliza «paso por referencia» y c... 10/12/2019


¿Cuándo se utiliza «paso por referencia» y cuándo «paso por valor»? Página 3 de 10

Una referencia es, en un sentido amplio, un valor que nos permite acceder indirectamente a un dato en
particular dentro de un programa; dicho dato podría encontrarse, por ejemplo, en la memoria principal de una
computadora. Poniéndolo en palabras más simples, si algo se refiere a un dato, ese algo es considerado una referencia.

En base a lo anterior, ¿cómo definirías ahora un paso por referencia? Muy sencillo, si le otorgas a una función una
referencia, esta forma de paso de variable es, en toda regla, un paso por referencia. Aún así, cabe mencionar
que los diseñadores de lenguajes de programación no nos la pondrán tan fácil y lograrán, tal vez sin ser su verdadera
intención, complicarnos la vida.

Las referencias toman diferentes formas y pueden conocerse de distinta manera en un lenguaje de programación o en
otro. Saber identificar referencias se convertirá en una habilidad muy importante que nos permitirá hacer un correcto uso
de ellas (y de paso ahorrarnos unas horas de debug). No hay forma de perderse, solo hay que tener siempre presente
idea principal que ya hemos comentado. Pasemos a ver algunas implementaciones de referencias.

Distintos tipos de referencias

Como te comenté, las referencias pueden encontrarse de varias formas, todo depende de la creatividad de la persona que
diseñó el lenguaje de programación que estés utilizando; además de esta implementación, también debe existir una
manera de usar dicha referencia a fin de acceder al dato que queremos. Para ilustrar lo que acabo de decir, me
en 3 de los lenguajes de programación más famosos que existen y de los cuales, seguro, haz llegado a utilizar al menos
uno; hablamos de C, C++ y Java.

Lenguaje C

En este lenguaje existe una implementación muy particular de una referencia: el apuntador. Por definición, un
apuntador es un tipo especial de variable que almacena una dirección de memoria. ¿A quién pertenece esta
dirección de memoria? Pues a algo que esté residiendo en memoria, por ejemplo una variable de tipo entero, tal vez un
arreglo o una estructura.

Teniendo ya la implementación, resta saber la forma de acceder al dato haciendo uso del apuntador; para esto, C integra
un operador conocido como “de desreferencia” * . Al utilizar dicho operador, logramos acceder al valor al que el
apuntador se refiere.

1. // Ejemplo de un apuntador
2. int num = 5;
3. int *ptr_num = #
4.
5. printf("valor: %d\n", *ptr_num);
6.
7. // Salida
8. // valor: 5

Lenguaje C++

Este otro lenguaje es muy parecido a C y, de hecho, también incluye a los apuntadores en su repertorio, ¿pero qué crees?
C++ cuenta con otra implementación de referencia que, para nuestra “mala suerte”, lleva exactamente el mismo nombre:
referencia.

La referencia en C++ es una característica específica de este lenguaje y que tiene un comportamiento muy particular; lo

mhtml:file://C:\Users\Rafael\Downloads\¿Cuándo se utiliza «paso por referencia» y c... 10/12/2019


¿Cuándo se utiliza «paso por referencia» y cuándo «paso por valor»? Página 4 de 10

que se logra con esto es darle un alias a una variable que ya se encuentra en existencia para, de esta forma,
lograr realizar cambios sobre dicha variable por medio de ese alias. En términos más sencillos, solo es darle otro
nombre a la misma variable.

1. // Ejemplo de una referencia de C++


2. int jose = 5;
3. int &pepe = jose;
4.
5. // Cambiamos el valor de "jose" utilizando su alias
6. pepe = 10;
7.
8. // Comprobamos que el valor original ha sido modificado
9. std::cout << "Valor: " << jose << std::endl;
10.
11. // Salida
12. // Valor: 10

Puedes apreciar que, a diferencia de los apuntadores, aquí no es necesario realizar algo en particular sobre la
(o alias) para lograr acceder al valor original, dicha referencia puede utilizarse como una variable común y corriente. No
obstante, nunca debes perder de vista que estas referencias son diferentes a los apuntadores. En las siguientes líneas de
código te muestro las principales diferencias entres ambos conceptos:

Primera diferencia:

1. // - Las referencias no pueden almacenar un valor nulo -


2. int *ptr = NULL;
3. int &reference = NULL; // ¡ERROR!

Segunda diferencia:

1. // - Las referencias deben inicializarse al momento en que se crean -


2. int i = 4;
3.
4. int &ref_i = i; // "ref_i" es el alias de la variable "i"
5. int &ref_j; // ¡ERROR! A "ref_j" se le debe asignar alguna variable
6.
7. // - Los apuntadores pueden ser inicializados posteriormente -
8. int *ptr_i; // Declaramos al apuntador
9. ptr_i = &i; // Ahora lo hacemos que apunte a la variable "i"

Tercera diferencia:

1. // - Las referencias no pueden reasignarse a otra variable -


2. int x = 1;
3. int y = 2;
4.
5. int &ref_n = x; // "ref_n" es un alias de "x"
6. ref_n = y; // ¡ERROR! "ref_n" está unido de por vida a "x"
7.
8. // - Los apuntadores pueden cambiar de valor en cualquier momento -
9. int *ptr_n = &x; // "ptr_n" apunta a la variable "x"
10. ptr_n = &y; // Ahora "ptr_n" apunta a la variable "y"

Lenguaje Java

¿Qué podría ser peor que tener un lenguaje de programación que utiliza el término referencia con un significado
Fácil, tener dos lenguajes que utilizan el término referencia con significados totalmente distintos. Java no quiso quedarse
atrás y decidió crear sus propias referencias.

mhtml:file://C:\Users\Rafael\Downloads\¿Cuándo se utiliza «paso por referencia» y c... 10/12/2019


¿Cuándo se utiliza «paso por referencia» y cuándo «paso por valor»? Página 5 de 10

En Java, los manejos explícitos de memoria no existen, él es quien se encarga de realizar todo el trabajo sucio por ti
(dejemos a los programadores preocuparse de cosas más importantes). Cuando tú instancias objetos en este lenguaje,
dichos objetos se crean en algún lugar de la memoria; ellos no son algo que puedas tomar y guardarlo en una variable,
necesitas de una entidad que te permita comunicarte con dicho objeto para poder trabajar sobre él. Esta entidad es
precisamente lo que se conoce como referencia en Java.

Aunque las referencias de Java son totalmente diferentes de sus homónimas en C++, sí que guardan cierta similitud con
los apuntadores. No obstante, veamos dos de las diferencias más importantes entre apuntadores y referencias de Java:

1. No hay aritmética de apuntadores


No es posible manipular el valor de una referencia de Java, es decir, no se le podrá sumar ni restar valor alguno a dicha referencia
de acceder a una región de memoria cercana a la que tenemos originalmente.
2. Las referencias tienen tipado fuerte
En Java no es posible que sus referencias se comporten como algo que no son. Por ejemplo, a una referencia de tipo Object
podría realizar un cast a String si el objeto referido es efectivamente un String.

1. // Ilustración del punto 2


2. void casting(Object o) {
3. String s = (String) o; // Válido solo si "o instanceof String == true"
4. }

Para obtener la referencia de un objeto, Java utiliza el operador new ; una vez obtenida, la podemos almacenar en
variable y, a partir de ese momento, podemos utilizar a dicha variable como si prácticamente fuera el objeto que se ha
creado en memoria.

1. class Objeto {
2. public int valor;
3. }
4.
5. Objeto o = new Objeto();
6. o.valor = 4;

Como te puedes dar cuenta, un apuntador, una referencia de C++ y una referencia de Java son, en esencia, la misma
cosa. Los tres son meras implementaciones del concepto de referencia que definimos en un principio, es decir, son
valores que se refieren a otro valor. Cada implementación tiene su propia particularidad, sus ventajas y desventajas
(siendo la desventaja más importante el tener como nombre un término totalmente genérico).

Si tú pasas cualquiera de estas referencias a una función, no puedes estar equivocado, es un paso por referencia. Sin
embargo, un último reto nos espera y radica en reconocer que, dependiendo del tipo de referencia que se trate,
esta también podría ser pasada por valor o por referencia. En la siguiente sección trataremos este dilema.

Pasar una referencia por valor o por referencia

Echemos un vistazo a esta función tan famosa que permite intercambiar el valor de los dos parámetros que recibe:

mhtml:file://C:\Users\Rafael\Downloads\¿Cuándo se utiliza «paso por referencia» y c... 10/12/2019


¿Cuándo se utiliza «paso por referencia» y cuándo «paso por valor»? Página 6 de 10

1. // Esta primera versión puede implementarse en C o C++


2. void intercambio(int *a, int *b) {
3. int temp = *a;
4. *a = *b;
5. *b = *temp;
6. }
7.
8. // Esta segunda versión solo puede implementarse en C++
9. void intercambio(int &a, int &b) {
10. int temp = a;
11. a = b;
12. b = temp;
13. }

Ambas versiones de la función realizan la misma tarea y ambas realizan paso por referencia pero ¿ambas funciones están
recibiendo el mismo tipo de parámetros? No realmente… Aunque al finalizar la función tendremos a nuestras variables
originales con sus valores intercambiados, la verdad es que la información que recibimos en cada función es diferente. En
la primera versión, nuestros parámetros son apuntadores y en la segunda son referencias de C++.

¿Recuerdas lo que dijimos de que cada implementación de referencia tiene su propia particularidad? Este es un excelente
momento para tomar eso en cuenta. De acuerdo a lo que ya sabemos sobre apuntadores y referencias, puedes ver que
en la primera función lo que recibimos son direcciones de memoria y, en la segunda, es como si estuviéramos recibiendo
la misma variable original.

De acuerdo a la primera definición que teníamos de “paso por referencia” al inicio de esta nota, este modo significa recibir
la variable original como parámetro. Si tomamos esa idea como base, puedes ver que nuestra primera versión de la
función intercambio() no puede continuar considerándose un paso por referencia, mientras que la segunda versión
¿Quiere esto decir que todo lo que he leído hasta el momento ha sido pura pérdida de tiempo? Absolutamente no, al
contrario, ¡haz encontrado el problema!

Resulta que con la idea que todos teníamos sobre el paso por referencia, es como llegaron a surgir todos los problemas y
confusiones que aquejan a varios programadores. En ocasiones, mantener dicha idea nos lleva a generar “excepciones
en nuestras interpretaciones para tratar de evitar caer en alguna contradicción. Un ejemplo de esto es precisamente la
función de intercambio() escrita en C, aquí podríamos llegar al punto de decir que estamos simulando un paso por
referencia, todo con el afán de acercarnos lo más posible al hecho de que estamos recibiendo la variable original (aunque
en realidad no sea así).

Si ahora volvemos a la definición que hemos trabajado con tanto empeño en esta nota, verás que ambas versiones de la
función ya descrita caen, sin ningún problema, en el modo de “paso por referencia”. ¿Qué es lo que falta? Conocer el
funcionamiento de la implementación de la referencia que estemos utilizando. En nuestro ejemplo anterior debemos
conocer cómo funcionan los apuntadores para el primer caso y, para el segundo, debemos de saber cómo funcionan las
referencias de C++.

Siendo las referencias de C++ muy sencillas de utilizar, pasemos a un nuevo ejemplo donde hablemos sobre los
apuntadores; para esto, utilicemos una función que crea un nuevo nodo para una lista enlazada:

mhtml:file://C:\Users\Rafael\Downloads\¿Cuándo se utiliza «paso por referencia» y c... 10/12/2019


¿Cuándo se utiliza «paso por referencia» y cuándo «paso por valor»? Página 7 de 10

1. typedef struct _Nodo {


2. int dato;
3. struct _Nodo *siguiente;
4. } Nodo;
5.
6. void crearNodo(Nodo* n, int d) {
7. n = malloc(sizeof(Nodo));
8. n->dato = d;
9. n->siguiente = NULL;
10. }
11.
12. // Probamos la función
13. Nodo *nuevo = NULL;
14. crearNodo(nuevo, 4);
15.
16. if (nuevo == NULL) {
17. printf("No se creo el nodo :(\n");
18. }
19. else {
20. printf("Nodo creado con exito :D\n");
21. }
22.
23. // SALIDA
24. // No se creo el nodo :(

Tristemente no fue posible crear un nuevo nodo, ¿por qué ha pasado esto? Bueno, resulta que nuestra referencia, o más
específicamente, nuestro apuntador, fue pasado por valor a la función crearNodo() . Esto quiere decir exactamente lo
estás pensando, recibimos una copia de la dirección de memoria y esta se almacena en el parámetro con nombre
el interior de nuestra función, desechamos dicha copia y le otorgamos a n un nuevo valor por medio de
Cuando volvemos al código que llamó a la función, podemos notar que el cambio realizado se ha perdido, nuestro
apuntador nuevo continúa teniendo el valor NULL .

¿Puedes ver lo que lo anterior implica? Veamos esta otra función donde ahora queremos cambiar solo el dato de un nodo:

1. void cambiarDato(Nodo* n, int d) {


2. n->dato = d;
3. }
4.
5. Nodo nd = {5, NULL};
6. printf("Dato inicial: %d\n", nd.dato);
7.
8. cambiarDato(&nd, 8);
9. printf("Dato nuevo: %d\n", nd.dato);
10.
11. // SALIDA
12. // Dato inicial: 5
13. // Dato nuevo: 8

Antes de continuar, ¿podrías decir si es un “paso por valor” o “paso por referencia” lo que estamos realizando en la
función cambiarDato() ? Si utilizas todo lo que hemos visto hasta ahora, deberías llegar a la conclusión de que
utilizando ambos. ¿Cómo es eso? Bueno, si hablas del nodo que se está pasando, este está siendo pasado por
referencia, la referencia en cuestión es la dirección de memoria del nodo. Ahora, si hablamos de la referencia
misma, esta está siendo pasada por valor, se genera una copia de la dirección de memoria y se almacena en el
parámetro n de la función.

Ahora sí, ¿por qué se realizó el cambio que buscábamos? Se debe a que no hicimos cambio alguno en el valor del
apuntador que tenemos como parámetro, la asignación fue realizada sobre el campo de la estructura a la que nos
estamos refiriendo con ese apuntador. En otras palabras, no cambiamos la dirección que se refiere a la estructura,
cambiamos el contenido de la estructura misma.

mhtml:file://C:\Users\Rafael\Downloads\¿Cuándo se utiliza «paso por referencia» y c... 10/12/2019


¿Cuándo se utiliza «paso por referencia» y cuándo «paso por valor»? Página 8 de 10

Volviendo al código que aparece al inicio de esta nota, seguro ya puedes darte una idea de por qué no está realizando lo
que se quiere. La respuesta tiene mucho que ver con lo que acabamos de discutir, por tanto, ¿qué te parece si te lo dejo
como ejercicio? Una vez que lo hayas resuelto, puedes pasar al link que dejaré al final y verificar tu respuesta. Si te
gustan los retos, puedes tratar de crear un método intercambio() en Java (de igual manera te dejaré un link
una aparente solución).

En conclusión

En un principio puede parecer poca cosa pero, en esta ocasión, te has dado cuenta cuán importante es conocer la
definición de algún término dependiendo del contexto en el que este se encuentre. A diferencia de aquellos con
experiencia en los lenguajes citados en esta nota, para las personas que recién comienzan a aprender, todo esto resulta
muy confuso al ser común que se utilicen los mismos términos para cosas que tienen una función completamente
diferente.

Casos como este aparecerán en multitud de lugares y por eso es importante que investigues bien los significados de
acuerdo al área donde te encuentres. Leer la documentación es el primer paso a dar frente a cualquier duda, de ahí en
más solo queda preguntar o experimentar por tu propia cuenta.

Te felicito y agradezco si lograste leer completamente hasta aquí. Espero esta nota haya sido de tu agrado y que
cumplido su propósito de aclarar ese problema tan frecuente al que muchos nos enfrentamos cuando llegamos a conocer
esos dos modos de pasar una variable. Cualquier comentario o sugerencia puedes colocarla directamente en los
comentarios. Nos vemos en una siguiente entrega, hasta entonces.

Repositorio de código

https://github.com/codingornot/Paso-por-referencia-y-paso-por-valor

Referencias

Sintes, T. (2000, Mayo 26). Does Java pass by reference or pass by value? Recuperado
de http://www.javaworld.com/article/2077424/learn-java/does-java-pass-by-reference-or-pass-by-value.html

Java passes by value. (2014, Noviembre 13). Recuperado de http://wiki.c2.com/?JavaPassesByValue

Pass by reference. Recuperado de http://clc-wiki.net/wiki/C_language:Terms:Pass_by_reference

Reddit. Recuperado de https://www.reddit.com/r/programming/comments/yitzw/is_c_pass_by_value_or_reference/

Jacobson, S. An overview of C++ references. Recuperado de http://www-cs-students.stanford.edu/~sjac/c-to-cpp


info/references

Pass by reference vs. pass by value. Recuperado de https://www.cs.fsu.edu/~myers/c++/notes/references.html

mhtml:file://C:\Users\Rafael\Downloads\¿Cuándo se utiliza «paso por referencia» y c... 10/12/2019


¿Cuándo se utiliza «paso por referencia» y cuándo «paso por valor»? Página 9 de 10

Flanagan, D. (2005). Java in a nutshell. O’Reilly Media.

Ritchie, D. M. (1988). The C Programming Language. Prentice Hall.

Gosling, J. (2005). The Java Programming Language. Addison-Wesley Professional.

APUNTADORES C C LANGUAGE DIFERENCIAS DIRECCIÓN DE MEMORIA FUNCIONES JAVA LENGUAJES


DE
PROGRAMACIÓN

OBJETOS PARÁMETROS PASO POR REFERENCIA PASO POR VALOR PROGRAMACIÓN REFERENCIAS

5 recomendaciones de lenguajes de programación para aprender en 2017


¿Qué son los snippets y cómo crear uno propio usando Atom?

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Comentario

Nombre *

Correo electrónico *

Web

Publicar comentario

mhtml:file://C:\Users\Rafael\Downloads\¿Cuándo se utiliza «paso por referencia» y c... 10/12/2019


¿Cuándo se utiliza «paso por referencia» y cuándo «paso por valor»? Página 10 de 10

Powered by WordPress and Maxwell.

mhtml:file://C:\Users\Rafael\Downloads\¿Cuándo se utiliza «paso por referencia» y c... 10/12/2019

También podría gustarte