In this video, we'll learn how to access the address or location
and memory of any variable.
We'll also learn how to initialize a pointer variable
to point to another variable.
In c++, we can use the address operator, which is the ampersand
symbol to the left side of an operand.
The address operator is a unary operator, and when used in an
expression, it evaluates to the address of its operand.
Of course, the operand must have an l value, so it can't be a
constant or an expression that evaluates to temporary values.
In the example code, we have a variable num which
is a simple integer variable that's been initialized to 10.
If we display num, then we're displaying the
contents of num which is 10.
If we display the size of num, then we're displaying how much
storage is allocated by num.
In other words, how much storage do we need on my
machine to store an integer.
In this case, it's 4 bytes.
Finally, if we display the address of num using the address
operator, we get a hexadecimal number that represents the location
in memory of the variable num.
A hexadecimal number is just a base 16 number.
So far so good.
You can see that the address operator evaluates to exactly what we expect,
the address of the variable num.
Now let's see these same statements with pointer variables.
In the first line, we declare p to be a pointer to an integer variable.
So that means that p can hold values that are addresses of integers.
Also notice that we didn't initialize the pointer p.
In the first output statement, we're displaying the value of p.
The value of p is the value that's stored in p.
Since we didn't initialize p, we have garbage data in p and you
can see that address displayed.
In the second output statement, we're displaying the address
of the variable p, since we're using the address operator.
And in the third statement, we display the size of p
using the sizeof operator.
On my machine, this displays a 4, which means that p
is 4 bytes of storage.
Since p holds addresses, this also means that addresses on my machine
can be stored in four bytes.
On the next line, we assign null pointer to p.
This sets p to 0, which means it's pointing nowhere.
Since p is a variable, we can change its value.
This seems obvious, but it's important since when we talk
about references in a bit, you'll see that you can't change your
reference once it's initialized.
Finally, in the last output statement, we display the value of p again.
And this time, we get 0 because we zeroed it out.
I know these examples seem pretty simple, but please try them out
on your machine and be sure you understand these fundamental concepts
since everything else builds on them.
Here you can see that I'm defining five pointer variables
p1 through p5 and initialize them all to null pointer.
Each pointer variable points to a different type.
So each can hold addresses of variables of the type they point to.
If we displayed the size of each of these pointer variables,
what do you think would display?
Well, the size of p1 be less than the size of p4 because p1 points to
an int and p4 to a vector object.
If you set 4 for each pointer, you'd be right.
Based on the previous example, all pointers in my program
will hold values that can be represented in four bytes.
An address of an integer and an address of a vector and the
address of a string all have size of four on my machine.
There's a big difference between the size of the pointer variable itself
and the size of what it points to.
Again, take your time and make sure you understand the difference between
a pointer and what it points to.
It's very common to think of a pointer as what it points
to and that's a mistake.
A pointer is just a simple variable.
What it points to could be simple or a very complex structure.
When we declare pointers, as we've done so far, they're typed pointers.
This means that we explicitly declare the pointer variable to point to
a variable of a specific type.
In this example, we're declaring an integer score and initializing
it to 10 and a double high temp and initializing it to 100.7.
Then we declare score pointer as a pointer to an integer.
So far so good.
Now we assign the address of score to score pointer.
The compiler is fine with that since score pointer holds addresses
of integers and scores an integer.
But look at the last assignment statement.
In this case, we're assigning the address of high temp to score pointer.
The compiler won't let you do this, you'll get a compiler error.
You told the compiler that score pointer holds addresses of integers
but you're asking it to store the address of a double, both addresses
are four bytes long, so the issue isn't the size won't fit, the issue
is that there's a type conflict.
In c++, we can also have untyped void pointers.
I'm not going to talk about those but they aren't used that much
in c++., they're more used in c.
Great, so let's review a very simple concept but a very important concept.
Pointers are variables, so they can change pointers can be null
and pointers can be uninitialized.
That's not usually a good idea, but it can happen.
The example code shows all these options.
First, we declare two double variables, high and low
temp, and we initialize them.
Then we declare temp pointer as a pointer to a double
and we don't initialize it.
So it's pointing anywhere.
Then we assign the address of high temp to 10 pointer, and then we change
temp pointer to point somewhere else by assigning the address of low temp.
Finally, with null out 10 pointer by assigning null pointer.
We'll come back to these pointer properties later when we compare
pointers and references, and we'll go over some guidelines as when
to use pointers versus reference.
Let's head over to the IDE now and go over these examples in live code.
And then in the next video, we'll learn how to follow a pointer and get
to the data that it's pointing to.
Okay, so I'm in the CodeLite IDE, and I'm in the section 12 workspace
in these simple pointers project.
In this project, we're just going to go over some real simple
examples of declaring pointers, looking at the size of pointers,
looking at addresses, just so you get a really good feel of
about what's going on here.
First thing you'll notice here is that we're declaring num to be an integer,
and we're initializing it to 10.
That's just a plain old integer variable.
There's no pointer involved here at all.
So in this case, I've got a variable it's called num, and
it exists somewhere in memory.
Let's say it's somewhere in memory here.
Obviously, that memory has to have a location, right, we need an address.
So let's just say that the address is a 1000.
I'll use a thousand in these examples.
Obviously, it won't be a 1000 when we display it.
But you'll -- it's easier to understand this way.
So right now it's got a 10 in it because we've initialized it, so
that's the value of num is 10.
So in this case here, i print out the value of num is num,
which will display a 10.
Then I'll ask what's the size of num?
What is the size of an integer on my machine?
This may be different on your machine, but on my machine
an integer is 4 bytes.
And then at the end here, we'll say what is the address of num?
And this is where the address operator comes in, that ampersand
right before the variable name.
This evaluates to the location and memory or the
address of that variable.
In this case, it would be a 1000, so it would print the 1000.
But obviously, it will print something different when I
actually run the program.
So let's take a look at the output from here.
Okay, so here's the output.
I'll just put this side by side, so we can read it.
The value of num is 10 that's exactly what we expected.
And I knew that the size of an integer on my machine is 4, on
yours it might be 8, it might be 4.
And then the address of num is a hexadecimal number, so this is the way
that addresses are represented in c++.
A hex number is just a number to base 16.
So that's the address of that integer variable.
Okay, so hopefully, this makes sense.
This is the real foundation to understanding pointers and
is understanding locations or addresses of variables, so
hopefully this makes sense.
So let me clear this out.
And then let's do this next example here.
Here's where we're actually declaring a pointer, and we're
doing that right here on line 17.
We're declaring p to be a pointer to an integer.
Remember, you read these from right to left.
So p is a pointer to an integer.
What is p, it's a variable.
So here's p.
It's got storage associated with it, and it's got a
location associated with it.
Let's say that the address of p is 2000 this time.
What's in p right now, I never initialized it.
So there's garbage in here.
There's a random bit pattern here.
And as far as c++ is concerned, that random bit pattern is
an address, right, because pointers hold addresses.
So this guy, right now, is pointing somewhere who knows where.
But it's definitely pointing somewhere.
So what's the value of p, whatever that bit pattern is, we're
going get garbage right here.
And you can see that the trouble or the danger of following that
pointer and putting something in this address here that could be
something pretty important on your machine and you just wiped it out.
Hopefully, you'll get a crash, and you can fix it.
Okay, so what's the address of p.
Well, the address of p is the location where this pointer
is stored, in this case 2000.
And then what's the size of p?
How big or how much storage do I need to represent a pointer on my machine?
Well, on my machine, it happens to be 4 bytes.
Again, yours it could be different.
So this will print out some garbage memory address.
Then it'll print out the address where this variable is stored
and then it should print out a 4.
So let's give that a shot.
And here you go, I'll move it over here as well.
The value of p is, there's the hex address.
That's the garbage address.
Okay, then the address of p is at this location right here ends ending
at 18, and the size of p is 4.
Now on line 22, I nulled out the pointer.
I said p equals null pointer.
Null pointer is basically addressed to 0.
So you're just zeroing out the pointer.
So if I print out now the value of p, I should get back a 0 and I do.
What we're doing here is we're making this pointer point nowhere,
which is real, real important.
Okay, so let's do a few more examples.
In this case, I'm declaring 5 pointers, p1 through p5,
just like I did in the slides.
And all of these pointers are pointing to different types.
Okay, so and they're all nulled out right now.
So in the case of p1, p1 has stored in memory obviously, right.
We need to allocate storage for that variable.
Right now, it's null.
So it's basically pointing nowhere.
P2 is also a pointer, and we're allocating space for it.
It's pointing nowhere.
Eventually, P1 will point to an integer.
P2 will point to a double.
P3 will point to unsigned long long.
And p4 to a vector.
And p5 to a string.
So what they're pointing to is very different from what.
They are they're just pointer variables, real primitive types.
In this case, what is the size of p1?
How much storage do I need to represent the address of an integer?
It turns out it's 4 bytes.
What's the size of p2?
How much storage do I need to represent the address of a double?
Again, it's 4 bytes.
On my machine 4 bytes, and I can represent any address of any variable.
So what you would expect here is to print 4 all the way down.
Okay, now this is important.
It's really important to understand the difference between the
pointer and what it's pointing to.
Let's say we've got p1.
Eventually, p1 is going to point to an integer, right.
That's the whole idea.
And p2 will point to a double, so we'll have much more storage here.
And let's say p4 is over here.
P4 will eventually point to a vector of string objects so it
could be pointing to a vector of string objects where this could
be Larry Moe and Curly, where these guys are all string objects.
So you can see the pointer itself is simple.
The pointer itself is simple.
They're all really simple.
What they point to could be very simple or it could be pretty
complex as you see right here.
Okay, so make sure you understand the difference between the
pointer and what it points to, it's really critical.
So in this example, if I run it, I expect to get
4 straight down the line.
And there you go, size of p1 is 4 all the way down the line
because all I need is 4 bytes to represent any address on my machine.
Again, this is very machine-specific.
You might have 8 on your machine.
Okay, so now let's go through one more little example here.
All right, so let's walk through this before we even run it.
In this case, what have I got I've got score as an integer,
and I'm initializing it to 10.
Okay, let's do that over here.
Here's score, it's an integer and I put a 10 in there.
Let's assume that that address is a 1000.
That's where score lives.
Again, it'll be different on your machine, for sure.
I'm just making that thousand up.
Then I've got a double called high temperature.
Obviously, I need more storage for double, right.
And this is called high temp.
And right now i have a 100.7 in there.
And let's say that this is an address 2000.
Okay, so those are the addresses for those variables.
Now here's my pointer.
It's called score pointer.
It's got storage associated with it.
Right now, I've nulled it out so it's pointing nowhere.
So far so good.
Now this is what I'm doing here.
I'm saying score pointer is equal to the address of score.
I'm initializing that pointer to point somewhere now.
What's the address of score?
It's right here, 1000.
So I'm going to put a 1000 in here.
I'm not putting the 10 in here.
I'm putting the 1000 in here.
That's my pointer.
So now score pointer is pointing to an integer because it holds
the address of an integer.
So score pointer is pointing to score.
That's what we're doing right here.
So now let's display what's the value of score?
Well, the value of score is 10, right, right here.
So this should display a 10.
What's the address of score?
In this example, it's a 100.
And what's the value of the score pointer?
A 1000.
And so when we run this now, we're definitely going to get a 10 here.
And we're going to get obviously not a 1000 here.
But what's important is that those two numbers will be the same, they
have to be the same because score pointer is pointing to score and
score has an address, which is the one that's in score pointer.
Okay, so when we run this, we're expecting, as I said,
a 10 and then two memory addresses that are the same.
So let's give that a try.
And this is where we're at, the value of score is 10, and then the
address of score is, we can see here ending in F0, value score pointer F0.
So these are the exact same address, which is exactly what we expected.
And then this last little compiler error here, let me show you that so
that you can see the compiler and what it looks like in case you run into it.
This is a pretty common mistake.
Actually what happens here is we're saying score pointer, right
here, points to an integer, right.
It holds addresses of integers.
But we're trying to put in here the address of high temp.
High temp is a double.
The compiler is going to say sorry.
I don't know what you're talking about.
You're telling me that score pointer holds addresses of integers.
But now you're trying to put the address of a double
in there, I can't do that.
And let's compile this so you can see what the error looks
like, and it makes sense, right.
It says I cannot convert a pointer to a double to a pointer to an integer.
Okay, so that gives you some insight.
Play around with these examples, create some of your own, walk
through them, draw like I did, so you really understand these
connections between the pointer variable and what it points to.