[MUSIC] It's time to delve into the topic of pointers. We've seen pointers already. You may not have realized it, though. Pointers are what that star notation, that asterisk refers to. The motivation comes from the fact that sometimes scopes can be too restrictive. If you look at this example of code here, it's worth taking a moment to think about it. If you look at this main function what we would do is we declare a variable called x and set its value to two. We output it's value with a printf statement, and then we call this function, addFive, passing it the value of x that we just declared. When addFive returns, we use another printf statement to output the value. Well something interesting happened. We passed x to addFive and addFive has no return value, it's void so there's no return statement. And within addFive we added five to the variable x and yet when we look at the output statements, the first value of x is two and then even after adding five the value is still two. Something's happened here which doesn't seem to be quite right. What good is a function addFive if it doesn't actually add five? What's happened is that every function call creates a frame with a copy of the input variables. It creates a sub scope in which the variables can be altered without having any effect on the variables in the function that called this sub function. When the frame is destroyed the copy that was created with the function call is destroyed but the original remains intact. So, the same code is on the left, if we imagine what's happening using a box and line diagram on the right, we see that the main function has inputs argc and argv, and has an output of type int that we return zero. When we run our main function, an integer x is declared. When we call addFive, a new frame is created. That integer x is passed as an input, and it's copied, and added to the scope of addFive. The variable x has five added to it. So within the scope of addFive, what was originally a variable with a value of 2, becomes a variable with a value of 7. The function ends right away, so we don't do anything with that value of 7. And when the function ends, the frame is destroyed and the copy of integer x is destroyed with it. When control flow moves back to the main function, although the copy of integer x that was made when addFive was created was destroyed, the original integer x that was declared within main remains the same. Not only does it remain the same in terms of not being destroyed but it remains the same in terms of the value that it had before addFive was called. And we can see that makes sense when we look at the output. We declare x to be equal to two, we output its value and it's two. We call addFive which creates a new frame encapsulates a copy of the variable, does whatever it wants to to that variable, destroys it on its return and when we come back to the control flow in main, we see that later x still has a value of two. This is kind of what a scope does. New namespace, new version of x. Well, really what good is an addFive function if the changes don't persist? There's no point in trying to come up with a function that changes variables if the variable's changes don't stick around. Seems like a sort of limited use of a function. Well, addFive's version of x was local to that scope, and so we call that version of the integer x that was within the addFive name, space, and scope a local variable. Finding a way to have non-local variables is one of the motivations for having pointers. A way to have those changes persist, so to understand a little bit more about pointers, we have to talk a little bit more about memory. Objective-C programs actually have two kinds of memory. One kind of memory is the kind that's used for frames and for local variables. And that's called stack memory. If you remember from our example when we were looking at recursion, when our program ran itself forever and ran out of memory, the kind of memory that it ran out of was stack memory. The second kind of memory is heap memory, and heap memory we're going to delve into a little bit more in future lectures, but it is a kind of memory that is managed more directly by programmers. Regardless of what kind of memory we're talking about, you can think about memory as a long list of zeros and ones. The most fundamental element that a computer maintains state over. These are implemented in transistors at a very low level, but you can think about it abstractly as a long list of zeros and ones. And those zeros and ones get chunked up into bytes of eight bits each. Each one of those bytes is given what's called an address. And this is very similar to a street address for a house. This is necessary so that the computer, in this long line of bits, can find specific bytes that it wants to use over and over again. Like an index into a page in a book or a street address. When a computer wants to go to a specific spot it has to know the address. So here's a diagram that kind of shows each byte being assigned an address like a street address. The first one being address 12345. So, if x, a variable that we declare, is a 16 bit integer, it's going to use two bytes. And it's going to take up the number of bytes that are indicated by the yellow. When you make a function call, then a copy is going to be made on the stack. More things happen than just this, but this is an abstraction of what happens. Another copy of x is added to memory. Later when the function is returned that copy is removed. Even if some changes had been made to that copy, it gets destroyed and the original value remains in memory at the same spot untouched. For function calls and method calls, this copying and destroying is handled automatically. It's part of the language to create frames, and destroy that memory and take care of it. And that happens on stack memory. Now I draw a differentiation from that because later when you as a programmer start working with heap memory, destroying and creating bytes in heap memory is not gonna be done automatically for you. If a programmer wants changes to x to persist then she has to manage the memory herself. And that requires using the address of x. So, in this case rather than having talking about x. We need to talk about the address of x. In this case 2 is the address of x. 2 is what we call a pointer to x if we want to keep track of pieces of memory, we use pointers. Well we know how to declare an integer. We've seen that. We use the keyword int and the variable named x and a semicolon. If we want to declare a pointer to an integer we use the star notation. So in this case we use int star y or we say y is a pointer to an int. Pointer to an integer, y is a pointer. The type of this variable actually includes the star. So when you parse this out, you should think about int star as being a type, right. Just like we talked about struct time or a float. Both of those components are part of the type, and the name itself is simply y, in this case. So now what we can do is we can convert our program into a version that uses pointers so that the changes persist. So lets walk through this a little bit. First of all, we can see where we declared a local variable to the main function called x, and we set its value equal to 2. Well now, what we're going to do is we're gonna add this new variable whose name is pointerToX and whose type is int star. Its type is a pointer to int. We're gonna set its value not to x but to &x. So, if you remember from our long list of bits, what &x is, it's a way of saying I have the variable x but I want to know is I want to know the address of x. What is the street address associated with that variable? And so if we were using our example before, &x would give us the street address of 2. In practice, getting the address of a variable in actual code, ends up being a much more complicated number. So what we're gonna do is we're gonna set the variable pointer to x, equal to the address of x. Then, when we call the addFive function, we're not gonna call it with the variable. We're gonna call it with the pointer to that variable or the address of that variable. In order to do that though, we're going to need to change the signature of the variable. So that rather than taking an input in integer, we're going to take, as an input, the address, the pointer to that integer and then when we want an increment, we are going to do something called dereferencing the pointer. We know that the pointerToX is an address, and so we don't want to change the address, we want to change the thing that the address points to. To do that we use the syntax of star pointer and don't get confused when you declare a type you say int star but what we're doing now is we're using star in a different way. We're saying don't change the address, change the thing that the address points to. In this case what we say is we wanna say the thing that the address points to needs to be incremented by five. So note here that addFive didn't return anything, it had a void return type. There's no outputs to this function. Instead this function had a side effect, and that side effect was adding five to the variable x and we did that by using a pointer. So when we use pointers, in order to get the address of a variable, we use an ampersand. In order to get the value that an address points to, we use a star. This process of using a star to get to the variable is called dereferencing. Here's a little bit of code that uses all of these different mechanisms. First, we declare a variable named y, who is of type int. And that gets a value of 5. Then we declare a variable of type int star whose name is x. And we assign the variable x the address of y. Then we take the address of y and we dereference it. We say, I don't want the address of y, I want y itself and I want to set that equal to six. So after we print this line out, what we will see is we will see that y has the value of six. In this code what we do is we say that x points to y. So here's an example of the code. There is one special address, that special is called NULL. NULL is a special value in it, it is the address zero. You can set any pointer equal to NULL, and then you can use that to check in conditionals to see whether or not the pointer is something that you expected or didn't. So here's an example of doing that. We declare a variable of y equal to 5. We set the value of x equal to NULL. The type of x is an int star. Then we check. Is x equal to NULL? Is x the zero address? If it is, then we're gonna assign x the address of y. Then we're going to say, well we know x is an address, we don't wanna change the address. We wanna change the thing that the address points to. In this case we wanna set the thing that x points to to six. Well what does x point to? X points to y. And so when we print out the value of y, we'll see that y has, the value has changed to six. So now don't get too confused if this is the first time you've seen pointers. The first time you see pointers it can be very overwhelming and confusing because of this level of indirection. That you start talking about sign post to variables instead of the variables instead. It becomes important to be able to work with these things as we move forward in Objective-C value. So now be careful. Just because you've made a pointer doesn't mean that it points to something meaningful. You've got to assign it first. So in this code here we assign a variable y, integer y equal to 5. Great, that's a local variable, it stands on it's own. Then we declare a variable x. X is a type of pointer to integer. But we never actually assign x anything. So it maybe a pointer to integer. But it doesn't actually have an address in it, and so if we dereference it, we don't know what address is in y. It's some random bits that were present there when we declared the variable, cuz we never set it. And so when we try and set the thing that x points to equal to 6, the compiler throws an error and says, hey, that was a bad pointer. That didn't point to something that was meaningful so it's going to give you an error and not run. Finally, don't explicitly dereference a NULL pointer. So, in this case, after we declare our variables y and x, we set x equal to null or the zero address. If we then explicitly try and dereference it, we get the same error that we saw before. In this case, we know x was set equal to null. We try and say, hey, what's at zero address? And the compiler intercepts that and says, you can't ask what's at the zero address, that's a special address. We use that for checking for errors, and making sure that you're not making some mistake in your code. You can actually have a pointer to any kind of variable, not just an integer. And to do that you use the star notation using the same pattern. Using the star notation is how you define your variable to be a pointer to a type, not the type itself. So in this case was have a pointer to an integer, a pointer to a floating point, a pointer to a character, a pointer to a 32 bit integer, a pointer to a struct time. Pretty much as far as I can think of at the moment, anything can have a pointer to it in addition to being declared as a variable itself. Okay, so what's next? What's coming up? In these examples we use pointers in order to keep track of stack memory, meaning variables that we declared within frames of a function. This stack memory still gets destroyed when the frame is destroyed. Advanced programmers can use pointers to keep track of heap memory too. We haven't talked about heap memory but we did say that there's a stack memory that's created in frames and that there's this other heap memory. Heap memory is available for long-term persistence of objects and that doesn't get destroyed unless a programmer explicitly tells the computer to destroy it or sets up ways, specific rules of how it should be destroyed. Because of that, heap memory is very powerful but it can also be difficult to manage because it requires explicit care to make sure that you don't run out of it. So, in summary, pointers are a new type. You can have a pointer to any other type of data. The pointer to a type is its own kind of type. Pointers don't keep track of data. They keep track of addresses that point to data. Finally, pointers allow you to pass parameters to functions when you want the changes to those parameters, to those variables, to persist after the function is done and the frame is destroyed. Finally, if you have a pointer and you want to get access to the data, you use what's called dereferencing in order to get to it. You add a star to the front of it and that causes the compiler to know that what you want is the data that is pointed to by your variable. That's pointers, pretty tricky the first time you've heard it. Very important to what we're gonna be talking about coming up in the rest of our lectures. Great, thanks a lot. [MUSIC]