WEBVTT

00:00:00.340 --> 00:00:04.580
Here is the simple program we talked about in the previous lesson. We

00:00:04.580 --> 00:00:08.060
only declare this variable and initialize it to 2.

00:00:08.940 --> 00:00:13.840
I will print out the value stored inside of this variable and also the memory

00:00:13.840 --> 00:00:19.450
address. I'm using the address of operator to get the address.

00:00:20.540 --> 00:00:23.150
Alright, now let's compile this program.

00:00:25.440 --> 00:00:27.820
The stored value is not a big surprise,

00:00:27.830 --> 00:00:31.160
but let's take a look at the output for the memory address.

00:00:32.340 --> 00:00:34.590
It is prepended with 0 and x,

00:00:34.880 --> 00:00:38.790
which means that this is a hexadecimal number. In a decimal

00:00:38.790 --> 00:00:41.540
notation, that number would look like this.

00:00:41.570 --> 00:00:42.560
Either way,

00:00:42.570 --> 00:00:45.350
we don't really care for the exact number since we are

00:00:45.350 --> 00:00:47.800
never going to type up the address by hand.

00:00:47.810 --> 00:00:52.750
That is what the reference operator is here for. Now let's say that I

00:00:52.750 --> 00:00:55.860
want to store this memory address for later use.

00:00:57.040 --> 00:01:01.500
I want to store it inside of this addr_of_x variable, but I don't know

00:01:01.500 --> 00:01:04.750
which data type should I use to store memory addresses.

00:01:05.540 --> 00:01:08.430
So let's use the auto keyword, which will force the

00:01:08.430 --> 00:01:11.150
compiler to deduce the data type itself.

00:01:11.940 --> 00:01:15.910
I will now hover over the identifier to see which data type was

00:01:15.910 --> 00:01:20.400
chosen to store the address by the compiler. And it seems like the

00:01:20.400 --> 00:01:24.300
data type is integer, but there is also this asterisk character

00:01:24.300 --> 00:01:26.050
next to the variable name.

00:01:26.060 --> 00:01:29.910
It is the same character we use as a multiplication operator, but

00:01:29.920 --> 00:01:35.310
obviously in this case nothing is getting multiplied. C++ knows that

00:01:35.320 --> 00:01:40.550
this is not a multiplication operator because of the context. In this

00:01:40.550 --> 00:01:45.060
context, the asterisk is actually informing the compiler that we want to

00:01:45.060 --> 00:01:47.260
use this variable as a pointer.

00:01:47.640 --> 00:01:49.460
So what is a pointer?

00:01:50.440 --> 00:01:54.540
Pointer is just a variable that holds a memory address.

00:01:54.620 --> 00:01:59.200
In other words, if you want to store a memory address inside of a variable,

00:01:59.210 --> 00:02:04.840
you can store it inside of a pointer. And pointer is just a

00:02:04.840 --> 00:02:07.470
variable with this character in front of it.

00:02:07.480 --> 00:02:10.560
This is what separates it from other data types.

00:02:11.240 --> 00:02:15.910
So if this character tells the compiler that this variable is a pointer,

00:02:15.920 --> 00:02:18.570
why do we also need this int keyword?

00:02:18.620 --> 00:02:22.360
We will discuss this in more detail later, but for now, just

00:02:22.360 --> 00:02:25.980
remember that if your pointer variable is holding an address

00:02:25.990 --> 00:02:31.250
at which the integer is stored, then the pointer should also be an integer.

00:02:32.840 --> 00:02:35.890
So, as an example, if this variable was a double,

00:02:35.900 --> 00:02:40.540
we would also need to put double here so that we can store an address to that

00:02:40.540 --> 00:02:47.020
place in memory which holds that type of data. Before we move on, let's try to

00:02:47.020 --> 00:02:49.530
imagine how this looks like behind the scenes.

00:02:49.550 --> 00:02:50.480
So, again,

00:02:50.490 --> 00:02:54.460
here is our variable x. Compiler will assign an address to this

00:02:54.460 --> 00:02:59.290
variable and store the number 2 inside of it. And now we can create

00:02:59.300 --> 00:03:02.060
another variable which will store that address.

00:03:02.340 --> 00:03:06.540
This variable also gets assigned some other place in memory. I will

00:03:06.540 --> 00:03:10.780
keep this asterisk character as a part of the identifier so that we

00:03:10.790 --> 00:03:15.130
always know which variable is a pointer, but in practice pointers are

00:03:15.130 --> 00:03:17.010
just like any other variable.

00:03:17.020 --> 00:03:18.970
They also have their own place in memory,

00:03:18.980 --> 00:03:22.350
their own memory address, and they can also store some value.

00:03:22.540 --> 00:03:25.690
In this case, we are taking the address of the variable x

00:03:25.690 --> 00:03:28.150
and storing it inside of the pointer.

00:03:29.440 --> 00:03:32.200
And since this address is holding an integer,

00:03:32.210 --> 00:03:35.860
we need to also define this pointer variable as an integer.

00:03:36.540 --> 00:03:40.930
So why are these address storing variables called pointers?

