WEBVTT

00:00:00.540 --> 00:00:03.460
Now that we know how scope works, we are ready to learn about

00:00:03.460 --> 00:00:06.460
one of the main reasons why pointers were invented in the

00:00:06.460 --> 00:00:10.350
first place. To demonstrate this, I created a simple program.

00:00:10.940 --> 00:00:14.570
First we declare and initialize this x variable, and then

00:00:14.570 --> 00:00:17.150
we pass it to the addThree function.

00:00:17.840 --> 00:00:20.510
The only purpose of this function is to increment the

00:00:20.510 --> 00:00:22.850
number from the parameter by 3.

00:00:23.740 --> 00:00:27.940
I also printed out the value of x to the terminal in three places

00:00:27.940 --> 00:00:31.000
throughout the code. Before continuing with the lesson,

00:00:31.000 --> 00:00:34.380
try to guess what each one of these cout statements will print

00:00:34.380 --> 00:00:38.850
out. Now, let's compile it to see what we'll get.

00:00:41.440 --> 00:00:44.570
It seems that the function worked, since the second line

00:00:44.570 --> 00:00:47.590
says 8, but what about this third line.

00:00:47.710 --> 00:00:51.700
After we exit the function, the value of x is 5 again.

00:00:51.760 --> 00:00:52.450
Why?

00:00:53.640 --> 00:00:56.460
Let's see what's going on in memory line by line.

00:00:57.240 --> 00:01:01.640
Main function will get executed first, so this means that the main scope is

00:01:01.640 --> 00:01:06.270
created. Inside of the scope, we declared a variable x.

00:01:07.340 --> 00:01:11.480
As we know, this will allocate a space in memory and store this number 5

00:01:11.480 --> 00:01:17.450
inside of it. And, of course, this cout will then print out the number 5.

00:01:18.940 --> 00:01:21.710
The addThree function will get executed next,

00:01:21.710 --> 00:01:25.560
which means that the new scope for this function is spawned into existence.

00:01:26.140 --> 00:01:29.350
Official term would be pushed onto the stack, but we will

00:01:29.350 --> 00:01:31.060
talk about stack in the next module.

00:01:31.640 --> 00:01:32.210
Now,

00:01:32.220 --> 00:01:35.840
this is the important part, so pay close attention. In the previous

00:01:35.840 --> 00:01:39.690
lesson, we said that the parameter variables are just local variables

00:01:39.690 --> 00:01:43.960
that belong to the scope of the function, so a new place in memory is

00:01:43.970 --> 00:01:46.520
allocated for this local variable x.

00:01:47.010 --> 00:01:50.860
As you can see, now we have two variables with the same name,

00:01:50.940 --> 00:01:55.580
same identifier, but they are not the same. They don't have the same place in

00:01:55.580 --> 00:01:59.150
memory, and each of them exist in their own separate scope.

00:01:59.940 --> 00:02:03.490
You can use the same name for more variables, as long as

00:02:03.490 --> 00:02:05.360
you don't use it in the same scope.

00:02:06.040 --> 00:02:08.440
So what happens when you pass a variable as a

00:02:08.440 --> 00:02:10.900
parameter inside of a function call?

00:02:10.970 --> 00:02:15.260
C++ will copy the value from the passed variable inside of the

00:02:15.260 --> 00:02:19.430
parameter variable. In this case, this is the functional local x

00:02:19.430 --> 00:02:24.350
variable, so the value of 5 gets copied from this place in memory

00:02:24.360 --> 00:02:25.860
to this place in memory.

00:02:26.040 --> 00:02:29.290
Since the value is passed from one variable to another,

00:02:29.300 --> 00:02:34.360
we call this event passed by value. The value in this local variable x

00:02:34.360 --> 00:02:38.800
will then increment by 3, and the number 8 will be printed out to the

00:02:38.800 --> 00:02:42.680
terminal. And now this function scope is done,

00:02:42.690 --> 00:02:45.170
which means that all of the declared variables from

00:02:45.170 --> 00:02:47.450
the scope are released from memory.

00:02:47.470 --> 00:02:51.760
This local variable x from the parameter does not exist anymore.

00:02:52.540 --> 00:02:56.110
We are now back in the main function, and we print out the value of x,

00:02:56.110 --> 00:03:00.660
which is 5, because this x variable from the main function scope was

00:03:00.660 --> 00:03:05.850
never even touched, and now the output we saw makes sense. To make this

00:03:05.850 --> 00:03:09.310
work as intended, we could have returned the value from the incremented

00:03:09.310 --> 00:03:13.710
variable x from the function and then overwrite that value inside of the

00:03:13.710 --> 00:03:14.760
main function x.

00:03:15.030 --> 00:03:19.150
So this function should return int, and we assign its

00:03:19.150 --> 00:03:22.350
return value to the x from the main scope.

00:03:25.440 --> 00:03:27.150
When this function is finished,

00:03:27.160 --> 00:03:30.960
the value from x, which is 8, will get copied from this place

00:03:30.960 --> 00:03:33.260
in memory back to this place in memory.

00:03:34.240 --> 00:03:36.940
The scope of this function will still be destroyed,

00:03:36.950 --> 00:03:39.660
but the value is incremented by 3.

00:03:40.840 --> 00:03:42.980
As you can see, this is really expressive.

00:03:42.980 --> 00:03:46.330
What if we just wanted to simply increment this variable without

00:03:46.330 --> 00:03:50.630
returning anything from the function. And, more importantly,

00:03:50.640 --> 00:03:52.950
what if we didn't pass a simple integer?

00:03:52.960 --> 00:03:56.700
What if this was an object that had 50 bytes of data and this

