Skip to content
Structs
step 1/5

Reading — step 1 of 5

Learn

~3 min readMemory and Structs

Structs

Arrays collect many of the same thing; structs collect the different parts of one thing. It's C's only tool for building compound types — no classes, no objects — and paired with functions and pointers it turns out to be enough: most of the abstractions you know from "bigger" languages are structs wearing conventions.

Defining and using

struct Point {
    double x;
    double y;
};

struct Point p = {3.0, 4.0};              /* positional init */
struct Point q = {.x = 1.0, .y = 2.0};    /* designated init — clearer, use it */

p.x = 10.0;                               /* dot: access a member */
double dx = p.x - q.x;

The type's full name is struct Point — the keyword travels with it (a typedef can shorten it; you'll see both styles constantly in real code). Members are laid out in order, adjacently in memory — a struct is a little contiguous record, the same honest bytes-in-a-row story as arrays.

Structs are values

Assignment copies the whole thing, member by member:

struct Point a = {1, 2};
struct Point b = a;       /* full copy */
b.x = 99;
printf("%f\n", a.x);      /* 1.0 — a untouched */

Same for function calls: pass a struct, the function gets a copy (all of chapter 4 applies). For a two-double Point, copying is cheap and good — no aliasing surprises. For big structs, or when the function must modify the original, pass a pointer — which brings us to C's best piece of syntactic sugar:

The arrow

void moveRight(struct Point *p, double dist) {
    p->x += dist;         /* p->x  ≡  (*p).x  — follow pointer, take member */
}

moveRight(&pt, 5.0);

-> exists because (*p).x is miserable to type and the pattern is everywhere: pointer-to-struct is the default calling convention for anything non-trivial. Reading rule: dot when you hold the struct, arrow when you hold its address. Miss it and the compiler's error (request for member in something not a structure) at least points at the right line.

This function-taking-struct-pointer shape — moveRight(&pt, …), player_heal(&p, 20) — is, honestly, most of what "methods" are: the pointer parameter that OO languages spell this and pass invisibly, C spells out loud. Once you see it, object systems stop being magic.

Structs compose

struct Circle {
    struct Point center;   /* structs nest */
    double radius;
};

struct Circle c = {{0, 0}, 5.0};
c.center.x                 /* chained dots */

Records of records — plus arrays of structs (struct Point path[100];) — cover an enormous amount of real modeling before anything fancier is needed.

Your exercise: Point Distance Squared

Read two points, print the squared distance: (x₂−x₁)² + (y₂−y₁)² — no square root, which neatly sidesteps floating-point formatting if the inputs are integers (check the examples: they decide int members with %d versus double with %lf/%f, chapter 1's asymmetry included). Structure it like you mean it: a struct Point, a function taking two of them (by value — they're small) returning the squared distance, main doing only I/O. Scanning into members works exactly like variables: scanf("%lf %lf", &p.x, &p.y) — the & reaches inside structs just fine.

Discussion

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

Sign in to post a comment or reply.

Loading…