Step 3 of 7
Pointers to structs and ->
To let a function change a struct, or to avoid copying a big one, pass a pointer to it. You'd then write (*p).kills to reach a member (the parentheses are needed because . binds tighter than *). That's so common that C has a shortcut: p->kills means exactly (*p).kills.
#include <stdio.h>
struct Account {
const char *owner;
int balance;
};
int withdraw(struct Account *a, int amount) {
if (amount > a->balance) {
return 0;
}
a->balance -= amount;
return 1;
}
int main(void) {
struct Account acc = {"Ada", 100};
int ok1 = withdraw(&acc, 30);
int ok2 = withdraw(&acc, 500);
printf("%d %d balance %d\n", ok1, ok2, acc.balance);
return 0;
}
1 0 balance 70
Dot or arrow?
- A struct variable: use
.(acc.balance). - A pointer to a struct: use
->(a->balance).
The compiler tells you if you mix them up: member reference type 'struct Account *' is a pointer; did you mean to use '->'? means you used . on a pointer.
Conventions
- Pass
struct X *when the function modifies the struct. - Pass
const struct X *when it only reads a large struct. You get the speed of a pointer and the safety of a copy: the compiler rejects any attempt to modify through it. - Small structs (a couple of numbers) are fine to pass by value.
Use the Watch it run link to see the pointer's arrow lead back to the struct in main.
Your turn: write void record_round(struct Player *p, int kills, int died) that adds kills to p->kills and adds 1 to p->deaths if died is non-zero.