Si C no admite pasar una variable por referencia, ¿por qué funciona esto?
#include <stdio.h>
void f(int *j) {
(*j)++;
}
int main() {
int i = 20;
int *p = &i;
f(p);
printf("i = %d\n", i);
return 0;
}
Salida:
$ gcc -std=c99 test.c
$ a.exe
i = 21
&
) antes de llamar a la función y desreferenciarla explícitamente (con*
) en la función.f(&i);
esto es una implementación de pase por referencia, que no existe únicamente en C. C pase por referenciaRespuestas:
Porque pasa el valor del puntero al método y luego lo desreferencia para obtener el entero al que apunta.
fuente
func
:func(&A);
esto pasaría un puntero a A a la función sin copiar nada en absoluto. Es paso por valor, pero ese valor es una referencia, por lo que está 'pasando por referencia' la variable A. No se requiere copia. Es válido decir que es paso por referencia.Eso no es pasar por referencia, es pasar por valor como otros han dicho.
La regla es la siguiente:
Intentemos ver las diferencias entre los parámetros escalares y de puntero de una función.
Variables escalares
Este breve programa muestra el paso por valor utilizando una variable escalar.
param
se llama parámetro formal yvariable
en la invocación de la función se llama parámetro real. El incremento de notaparam
en la función no cambiavariable
.El resultado es
Ilusión de paso por referencia
Cambiamos un poco el código.
param
Es un puntero ahora.El resultado es
Eso te hace creer que el parámetro se pasó por referencia. No era. Se pasó por valor, el valor de parámetro es una dirección. El valor de tipo int se incrementó, y ese es el efecto secundario que nos hace pensar que era una llamada de función de paso por referencia.
Punteros - pasados por valor
¿Cómo podemos mostrar / probar ese hecho? Bueno, tal vez podamos probar el primer ejemplo de variables escalares, pero en lugar de escalar, usamos direcciones (punteros). Veamos si eso puede ayudar.
El resultado será que las dos direcciones son iguales (no se preocupe por el valor exacto).
Resultado de ejemplo:
En mi opinión, esto demuestra claramente que los punteros se pasan por valor. De
ptr
lo contrario seríaNULL
después de la invocación de la función.fuente
Fuente: www-cs-students.stanford.edu
fuente
Porque no hay paso por referencia en el código anterior. Usar punteros (como
void func(int* p)
) es pasar por dirección. Esto es paso por referencia en C ++ (no funcionará en C):fuente
Su ejemplo funciona porque está pasando la dirección de su variable a una función que manipula su valor con el operador de desreferencia .
Si bien C no admite tipos de datos de referencia , aún puede simular el paso por referencia pasando valores de puntero explícitamente, como en su ejemplo.
El tipo de datos de referencia de C ++ es menos potente pero se considera más seguro que el tipo de puntero heredado de C. Este sería su ejemplo, adaptado para usar referencias de C ++ :
fuente
Estás pasando un puntero (ubicación de la dirección) por valor .
Es como decir "aquí está el lugar con los datos que quiero que actualices".
fuente
p es una variable de puntero. Su valor es la dirección de i. Cuando llamas a f, pasas el valor de p, que es la dirección de i.
fuente
No hay referencia de paso en C, pero p "se refiere" a i, y usted pasa p por valor.
fuente
En C todo es paso por valor. El uso de punteros nos da la ilusión de que estamos pasando por referencia porque el valor de la variable cambia. Sin embargo, si imprimiera la dirección de la variable de puntero, verá que no se ve afectada. Se pasa una copia del valor de la dirección a la función. A continuación hay un fragmento que lo ilustra.
fuente
Porque está pasando un puntero (dirección de memoria) a la variable p en la función f. En otras palabras, está pasando un puntero, no una referencia.
fuente
Respuesta corta: Sí, C implementa el paso de parámetros por referencia utilizando punteros.
Al implementar el paso de parámetros, los diseñadores de lenguajes de programación utilizan tres estrategias diferentes (o modelos semánticos): transferir datos al subprograma, recibir datos del subprograma o hacer ambas cosas. Estos modelos se conocen comúnmente como en modo, modo fuera y modo fuera, correspondientemente.
Los diseñadores del lenguaje han diseñado varios modelos para implementar estas tres estrategias de paso de parámetros elementales:
Paso por valor (semántica en modo) Paso por resultado (semántica en modo fuera) Resultado por valor en paso (semántica en modo entrante) Paso por referencia (semántica en modo entrante) Paso por nombre (modo entrante) semántica)
Pass-by-reference es la segunda técnica para pasar parámetros en modo inout. En lugar de copiar datos entre la rutina principal y el subprograma, el sistema de tiempo de ejecución envía una ruta de acceso directo a los datos para el subprograma. En esta estrategia, el subprograma tiene acceso directo a los datos compartiendo efectivamente los datos con la rutina principal. La principal ventaja de esta técnica es que es absolutamente eficiente en tiempo y espacio porque no hay necesidad de duplicar espacio y no hay operaciones de copia de datos.
Implementación de paso de parámetros en C: C implementa la semántica de paso por valor y también de paso por referencia (en modo sin salida) utilizando punteros como parámetros. El puntero se envía al subprograma y no se copia ningún dato real. Sin embargo, debido a que un puntero es una ruta de acceso a los datos de la rutina principal, el subprograma puede cambiar los datos en la rutina principal. C adoptó este método de ALGOL68.
Implementación de paso de parámetros en C ++: C ++ también implementa la semántica de paso por referencia (en modo inout) usando punteros y también usando un tipo especial de puntero, llamado tipo de referencia. Los punteros de tipo de referencia se desreferencian implícitamente dentro del subprograma, pero su semántica también se pasa por referencia.
Entonces, el concepto clave aquí es que el paso por referencia implementa una ruta de acceso a los datos en lugar de copiar los datos en el subprograma. Las rutas de acceso a datos pueden ser punteros desreferenciados explícitamente o punteros desreferenciados automáticamente (tipo de referencia).
Para obtener más información, consulte el libro Conceptos de lenguajes de programación de Robert Sebesta, décima edición, capítulo 9.
fuente
No estás pasando un int por referencia, estás pasando un puntero a un int por valor. Sintaxis diferente, mismo significado.
fuente
void func(int* ptr){ *ptr=111; int newValue=500; ptr = &newvalue }
conint main(){ int value=0; func(&value); printf("%i\n",value); return 0; }
, imprime 111 en lugar de 500. Si está pasando por referencia, debería imprimir 500. C no admite parámetros de paso por referencia.ptr = &newvalue
no se permitirá. Independientemente de la diferencia, creo que está señalando que el "mismo significado" no es exactamente cierto porque también tiene una funcionalidad adicional en C (la capacidad de reasignar la "referencia" en sí misma).ptr=&newvalue
si se pasa por referencia. En su lugar, escribimosptr=newvalue
Aquí hay un ejemplo en C ++:void func(int& ptr){ ptr=111; int newValue=500; ptr = newValue; }
el valor del parámetro pasado a func () se convertirá500
.param = new Class()
dentro de una función no tendría ningún efecto para la persona que llama si se pasa por valor (puntero). Siparam
se pasa por referencia, los cambios serían visibles para la persona que llama.En C, para pasar por referencia, usa la dirección de operador
&
que debe usarse contra una variable, pero en su caso, dado que ha usado la variable de punterop
, no necesita prefijarla con la dirección de operador. Hubiera sido cierto si se ha utilizado&i
como parámetro:f(&i)
.También puede agregar esto, para desreferenciar
p
y ver cómo coincide ese valori
:fuente
Los punteros y las referencias son dos thigngs diferentes.
Un par de cosas que no he visto mencionadas.
Un puntero es la dirección de algo. Un puntero se puede almacenar y copiar como cualquier otra variable. Por lo tanto, tiene un tamaño.
Una referencia debe verse como un ALIAS de algo. No tiene un tamaño y no se puede almacenar. DEBE hacer referencia a algo, es decir. no puede ser nulo o cambiado. Bueno, a veces el compilador necesita almacenar la referencia como un puntero, pero eso es un detalle de implementación.
Con las referencias, no tiene problemas con los punteros, como el manejo de la propiedad, la verificación nula, la desreferenciación en uso.
fuente
'Pasar por referencia' (mediante el uso de punteros) ha estado en C desde el principio. ¿Por qué crees que no es así?
fuente
j
( no*j
) enf()
no tiene ningún efectoi
enmain()
.Creo que C, de hecho, admite pasar por referencia.
La mayoría de los idiomas requieren azúcar sintáctico para pasar por referencia en lugar de valor. (C ++, por ejemplo, requiere & en la declaración de parámetros).
C también requiere azúcar sintáctico para esto. Está * en la declaración de tipo de parámetro y & en el argumento. Entonces * y & es la sintaxis de C para pasar por referencia.
Ahora se podría argumentar que el pase real por referencia solo debería requerir sintaxis en la declaración del parámetro, no en el lado del argumento.
Pero ahora viene C #, que hace de soporte que pasa por referencia y requiere azúcar sintáctico en ambos lados de parámetros y argumentos.
El argumento de que C no tiene derivación de referencia hace que los elementos sintácticos que lo expresen exhiban la implementación técnica subyacente no es un argumento en absoluto, ya que esto se aplica más o menos a todas las implementaciones.
El único argumento restante es que pasar por ref en C no es una característica monolítica, sino que combina dos características existentes. (Tome la referencia del argumento por &, espere que la referencia escriba por *.) C #, por ejemplo, requiere dos elementos sintácticos, pero no se pueden usar el uno sin el otro.
Obviamente, este es un argumento peligroso, porque muchas otras características en los idiomas están compuestas de otras características. (como soporte de cadena en C ++)
fuente
Lo que está haciendo es pasar por valor, no pasar por referencia. Debido a que está enviando el valor de una variable 'p' a la función 'f' (en main como f (p);)
Se verá el mismo programa en C con paso por referencia, (!!! este programa da 2 errores ya que el paso por referencia no es compatible con C)
Salida:-
fuente