Menu
Coddy logo textTech

Const Correctness

Parte da seção Object Oriented Programming do Journey de C da Coddy — lição 8 de 61.

Ao escrever funções que atuam como métodos, algumas devem modificar o objeto (como player_take_damage), enquanto outras devem apenas ler dados sem alterar nada. A palavra-chave const permite que você aplique essa distinção no nível do compilador.

Ao marcar um parâmetro de ponteiro como const, você está prometendo que a função não modificará os dados para os quais ele aponta. Se você tentar alterar um membro acidentalmente, o compilador produzirá um erro:

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

// Esta função pode apenas LER o ponto
void point_print(const Point *self) {
    printf("(%d, %d)\n", self->x, self->y);
    // self->x = 10;  // ERRO: não é possível modificar através de um ponteiro const
}

// Esta função pode MODIFICAR o ponto
void point_move(Point *self, int dx, int dy) {
    self->x += dx;
    self->y += dy;
}

O parâmetro const Point *self informa tanto ao compilador quanto a outros programadores que point_print é um "getter" ou uma operação de apenas leitura. Isso é chamado de const correctness—usar const sempre que a modificação não for necessária.

Essa prática detecta bugs precocemente. Se você escrever uma função display e acidentalmente modificar um campo, o compilador interrompe você imediatamente em vez de deixar o bug passar para o seu programa.

challenge icon

Desafio

Fácil

Vamos construir um módulo Temperature que armazena um valor de temperatura e fornece operações de leitura e modificação. Isso ajudará você a praticar o uso de ponteiros const para distinguir claramente entre funções que apenas leem dados e aquelas que os alteram.

Você criará três arquivos:

  • temperature.h: Declare uma struct Temperature com um único membro double celsius. Também declare três funções:
    • temp_display — recebe um ponteiro const para Temperature e imprime a temperatura atual (somente leitura)
    • temp_adjust — recebe um ponteiro comum para Temperature e um valor double, então adiciona o valor ao celsius (modificação)
    • temp_to_fahrenheit — recebe um ponteiro const para Temperature e retorna o valor convertido para Fahrenheit (somente leitura)
    Use include guards com o símbolo TEMPERATURE_H.
  • temperature.c: Implemente as três funções. A função temp_display deve imprimir no formato Current: %.1fC\n. A função temp_to_fahrenheit deve retornar celsius * 9.0 / 5.0 + 32.0. Lembre-se de que funções que usam ponteiros const não podem modificar os dados da struct.
  • main.c: Crie uma Temperature, realize operações e exiba os resultados.

Você receberá duas entradas: o valor inicial em celsius (como um double) e o valor de ajuste (como um double).

No seu arquivo principal:

  1. Inicialize uma Temperature com o valor inicial em celsius
  2. Chame temp_display para mostrar a temperatura inicial
  3. Chame temp_adjust para modificar a temperatura pelo valor de ajuste
  4. Chame temp_display novamente para mostrar a temperatura atualizada
  5. Imprima a conversão para Fahrenheit usando temp_to_fahrenheit

Imprima os resultados neste formato:

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

Use %.1f para todos os valores de temperatura para exibir uma casa decimal.

Por exemplo, com um valor inicial de 20.0 e ajuste de 5.0, a saída seria:

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

Folha de consulta

A palavra-chave const pode ser usada com parâmetros de ponteiro para indicar que uma função não modificará os dados que estão sendo apontados. Isso é chamado de const correctness.

Quando um parâmetro de ponteiro é marcado como const, o compilador impedirá quaisquer modificações nos dados através desse ponteiro:

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

// Função somente leitura - não pode modificar o ponto
void point_print(const Point *self) {
    printf("(%d, %d)\n", self->x, self->y);
    // self->x = 10;  // ERRO: não é possível modificar através de um ponteiro const
}

// Função de modificação - pode alterar o ponto
void point_move(Point *self, int dx, int dy) {
    self->x += dx;
    self->y += dy;
}

Usar const Point *self comunica tanto ao compilador quanto a outros programadores que a função é uma operação de somente leitura. Isso ajuda a capturar bugs precocemente — se você acidentalmente tentar modificar dados em uma função que não deveria alterar nada, o compilador produzirá um erro imediatamente.

Melhor prática: Use const para parâmetros de ponteiro sempre que a função não precisar modificar os dados. Isso torna a intenção do seu código mais clara e evita modificações acidentais.

Experimente você mesmo

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

int main() {
    double initial_celsius, adjustment;
    scanf("%lf", &initial_celsius);
    scanf("%lf", &adjustment);
    
    // TODO: Crie uma struct Temperature e inicialize-a com initial_celsius
    
    // TODO: Chame temp_display para mostrar a temperatura inicial
    
    // TODO: Chame temp_adjust para modificar a temperatura pelo valor de adjustment
    
    // TODO: Chame temp_display novamente para mostrar a temperatura atualizada
    
    // TODO: Imprima a conversão para Fahrenheit usando temp_to_fahrenheit
    // Formato: "Fahrenheit: %.1fF\n"
    
    return 0;
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Object Oriented Programming