Menu
Coddy logo textTech

Const Correctness

Parte de la sección Object Oriented Programming del Journey de C de Coddy — lección 8 de 61.

Al escribir funciones que actúan como métodos, algunas deberían modificar el objeto (como player_take_damage), mientras que otras solo deberían leer datos sin cambiar nada. La palabra clave const te permite aplicar esta distinción a nivel del compilador.

Al marcar un parámetro de puntero como const, estás prometiendo que la función no modificará los datos a los que apunta. Si intentas cambiar un miembro accidentalmente, el compilador producirá un error:

typedef struct {
    int x;
    int y;
} Point;

// Esta función solo puede LEER el punto
void point_print(const Point *self) {
    printf("(%d, %d)\n", self->x, self->y);
    // self->x = 10;  // ERROR: no se puede modificar a través de un puntero const
}

// Esta función puede MODIFICAR el punto
void point_move(Point *self, int dx, int dy) {
    self->x += dx;
    self->y += dy;
}

El parámetro const Point *self indica tanto al compilador como a otros programadores que point_print es un "getter" o una operación de solo lectura. Esto se llama const correctness: el uso de const siempre que no sea necesaria una modificación.

Esta práctica detecta errores de forma temprana. Si escribes una función display y accidentalmente modificas un campo, el compilador te detiene inmediatamente en lugar de permitir que el error se cuele en tu programa.

challenge icon

Desafío

Fácil

Vamos a construir un módulo Temperature que almacena un valor de temperatura y proporciona operaciones tanto de solo lectura como de modificación. Esto te ayudará a practicar el uso de punteros const para distinguir claramente entre las funciones que solo leen datos y aquellas que los cambian.

Crearás tres archivos:

  • temperature.h: Declara una estructura Temperature con un único miembro double celsius. También declara tres funciones:
    • temp_display — recibe un puntero const a Temperature e imprime la temperatura actual (solo lectura)
    • temp_adjust — recibe un puntero normal a Temperature y un valor double amount, luego suma esa cantidad a celsius (modificación)
    • temp_to_fahrenheit — recibe un puntero const a Temperature y devuelve el valor convertido a Fahrenheit (solo lectura)
    Usa protectores de inclusión (include guards) con el símbolo TEMPERATURE_H.
  • temperature.c: Implementa las tres funciones. La función temp_display debe imprimir en el formato "Current: %.1fC\n". La función temp_to_fahrenheit debe devolver celsius * 9.0 / 5.0 + 32.0. Recuerda que las funciones que usan punteros const no pueden modificar los datos de la estructura.
  • main.c: Crea una Temperature, realiza operaciones y muestra los resultados.

Recibirás dos entradas: el valor inicial en celsius (como un double) y la cantidad de ajuste (como un double).

En tu archivo principal:

  1. Inicializa una Temperature con el valor inicial en celsius
  2. Llama a temp_display para mostrar la temperatura inicial
  3. Llama a temp_adjust para modificar la temperatura según la cantidad de ajuste
  4. Llama a temp_display de nuevo para mostrar la temperatura actualizada
  5. Imprime la conversión a Fahrenheit usando temp_to_fahrenheit

Imprime los resultados en este formato:

Current: {celsius}C
Current: {celsius}C
Fahrenheit: {fahrenheit}F

Usa %.1f para todos los valores de temperatura para mostrar un decimal.

Por ejemplo, con un valor inicial de 20.0 y un ajuste de 5.0, la salida sería:

Current: 20.0C
Current: 25.0C
Fahrenheit: 77.0F

Hoja de referencia

La palabra clave const puede usarse con parámetros de puntero para indicar que una función no modificará los datos a los que se apunta. Esto se llama const correctness.

Cuando un parámetro de puntero se marca como const, el compilador evitará cualquier modificación de los datos a través de ese puntero:

typedef struct {
    int x;
    int y;
} Point;

// Función de solo lectura - no puede modificar el punto
void point_print(const Point *self) {
    printf("(%d, %d)\n", self->x, self->y);
    // self->x = 10;  // ERROR: no se puede modificar a través de un puntero const
}

// Función de modificación - puede cambiar el punto
void point_move(Point *self, int dx, int dy) {
    self->x += dx;
    self->y += dy;
}

El uso de const Point *self comunica tanto al compilador como a otros programadores que la función es una operación de solo lectura. Esto ayuda a detectar errores a tiempo: si accidentalmente intentas modificar datos en una función que no debería cambiar nada, el compilador producirá un error de inmediato.

Mejor práctica: Usa const para parámetros de puntero siempre que la función no necesite modificar los datos. Esto hace que la intención de tu código sea más clara y evita modificaciones accidentales.

Pruébalo tú mismo

#include <stdio.h>
#include "temperature.h"

int main() {
    double initial_celsius, adjustment;
    scanf("%lf", &initial_celsius);
    scanf("%lf", &adjustment);
    
    // TODO: Crear una estructura Temperature e inicializarla con initial_celsius
    
    // TODO: Llamar a temp_display para mostrar la temperatura inicial
    
    // TODO: Llamar a temp_adjust para modificar la temperatura por la cantidad de ajuste
    
    // TODO: Llamar a temp_display de nuevo para mostrar la temperatura actualizada
    
    // TODO: Imprimir la conversión a Fahrenheit usando temp_to_fahrenheit
    // Formato: "Fahrenheit: %.1fF\n"
    
    return 0;
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Object Oriented Programming