Unit 10: Structs
Making your own kind of thing.
Unit 10 of 11 in C programming for kids. Its 6 lessons are Keeping Things Together, Structs Get Copied, Lots of Them, Names for Types, Unions and Struct Master — below is everything each one explains, and a question or two from it to try.
Every sample on this page was compiled and run with gcc before it shipped, and prints exactly what it says it prints.
This unit opens with a fortnight’s trial of everything — no card needed — or with a family plan, bought in the iPhone app. The first two units of every track are free for ever. Try it in the app.
📦 Keeping Things Together
One box holding several values
A struct puts related values into a single thing. Describe the shape once, then make as many as you like — and reach inside with a dot.
C
#include <stdio.h>
struct Point {
int x;
int y;
};
int main() {
struct Point p;
p.x = 3;
p.y = 4;
printf("%d %d\n", p.x, p.y);
return 0;
}
It prints
3 4
Filling it in as you make it
Braces set the members in the order they were declared. Anything you leave out starts at zero.
C
#include <stdio.h>
struct Point {
int x;
int y;
int z;
};
int main() {
struct Point a = {1, 2, 3};
struct Point b = {7};
printf("%d %d %d\n", a.x, a.y, a.z);
printf("%d %d %d\n", b.x, b.y, b.z);
return 0;
}
It prints
1 2 3 7 0 0
Members can be any type at all
Including arrays — which is how a struct holds a name.
C
#include <stdio.h>
#include <string.h>
struct Dog {
char name[10];
int age;
};
int main() {
struct Dog rex;
strcpy(rex.name, "Rex");
rex.age = 4;
printf("%s is %d\n", rex.name, rex.age);
return 0;
}
It prints
Rex is 4
Try it yourself
Why does the struct definition end with a semicolon?
- A mistake in C
- Because it is a declaration, and you could name a variable before the semicolon
- To separate it from main
- It does not need one
What does this print?
C
#include <stdio.h>
struct Box {
int width;
int height;
};
int main() {
struct Box b = {3, 5};
printf("%d\n", b.width * b.height);
return 0;
}
Answer them in the app
📋 Structs Get Copied
Assigning one makes a real copy
This is the thing arrays would not do. b = a copies every member, and the two are then completely separate.
C
#include <stdio.h>
struct Point { int x; int y; };
int main() {
struct Point a = {1, 2};
struct Point b = a;
b.x = 9;
printf("%d %d\n", a.x, b.x);
return 0;
}
It prints
1 9
And a function gets a copy too
Pass a struct and the function works on its own copy, so the original is safe. Compare that with an array, where the function shares the real thing.
C
#include <stdio.h>
struct Point { int x; };
void change(struct Point p) {
p.x = 999;
}
int main() {
struct Point a = {1};
change(a);
printf("%d\n", a.x);
return 0;
}
It prints
1
Send its address to change the real one
A pointer to a struct uses -> instead of . — the arrow means "follow the pointer, then take that member".
C
#include <stdio.h>
struct Point { int x; };
void change(struct Point *p) {
p->x = 999;
}
int main() {
struct Point a = {1};
change(&a);
printf("%d\n", a.x);
return 0;
}
It prints
999
A function can hand a whole struct back
Returning a struct copies it out to the caller, so it is safe to build one inside a function and return it.
C
#include <stdio.h>
struct Point { int x; int y; };
struct Point make(int x, int y) {
struct Point p;
p.x = x;
p.y = y;
return p;
}
int main() {
struct Point p = make(3, 4);
printf("%d %d\n", p.x, p.y);
return 0;
}
It prints
3 4
Try it yourself
When do you use -> rather than .?
- Whenever you like
- When what you have is a pointer to the struct rather than the struct itself
- Only inside functions
- Only for ints
Answer it in the app
🗃️ Lots of Them
An array of structs
Structs go in arrays like anything else. Each set of inner braces fills one of them.
C
#include <stdio.h>
struct Score { int player; int points; };
int main() {
struct Score board[3] = {{1, 10}, {2, 7}, {3, 4}};
for (int i = 0; i < 3; i++) {
printf("player %d: %d\n", board[i].player, board[i].points);
}
return 0;
}
It prints
player 1: 10 player 2: 7 player 3: 4
Structs inside structs
A member can be another struct, and the dots simply stack up.
C
#include <stdio.h>
struct Point { int x; int y; };
struct Rect { struct Point corner; int width; };
int main() {
struct Rect r = {{2, 3}, 10};
printf("%d %d %d\n", r.corner.x, r.corner.y, r.width);
return 0;
}
It prints
2 3 10
A struct is as big as its parts, plus padding
C leaves gaps so each member starts at a tidy address. That is why this struct is 8 bytes and not 5 — an int likes to begin at a multiple of 4.
C
#include <stdio.h>
struct Padded { char c; int i; };
struct Plain { int a; int b; };
struct Tiny { char x; char y; };
int main() {
printf("%d\n", (int)sizeof(struct Padded));
printf("%d\n", (int)sizeof(struct Plain));
printf("%d\n", (int)sizeof(struct Tiny));
return 0;
}
It prints
8 8 2
Try it yourself
What does this print?
C
#include <stdio.h>
struct Pet { int legs; };
int main() {
struct Pet pets[3] = {{4}, {2}, {8}};
int total = 0;
for (int i = 0; i < 3; i++) {
total = total + pets[i].legs;
}
printf("%d\n", total);
return 0;
}
Answer it in the app
🏷️ Names for Types
typedef saves you writing struct every time
typedef gives a type a shorter name. With it, struct Point p; becomes just Point p;.
C
#include <stdio.h>
typedef struct {
int x;
int y;
} Point;
int main() {
Point p = {3, 4};
printf("%d %d\n", p.x, p.y);
return 0;
}
It prints
3 4
It works on any type
Not just structs. A good alias explains what a number is *for*.
C
#include <stdio.h>
typedef int Score;
int main() {
Score points = 42;
printf("%d\n", points);
return 0;
}
It prints
42
enum gives names to numbers
An enum is a list of named whole numbers. They count up from 0 unless you say otherwise — and a name explains far more than a bare 2 ever will.
C
#include <stdio.h>
enum Colour { RED, GREEN, BLUE };
int main() {
enum Colour c = GREEN;
printf("%d %d %d\n", RED, GREEN, BLUE);
printf("%d\n", c);
return 0;
}
It prints
0 1 2 1
You can choose the numbers
Give one a value and the rest carry on from there.
C
#include <stdio.h>
enum Level { LOW = 5, MEDIUM, HIGH = 10 };
int main() {
printf("%d %d %d\n", LOW, MEDIUM, HIGH);
return 0;
}
It prints
5 6 10
Try it yourself
Why use an enum instead of just writing 0, 1 and 2?
- It is faster
- The names say what the numbers mean, so the code explains itself
- It uses less memory
- C requires it
Answer it in the app
🔀 Unions
One space, several names
A union looks like a struct but every member sits in the *same* space. It holds one of them at a time, so it is only as big as its widest member.
C
#include <stdio.h>
union Either {
int number;
char letter;
};
int main() {
union Either e;
e.number = 65;
printf("%d\n", e.number);
printf("%d\n", (int)sizeof(union Either));
return 0;
}
It prints
65 4
Writing one forgets the other
They share the space, so setting the letter overwrites what the number was. A union only ever holds the thing you last put in.
C
#include <stdio.h>
union Either { int number; char letter; };
int main() {
union Either e;
e.number = 1000;
e.letter = 66;
printf("%d\n", e.letter);
return 0;
}
It prints
66
Try it yourself
What is the difference between a struct and a union?
- None, they are the same
- A struct holds all its members at once; a union holds one at a time in the same space
- A union is faster
- A union can only hold numbers
What does this print?
C
#include <stdio.h>
struct Both { int a; int b; };
union One { int a; int b; };
int main() {
printf("%d %d\n", (int)sizeof(struct Both), (int)sizeof(union One));
return 0;
}
Answer them in the app
🏆 Struct Master
Try it yourself
What does this print?
C
#include <stdio.h>
struct P { int x; int y; };
int main() {
struct P a = {1, 2};
struct P b = a;
a.x = 100;
printf("%d %d\n", a.x, b.x);
return 0;
}
Answer it in the app