Skip to content
Lesson 10 of 13

Step 1 of 5 · Reading · ~3 min

Learn

Memory and Structs

Structs

Arrays collect many values of one type; a struct collects the different parts of one thing into a single value. By the end of this lesson you can define a struct type, build values of it, read their members, and pass them to your own functions.

Defining and building

struct Clock {
    int hours;
    int minutes;
};

struct Clock start = {9, 45};                    /* positional: members in order */
struct Clock stop  = {.hours = 11, .minutes = 5}; /* designated: named members */

printf("%d:%d\n", start.hours, start.minutes);   /* 9:45 */

A member is one named field inside the struct; the dot operator start.hours reads or writes it. Members sit in memory in the order you declared them, one after another, like a small array whose slots have names and may have different types.

typedef: naming the type once

The type above is spelled struct Clock everywhere. Most C code gives it a shorter name with typedef:

typedef struct {
    int w, h;
} Size;

Size box = {4, 3};        /* no `struct` keyword */

After this there is no tag called Size, only the alias. Writing struct Size box; names a type the compiler has never seen and fails with storage size of 'box' isn't known. The rule: struct Name { ... }; means you write struct Name; typedef struct { ... } Name; means you write Name.

Structs are values

Assignment and function calls copy every member:

Size a = {4, 3};
Size b = a;          /* full copy */
b.w = 99;
printf("%d\n", a.w); /* 4 -- a is untouched */

So a function can take whole structs as parameters and read their members:

int minutes_between(struct Clock from, struct Clock to) {
    int dh = to.hours - from.hours;
    int dm = to.minutes - from.minutes;
    return dh * 60 + dm;
}

Trace it with start = {9, 45} and stop = {11, 5}: dh is 11 - 9 = 2, dm is 5 - 45 = -40, and the result is 2 * 60 - 40 = 80 minutes. The negative dm is fine: each member is subtracted from the same member of the other struct, and the arithmetic sorts out the sign.

The arrow

When a function must change the caller's struct, pass its address (last lesson's pointers) and use ->:

void grow(Size *s, int by) {
    s->w += by;      /* s->w  means  (*s).w */
}
grow(&box, 2);       /* box is now {6, 3} */

Dot when you hold the struct, arrow when you hold its address. Structs also nest: a member can itself be a struct, reached with chained dots like line.start.x.

The squaring trap

C has no power operator. ^ compiles, but it is bitwise XOR:

int side = 3;
printf("%d\n", side ^ 2);    /* 1 -- XOR, not a square */
printf("%d\n", side * side); /* 9 -- what you meant */

Common mistakes

  • Squaring with ^. For differences 3 and 4, 3 ^ 2 is 1 and 4 ^ 2 is 6, so you print 7 instead of 25. Multiply the value by itself.
  • Crossing members. Subtracting a.y from b.x mixes two axes and prints 29 instead of 25 for points (1, 2) and (4, 6). Always pair x with x and y with y.
  • Adding before squaring. Squaring dx + dy lets opposite signs cancel: for (0, 0) and (3, -4) it gives 1 instead of 25.
  • Leaving the points at {0, 0}. Every answer becomes 0; only the identical-points test passes.

Your exercise

Complete int dist2(Point a, Point b) so it returns the squared distance between two points, and replace the two {0, 0} placeholders in main with points built from the numbers already read. The Point typedef and all input and output are done; the likeliest slip is squaring with ^.

Up nextmalloc and freeMemory and Structs

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…