Skip to Content
Course content

61: Defining and Using Structs

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Up until now, we've been handling variables as isolated pieces of data. That works fine for a simple script, but imagine you're building a small RPG. You have a player with a name, a level, and some health. If you keep those as separate variables—char name[50], int level, float health—you'll quickly find yourself passing three or four arguments into every single function you write. It gets messy, fast.

Grouping player data together

This is where structs come in. A struct lets us wrap different data types into one single package. I like to think of it as creating my own custom data type. Instead of managing three different variables, I can just manage one "Player" object.

struct Player {
    char name[50];
    int level;
    float health;
};

Now, whenever I need a player, I can just declare it like this: struct Player hero;. To get to the actual data inside, I use the dot operator. For example, hero.level = 1;. It's clean, it's logical, and it keeps the related data glued together.

Dealing with the "struct" keyword fatigue

One thing that always annoyed me when I first started with C is that you have to write the word struct every single time you declare a variable. Writing struct Player hero1; struct Player hero2; feels redundant. We can get around this using typedef. This basically tells the compiler, "From now on, when I say Player, I mean struct Player."

typedef struct {
    char name[50];
    int level;
    float health;
} Player;

// Now I can just do this:
Player hero;
hero.level = 1;

I almost always use typedef for my structs. It just makes the code read more like a modern language and saves a few keystrokes.

Passing the player to a function

Now, let's say we want a function that heals the player. Since we've grouped the data, we only need to pass one thing to the function. However, if I pass the struct by value, C makes a complete copy of the whole struct. For a small struct, that's fine, but for larger ones, it's a waste of memory and slow. The professional way to do this is to pass a pointer to the struct.

void heal_player(Player *p) {
    p->health += 10.0f;
}

Fixing the pointer access bug

Here is where I usually tripped up for the first few months. In my first attempt at this function, I tried to do this: p.health += 10.0f;. The compiler immediately screamed at me. Why? Because p is a pointer (an address), not the actual struct. You can't use the dot operator on a pointer.

To fix this, you have two choices. You could dereference the pointer first: (*p).health += 10.0f;. But honestly, nobody does that because the parentheses make it look clunky. Instead, C gives us the arrow operator ->. It's shorthand for "dereference this pointer and then access this member."

// The right way
void heal_player(Player *p) {
    p->health += 10.0f; // Much cleaner
}

Once you get used to the arrow operator, you'll find it's the bread and butter of working with structs in C. Just remember: . for the actual variable, -> for the pointer to the variable.




📋 Practical Task

Build a Library Book Inventory System

Create a program that manages a book in a library. Your task is to:

  • Define a Book struct using typedef. It should contain a title (string), author (string), and pages (integer).
  • Create a function called print_book_details that takes a pointer to a Book struct and prints all its information to the console.
  • In your main function, instantiate one Book, assign it some values, and call your print function.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.