C Structs (structures) Tutorial

In this C tutorial we learn how to define our own types in C with structs.

We cover how to define a struct, declare a struct variable, assign data to a struct member and how to assign data to a struct pointer member.

Here's a table of contents of what you'll learn in this lesson:
(click on a link to skip to its section)

Let's jump right in.

What is a struct

A struct is a user-defined type that can store one or more variables of different types. We use structs to model our application after entities in the real world, grouping related code.

As an example, let’s consider a player character in an first person shooter game. Each player has a list of properties associated with them.

  • Player name
  • Hit points
  • Stamina
  • Armor
  • Primary weapon
  • Secondary weapon
  • Consumable
  • Ammunition

Our first thought would be to throw all these properties into an array, however, the properties have different types.

We could create individual variables, but what if the player wants to play a co-op match where more than one player’s data needs to be stored.

This is where a struct is useful. A struct allows us to group all of these properties together as a single unit, and then create multiple units.

For example, we group the player properties into a struct called Player. We can then create multiple players of type Player, each with different values.

How to define a struct

To define a struct, we use the keyword struct , followed by a name and a code block. Inside the code block we define the struct properties.

Syntax:
struct StructName
{
	// properties
};

Note that a struct’s code block is terminated with a semicolon.

Example:
#include <stdio.h>

struct Player
{
    char name[40];
    float hp;

    char weapon[10];
    int ammo;
};

int main()
{
    return 0;
}

In the example above, we define the struct above the main() function. If we define it below the main() function the compiler will raise an error.

The C languages is organized around one pass compilation, which means it scans the document only once from top to bottom before compiling.

If we define a struct below a point where it’s used, the main() function for example, the compiler will see an undefined type because it doesn’t know about the struct yet.

In functions we get around this problem with a prototype at the top of the document. But, structs don’t have prototypes so we define them above the point they would be used.

Typically, a struct would go into an external file, something like player.h and be included at the top of the document like we do with the stdio.h file.

How to declare a struct variable

When we define a structure, it becomes a type, like int or char. Therefore, we need a variable that is of the struct’s type.

There are two ways to create a struct variable:

  • After the structure definition.
  • With the structure definition.

Let’s take a look at declaring a struct variable the struct’s definition first.

We write the struct keyword, followed by the struct name as the type. Lastly, we give our variable a name.

Syntax:
// struct definition
struct StructName
{
	// properties
};

// struct variable
struct StructName variableName;
Example:
#include <stdio.h>

struct Player
{
    char name[40];
    float hp;

    char weapon[10];
    int ammo;
};

int main()
{
    struct Player p1;

    return 0;
}

In the example above, we create a new struct variable with the name p1 of type Player. We will be able to access the struct’s properties with the p1 variable.

We can also declare a variable for the struct when we define the struct itself.

To do this we add the variable name after the closing curly brace of the struct, but before the semicolon terminator.

Syntax:
// struct definition
struct StructName
{
	// properties

} variableName;
Example:
#include <stdio.h>

struct Player
{
    char name[40];
    float hp;

    char weapon[10];
    int ammo;

} p1, p2, p3;

int main()
{
    return 0;
}

In the example above, we declare three variables after the struct’s closing curly brace. When declaring multiple struct variables, we can just separate them with a comma.

How to access and assign data to a struct property member

If we’ve declared a struct variable, we can use it to access any property inside the struct with dot notation.

Dot notation is separating the variable name and property name with a dot operator ( . ).

Syntax:
// struct definition
struct StructName
{
	int property;

} variableName;

// access property
variableName.property;

To assign data we use the assignment operator followed by the data we want to store in the property.

Syntax:
 variableName.property = data;
Example:
#include <stdio.h>

struct Player
{
    char name[40];
    float hp;

    char weapon[10];
    int ammo;

};

int main()
{
    struct Player p1;

    p1.ammo = 30;

    printf("Ammo count: %d\n", p1.ammo);

    return 0;
}

In the example above, we add ammuntion to our ammo property and then print it to the console.

When we assign data to a property, it doesn’t affect the struct itself, only the p1 instance of it.

How to access and assign data to a struct pointer

Since we can create pointers to any type, and a structure is a type, we can also create pointers to structs.

However, we are not allowed to access the structure pointer member by using the dot operator. Instead, we use arrow notation ( -> ) to access the structure member.

Syntax:
// struct definition
struct StructName
{
	int property;

} *variableName;

// access property
variableName->property;

Before we are able to access the property, we will need to initialize the pointer to the struct through dynamic memory allocation .

Syntax:
// struct definition
struct StructName
{
	int property;

} *variableName;

// initialize pointer
variableName = (struct variableName*) malloc(sizeof(struct StructName));

// access property
variableName->property;
Example:
#include <stdio.h>
#include <stdlib.h>

struct Player
{
    char name[40];
    float hp;

    char weapon[10];
    int ammo;

};

int main()
{
    struct Player *p1;

    // initialize pointer
    p1 = (struct p1*) malloc(sizeof(struct Player));

    p1->ammo = 30;

    printf("Ammo count: %d\n", p1->ammo);

    // remember to free from malloc
    free(p1);

    return 0;
}

In the example above, we create a struct pointer p1. Then we initialize the pointer as a struct pointer with the appropriate size. Finally, we access the members of p1 with arrow notation ( -> ).

Remember to release the memory afterwards with the free() function.

Summary: Points to remember

  • A struct is a user-defined type that can hold multiple different types of variables.
  • A struct variable can be declared either on its own or as part of the struct definition.
  • We access a struct property member with dot notation ( . ).
  • We access a struct pointer member with arrow notation ( -> ).