00:03:56.700 --> 00:03:59.290
function had to be executed more than once.

00:03:59.460 --> 00:04:02.430
This means that the object from this scope will have to be

00:04:02.430 --> 00:04:06.290
copied over from this place in memory to this one, and then

00:04:06.290 --> 00:04:07.800
when the function is finished,

00:04:07.810 --> 00:04:11.620
the local object will have to copy the value back to the first place in

00:04:11.620 --> 00:04:15.320
memory. And don't forget that you also have to allocate a new place in

00:04:15.320 --> 00:04:19.779
memory for this temporary object every time the function gets called. This

00:04:19.779 --> 00:04:24.010
memory allocation and copying of values around in memory will degrade the

00:04:24.010 --> 00:04:28.200
performance of your programs, and that is one of the main reasons why we

00:04:28.200 --> 00:04:33.410
needed to invent something like pointers. Instead of passing the value from

00:04:33.410 --> 00:04:36.180
this variable, let's pass its memory address.

00:04:36.380 --> 00:04:38.760
We can do this with the reference operator.

00:04:41.540 --> 00:04:43.250
Since we are now passing the address,

00:04:43.260 --> 00:04:46.960
this parameter variable needs to be able to store that address.

00:04:47.440 --> 00:04:49.520
Integer variables don't do that,

00:04:49.530 --> 00:04:54.330
but the pointers to integers do. So this will create a pointer

00:04:54.330 --> 00:04:57.490
variable inside of the function scope, which will store the

00:04:57.490 --> 00:05:00.060
address passed on from the main function.

00:05:01.940 --> 00:05:05.830
And now, instead of incrementing this local variable by 3,

00:05:05.840 --> 00:05:07.850
we need to dereference this pointer.

00:05:09.840 --> 00:05:15.370
This means that this value 5 will be incremented by 3, the same place in

00:05:15.370 --> 00:05:19.840
memory occupied by the variable x inside of the main scope.

00:05:19.850 --> 00:05:24.780
So with the help of pointers, we access the variable from another scope, and

00:05:24.780 --> 00:05:28.260
this scope still exists because main function is not done yet.

00:05:28.540 --> 00:05:30.560
Once the addThree function is finished,

00:05:30.570 --> 00:05:34.540
the function scope is deleted, and this pointer variable is removed

00:05:34.540 --> 00:05:39.250
from memory. But we don't care, because the value from this variable we

00:05:39.250 --> 00:05:41.860
passed in still has an incremented value.

00:05:44.440 --> 00:05:46.910
If I compile this version of the program,

00:05:46.920 --> 00:05:52.360
the result will be 5, 8, and 8, and this is exactly what we wanted.

00:05:53.240 --> 00:05:54.430
At the first glance,

00:05:54.430 --> 00:05:57.800
this program looks similar to the first version without pointers.

00:05:57.830 --> 00:05:58.620
After all,

00:05:58.620 --> 00:06:02.700
we still have to allocate memory for this pointer and copy this address

00:06:02.710 --> 00:06:06.460
inside of it. But this program is a lot more efficient.

00:06:06.740 --> 00:06:07.470
First of all,

00:06:07.470 --> 00:06:11.000
we are not returning anything, so there is no copying of value

00:06:11.000 --> 00:06:13.660
back to the variable x from the main function.

00:06:13.840 --> 00:06:14.540
Second,

00:06:14.550 --> 00:06:19.310
this local variable is now just a pointer, which means that we allocate only 4

00:06:19.310 --> 00:06:22.710
or 8 bytes of data, depending on the computer's architecture.

00:06:22.830 --> 00:06:25.280
If we pass around big complex objects,

00:06:25.290 --> 00:06:28.520
you can see that it is easier and more efficient to store a

00:06:28.520 --> 00:06:32.240
simple address instead of copying a big object and allocating a

00:06:32.240 --> 00:06:34.450
lot of space to store it temporarily.

00:06:34.740 --> 00:06:38.770
This idea of indirectly modifying data and memory from the scope of

00:06:38.770 --> 00:06:42.060
a different function by storing an address of an argument as a

00:06:42.060 --> 00:06:45.470
parameter is known as passing by reference.

00:06:45.480 --> 00:06:47.460
So instead of passing by value,

00:06:47.470 --> 00:06:50.260
which means copying the value from this variable to this one,

00:06:50.270 --> 00:06:51.780
you are passing by reference,

00:06:51.780 --> 00:06:54.860
which means that you are only storing an address, in other words,

00:06:55.040 --> 00:06:59.220
a reference. You are referring to this variable in memory through the

00:06:59.220 --> 00:07:04.280
pointer. Passing by reference is a far more efficient way to work with

00:07:04.280 --> 00:07:06.880
objects that need to be passed to functions.

00:07:06.890 --> 00:07:10.930
Of course, there are some cases where you really want to just pass by value,

00:07:10.940 --> 00:07:14.680
because you need to use this value for some other purpose and you are not

00:07:14.680 --> 00:07:19.160
interested in the variable that passed it in. However, passing by reference is

00:07:19.160 --> 00:07:21.690
usually the preferred way, but as you can see,

00:07:21.700 --> 00:07:23.940
it can seem a little bit frightening at first,

00:07:23.950 --> 00:07:27.930
especially because you need to remember to pass an address and then also

00:07:27.930 --> 00:07:31.850
dereference this pointer to work with the value at that address.

00:07:31.880 --> 00:07:34.740
C programmers are very familiar with this,

00:07:34.750 --> 00:07:36.860
but since we are working in C++,

00:07:36.870 --> 00:07:39.460
you can be sure that there is a better way to do this,

00:07:39.470 --> 00:07:41.860
and we will talk about it in the next lesson.
