Pointers to Structures

In the previous exercise, the function sell_one changed only its copy of the product. You know the solution from the lesson on pointers: give the function the address of the variable, and it can change the original through it. With structures, it works the same way:

typedef struct {
    char name[20];
    double price;
    int count;
} Product;

void add_count(Product *item, int extra) {
    (*item).count += extra;
}

The parameter item is a pointer to a Product. *item is the product it points to, and (*item).count is the count of that product. The parentheses are necessary: the dot is evaluated before the asterisk, so *item.count would mean "the member count of item, and then *", but item is a pointer, not a structure. That's why C has a shorter and clearer way to write it, the arrow ->, written as a minus sign and a greater-than sign:

#include <stdio.h>

typedef struct {
    char name[20];
    double price;
    int count;
} Product;

void add_count(Product *item, int extra) {
    item->count += extra;
}

int main(void) {
    Product milk = {"Milk", 24.9, 3};
    add_count(&milk, 2);
    printf("%s: %d\n", milk.name, milk.count);
    return 0;
}

This prints:

Milk: 5

item->count means exactly the same as (*item).count: "the member count of the structure that item points to". Programmers write the arrow, and so will we. You call the function with the address of the product, &milk, as with any pointer parameter.

So when do you write a dot and when an arrow? Look at what stands on the left. A structure (milk, cart[i], or a parameter Product item) gets a dot. A pointer to a structure (a parameter Product *item) gets an arrow. When you mix them up, the compiler tells you and even suggests the right one:

main.c:10:9: error: member reference type 'Product *' is a pointer; did you mean to use '->'?
   10 |     item.count += extra;
      |     ~~~~^
      |         ->

The other way round, milk->count ends with member reference type 'Product' is not a pointer; did you mean to use '.'?. And when you forget the & in the call, add_count(milk, 2), the error is passing 'Product' to parameter of incompatible type 'Product *'; take the address with &: the function wants an address, so pass it one with &.

A pointer is useful even when the function doesn't change the structure. A structure parameter gets a copy of the whole structure on every call, and some structures are big. A pointer is just one address. When the function only reads the structure, add const, as you did with arrays: in double line_total(const Product *item), the function can read item->price but can't change it by mistake.

And an array of structures? A function gets the caller's array itself, not a copy, as with any array. In a function with the parameter Product cart[], cart[i] is a structure, so you write a dot, cart[i].count = 0;, and the change stays in the caller's array. To pass one element of the array to add_count, give it the element's address: add_count(&cart[1], 2);.

Instructions

The function record_win should add 3 points to a team for a win, but the program prints Lions: 5 points. Change the function so that it gets a pointer to the team, use -> in it, and call it with the address of lions. The program then prints Lions: 8 points.

Below record_win, write a function void record_match(Team *team, int scored, int conceded) for any match. When the team scored more goals than it conceded, it won and gets 3 points; for a draw (the same number of goals) it gets 1 point; for a loss, nothing. At the end of main (before return 0;), call it twice, record_match(&lions, 2, 2) and record_match(&lions, 3, 1), and then print the team again with the same printf. The last line is Lions: 12 points.

Start programming for free

By signing up, you agree to the Terms of Service and Privacy Policy.

Or sign up with:

7/9