Educational Blog

How to Use Structs in C

Learn how to define, initialize, and use structs in C with practical examples.

Structs are one of the simplest ways to make C code feel organized instead of scattered across separate variables. They let you bundle related values into a single type, pass that type around cleanly, and build data models that are easier to read and maintain.

If you are learning C, structs are usually the first step from “toy examples” to code that starts to resemble real programs. They show up in everything from geometry and inventory systems to file formats, linked lists, and operating-system code. Once you understand them, a lot of C becomes easier to reason about.

What a struct is

A struct is a user-defined type that groups multiple fields under one name. Each field can have its own type.

For example, instead of managing a person’s name, age, and height as separate standalone variables, you can store them in one struct:

struct Person {
    char name[50];
    int age;
    float height;
};

That definition creates a blueprint. It does not allocate a specific person yet. It just tells the compiler what a Person looks like.

Declaring and using a struct

Once you define a struct, you can create variables from it:

struct Person {
    char name[50];
    int age;
    float height;
};

int main(void) {
    struct Person alice = {"Alice", 28, 1.68f};

    printf("%s is %d years old and %.2f meters tall\n",
           alice.name, alice.age, alice.height);

    return 0;
}

Use the dot operator . to access fields in a normal struct variable.

Key idea

A struct variable is like a box with labeled compartments. The labels are the field names. The fields live together, but each one can still be read and changed independently.

Why structs are useful

Structs solve a few common problems:

  • They keep related data together.
  • They make function arguments clearer.
  • They make arrays of records possible.
  • They help you represent real-world objects and program state.
  • They reduce the number of unrelated variables floating around a program.

The alternative is usually a pile of parallel variables such as person_name, person_age, and person_height. That works for tiny programs, but it gets messy fast.

Defining a struct the clean way

You can define a struct and create a typedef at the same time so you do not need to repeat struct every time.

#include <stdio.h>

typedef struct {
    char name[50];
    int age;
    float height;
} Person;

int main(void) {
    Person bob = {"Bob", 34, 1.82f};
    printf("%s\n", bob.name);
    return 0;
}

This version is common in modern C because it is shorter and easier to read. It does the same thing as the plain struct Person version, but the type name becomes Person.

Initializing struct fields

There are several ways to initialize a struct.

MethodExampleNotes
Positional initializerPerson p = {"Ana", 22, 1.70f};Simple, but order matters
Designated initializerPerson p = {.age = 22, .name = "Ana"};Clear and flexible
Field-by-field assignmentp.age = 22;Useful when values arrive later

Designated initializers are especially useful when you want to make the intent obvious or only set a few fields.

Person carol = {
    .name = "Carol",
    .age = 41,
    .height = 1.65f
};

Accessing and modifying fields

You use . for a struct variable and -> for a pointer to a struct.

struct Person dave = {"Dave", 30, 1.75f};
dave.age = 31;

If you have a pointer:

struct Person *ptr = &dave;
ptr->age = 32;

The arrow operator is just shorthand for “dereference the pointer, then access the field.” In other words, ptr->age is equivalent to (*ptr).age.

Passing structs to functions

A struct can be passed to a function by value or by pointer.

Pass by value

void print_person(struct Person p) {
    printf("%s is %d\n", p.name, p.age);
}

This copies the whole struct into the function. That is fine for small structs, but it can be expensive for large ones.

Pass by pointer

void birthday(struct Person *p) {
    p->age += 1;
}

This avoids copying the data and lets the function update the original object.

A practical rule:

  • Use pass-by-value for small structs when you only need a read-only snapshot.
  • Use pointers when the struct is large or when the function must modify it.

Arrays of structs

Structs become much more useful when you store many of them in an array.

#include <stdio.h>

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

int main(void) {
    Player team[3] = {
        {"Mia", 10},
        {"Noah", 14},
        {"Zoe", 12}
    };

    for (int i = 0; i < 3; i++) {
        printf("%s: %d\n", team[i].name, team[i].score);
    }

    return 0;
}

This is one of the most common patterns in C. A struct becomes a single record, and an array of structs becomes a table of records.

Nested structs

Structs can contain other structs.

typedef struct {
    int year;
    int month;
    int day;
} Date;

typedef struct {
    char title[100];
    Date released;
} Movie;

Nested structs are useful when a concept naturally contains sub-parts. A movie has a release date. A student has an address. A company has a founding date.

Structs and memory layout

C structs are also a low-level feature. The compiler stores fields in memory in a defined order, but it may insert padding between fields for alignment.

That means two important things:

  • The size of a struct may be larger than the sum of its field sizes.
  • The order of fields can affect memory usage.

For example, if you place a char before an int, the compiler may add padding so the int is properly aligned.

You usually do not need to micro-optimize this while learning, but it matters in systems code, file formats, and performance-sensitive programs.

Common mistakes

Forgetting the struct tag or typedef form

If you define a struct with struct Person, you must either use struct Person later or create a typedef.

Confusing . and ->

Use . for a struct variable.

Use -> for a pointer to a struct.

Returning pointers to local structs

Do not return a pointer to a stack-allocated local struct. It stops being valid after the function returns.

Mixing up initialization order

If you use positional initialization, the values must match the field order exactly.

When to use structs

Use a struct whenever several values describe one thing.

Good candidates include:

  • User accounts
  • Game objects
  • Sensor readings
  • Inventory items
  • Configuration settings
  • Nodes in data structures
  • File metadata

If the values belong together conceptually, a struct is usually the right tool.

A small complete example

Here is a compact program that defines, initializes, updates, and prints a struct:

#include <stdio.h>

typedef struct {
    char name[50];
    int age;
} Person;

void celebrate_birthday(Person *p) {
    p->age += 1;
}

int main(void) {
    Person person = {.name = "Jordan", .age = 20};

    printf("Before: %s is %d\n", person.name, person.age);
    celebrate_birthday(&person);
    printf("After: %s is %d\n", person.name, person.age);

    return 0;
}

That example shows the basic lifecycle:

  1. Define the type.
  2. Create a variable.
  3. Read fields with ..
  4. Update through a pointer with ->.
  5. Pass the struct into functions when needed.

How to get comfortable with structs

The fastest way to learn structs is to build tiny programs with them. Start with a simple record type, then add arrays, then pointers, then nested structs.

A good practice sequence is:

  • Make a Person or Product struct.
  • Put a few values in an array.
  • Write a function that prints one item.
  • Write a function that updates one field.
  • Add another struct inside it.

That progression teaches the syntax and the mental model at the same time.

Final takeaway

Structs let you organize related data into one named type, making C programs easier to read, maintain, and scale. Learn how to define them, initialize them, access fields, and pass them into functions. Once those pieces click, you can use structs to model almost anything your program needs to track.

Written by

c-double.com Editorial Team

Editorial team

c-double.com publishes practical how-to guides and educational articles with clear steps and useful context.