Inicialización en Stack
Parte de la sección Object Oriented Programming del Journey de C de Coddy — lección 14 de 61.
No todos los objetos necesitan residir en el heap. Cuando un struct es pequeño y tiene un tiempo de vida corto, asignarlo en el stack es más sencillo y rápido: sin malloc, sin free y sin riesgo de fugas de memoria.
En lugar de devolver un puntero, una función de fábrica puede devolver el struct por valor. El struct completo se copia al llamador:
typedef struct {
int x;
int y;
} Point;
Point create_point(int x, int y) {
Point p;
p.x = x;
p.y = y;
return p;
}
El llamador recibe una copia completamente inicializada:
Point origin = create_point(0, 0);
Point cursor = create_point(100, 50);
printf("Cursor: (%d, %d)\n", cursor.x, cursor.y);
Sin punteros, no se requiere limpieza. Cuando origin y cursor salen de ámbito, se destruyen automáticamente.
Este enfoque funciona mejor para structs pequeñas sin miembros asignados dinámicamente. Para objetos más grandes o aquellos que contienen punteros a la memoria heap, el patrón de constructor con malloc sigue siendo la mejor opción.
Desafío
FácilVamos a construir un módulo Temperature que crea lecturas de temperatura en el stack utilizando una función de fábrica (factory function). A diferencia de los constructores basados en el heap de lecciones anteriores, este enfoque devuelve la estructura por valor: sin malloc, sin free, solo una asignación en el stack simple y eficiente.
Crearás tres archivos:
temperature.h: Declara una estructuraTemperaturecon dos miembros:double celsiusychar scale(para almacenar'C'para Celsius). También declara dos funciones:create_temperature— toma un valor double y devuelve una estructuraTemperaturepor valor (¡no un puntero!)temperature_to_fahrenheit— toma unconst Temperature *y devuelve la temperatura equivalente en Fahrenheit como un double
TEMPERATURE_H.temperature.c: Implementa ambas funciones. Tu función de fábrica debe crear una variable localTemperature, inicializar sus campos (establecescalea'C') y devolverla. La fórmula de conversión es:fahrenheit = celsius * 9.0 / 5.0 + 32.0main.c: Usa tu función de fábrica para crear una lectura de temperatura y mostrar tanto el valor en Celsius como en Fahrenheit.
Recibirás una entrada: la temperatura en Celsius (como un double).
En tu archivo principal, usa create_temperature para crear una estructura Temperature con el valor dado. Luego imprime el valor original en Celsius y su equivalente en Fahrenheit.
Imprime la salida en este formato:
Celsius: {celsius}
Fahrenheit: {fahrenheit}Usa %.2f para ambos valores para mostrar dos decimales.
Por ejemplo, con una entrada de 25.0, la salida sería:
Celsius: 25.00
Fahrenheit: 77.00Observa lo limpio que es este enfoque: recibes una estructura completamente inicializada sin preocupaciones de gestión de memoria. Cuando tu variable Temperature sale de su ámbito (scope), se limpia automáticamente.
Hoja de referencia
Las funciones de fábrica pueden devolver structs por valor en lugar de punteros. Esto asigna el struct en la pila (stack): sin malloc, sin free y sin fugas de memoria.
Ejemplo de una función de fábrica que devuelve por valor:
typedef struct {
int x;
int y;
} Point;
Point create_point(int x, int y) {
Point p;
p.x = x;
p.y = y;
return p;
}
Uso de la función de fábrica:
Point origin = create_point(0, 0);
Point cursor = create_point(100, 50);
printf("Cursor: (%d, %d)\n", cursor.x, cursor.y);
El struct se copia al llamador y se destruye automáticamente cuando sale de su ámbito (scope). Este enfoque funciona mejor para structs pequeños sin miembros asignados dinámicamente.
Pruébalo tú mismo
#include <stdio.h>
#include "temperature.h"
int main() {
double celsius_input;
scanf("%lf", &celsius_input);
// TODO: Usa create_temperature para crear una struct Temperature
// TODO: Imprime el valor Celsius usando el formato %.2f
// TODO: Usa temperature_to_fahrenheit para convertir e imprimir el valor Fahrenheit
return 0;
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Object Oriented Programming
1Fundamentos de programación modular
Archivos de cabeceraGuardas de inclusiónArchivos fuenteFunciones estáticasRepaso: Calculadora modular4Encapsulamiento
Concepto de punteros opacosDefinición de structs opacosGetters y SettersValidación en settersResumen: Caja secreta7Punteros a funciones
Declaración de punteros a funcionesLlamada a punteros a funcionesTypedef para punteros a funcionesPasar funciones como argumentosRepaso: Dispatch de calculadora10Contenedores genéricos
Repaso de punteros voidWrapper genéricoSwap genéricoComparación genéricaRepaso: Array genérico2Objetos y métodos
Structs como objetosEl puntero 'Self'Const CorrectnessPuntero vs. ValorMétodos auxiliaresResumen: Point Manager5Proyecto: Cuenta bancaria simple
Configuración del proyectoImplementación de la cuenta3Ciclo de vida de los objetos
Patrón ConstructorPatrón DestructorInicialización en StackCopia profundaResumen: String Wrapper6Herencia mediante composición
Incrustación de StructsLa regla del primer miembroAcceso a miembros padreUpcastingResumen: Jerarquía de formas9Proyecto: Dibujador de figuras
Descripción general del proyectoImplementación del círculo