Pregunta

He estado estudiando Java durante unos meses y ahora estoy empezando a aprender C.

Estoy un poco confundido, tenía la impresión de que pasar un objeto por referencia y pasar un puntero a ese objeto era lo mismo: pensé que la diferencia era que en Java todo el paso de objetos se realiza con punteros automáticamente, donde, como en C, uno tiene que esparcir pequeños asteriscos y símbolos aquí y allá. Recientemente, en una conversación, ¡me aseguraron que había una diferencia!

¿Cuál es la diferencia entre pasar por referencia y pasar un puntero?

¿Fue útil?

Solución

Ni Java ni C tiene paso por referencia. Ambos son estrictamente pasados ??por valor.

La semántica de paso por referencia significa que cuando cambia el valor del parámetro en el método, la persona que llama verá ese cambio en el argumento.

Ahora, puedes estar pensando: " ¡Pero ese es el caso en Java! Si cambio un objeto durante el método, la persona que llama ve ese cambio. & Quot; El objeto no es el parámetro. El parámetro es solo la variable, y si cambia el valor de esa variable, la persona que llama no verá eso. Por ejemplo:

public void foo(Object x)
{
    x = null;
}

public void caller()
{
    Object y = new Object();
    foo(y);
    // y is still not null!
}

Si el parámetro se realmente pasara por referencia, y sería nulo después. En su lugar, el valor de y es solo una referencia, y esa referencia se pasa por valor. Es confuso porque la palabra " referencia " Es en ambos términos, pero son cosas diferentes.

Puede consultar mi artículo sobre el paso de parámetros de C # para ver qué sería posible si Java tuviera una semántica de paso por referencia, como lo hace C # cuando (y solo cuando) usa la palabra clave ref .

También puede consultar los comentarios a my Respuesta de desbordamiento de pila relacionada con el tema.

Otros consejos

  

Pensé que la diferencia era que en Java todo el paso de objetos se realiza con punteros automáticamente, donde como en C uno tiene que rociar pequeños asteriscos y símbolos de aquí y allá.

Concepcional, eso es correcto. Si somos pedantes (y eso es bueno), incluso podemos decir que los objetos no se pasan en absoluto en Java. Lo que se pasa solo es siempre el " puntero " ;, que en Java se denomina referencia. Toda indirección se realiza automáticamente. Así que cuando hagas " objref- > foo " en lugar de "objref.foo" en C y no puede usar el punto porque trabaja con un puntero, en Java aún puede usar el punto porque de todos modos no sabe nada más para acceder a los miembros. En C, puede pasar el puntero (y aquí, en realidad se llama puntero) y puede pasar el objeto en sí, en cuyo caso se pasa una copia. En C, accede al objeto al que se refiere un puntero indirectamente usando la estrella o " - > " ;. En Java, la única forma en que se accede a los objetos de todos modos es usando el punto (objref.member).

Si volvemos a ser pedantes (ahora más importante otra vez), ni en Java ni en C hay "pasar por referencia". Lo que pasamos en Java es la referencia / puntero al objeto y en C pasamos una copia del objeto (caso obvio) o volvemos a pasar solo una copia de un puntero al objeto. Entonces, en ambos casos, Java y C, lo que pasamos son las direcciones de los objetos. Sin hablar de los tipos Java primitivos, que se copian tanto en Java como en C, aunque también se puede pasar su dirección en C, no hay diferencia entre un tipo agregado (es decir, una estructura) y un tipo primitivo. en C en que se refiere.

Las diferencias son sutiles. A nivel de ensamblaje, en ambos casos, la dirección del objeto se pasa a la función. Sin embargo, en el caso del puntero, el parámetro es un puntero independiente que se puede usar para modificar el objeto de destino (* pch = 'x') o se puede usar para acceder a un objeto diferente (pch = " newstr "). En el caso de referencia, el parámetro se desvía automáticamente al objeto de destino.

Creo que un puntero es una variable que contiene una referencia. Con & amp; puede obtener una dirección de memoria (referencia) y con * puede acceder al contenido de una dirección de memoria. Sugiero el libro El lenguaje de programación C .

Saludos

Verdadero paso por referencia significa que puede asignar un nuevo valor para la referencia, y este nuevo valor será visible en el contexto de llamada al igual que dentro del método llamado.

En Java, esto no es posible, porque las referencias a objetos se pasan por valor .

Algunas cosas

  • C no tiene referencias (a pesar de C ++)
  • Java no tiene punteros
  • La diferencia entre los punteros y las referencias es que los punteros son prácticamente direcciones de memoria con las que se puede calcular. Las referencias no se pueden calcular con
  • Java y C pasan por valor (al pasar un objeto en Java, la referencia se copia a la función)

