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
EasyLet'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 aTemperaturestruct with a singledouble celsiusmember. Also declare three functions:temp_display— takes aconstpointer 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 aconstpointer to Temperature and returns the value converted to Fahrenheit (read-only)
TEMPERATURE_H.temperature.c: Implement all three functions. Thetemp_displayfunction should print in the formatCurrent: {celsius}C. Thetemp_to_fahrenheitfunction should returncelsius * 9.0 / 5.0 + 32.0. Remember that functions usingconstpointers 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:
- Initialize a
Temperaturewith the initial celsius value - Call
temp_displayto show the starting temperature - Call
temp_adjustto modify the temperature by the adjustment amount - Call
temp_displayagain to show the updated temperature - Print the Fahrenheit conversion using
temp_to_fahrenheit
Print the results in this format:
Current: {celsius}C
Current: {celsius}C
Fahrenheit: {fahrenheit}FUse %.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.0FCheat 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;
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Modular Programming Basics
Header FilesInclude GuardsSource FilesStatic FunctionsRecap: Modular Calculator4Encapsulation
Opaque Pointers ConceptDefining Opaque StructsGetters and SettersValidation in SettersRecap: Secret Box2Objects and Methods
Structs as ObjectsThe 'Self' PointerConst CorrectnessPointer vs ValueHelper MethodsRecap: Point Manager5Project: Simple Bank Account
Project SetupImplementation of Account3Object Lifecycle
Constructor PatternDestructor PatternStack InitializationDeep CopyRecap: String Wrapper6Inheritance via Composition
Struct EmbeddingThe First Member RuleAccessing Parent MembersUpcastingRecap: Shape Hierarchy