Cuando pasa una variable a una función, ¿por qué la función solo obtiene un duplicado de la variable?

Cuando pasa una variable a una función, ¿por qué la función solo obtiene una copia/duplicado de la variable?

int n=1;

void foo(int i)
{
    i++;
}

Como todos sabemos, la función foo() no puede cambiar el valor de n usando foo(n).

Por supuesto, podemos pasar la dirección de la variable para realizar algún cambio en la variable del parámetro.
¿Pero no crees que eso es un poco inconveniente?

¿Por qué c/c++ está diseñado para dar solo un duplicado a la función en lugar de dar directamente la variable "real" a la función?
¿Cuál es el pro/beneficio de este paradigma?


Actualizar:
He leído la respuesta de @paxdiablo. Creo que su explicación de "encapsulación, modularidad y localización del efecto" es buena.
Pero a mi manera, también puede preservar el valor del argumento del parámetro. También puede realizar encapsulación. De esta manera: (suponga que la función puede obtener directamente la variable "real" en lugar de un duplicado por defecto)

void foo(int n)
{
    int temp=n;
    //Do something to temp...

}

Y en mi camino, Se puede eliminar el mecanismo complicado, como "pasar por referencia" o puntero cuando desea cambiar el valor de los parámetros pasados. Ese es el beneficio.

Después de un tiempo de reflexión. ¡Me doy cuenta de que la razón por la cual c/c++ no está diseñado como propuse es solo por la INCONVENIENCIA de mi manera!
A mi manera, si una función tiene una larga lista de variables, sería terrible. Lo que pensé que es la forma más conveniente es de hecho inconveniente:
Debes escribir así:

void foo(int a,int b,double c,float d,char s...)
{
    int temp1=a;
    int temp2=b;
    double temp3=c;
    float temp4=d;
    char temp5=s;
    ...
    //Do something to temp{1,2,3,4,5....}

}

Entonces, los diseñadores de c/c++ introducen un mecanismo complejo para compensar con conveniencia.
¿Estoy en lo cierto?

preguntado el 31 de julio de 12 a las 09:07

@iammilind: NO. Entiendo bien los conceptos de pasar por referencia/valor.I No estoy preguntando eso. -

9 Respuestas

Hay básicamente dos escuelas de pensamiento sobre este asunto.

El primero es pass-by-value donde un copia del valor se crea para la función llamada.

La segunda es pass-by-reference donde el parámetro que aparece en la función llamada es un "alias" de la original. Eso significa que los cambios que le hagas se reflejarán en el original.

C es generalmente un lenguaje de paso por valor. Puede emular el paso por referencia pasando el dirección de una variable y luego usar eso para modificar el original:

void setTo42 (int *x) { *x = 42; }
:
int y;
setTo42 (&y);
// y is now 42

pero eso es más pasar el puntero a una variable por valor, que pasar la variable misma por referencia.

C++ tiene verdaderos tipos de referencia, posiblemente porque mucha gente tiene problemas con los punteros de C :-) Se hacen de la siguiente manera:

void setTo42 (int &x) { x = 42; }

:
int y;
setTo42 (y);
// y is now 42

El paso por valor suele ser preferible ya que limita los efectos que una función puede tener en el "mundo exterior": la encapsulación, la modularidad y la localización del efecto suelen ser algo bueno.

Ser capaz de modificar arbitrariamente cualquier parámetro pasado sería casi tan malo como las variables globales en términos de modularidad y gestión de código.

Sin embargo, a veces necesita pasar por referencia, ya que podría tener sentido cambiar una de las variables pasadas.

Respondido 31 Jul 12, 09:07

La mayoría de los lenguajes modernos están definidos para usar pasar por valor. La razón es simple: simplifica significativamente el razonamiento sobre el código si sabe que una función no puede cambiar su estado local. Siempre puede pasar por referencia no constante si quieres una función para poder modificar el estado local, pero tales casos deberían ser extremadamente raros.

EDITADO para responder a la pregunta actualizada:

No, no tienes razón. Pasar por valor es el mecanismo más simple para pasar parámetros. El paso por referencia o la copia de entrada/salida son más complejos (y, por supuesto, el reemplazo de expresiones de Algol es el más complicado).

Piénsalo por un momento. Considerar f(10). Con llamada por valor, el compilador simplemente empuja 10 en la pila, y la función solo accede al valor in situ. Con la llamada por referencia, el compilador debe crear un temporal, inicializarlo con 10y luego pasarle un puntero a la función. Dentro de la función, el compilador debe generar una indirección cada vez que accede al valor.