Si estás estudiando C (en lugar de C ++), entonces no hay referencias.

El término " pasa por referencia " en C simplemente significa que está pasando un puntero como la dirección en la que se almacenará el valor, de modo que la función puede cambiar su valor. De lo contrario, está pasando por un valor, lo que significa que se genera una copia de la variable en la pila y las modificaciones no tienen impacto.

En muchos sentidos, esto es similar a lo que ve en Java, excepto que en Java no tiene que convertir explícitamente las cosas en un puntero o desreferenciarlas. En otras palabras, cuando pasa un puntero, la dirección se copia en la pila, por lo que si su función cambia el puntero (en lugar de los datos a los que apunta), los cambios desaparecen cuando termina la función. Del mismo modo, cuando pasa una referencia de objeto en Java, puede cambiar el contenido del objeto (por ejemplo, llamando a funciones), pero cambiar el varialbe para apuntar a otro objeto no tendrá ningún efecto una vez que se vaya.

Si estaba usando C ++ (que se parece a C), puede pasar por referencia, en cuyo caso no necesita tratar con punteros, y los cambios en la variable en la función en realidad cambian el valor externo directamente ( excepto que no puedes hacer que apunte a otra cosa).

Hay un artículo reciente de Eric Lippert sobre esto. Es un programador en el compilador de C #, pero lo que sea que diga tiene la generalidad suficiente para extenderse a otros lenguajes de GC como Java:

http: // blogs .msdn.com / ericlippert / archive / 2009/02/17 / references-are-not-Address.aspx

Cita del artículo:

  

Los punteros son estrictamente " más potentes " que las referencias; Cualquier cosa que puedas hacer con referencias que puedas hacer con punteros. [...]

     

Los punteros normalmente se implementan como direcciones. Una dirección es un número que es un desplazamiento en la "matriz de bytes". ese es todo el espacio de direcciones virtuales del proceso. [...]

     

Por todas estas razones, no describimos referencias como direcciones en la especificación. La especificación solo dice que una variable de tipo de referencia " almacena una referencia " a un objeto, y lo deja completamente vago en cuanto a cómo se podría implementar. De manera similar, una variable de puntero almacena " la dirección " De un objeto, que a su vez, queda bastante vago. En ninguna parte decimos que las referencias son las mismas que las direcciones.

     

Entonces, en C # una referencia es algo vago que le permite hacer referencia a un objeto. No puede hacer nada con una referencia, excepto desreferenciarla y compararla con otra referencia para la igualdad. Y en C # un puntero se identifica como una dirección.

     

En contraste con una referencia, puede hacer mucho más con un puntero que contiene una dirección. Las direcciones pueden ser manipuladas matemáticamente; puede restar uno de otro, puede agregarles números enteros, y así sucesivamente. Sus operaciones legales indican que son "números elegantes" ese índice en la " matriz " Ese es el espacio de direcciones virtuales del proceso.

Los lectores familiarizados con C / C ++ probablemente han notado que aparecen referencias a objetos Para ser similar a los punteros. Esta sospecha es, esencialmente, correcta. Una referencia de objeto es similar a un puntero de memoria. La principal diferencia & # 8212; y la clave para la seguridad de Java & # 8217; es que No puede manipular referencias como puede punteros reales. Por lo tanto, no puede causar un La referencia del objeto apunta a una ubicación de memoria arbitraria o la manipula como un entero.

  • java no es compatible & amp; operador, entonces, ¿cómo puede obtener la dirección del objeto en java?
  • En java la referencia se realiza por objeto, por ejemplo,

MyClass object1 = new MyClass ();

MyClass object2 = object1;

es decir, podría pensar que object1 y object2 se refieren a objetos separados y distintos. Sin embargo, esto estaría mal. En cambio, después de que se ejecute este fragmento, object1 y object2 se referirán al mismo objeto. si cambia en cualquier otro efecto

* no puede cambiar la dirección del objeto después de inicializar es decir, MyClass obj = new MyClass (); como referencia en c ++, con objeto puede cambiar solo el valor de instancia de objeto

Nota: java proporciona una característica especial         object1 se ha establecido en nulo, pero object2 todavía apunta al objeto original.

No estoy seguro acerca de Java, pero en C # o VB.net puede pasar por valor o por referencia

ejemplo de paso por referencia

    static void Main(string[] args)
    {
        int x = 1;
        Foo(ref x);
        Console.WriteLine(x.ToString());//this will print 2
    }

    private static void Foo(ref int x)
    {
        x++;
    }

note que x es igual a 1 pero cuando llama al método Foo y pasa x por refrencia cuando x se incrementa en uno en Foo, el valor original también se incrementa

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top