Structs & Data Structures · beginner · ~12 min

Structs

Group related fields into one type.

Overview

A struct groups related variables (called members or fields) under one type. Access members with . on a struct value, or -> on a struct pointer. Structs are how C programs build composite data — coordinates, records, network packets, anything with more than one piece of state.

Why it matters

Without structs, you'd pass 10 separate parameters every time you wanted to describe a 'user' or a 'TCP segment'. With structs, you pass one pointer and the receiver has clear, named access to each piece. Every non-trivial data structure (linked list node, hash entry, file struct) is built on structs.

Core concepts

Definition vs declaration. struct point { int x; int y; }; declares the layout. struct point p; makes an instance. Anonymous, named, and typedef'd. typedef struct { int x; int y; } point_t; makes point_t p; work without the struct keyword. Memory layout. Fields are stored in declaration order, with padding inserted for alignment. Pass by pointer. Always pass big structs by pointer (const point_t *p) — pass-by-value copies the whole thing.

Syntax notes

typedef struct {
    int x, y;
} point_t;

point_t a = {3, 4};            // initialise members
printf("%d,%d\n", a.x, a.y);  // dot access on a value
point_t *q = &a;
printf("%d\n", q->x);          // arrow access on a pointer

Lesson

A struct bundles several values into one named type. Access fields with . (on a struct value) or -> (on a pointer to a struct).

C is value-typed: passing a struct to a function copies it. Pass const T * for read-only, T * for read-write.

Code examples

struct point { double x, y; };
struct point p = {1.0, 2.0};
printf("%g %g\n", p.x, p.y);
struct point *q = &p;
q->x = 5.0;     // same as (*q).x

Common mistakes

  • Forgetting struct keyword (use typedef to remove it — next lesson).
  • Comparing structs with == — not supported. Compare field by field, or use memcmp only if there's no padding.

Debugging tips

Use gdb's print *p to dump every member. sizeof(point_t) shows the actual size including padding — often larger than the sum of fields, which is why you can't memcmp two structs naively (the padding bytes may differ).

Memory safety

When malloc'ing a struct, calloc(1, sizeof(*p)) zero-initialises every field — much safer than malloc + 'remember to set every field'. Don't strcpy into a fixed-size struct member without checking the source length — that's a classic stack-smash vector.

Real-world uses

Every C struct in <stdio.h> (FILE), <sys/socket.h> (sockaddr_in), the kernel's task_struct, every linked-list / tree / hash-table node, every protocol header.

Practice tasks

  1. Define a point_t and a function double distance(point_t a, point_t b). 2. Make a struct for a 'user' with name and age, write a print function. 3. Allocate a struct on the heap, fill it, free it.

Summary

Structs group related values under one named type. Use . on values, -> on pointers, calloc to zero-init, and pass big structs by pointer. They are how C grows from individual variables into real data structures.

Practice with these exercises