DOUG LLOYD: So at this point, we're pretty
familiar with all of the data types that come
native to C. We have characters, and floats, and integers, and doubles,
and we're also familiar now with the CS50 data types of strings and Booles.
But that doesn't limit everything that we can do.
We surely can do more.
Indeed, with structures, that gives us an ability
to start to define our own data types that
might be useful for our own programs.
What's cool about structures is they allow
us to unify many different variables of different data types
into a single brand new type.
And we can give that new type its own unique type
name as a way to identify it.
This isn't the first time we've seen the ability
to combine multiple variables together.
We've seen that with arrays.
Remember, the restriction with arrays is that we can only
combine things of the same type.
We can have a whole bunch of integers or a whole bunch of floats.
But we can't mix them up.
With structures, we actually can.
We can group together logical--
we can group together elements that have a logical connection to one another.
So for example, we can group together a structure
for say a student, where a student would have an ID
number, which is probably an integer.
But they also have a name, which is a string.
And they might have a GPA, which is a float.
And we can have all of these things tied together in basically
what's a super variable.
It's a variable that has other variables within it.
The way to do this in C is actually pretty straightforward.
Some syntax might look like this.
Instead of a student in this example, let's use a car.
We introduced the concept of a structure by saying, struct.
We're about to define a structure type.
And in particular, we're going to define a struct car.
And struct car actually now becomes our type name.
It's not just car.
It's struct car.
Inside of the curly braces from this point forward,
we can define all of the different variables
that we want inside of our super variable.
So for example, here are some things that are common to cars.
They have a year, the year they were manufactured.
We have a model, and a license plate, and an odometer, which
is a number of miles, and maybe they have an engine size,
which in the United States is usually represented
as a float for how many leaders the engine capacity is.
And notice that these are all different data types being mixed together.
We have integers, and we have two strings,
and we have a float, or a double all mixed up inside of one super variable.
To finish our definition of the structure,
we have a closing curly brace.
And then really important, a common syntax error
is a semicolon at the end, which completes
our definition of a struct car.
Once we define the structure, and usually we
define our structure at the very top of our program
up near our pound includes, and our pound defines,
but we also might define them in a separate dot H file
because maybe we're using this type definition in several different files,
or several different programs.
And so it makes sense to define it somewhere outside of one--
outside of a single file and have it be a dot H file that we can pound
include in multiple different contexts.
Now we have effectively created this new type and we can start to use it.
And we can create variables of this type just like we
can create variables of any other type.
Int x, that's how we create an integer called x.
Struct car y, that's how we create a variable called y of type struct car.
So that's how we create the variable overall.
How do we create the individual fields, or members of that?
Or rather, how do we access the individual fields or members
of that structure?
We can do so using something called the dot operator.
Let's take a look at what that looks like.
So the top here, I have a variable declaration.
Struct car, my car.
Again, here the type is struct car.
And the variable name is my car.
From this point forward, whenever I want to refer to a field,
or a member within my car, which is again, the variable name,
I can use the dot operator to access those individual fields within my car.
So I can say, for example, mycar.year equals 2011.
I can't just say year equals 2011.
Year is something that is part of my car.
So I have to always refer to it in the context of my car.
I can say strcpy(mycar.plate, "CS50").
Remember, it's a string.
I can't just assign it.
I have to copy that string into the variable.
I can say, mycar.odometer equals 50505 or anything else that I want to do.
I can set the engine size, and I can set the model.
I can do whatever else I want to do just by accessing
the fields similar to this.
But structures like variables of all other data types,
we don't have to just use the stack for this.
We don't just have to say struct car, my car, semicolon.
We could dynamically allocate this if we don't
know at the beginning of our program, for example,
that we're going to need a certain number of these things.
We can just declare this on the fly dynamically using pointers of course.
In order to access our fields in that situation,
we don't use just the dot operator because we
have a pointer to a structure.
We also have to first, as you may recall, dereference that pointer
and then access its fields.
It adds a little bit of extra stuff, but let's take a look again here.
So here now, instead of statically declaring a struct car called my car,
I'm going to dynamically allocate a struct car called my car.
So struct car star my car, and then I'm going to malloc space for a struct car.
And here's a cool thing about size of.
Size of is not just built in.
It doesn't just happen to know just the size of integers, characters, floats,
and doubles.
It can also figure out on the fly exactly how much space
is required for a struct car.
So you don't have to go through and figure out, OK, well, this
is probably like 30 bytes or something.
You can just say, size of struct car, and let
the computer figure it out for you.
So struct car star my car equals malloc size of struct car.
That dynamically allocates on the heap one chunk of memory large enough
to hold a single struct car within it.
And then I can access my fields by first dereferencing the pointer.
And then once I've dereferenced the pointer,
I can then use the dot operator to access the fields.
Again, it's very similar to what we just saw.
But the syntax here is a little cumbersome.
Now we have extra parentheses, we have this star, we have this dot,
surely there's got to be an easier way.
C programmers love for there to be easier ways to do things.
And in fact, there is a shortcut for this.
It so happens that accessing the field of a structure via its pointer
is a common enough operation that there is an entirely different operator that
allows us to do this much more succinctly.
And it is called the arrow operator, which
is a hyphen and then a greater than symbol,
literally making it look like it's an arrow.
It does two operations back to back.
So for the first thing it does is it dereferences the pointer, which
is on the left of the arrow.
And then it's going to access the field, which is on the right of the arrow.
So for example, this is what the code looked like before.
This is what we just had on the slide a second ago
where I'm dereferencing pointers.
And then I'm using the dot operator to access the fields.
Here is what the same code would look like with the arrow syntax.
And the same thing is happening here.
The first thing I'm doing is I'm dereferencing my car.
But the arrow operator does that for me.
I don't have to use the star syntax.
It just knows if I have an arrow there, I
need to first dereference the thing on the left,
and then I can access the field on the right.
So using the arrow operator is a great way
to have a shorthand for accessing the field of a structure to which you only
have a pointer.
And you'll probably use this a fair amount.
So it's syntax definitely to befriend and to get used to.
I'm Doug Lloyd.
This is CS50.