00:03:40.940 --> 00:03:46.340
Well, because we can kind of imagine that they point to another place in memory.

00:03:46.350 --> 00:03:51.060
In this case, the addr_of_x pointer points to the variable x.

00:03:53.240 --> 00:03:56.790
Let's print out the addr_of_x variable in the same way

00:03:56.800 --> 00:03:58.960
and see if we get what we expected.

00:04:00.340 --> 00:04:02.560
Now, let's compile the program again.

00:04:04.140 --> 00:04:06.150
And did we get what we expected?

00:04:06.640 --> 00:04:06.980
Well,

00:04:06.980 --> 00:04:11.590
it seems like we did. The most important part of this output is that

00:04:11.590 --> 00:04:15.960
the memory address of x and the value stored in the pointer variable

00:04:15.970 --> 00:04:18.250
are the exact same memory address.

00:04:19.940 --> 00:04:24.750
This last line was just to show you that pointers are just like other variables.

00:04:24.750 --> 00:04:26.970
They also have their own place in memory.

00:04:26.980 --> 00:04:30.820
So you can basically have pointers to pointers, variables

00:04:30.820 --> 00:04:34.570
that store a memory address of another pointer that stores

00:04:34.580 --> 00:04:36.950
another memory address, and so on.

00:04:37.140 --> 00:04:41.850
You might notice that your addresses are different than mine, and that is okay.

00:04:42.040 --> 00:04:45.730
As I mentioned, different OSs and architectures store

00:04:45.730 --> 00:04:47.600
the addresses in different ways.

00:04:47.610 --> 00:04:50.570
But you can also notice that every time we recompile the

00:04:50.570 --> 00:04:53.160
program we get different memory addresses.

00:04:53.440 --> 00:04:56.480
This is done on purpose, mostly to increase security of your

00:04:56.480 --> 00:04:59.200
programs, and if you want to know more about this,

00:04:59.210 --> 00:05:04.610
you can read about address space layout randomization, or ASLR. I just

00:05:04.610 --> 00:05:07.460
wanted you to know that this is the expected behavior.

00:05:08.640 --> 00:05:11.380
As you can see, pointers are a really simple concept,

00:05:11.390 --> 00:05:13.150
but if you never used them before,

00:05:13.160 --> 00:05:15.550
you might want to take it slow and try to draw

00:05:15.550 --> 00:05:18.220
memory like I did for these examples,

00:05:18.230 --> 00:05:22.370
at least in the beginning. I always put this character next to the

00:05:22.370 --> 00:05:25.780
variable name, and I will continue to do so throughout the course,

00:05:25.780 --> 00:05:29.880
but you may also see programmers declare a pointer with the asterisk

00:05:29.890 --> 00:05:32.360
next to the data type like this.

00:05:32.640 --> 00:05:36.420
It really doesn't matter, and it all depends on how you think about pointers,

00:05:36.430 --> 00:05:41.210
but I urge you to declare pointers like me for one simple reason. Let's say

00:05:41.210 --> 00:05:45.920
that you want to declare more than one pointer at the same time, so you may

00:05:45.920 --> 00:05:51.030
type out a statement that looks something like this. But this will not create

00:05:51.030 --> 00:05:53.020
three pointers to integers.

00:05:53.030 --> 00:05:56.760
The first variable will be a pointer, but the other two will

00:05:56.760 --> 00:06:00.560
be just simple integer variables, because the compiler will

00:06:00.560 --> 00:06:02.480
see our statement like this.

00:06:02.540 --> 00:06:06.260
The asterisk is only referring to the first variable.

00:06:07.040 --> 00:06:10.090
However, if you add an asterisk to every variable,

00:06:10.090 --> 00:06:13.580
this will create three pointers, just like we wanted, so I

00:06:13.580 --> 00:06:16.000
advise you to declare them like this,

00:06:16.010 --> 00:06:20.540
but the final decision is up to you. Everyone has their own coding style,

00:06:20.550 --> 00:06:23.810
but when you choose your own, please be consistent, at least in

00:06:23.810 --> 00:06:27.510
the same code base, because if you don't, well, that's just

00:06:27.510 --> 00:06:31.510
rude. If you need to declare a pointer, but you don't want to

00:06:31.510 --> 00:06:34.370
initialize it right away, set it to nullptr.

00:06:35.340 --> 00:06:38.870
This is a special C++ keyword that defines a pointer

00:06:38.870 --> 00:06:40.580
that doesn't point to anything.

00:06:40.590 --> 00:06:43.450
It is basically the same as writing NULL or 0,

00:06:43.460 --> 00:06:46.230
but using this keyword instead is recommended in

00:06:46.230 --> 00:06:51.150
modern C++. If you don't do this, your pointer will hold some garbage data,

00:06:51.240 --> 00:06:55.440
the collection of bits that was already there at the address in memory before

00:06:55.440 --> 00:06:59.560
it was assigned to your pointer, and you don't want that because in some

00:06:59.560 --> 00:07:02.650
situations this could be dangerous and lead to bugs.
