Say we want to try recreating Pokémon Red/Blue. What kinds of variables/data would we use to store information about our Pokémon? We could try something like the following:

 
//Different pieces of data about the pokemon in our party
int partySpecies[6];
int partyLevels[6];
int partyHP[6];
int partyAttack[6];
.
.
.

But this would get annoying pretty quickly. We have language features that allow us to create groupings of the same type (arrays), but we haven’t yet explored ways to create groupings of different types of data.

Enter… structures! (we call them structs)

Structures are a language feature that allows us to group different types of data together, into a single aggregate data type. We sometimes refer to structs as user defined types.

So, what do they look like?

//Create a new struct
 
struct Pokemon
{
	int species;
	int level;
	int hp;
	int attack;
};
 

Now we have our own struct, which represents a Pokemon! And we can create different Pokemon just as we would create integers, floats, or any other type. Think of the struct definition above as a sort of… template, for creating new Pokemon in the future.

 
struct Pokemon myAmpharos;
 
myAmpharos.species = 181;
myAmpharos.level = 100;
 
struct Pokemon myUmbreon;
 
myUmbreon.species = 197;
myUmbreon.level = 60;

The syntax above is how we would access the individual members of our Pokemon variables. Similar to how arrays use array syntax to access individual elements in an array, structs use the dot operator to access individual fields by name.

NOTE: There are other annoying ways/syntax to define/create structs, but they’re only historically important. We’re focusing on the two main ways you would define a struct.

The second way to create a struct (and honestly the one you SHOULD be using) is done like so:

typedef struct
{
	int species;
	int level;
	int hp;
	int attack;
} Pokemon;
 

There are historical precedents for why defining structs is a bit odd in C. This syntax is cleaner in C++, so you won’t have to worry about this as much in CS170 and beyond. But for our class when you create structs, you should probably use the typedef version seen above.

With the typedef version, when you create individual Pokemon, you don’t need to include the struct keyword:

 
Pokemon myTyranitar;
 
myTyranitar.species = 248;
myTyranitar.level = 900;

So, what can we do with structs? Well, we can print them out, though we have to do so by each individual field. We can also assign structures to each other, which might seem odd. But it’s totally doable in C. And we can have arrays of structs! And we can use initializers for our structs, like so:

Pokemon myAmpharos = {181, 100, 230, 104};

Passing Structs

We can pass structs to functions too:

void GiveRareCandy(Pokemon myMon)
{
	++myMon.level;
}

Augh, but this doesn’t work as we expect! C passes things by value, even structs! Which means we need to pass a pointer to a struct if we want to modify the original, and not a copy:

void GiveRareCandy(Pokemon* myMon)
{
	++myMon->level;
}

Whoa whoa whoa… hold the phone. What’s going on with that ARROW thing up there?

Turns out, it is really annoying to have to use the dereference operator on a struct, then use the dot operator after that! So there’s a convenient operator used specifically to combine the two operations into one:

Pokemon* myMon;
int pokemonLevel;
 
//These two lines of code do the exact same thing!
pokemonLevel = (*myMon).level;
pokemonLevel = myMon->level;
 
 
//You can NOT do something like this:
(*myMon.level) //THIS IS ILLEGAL, the compiler things we're dereferencing an integer!
 

We can also have self-referential structs:

struct Pokemon
{
	int species;
	int level;
	int hp;
	int attack;
	struct Pokemon* nextInParty;
};
 

That seems super odd… why might that be useful or interesting?