Introducción

Continuando con las funciones en C vamos a ver hoy cómo es la llamada a las mismas por referencia y por valor.

Cuando las llamamos por referencia podemos hacer cosas que no podemos con una simple llamada por valor.

Llamada por valor

Ya conocemos las funciones en las que llamamos por valor. Cabe mencionar que esto sólo aplica a las funciones que reciben argumentos.

En esas funciones, una copia de la variable es creada dentro de la llamada de la función, y no afecta a la original. Veamos este ejemplo de una función que incrementa un entero:

int incrementar(int numero){
 //Incrementar en 1
 numero = numero + 1;
}

No estamos devolviendo nada, estamos simplemente alterando a la variable que recibimos. Ahora lo llamamos así:

#include<stdio.h>

// Es una buena práctica definir el prototipo de las funciones aquí arriba
// ojo: sólo el prototipo, no el cuerpo
int incrementar(int numero);

int main(int argc, char const *argv[])
{
 int numero = 10;
 printf("Antes de llamar a la funcion, numero es %d\n", numero);
 incrementar(numero);
 printf("Despues de llamar a la funcion, numero es %d", numero);
}

// Ahora sí definimos la función con todo y cuerpo
int incrementar(int numero){
 //Incrementar en 1
 numero = numero + 1;
}

La salida del programa es:

Antes de llamar a la funcion, numero es 10
Despues de llamar a la funcion, numero es 10

Como vemos, se crea una nueva variable dentro de la función. Y aunque afectemos a la misma, la variable original sigue intacta. Esto es a lo que referimos cuando pasamos variables por valor.

Llamada por referencia

Una llamada por referencia ocurre cuando no pasamos el nombre de la variable, sino su dirección. En este caso no se crea una nueva variable.

Modifiquemos la función para que ahora reciba el puntero o apuntador a una variable, no una variable en sí. Quedaría así:

int incrementar(int *numero){
 //Incrementar en 1
 (*numero) = (*numero) + 1;
}

Ahora recibiremos direcciones de variables. Y al incrementar, incrementamos el valor que haya en la dirección que dijimos.

Corremos el programa con esto:

#include<stdio.h>

// Es una buena práctica definir el prototipo de las funciones aquí arriba
// ojo: sólo el prototipo, no el cuerpo
int incrementar(int *numero);

int main(int argc, char const *argv[])
{
 int numero = 10;
 printf("Antes de llamar a la funcion, numero es %d\n", numero);

 // Con el operador & obtenemos la dirección de numero
 incrementar(&numero);
 printf("Despues de llamar a la funcion, numero es %d", numero);
}

// Ahora sí definimos la función con todo y cuerpo
//Notar el * antes de numero
int incrementar(int *numero){
 //Incrementar en 1
 (*numero) = (*numero) + 1;
}

Notemos por favor el operador & que se encarga de obtener la dirección de memoria de una variable. Cuando ejecutamos el programa, la salida es:

Antes de llamar a la funcion, numero es 10
Despues de llamar a la funcion, numero es 11

Como vemos ahora sí se ha incrementado el número.

Usos de las llamadas por referencia

Las llamadas por referencia son más rápidas, ya que no creamos nuevos valores en la memoria.

Aparte del rendimiento, las funciones por referencia son usadas cuando queremos devolver dos variables; eso no es posible con una función normal, pero con una función por referencia sí lo es.

Veamos el caso de una función (sin sentido, pero sirve para ejemplificar) que devuelve dos números enteros. No puede hacer un return, en cambio mejor recibe a ambos números y a cada uno de ellos le asigna un valor.

#include<stdio.h>

// Es una buena práctica definir el prototipo de las funciones aquí arriba
// ojo: sólo el prototipo, no el cuerpo
int devolverEnteros(int *numero1, int *numero2);

int main(int argc, char const *argv[])
{
 int numero1 = 0, numero2 = 0;
 printf("Antes de llamar a la funcion, numero1 es %d y numero2 es %d\n", numero1, numero2);

 // Con el operador & obtenemos la dirección de numero
 devolverEnteros(&numero1, &numero2);
 printf("Despues de llamar a la funcion, numero1 es %d y numero2 es %d\n", numero1, numero2);
}

// Ahora sí definimos la función con todo y cuerpo
//Notar el * antes de numero
int devolverEnteros(int *numero1, int *numero2){
 (*numero1) = 10;
 (*numero2) = 20;
}

Con la siguiente salida:

Antes de llamar a la funcion, numero1 es 0 y numero2 es 0
Despues de llamar a la funcion, numero1 es 10 y numero2 es 20

Para intercambiar variables

Cuando queremos intercambiar una variable también hacemos uso de estas funciones.

Por ejemplo, si tenemos a= 50 y b = 85 y queremos intercambiarlas de modo que a = 85 y b = 50 podemos hacer esto:

#include<stdio.h>

// Es una buena práctica definir el prototipo de las funciones aquí arriba
// ojo: sólo el prototipo, no el cuerpo
int intercambiarEnteros(int *numero1, int *numero2);

int main(int argc, char const *argv[])
{
 int numero1 = 50, numero2 = 85;
 printf("Antes de llamar a la funcion, numero1 es %d y numero2 es %d\n", numero1, numero2);

 // Con el operador & obtenemos la dirección de las variables
 intercambiarEnteros(&numero1, &numero2);
 printf("Despues de llamar a la funcion, numero1 es %d y numero2 es %d\n", numero1, numero2);
}

// Ahora sí definimos la función con todo y cuerpo
int intercambiarEnteros(int *numero1, int *numero2){
 int temporal = (*numero1);
 (*numero1) = (*numero2);
 (*numero2) = temporal;
}

Primero ambas variables tienen un valor, la primera 50 y la segunda 85. Llamamos a la función que se encarga de intercambiarlas y al final la primera será 85 y la segunda 50:

Intercambio de variable: llamada por referencia en C

¿Quién usa llamadas por referencia?

En la API de SQLite para C, para abrir una base de datos llamamos a la función sqlite3_open que recibe el nombre y un apuntador a una variable de tipo sqlite3.

Si todo va bien, tendremos en la variable una referencia a la base de datos.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Ver comentarios

Entradas recientes

Creador de credenciales web – Aplicación gratuita

Hoy te voy a presentar un creador de credenciales que acabo de programar y que…

1 semana hace

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

2 semanas hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

2 semanas hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

2 semanas hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

2 semanas hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

2 semanas hace

Esta web usa cookies.