CodeMIRAI
0 XP

Structures

3 min read 6 runnable examples Quiz included

A structure (struct) bundles several values of different types into one thing. A student has a name, an age and a grade average; a struct keeps them together.

Defining and using a struct

C
#include <stdio.h>

struct Student {
    char name[20];
    int age;
    double gpa;
};

int main() {
    struct Student s = {"Asha", 20, 3.8};
    printf("%s is %d, GPA %.1f\n", s.name, s.age, s.gpa);
    s.age = 21;
    printf("Next year: %d\n", s.age);
    return 0;
}
Output
Asha is 20, GPA 3.8
Next year: 21

struct Student { ... }; describes the shape; struct Student s creates one. The dot reaches a member: s.age. The values in braces fill the members in order.

Naming the members, and typedef

C
#include <stdio.h>

typedef struct {
    double x;
    double y;
} Point;

int main() {
    Point a = {1.5, 2.0};
    Point b = {.y = 4.0, .x = 3.0};   // by name, in any order
    Point origin = {0};               // every member zero
    printf("a = (%.1f, %.1f)\n", a.x, a.y);
    printf("b = (%.1f, %.1f)\n", b.x, b.y);
    printf("origin = (%.1f, %.1f)\n", origin.x, origin.y);
    return 0;
}
Output
a = (1.5, 2.0)
b = (3.0, 4.0)
origin = (0.0, 0.0)
  • typedef gives the struct a short name, so you write Point instead of struct Point.
  • Designated initialisers (.x = 3.0) name each member, which reads better and survives reordering the struct.
  • {0} sets everything to zero. Members you leave out of an initialiser are zero too.

Arrays of structs

C
#include <stdio.h>

typedef struct {
    char name[16];
    int score;
} Player;

int main() {
    Player team[] = {{"Asha", 82}, {"Leo", 95}, {"Mei", 77}};
    int n = sizeof team / sizeof team[0];
    int best = 0;
    for (int i = 0; i < n; i++) {
        printf("%-5s %3d\n", team[i].name, team[i].score);
        if (team[i].score > team[best].score) best = i;
    }
    printf("Top scorer: %s\n", team[best].name);
    return 0;
}
Output
Asha   82
Leo    95
Mei    77
Top scorer: Leo

team[i].score reads naturally: element i of the array, then its score member. This is how C programs keep tables of records.

Passing a struct to a function

C
#include <stdio.h>

typedef struct {
    char owner[16];
    double balance;
} Account;

void deposit_copy(Account a, double amount) {
    a.balance += amount;          // changes the copy only
}

void deposit(Account *a, double amount) {
    a->balance += amount;         // a->balance means (*a).balance
}

int main() {
    Account acc = {"Asha", 100.0};
    deposit_copy(acc, 50);
    printf("After deposit_copy: %.2f\n", acc.balance);
    deposit(&acc, 50);
    printf("After deposit:      %.2f\n", acc.balance);
    return 0;
}
Output
After deposit_copy: 100.00
After deposit:      150.00

A struct passed by value is copied, so the function changes its own copy and the caller sees nothing. Pass a pointer to change the original, and reach the members with the arrow: a->balance is shorthand for (*a).balance.

Pointers are also cheaper for big structs, because only an address is copied. Use const Account *a when the function only reads.

Structs inside structs, and returning them

C
#include <stdio.h>

typedef struct { int day, month, year; } Date;
typedef struct { char title[24]; Date due; } Task;

Date next_day(Date d) {           // simplified: every month has 30 days
    d.day++;
    if (d.day > 30) { d.day = 1; d.month++; }
    if (d.month > 12) { d.month = 1; d.year++; }
    return d;
}

int main() {
    Task t = {"Submit report", {30, 12, 2026}};
    printf("%s, due %02d/%02d/%d\n", t.title, t.due.day, t.due.month, t.due.year);
    t.due = next_day(t.due);
    printf("Moved to %02d/%02d/%d\n", t.due.day, t.due.month, t.due.year);
    return 0;
}
Output
Submit report, due 30/12/2026
Moved to 01/01/2027

A member can itself be a struct (t.due.day), and a function can return a whole struct. Assigning one struct to another with = copies every member, arrays inside it included.

You can't compare structs with ==, though. Compare the members you care about:

C
if (a == b) { }                        // error: invalid operands to binary ==
if (a.x == b.x && a.y == b.y) { }      // compare member by member

Size and padding

C
#include <stdio.h>

struct A { char c; int i; char d; };
struct B { int i; char c; char d; };

int main() {
    printf("sizeof(struct A) = %zu\n", sizeof(struct A));
    printf("sizeof(struct B) = %zu\n", sizeof(struct B));
    return 0;
}
Output
sizeof(struct A) = 12
sizeof(struct B) = 8

Both hold the same three members (6 bytes of data), yet they differ in size. The compiler places each int at an address that's a multiple of 4, because processors read aligned values faster, and fills the gaps with padding. Ordering members from largest to smallest usually wastes the least space.

Finished this lesson?Mark it complete to earn +20 XP and move your progress on.