En el lenguaje C, al pasar una estructura a una función por valor, se crea una copia completa de la estructura en la memoria temporal (generalmente en la pila de la función). Esto significa que cualquier cambio dentro de la función no afectará al instancia original de la estructura fuera de la función.
Al pasar estructuras grandes por valor, se enfrenta a costos de tiempo y memoria debido a la necesidad de copiar todos los miembros de la estructura. Por lo tanto, la práctica estándar es pasar un puntero a la estructura:
#include <stdio.h> struct Data { int arr[1000]; int flag; }; void modify_by_value(struct Data d) { d.flag = 10; // Solo cambiará la copia local } void modify_by_pointer(struct Data *d) { d->flag = 20; // Cambiará el original } int main() { struct Data data = { {0}, 0 }; modify_by_value(data); // data.flag == 0 modify_by_pointer(&data); // data.flag == 20 return 0; }
Ventajas de pasar por puntero:
Desventajas de pasar por valor:
¿Qué pasará si la función devuelve una estructura por valor? ¿Qué riesgos existen?
Respuesta:
En C se pueden devolver estructuras por valor desde una función, por ejemplo:
struct Point { int x, y; }; struct Point make_point(int x, int y) { struct Point p = {x, y}; return p; // se devuelve una copia }
El principal riesgo es el rendimiento: se crea y devuelve una copia de la estructura. Además, si se devuelve erróneamente la dirección de una variable local, la estructura puede apuntar a una memoria inválida:
struct Point* bad() { struct Point p = {1, 2}; return &p; // error: devolución de la dirección de una variable local }
Historia
En dispositivos embebidos con poca pila, un desarrollador pasó una estructura grande (1 KB) por valor, lo que provocó un desbordamiento de pila y fallos esporádicos del sistema. La investigación mostró que la copia de cada estructura causaba falta de memoria en la pila con profundidades de llamada elevadas.
Historia
En un sistema de servidor corporativo, un programador devolvió un puntero a una estructura local y el código tuvo acceso a punteros "colgantes" después de salir de la función. Esto se manifestó como un fallo crítico en producción con baja reproducibilidad.
Historia
En un proyecto de código abierto, el rendimiento cayó drásticamente después de cambiar a una función que devolvía por valor una estructura compleja con arreglos internos. Un perfilador reveló los costos de tiempo del procesador en copias innecesarias de estructuras.