$ overview
overview/0x0C·Pointers & Memory

Structs & Unions

Grouping related values into one type, and passing them around.

A struct groups several related values, possibly of different types, into a single named type. Where an array holds many values of the same type, a struct holds a fixed set of fields that together describe one thing.

Defining and using a struct

struct.c
1struct Point {
2 int x;
3 int y;
4};
5 
6int main(void) {
7 struct Point origin = {0, 0};
8 struct Point p = {3, 4};
9 
10 printf("(%d, %d)\n", p.x, p.y);
11 p.x = 10; // dot notation to access and modify fields
12 
13 return 0;
14}

. accesses a field on a struct value directly. A typedef is commonly used so you don't have to write struct every time you name the type:

typedef.c
1typedef struct {
2 int x;
3 int y;
4} Point;
5 
6Point p = {3, 4}; // no "struct" keyword needed here

Structs and pointers

When you have a pointer to a struct, -> accesses a field without needing to dereference manually first:

arrow.c
1void move(Point *p, int dx, int dy) {
2 p->x += dx; // shorthand for (*p).x += dx
3 p->y += dy;
4}
5 
6int main(void) {
7 Point p = {0, 0};
8 move(&p, 5, 5);
9 printf("(%d, %d)\n", p.x, p.y); // (5, 5)
10 return 0;
11}
note: Structs are also passed by value
Passing a struct to a function copies every field, the same way passing an int copies it (0x06). For large structs, it's more efficient to pass a pointer instead — which is also the only way for the function to modify the caller's struct, as move does above.

Arrays of structs

array-of-structs.c
1Point path[3] = {
2 {0, 0},
3 {1, 1},
4 {2, 4}
5};
6 
7for (int i = 0; i < 3; i++) {
8 printf("(%d, %d)\n", path[i].x, path[i].y);
9}

Unions: sharing the same memory

A union looks like a struct but its fields all share the same memory — writing one field overwrites the others, and the union is only as big as its largest field. Unions are far less common than structs; they show up when memory is tight or when interpreting the same bytes in more than one way:

union.c
1union Value {
2 int as_int;
3 float as_float;
4};
5 
6union Value v;
7v.as_int = 42;
8printf("%d\n", v.as_int); // 42
9v.as_float = 3.14f;
10printf("%d\n", v.as_int); // meaningless now — as_float overwrote it