C/C++ Arena

Step 4 of 7

const-correct interfaces

In a header, each function signature is a contract with every caller. Pointer parameters raise one question above all: will this function modify what I pass in? const answers it in the signature itself:

size_t count_alive(const Player *team, size_t n);   /* only reads */
void heal_all(Player *team, size_t n, int amount);  /* modifies */

Why it matters

#include <stdio.h>
#include <stddef.h>

typedef struct {
    const char *name;
    int stock;
} Item;

int total_stock(const Item *items, size_t n) {
    int sum = 0;
    for (size_t i = 0; i < n; i++) sum += items[i].stock;
    return sum;
}

void restock(Item *items, size_t n, int amount) {
    for (size_t i = 0; i < n; i++) items[i].stock += amount;
}

int main(void) {
    Item shop[] = {{"pen", 3}, {"cup", 0}};
    restock(shop, 2, 5);
    static const Item catalog[] = {{"lamp", 2}, {"desk", 1}};
    printf("%d %d\n", total_stock(shop, 2), total_stock(catalog, 2));
    return 0;
}
13 3

total_stock accepts both the modifiable shop and the read-only catalog, because it promises not to change either. restock(catalog, ...) gets a warning, and for good reason: it would write to data declared const, which is undefined behavior.

Get it right early

Adding const later is painful: once a function takes const Item *, every function it passes that pointer to must also take const, all the way down. That ripple is why experienced C programmers make parameters const from the start, whenever the function only reads.

Your turn: fix the three signatures. The read-only ones need const; heal_all really does modify the team, so it must stay non-const.

Previous: extern and shared state Next: Command-line arguments