OK.
So in this lecture, we're going to take a pretty serious deep dive into virtual memory.
I had one lecture that kind of just barely introduce you to a virtual memory was.
But we're going to expand upon that quite a bit and we're going to introduce some new topics, too.
So we've kind of already talked about process virtual memory a little bit, but we're going to expand
on that.
I have mentioned addresses, you know, the hex addresses that were kind of like the parking lot space
numbers.
Remember that analogy where I was talking about pieces of memory, like the addresses of memory being
like parking spots that had numbers to label them?
So we're going to kind of expand on that as well and look deeper into it.
I'm going to introduce a new topic called pointers and also a new topic called dynamic memory allocation.
So if you already know what these are but want to hear a little more about them, just want to like,
say that up front.
So you know that that is in this lecture.
So here is our virtual address space.
So think back to your favorite analogy, whether it be the parking lot with the numbered like spots,
right?
These are the numbers.
So these are considered addresses, right?
Memory addresses.
You could also think about another analogy like a bunch of maybe like houses lined up on on a road or
something like that right next to each other.
But the important another important thing to remember is that each car that would be parked here, each
space, actually, I should say each parking space.
Is eight minutes long or one bite?
So if you want to think of it like that, like a car, you know it have to be a car, a car could go
there.
There was maximum eight bits size, one bite and size.
Same with like a house, you know?
That's how much space is there at one specific address.
We also have our high address hex number here, so this is the like.
We would consider this like the highest address and the lowest address.
We may not actually use all zeros like we may not use that address literally when we're managing memory
and stuff like that.
But I just want to put that, you know, this is low, this is high.
We don't really care about the dark grey here or here.
What we care about is this right here when we run our program, it is loaded into memory in this area.
This point of the arrow to this point of the area, that arrow.
It is this light gray chunk here.
OK, so we run our program, our program gets loaded into this virtual address space, this virtual
memory space.
This is like our process virtual memory.
All right.
And this is like you can think of this as like somewhere in RAM, it is some volatile storage locations
and volatile memory location.
Right?
But this is a virtual thing.
It's not a physical thing.
We're just talking about this virtual imaginary space where our program is stored, right?
So what is it the bottom of this thing?
We're going to talk about the different pieces that make up this light gray.
This is something called our tech segment, and it literally holds the text code that we wrote, right?
We typed out a bunch of characters for our C++ code, and this is where it gets stored here at the bottom.
The next up is something called global variables, I haven't really explained what the global variable
is, but basically it's just like if you declared a variable at the top of a program above the main
function, above the other functions that might be above main.
It's just not in a function.
So it's not local to a function.
It's not a variable that's only known by one function.
A global variable means, you know, in the sense that global available to everything globally, available
to all of the functions, all the parts of the code.
But we're going to talk about global variables later on.
I just wanted to point out that that stuff was stored right here.
There's also some other things stored right here that I don't want to get into right now because I feel
like you just overcomplicate what I'm trying to get across.
What's after that?
So.
Oh yeah, another important thing.
These are two.
Generally, these two areas are generally a fixed size.
So this is something that's determined at compile time.
So when the program was compiled, when the program gets ran, it's not like these are going to change
size.
So that's why I wanted to point that out as well.
These two sections right here, something that does grow in size is the heap.
So that is an area right above here that grows upward towards higher memory addresses.
More explanation on that in a second.
We also have this thing that starts from the top and grows down, which is called the stack.
It grows towards lower memory addresses, so let's go ahead and check out what these two things are.
First, we'll look at the stack.
So the stack is primarily where the data from our function calls go, and I don't want to confuse you
with just saying function call.
It's really the stuff that you would see inside your function definition that would be stored here on
the stack for each one of your functions.
The fact is, though, is that those things don't really go onto the stack and tell the function gets
called intel.
The execution of your C++ code goes from the function.
Call into that function definition.
Once that happens, you know, once it sees the function call, it basically sets aside a new little
chunk of memory here on the stack.
When another function is called, it sets another thing aside, and it looks kind of like this.
Here's one function call.
Here's another function call.
Here's another function call and it kind of stacks up.
It's almost looks like plate stacking on top of each other, but like stacking downwards, right?
These things are called stack frames.
These green things right here.
So whenever a function call happens, it's represented in memory as a stack frame and it goes on the
stack, hence the name stack frame.
So these frames are these little chunks, these rectangles here, they hold data that is local to the
function scope.
So stuff inside the curly braces of the function definition like variables that you may put in there,
as well as the parameters that are inside of the function definition parentheses on that first line
of the function.
Different definition, right?
So if you have those parameters, those will be pushed onto the stack as well.
All right, cool.
So something interesting is when the stack rose downward too far, it can overwrite memory in another
section like we had the heap right here, right?
This results in something called Stack Overflow, and this can happen like a commonly in this happening
is when you have, like, you know, too much recursion.
Remember, we just talked about recursion.
We're not going to go deep into that until the second segment of the course, which is the data structures
and algorithms segment.
But I did show you that if you were to accidentally arrange like function calls in another function
call, it puts you in kind of a loop.
Then it went infinitely kind of like the infinite wow loop.
Remember from that lecture where the last like, I don't know was the last lecture election before?
We were having a function, a call, function B, call function C, stuff like that.
Well, if you had it function B call itself, it would just bounce around inside of itself and it would
never exit.
That can eventually lead to a stack overflow as well as you having some kind of indirect recursion.
I talked about that as well, which is kind of like know because a and then and then a calls B and then
in a sense, be called a just calls again, you know, and just keeps going back and forth like that.
That's indirect recursion.
So just want to point that out, something interesting.
There's also a popular site where you can look at how to solve errors and stuff is kind of like a forum
is called Stack Overflow.
Really popular website.
Lots of programmers use that.
So let's talk about the heap.
So the heap is a place where we can store something called dynamically allocated memory and variables.
It's not necessarily the only thing on the heap.
In fact, we were talking about global variables.
Sometimes that can be interpreted as being kind of part of the heap, even though we've got it here.
But now we're going to talk about like too much detail about the heap, but it's definitely capable
of storing this dynamically allocated memory flash variables thing.
And that's something we're going to talk about in this lecture a little bit later.
So the heap is useful for storing things that might grow a lot in size.
So we talked about the heap grows in the stack grows right.
The heap is kind of a more open space, though, because it's managed less by the operating system.
So it's a good space for us to store things where we're thinking maybe this could get pretty big, like
we have a container, I think the only container that we've talked about is an array so far.
But if we had a container that was just going to get really, really big when store like a crazy amount
of data in it or we, you know, we just had some.
Thing in our cold, it was going to be big, we might want a story here on the heap where we have more
space.
So let's talk about managing this memory, because C++ is a cool language and we can actually kind of
do lower level stuff and manage the memory so our programs can be more efficient.
So how do we refer to a specific location in memory?
I'm talking about like an address space and memory, you know, some sort of chunk of memory.
We can access memory and kind of refer to memory by using something called a pointer.
So what is a pointer?
And this is something that's a new concept we're going to have to introduce.
So a pointer is just something that holds an address.
So we talked about like having addresses right here, we have the Hex, like with the eight, right?
So imagine you have some hex address here.
We can store like in, let's say, an integer in memory.
Right?
So let's say there's an integer stored in here.
Maybe I want to have some sort of variable that doesn't necessarily store the integer that's here,
but instead it stores the address number.
So later on, I can follow that address number and then find the integer here.
The pointer is the thing that stores that address.
So it's kind of like, you know, storing the number for the parking spot, right?
So you can think of a pointer is basically an integer, although it is seen as a hex address, you know,
we're still seeing like zero x f f f f f, you know, all that stuff.
But you know, a hex number also has a decimal form, which you can think of as an integer.
So you can just think of pointers as just always holding integers right there, just holding an address.
So pointers are often, like really confusing for people.
So, you know, we're going to look more into this, but I'm trying to like make it as simple as possible.
So just think of pointers as integers or just addresses like it's just a holder, it's like a variable
that holds the address, right?
And you can use that address that's stored in the pointer to find what is stored there at that location
at that address, right?
So let's talk about how to use these pointers.
So to use pointers, we need to use some symbols that we're familiar with, but we're not going to be
using them in the same way we're going to have to use them in a different way.
So what you see right here is a main function.
So inside this main function, what we're doing is we're making a new integer a we are assigning the
value seven to a.
So make a new integer a sign the value seven to it.
And then this is going to go on the stack because it's inside of a function.
This is the main function, so.
Talking about pointers now, but since we're just talking about the stack, I wanted to go ahead and
throw this in there and let you know that the things inside the function are going to get stored on
the stack.
So these.
I shouldn't say things inside the function, these local variables that are local to the function will
be stored on the stack.
All right.
So.
Next, what we do is kind of weird.
We use this multiplication symbol, it's the asterisk, but we're not multiplying anything.
What we're doing here is making a pointer called B, and we're making this pointer point to the address
of A.
So obviously, seven was stored on the stack at some memory location, right?
It was stored in that memory space somewhere.
And a holds that value seven, if we want to get the address.
Of a though, and not just the value, we need to use this little ampersand here, right?
This ampersand here is something we've seen we've seen using two ampersand for the logical and operator,
and we've used one ampersand like this for pass by reference.
In fact, pointers are kind of related a little bit to pass by reference, so when you pass that thing
by pass a very BioReference member, we talked about how it really passes that actual memory location.
It's such that it's like a reference.
It's a constant reference to that memory location, like an alias to it, you know, or something like
that.
So this is pretty similar.
It's getting us the address, right?
It's referring to a.
But when you see that, see it in this position here and we're not passing it as a parameter.
You can just think of the ampersand as giving us the address of a.
So like I said, the star signifies that B is a pointer, this star right here next to the B and the
fact that we have an integer in front of it basically says that we're making a pointer that points to
an integer.
The end part is kind of irrelevant, though the only reason we're doing that is just because, like
we said, it points to an area of memory that's most likely storing the data type integer.
So that's why we put Int Pointer B.
And like I said, the end is used being used in a way that enable us to grab the address of a, as he
put it, before the A.
So but what's the point?
Hah, gotcha, funny.
Use the word point.
So similar to the past by referencing the pointer refers to the actual piece of memory, and what we
want is to potentially reference that from another piece of code.
So.
Think about a scenario where we store an array somewhere in memory, right, so we have an array and
that array has very large elements, it has very large items.
And later on, we're going to be interested in to we're going to be interested in referring back to
this array.
So we have, you know, the items that are large stored in a large array is taken up a large piece of
memory.
So now imagine we want to fill another array later on in our code with a bunch of copies of the stuff
that was in this other era.
Right.
So we want the same items that are in the other array.
We could go ahead and copy that stuff over to this new era.
You know, it's going to be another huge array with huge items in it.
Or instead, we could just store the addresses to those original elements or items in that other array.
And that would take up a lot less space and a lot of cases, because if the items are like some huge
data type imagines, maybe it's a data type we haven't talked about yet.
We're going to make our own data types later on, which might contain a ton of stuff, and they take
up a lot of space.
It's going to be better to just store an integer, right?
We talked about the point of just being integer right, but it's like a hex address.
It's a lot cheaper, less costly, less space to store and address than to like copy over the whole
like huge item like item by item, right?
We could just store have an array of pointers to those items, right, that refer to the original items.
So pointers can save you a lot of space.
And that's nice because when you write really large programs, honestly, space becomes a huge factor
in the efficiency of your product or your software that you're writing.
So if we are going to be storing big things, though, we should really be storing them on the heap
because remember, we were talking about the heap having a lot more open space available for us.
A caveat, though, is since the heap is not really managed the same way as the stack, the operating
system isn't doing as much stuff managing that region of memory.
We're going to have to manage that region of memory ourselves.
We have to manage to keep memory ourselves.
This means specifically allocating and allocating memory for our variables and using pointers to keep
track of them.
If you don't know what allocating and allocating means, like in the sense of memory is similar to just
like allocate, when you say allocating is just coming up with space for stuff.
Right, like, I allocate some space in the drawer for my clothes or something, right like right,
I free up some space are not free.
Sorry, I set aside some space in the drawer.
And freeing up space would be allocating, so basically when you allocate memory, it's basically like
you're putting stuff in memory, you're you're setting aside some room and then storing stuff there.
Right?
So you're you have to make space, you make space when you're allocating and then allocating is freeing
up that space.
So making it available again.
I guess that wasn't a very good analogy, maybe a good analogy is kind of like.
You know, I I when you set aside space, you're saying, OK, this space is reserved.
I'm reserving space for stuff.
And that's when you allocate, right?
And then when it's no longer reserved, you can allocate it to you like, Oh, it's free, it's vacant.
We have a vacancy now.
It was reserved.
Now it's vacant.
Right?
Maybe that's a better analogy.
And we're going to have to use pointers to do this because pointers are going to help us manage that
heat memory.
So we're going to take a look back at the last point, for example.
But instead of storing a and B on the stack, we're going to store it on the heap.
And in fact, I think in my example, I'm not going to really store B on the heap.
I'm just going to store a.
So we're going to need to add some additional syntax to make stuff go on the heap.
So this is what it's going to look like to store a on the heap rather than a stack.
We're going to need to use some additional syntax right here.
So what we're doing is on this line, we are making a pointer that contains the address of a and we're
making we're basically putting aside some space that allocation on the heap right here.
So this part and Star A says this is now a pointer containing the address of A.
And then on the heap part is basically this new entry here.
This new is the real key word.
It's a C++ keyword.
This you can you can basically look at this new and every time you see new, you can make up a heap
that means heap.
If I use the keyword new, it's dynamically allocating memory, which means it's going to be on the
heap.
New is the keyword for dynamic memory allocation.
New, it is going to set aside and reserve some space on the heap for an integer variable a specifically
since we talked about this since we defined this right here.
And Start A is just the syntax to say, Hey, I want to make a pointer.
With the name A.
That is going to point to an integer, right?
This line down here is something interesting.
So the star here isn't as like re declaring a pointer, it's actually something called D referencing
a.
So what we're doing is we are kind of.
Following it to the address and.
Opening up that memory kind of like clearing a path to that memory, and then we're assigning seven
to that memory spot.
So a is a pointer, so it stores an address, right?
You can't just say a equals seven without the star.
And the reason you can't do that is because, well, technically I don't want to say you can't, you
could, but you don't want to.
And the reason you don't want to.
Is because this is the thing that we want to store.
Yet a holds the address.
We don't want to put the thing that we want to store in memory and overwrite the address.
We want to put it at the location of the address.
And if you want to put it at the location of the address, you have to put a little star in front of
the A, which the references it and clears an open path for you to toss this seven into that open memory
slot.
All right.
So let's examine it a little closer, some of this I kind of already explained, but I just want to
reiterate.
And Star a US declaring a new pointer that points to an integer.
The new and part on the right side of the equals sign is a specifying that we want to clear new space
so reserved some space for an integer on the heap.
That's why we can also include the end on this side, not only this side.
Star A D references A, which means that it follows the pointer to the data stored at A's address,
except we haven't stored anything at this point until we take the seven and put it there.
That space in memory could have something there.
Remember, we've talked about like garbage values or just kind of floating around in memory, so something
might be there.
But the point is is that we're saying, Hey, this is reserved, and now we're going to put stuff there
and this equals seven is us putting stuff there.
This is almost like, you know, opening the curtains to that memory spot.
And then we put this thing there, right?
Opening the drawer.
So the drawer is open now.
We put the seven in the space that's inside the drawer.
Star, a reference references say for us to be able to do this so we don't overwrite that headdress
that is stored in the a pointer.
Right.
So.
Do referencing a would also give us the ability to access the data stored at AI's address, so if we
wanted to print out.
What is stored at A..
We could see out Star A..
And that would actually print out seven since seven is stored.
They're at that location now.
All right, so that's kind of all I have to say now about this memory allocation stuff.
We are going to practice doing dynamically allocated memory and using pointers more often, but I figure
that it was a good time to just introduce you to these topics.
We won't be using pointers all the time, but it's important to know what they can be used for in the
benefit, right, that they save space.
But I'm going to be honest that it is kind of difficult to use pointers in dynamically allocated memory,
sometimes because you have to manage it.
You remember that I talked about this D allocation part.
This is another thing that we're going to have to talk about when we're using these heap variables and
pointers dynamically allocated memory on the heap.
We're going to need to allocate it as well.
So something that I should just say right off the bat is that any time you see this new keyword, if
you're going to use the word new in your program like this to make something on the heap, just know
that since you did the allocation in this part, everything that gets allocated needs to be allocated,
which means you need to delete that stuff.
So we're going to have to go over that as well in our code.
Just something to keep in mind that, you know, if you're already familiar with some of this stuff,
but you maybe don't know this, you should always allocate any memory that you've allocated with the
key word new.
You need to explicitly delete it.
OK.
Because if you don't do that, you have something called a memory leak.
You've left stuff on the heap and it's filled with all these things that you allocated and never got
rid of.
That can cause problems down the line, and that's something else will get into.
All right.
So with that, I think I'm going to let you go and I will talk to you in the next lecture.