Además, la protección contra modificaciones dentro de la función realmente no ayuda a la legibilidad. Si la función no toma parámetros de referencia, sabe sin mirar dentro de la función que no puede modificar ninguna variable que pase como argumento. Independientemente de cómo alguien modifique la función en el futuro. (Incluso se podría argumentar que no se debe permitir que las funciones modifiquen el estado global. Lo que haría que la implementación de rand() Bastante difícil. Pero ciertamente ayudaría al optimizador).

Respondido 31 Jul 12, 11:07

Porque C pasa argumentos por valor.

De Kernighan & Richtie 2ª edición: (1.8 Llamada por valor) "En C, todos los argumentos de función se pasan por" valor ""

Respondido 31 Jul 12, 09:07

Si realmente desea que una función cambie su parámetro real, puede pasarla por referencia en C++

void foo(int& i)
{
    i++;
}

Respondido 31 Jul 12, 09:07

¡Vaya! No creo que entiendas lo que estoy preguntando... Sé cómo cambiarlo bastante bien. - duleshi

Es para asegurarse de que la función no cambie el valor original.

Respondido 31 Jul 12, 09:07

Supongo que una razón es la eficiencia, es más eficiente acceder a los valores directamente que a través de un puntero. Otra ventaja es la elección, la forma C/C++ en la que puede elegir pasar argumentos por valor o por puntero, su forma solo tiene la opción de pasar por puntero. Pero lo más importante es que pasar por valor significa que su función está aislada del resto de su código, y los cambios en las variables dentro de la función no afectan el resto del código. Créame, obtendría muchos más errores y la codificación sería más difícil si este no fuera el caso.

Respondido 31 Jul 12, 09:07

¿Cómo puede ser más eficiente? ¿Qué pasa si el argumento es un objeto de clase que contiene montones, montones de datos? Crear una copia de un objeto enorme cuando se pasa por valor es poco eficiente. - matemático 1975

Esto es cierto, estaba pensando en los tipos integrados. - jajaja

@mathematician1975: ¿Qué pasa si el argumento es un int (como el ejemplo del OP)? Copiarlo es eficiente y acceder a la copia directamente es más eficiente que acceder al original a través de un puntero sin referencia. Así es como puede ser más eficiente. - benjamin lindley

@BenjaminLindley Sí, totalmente de acuerdo. Solo decía que pasar por valor no es necesariamente más eficiente en TODOS los casos. - matemático 1975

Lo que sea. La eficiencia no es la principal motivación. El código correcto es. C (y otros lenguajes) aprendido de los errores de Fortran. (En las primeras versiones de Fortran, podría escribir algo como f(10)y la función f podría modificar el 10 para que tenga algún otro valor la próxima vez que ejecute esta línea.) - james kanze

Para cambiar el valor de un parámetro, debe pasar por referencia utilizando el símbolo '&'.

La razón por la que se hace esto es para que pueda elegir si desea o no que los cambios se mantengan con su variable. Si pasa por valor, puede estar seguro de que no cambiará y causará un error en su programa.

Respondido 31 Jul 12, 09:07

Una de las razones por las que C pasa por valor es que en FORTRAN, que pasa por referencia, era posible que pudiera llamar a una subrutina con una llamada como "CALL MYROUTINE(3)", y la subrutina cambiaría el valor de su argumento. Entonces, después de ese punto en el programa, “3” tendría el valor que le dio la subrutina.

Naturalmente, cuando esto ocurrió, causó una gran confusión. Hizo que los errores fueran difíciles de encontrar, porque el código fuente hizo algo muy diferente de lo que parecía hacer.

Entonces, como la gente ha aprendido acerca de los lenguajes de programación, uno de los principios utilizados en el diseño de lenguajes es evitar cosas que dificulten la comprensión del código o que aumenten la probabilidad de errores. (Este principio no siempre se aplica con éxito, ya que también estamos tentados a dar a los lenguajes de programación más poder expresivo y permitir que los compiladores optimicen el código).

Respondido 31 Jul 12, 10:07

Dependiendo de lo que estés tratando de hacer, puedes hacer esto:

int n = 1;

n = foo(n);

Solo asegúrese de que foo(int i) devuelva i después de modificarlo.

Respondido el 20 de junio de 20 a las 10:06

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.