Pasando por referencia en C
Si C no admite pasar una variable por referencia, ¿por qué funciona?
#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;
}
Producción:
$ gcc -std=c99 test.c
$ a.exe
i = 21
Porque estás pasando el valor del puntero al método y luego desreferenciandolo para obtener el número entero al que apunta.
Eso no es paso por referencia, es paso por valor como dijeron otros.
El lenguaje C se pasa por valor sin excepción. Pasar un puntero como parámetro no significa pasar por referencia.
La regla es la siguiente:
Una función no puede cambiar el valor real de los parámetros.
(La cita anterior es en realidad del libro K&R)
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 y variable
en la invocación de la función se llama parámetro real. Tenga en cuenta que el incremento param
en la función no cambia variable
.
#include <stdio.h>
void function(int param) {
printf("I've received value %d\n", param);
param++;
}
int main(void) {
int variable = 111;
function(variable);
printf("variable %d\m", variable);
return 0;
}
El resultado es
I've received value 111
variable=111
Ilusión de paso por referencia
Cambiamos ligeramente el fragmento de código. param
es un puntero ahora.
#include <stdio.h>
void function2(int *param) {
printf("I've received value %d\n", *param);
(*param)++;
}
int main(void) {
int variable = 111;
function2(&variable);
printf("variable %d\n", variable);
return 0;
}
El resultado es
I've received value 111
variable=112
Eso te hace creer que el parámetro fue pasado por referencia. No era. Se pasó por valor, siendo el valor del parámetro una dirección. El valor del tipo int se incrementó, y ese es el efecto secundario que nos hace pensar que fue una llamada a 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 escalares usamos direcciones (punteros). Veamos si eso puede ayudar.
#include <stdio.h>
void function2(int *param) {
printf("address param is pointing to %d\n", param);
param = NULL;
}
int main(void) {
int variable = 111;
int *ptr = &variable;
function2(ptr);
printf("address ptr is pointing to %d\n", ptr);
return 0;
}
El resultado será que las dos direcciones son iguales (no te preocupes por el valor exacto).
Resultado de ejemplo:
address param is pointing to -1846583468
address ptr is pointing to -1846583468
En mi opinión, esto demuestra claramente que los punteros se pasan por valor. De lo contrario ptr
sería NULL
después de la invocación de la función.
En C, el paso por referencia se simula pasando la dirección de una variable (un puntero) y eliminando la referencia de esa dirección dentro de la función para leer o escribir la variable real. Esto se denominará "paso por referencia estilo C".
Fuente: www-cs-students.stanford.edu
Porque no hay paso por referencia en el código anterior. El uso de punteros (como void func(int* p)
) es pasar por dirección. Esto es paso por referencia en C++ (no funcionará en C):
void func(int& ref) {ref = 4;}
...
int a;
func(a);
// a is 4 now