Menu
Coddy logo textTech

Const Correctness

Part of the Object Oriented Programming section of Coddy's C journey — lesson 8 of 61.

When writing functions that act as methods, some should modify the object (like player_take_damage), while others should only read data without changing anything. The const keyword lets you enforce this distinction at the compiler level.

By marking a pointer parameter as const, you're promising that the function won't modify the data it points to. If you accidentally try to change a member, the compiler will produce an error:

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

// This function can only READ the point
void point_print(const Point *self) {
    printf("(%d, %d)\n", self->x, self->y);
    // self->x = 10;  // ERROR: cannot modify through const pointer
}

// This function can MODIFY the point
void point_move(Point *self, int dx, int dy) {
    self->x += dx;
    self->y += dy;
}

The const Point *self parameter tells both the compiler and other programmers that point_print is a "getter" or read-only operation. This is called const correctness—using const wherever modification isn't needed.

This practice catches bugs early. If you write a display function and accidentally modify a field, the compiler stops you immediately rather than letting the bug slip into your program.

challenge icon

Challenge

Easy

Let's build a Temperature module that stores a temperature value and provides both read-only and modifying operations. This will help you practice using const pointers to clearly distinguish between functions that just read data and those that change it.

You'll create three files:

  • temperature.h: Declare a Temperature struct with a single double celsius member. Also declare three functions:
    • temp_display — takes a const pointer to Temperature and prints the current temperature (read-only)
    • temp_adjust — takes a regular pointer to Temperature and a double amount, then adds the amount to celsius (modifying)
    • temp_to_fahrenheit — takes a const pointer to Temperature and returns the value converted to Fahrenheit (read-only)
    Use include guards with the symbol TEMPERATURE_H.
  • temperature.c: Implement all three functions. The temp_display function should print in the format Current: {celsius}C. The temp_to_fahrenheit function should return celsius * 9.0 / 5.0 + 32.0. Remember that functions using const pointers cannot modify the struct's data.
  • main.c: Create a Temperature, perform operations, and display results.

You will receive two inputs: the initial celsius value (as a double) and the adjustment amount (as a double).

In your main file:

  1. Initialize a Temperature with the initial celsius value
  2. Call temp_display to show the starting temperature
  3. Call temp_adjust to modify the temperature by the adjustment amount
  4. Call temp_display again to show the updated temperature
  5. Print the Fahrenheit conversion using temp_to_fahrenheit

Print the results in this format:

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

Use %.1f for all temperature values to display one decimal place.

For example, with an initial value of 20.0 and adjustment of 5.0, the output would be:

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

Cheat sheet

The const keyword can be used with pointer parameters to indicate that a function will not modify the data being pointed to. This is called const correctness.

When a pointer parameter is marked as const, the compiler will prevent any modifications to the data through that pointer:

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

// Read-only function - cannot modify the point
void point_print(const Point *self) {
    printf("(%d, %d)\n", self->x, self->y);
    // self->x = 10;  // ERROR: cannot modify through const pointer
}

// Modifying function - can change the point
void point_move(Point *self, int dx, int dy) {
    self->x += dx;
    self->y += dy;
}

Using const Point *self communicates to both the compiler and other programmers that the function is a read-only operation. This helps catch bugs early—if you accidentally try to modify data in a function that shouldn't change anything, the compiler will produce an error immediately.

Best practice: Use const for pointer parameters whenever the function doesn't need to modify the data. This makes your code's intent clearer and prevents accidental modifications.

Try it yourself

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

int main() {
    double initial_celsius, adjustment;
    scanf("%lf", &initial_celsius);
    scanf("%lf", &adjustment);
    
    // TODO: Create a Temperature struct and initialize it with initial_celsius
    
    // TODO: Call temp_display to show the starting temperature
    
    // TODO: Call temp_adjust to modify the temperature by the adjustment amount
    
    // TODO: Call temp_display again to show the updated temperature
    
    // TODO: Print the Fahrenheit conversion using temp_to_fahrenheit
    // Format: "Fahrenheit: %.1fF\n"
    
    return 0;
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming