 All right, the camera's gone crazy, nice. So welcome back to APS 105. So back to regularly scheduled programming and we need to remember where we actually left off in terms of content, before we spent like a week and a bit actually doing practice. So this thing is broken. All right, so remember where we at before? Where we had local variables and they only exist while the function actually ran. So if we had some code that looks like this, very bad things happened. So let's see what would happen. So we started off by executing main so this should be reviewed. This is like the last piece of content we left off of. So we would have a region of memory here. It's technically called the stack. Don't really need to know that for that course but today we'll be talking about other regions of memory. So I will be specific and say that any of the variables in a function are going to be on the stack. So here we have main that is executing and the first thing main executes is a variable declaration of P which is a pointer to an int and then we call foo and foo returns a pointer to an int. So we would set aside some space for P on the stack which will hold an address but right now we don't know what the value is because we need to actually call the function foo. So we would start executing foo so that is a new function so we are in a new scope and any of the variables that were in main are now no longer accessible in foo. So foo declares a integer called x assigns the value equal to one so that would go on the stack. So now there's a value one and it's given by the name x and then we return the address of x. So a address that points to this value one. So we're returning a pointer that will point to this x and whenever we return from the function well turns out x no longer exists it gets essentially deleted. So in main we would have P which is just some address now pointing to wherever x was but because foo isn't running anymore it doesn't actually exist. So when we go ahead and we run this so when we go ahead and we run this we got a whole bunch of weird results before but just to make sure let's see what happens today. So today seems to give a segmentation fault so I'm trying to access some address that I'm not actually allowed to access so we get a segmentation fault which essentially means that we have some invalid memory so we're going to solve this issue today so this is like oh okay I want to actually return a pointer to memory that didn't exist in main before the call but with the tools we know how to do right now we don't actually know how to do this but at the end of the day we will and this lecture is so discouraged that even the White House doesn't want you to know how to do these things so this is like one of the reasons why programming in C is hard. So just as a warning so what we want to do here is we want to return a pointer to memory that is created in that function so any variables in a function are allocated so allocated is just a fancy word for saying created in memory they're created on the stack and whatever that function ends they disappear right they disappear we can no longer use them so previously in that example in X only exists in memory as long as we are running foo we can't actually if we have a pointer to it and foo is no longer running it is now no longer valid so this is getting into the danger land of C so we can actually explicitly allocate memory if we want so there's another region of memory that C can use and it's unrelated to the current running function this region of memory is called the heap and it's from the literal word heap like this is a heap of garbage like this is just a lot of things that's all it means so it's just a large amount of you might hear this word come up in data structures or other things later but in terms of memory the heap is just a region of memory that you can just use to store information so how do we actually use this well you can request memory from the heap using a function called malloc so it's function prototype it's in the C standard library it is called malloc it takes a single argument with this new type here so usually we saw like int char double or bool so this is a new type that you don't have to actually know for this course it's just how they define malloc so there's a size underscore t type and size underscore t it's basically just a positive integer type whose size actually varies on your machine so if you have a 32-bit machine it is 32 bits or four bytes if you have a 64-bit machine it is eight bytes or 64 bits but basically just think of it as an integer and it's always going to be positive because well if I'm allocating space if I need memory I can't have negative memory like I can't just like take away memory so it has to be positive and I can't really just say give me zero bytes of memory that also doesn't work so the size argument there is how many contiguous bytes to allocate in the heap so if I say give me four bytes I will get four bytes in memory all in a row all contiguous so remember that's what that means arrays are also contiguous so they're packed together all in a row so after malloc returns here it returns a void pointer or aka just a pointer and it's up to you to know what that type is based off what you're actually going to use this memory for so it just returns a pointer to the starting address and after that you can use size contiguous bytes so today we're going to start off by just using it to solve the problem we have before and just create a int which is just four bytes so other things you might see in software you might see the term API come up again so I'd be remiss if I didn't tell you what means so it stands for application programming interface basically it tells you how to use a library like what functions and what types and things are in it so a valid thing to say is you might just say hey what's the malloc API and that means someone just wants you to tell them what this is so malloc is a function that takes one argument that's the number of bytes to allocate and it returns a pointer so that would be like the malloc API kind of describes what it does and we'll see what malloc does basically it's just requesting some bytes of memory that we can go ahead and use that aren't tied directly to a function so let's go ahead and if we wanted to use malloc to create a pointer to an int so we could create an int pointer call it p and then assign it equal to malloc so malloc is requesting some bytes of memory so in order to properly store an it we need four bytes in a row so instead of just remembering how many bytes are in an int that's why we taught you what size of is so just to be clear you just in order to hold a byte or an int well we need this many bytes of space so in the case of an integer we would need four bytes don't have to remember itself we should always just use size of so this will have malloc return essentially a pointer to four bytes and we're going to use those four bytes as an integer so this memory will be on the heap so it's like we already took the address of it or something so the value it's pointing to however is going to be undefined so that is another word that you'll come up that you'll see when we talk about C programming and that means it could be any value you can't you have no idea what it could be no way you should depend on it same way as if I just like to int x and I try and use x that value is also undefined I have no idea what it could be so you can initialize a value by dereferencing it and that's typically what we would do right we're requesting some memory so we can actually use that value we can actually dereference p it's going to be valid it's going to represent an int we should probably initialize it to some value so we can change our function before so before we were trying to return the address to an integer that didn't exist in main and we wanted to create it in foo so we couldn't just return the address of like a local variable because it doesn't exist when foo is done so in this case we have to use malloc to request some memory so in this case instead of doing in x I have to be explicit and I have to say okay well C thanks for helping me out before by just giving me four bytes for an integer if it was just a normal variable but I actually need to request some memory on the heap so I would declare a pointer to an int called p and then assign it equal to the result of malloc after I request four bytes of information so after this p is a valid pointer so it's actually pointing to valid memory I just don't know what the value is so on the next line I can go ahead and just update the value so we can walk through what would happen in this case now so we would start executing at main main has its own local variable p it would go on main stack and we don't know the value of it because we are doing a function called the foo so in foo same rules as before it would have a new scope it would create its own variables that only it can access so in this case foo would also have a p and we assign it to malloc so what malloc is going to do is essentially grab us space for an integer that is somewhere else in memory and that somewhere else in memory is called the heap so p will be an address because it's still a pointer pointers are basically just addresses but instead of pointing to something like this p in main or some other variable if we declared an x instead of pointing to that it points to the value on the heap and because we just called malloc we don't know what the value is so I just put a question mark there so any questions about that so far so fun new region of memory called the heap yep yeah so the question is if I just like repeatedly call malloc in a loop or something and just update p going forth the then I would lose access to it right because I no longer I like overwrote the value of the pointer so now I don't have access to it and then your memory is essentially lost you just wasted all of that memory and has anyone ever used Chrome or a web browser that uses like gigabytes and gigabytes of memory boom that that is the reason why because well they just use it they forget to we don't know how to do it yet but there's a way to tell your computer that I'm done with this memory go ahead and use it for something else but we'll come up to that we'll come up to that a bit later and yeah malloc is literally just saying grab me some memory to use that I can access make sure it's valid and if you use it through the pointer you are allowed to do it do that so it's just some random bytes of memory somewhere else in memory that you will learn in much later courses for now it's just some memory somewhere else that always exists until you tell it you're done with it and we'll see that a bit later so right now if I dereference P that means I'm accessing the value that P is pointing to so that would be this random value on the heap and I assign it equal to one so after this line this is what my memory looks like so questions about this so now if I return P I'm just returning an address and that address is going to point to one so the address will still point to one but when we return we get a copy of it so foo would return a copy of that address but that address still points to one so in main P would just point to that same heap value so now if I go ahead and print I should be able to print exactly the value that we had before so here is that code so exact same thing we had before but now if I run it I will not get a segmentation fault I'll just see one because I wrote the value of one to it it's still a valid pointer and if I change this to whatever value something like 42 and I go ahead and I run it again well it's 42 it's still valid it's not just it's not invalid memory that I'm not allowed to use anymore it's valid until I say it is not which we will go into in a second but whoops and any questions about this so far and yeah so one question how big is the heap so the heap basically as much memory as your computer has if your operating system is actually working correctly so should be as much memory as your computer can handle sometimes it might actually be more because operating systems are quite smart but that's ECE 344 which is a fun course I'm not biased at all because I also teach that all right any other questions with this before we actually get into more the fun issues with this and I will show you something that will help you identify these issues because yeah and by RAM I mean yeah by memory I mean RAM but there's some tricks it can do where it can store some information on an SSD if it needs to it's just slow again don't worry yourself about it it's essentially you can think of it as just RAM so the heap should be most of the RAM spots until your computer actually runs out of memory so hopefully no one's actually has anyone actually like seen out of memory when they've been using their computer okay one so that's basically the program was calling malloc over and over again and then you ran out of physical memory and well can't do anything without memory so with that so malloc if we if our system actually runs out of memory malloc will tell us about it so because we're requesting memory and we may run out of memory it might return an error which is something slightly new for us so if there's no more room on the heap aka my computer has run out of RAM then malloc returns null so that means malloc cannot find memory for you it's out of memory too bad you get to handle it so we'll need to check the return value of malloc because if we don't how I wrote this before oops how I wrote this before potentially malloc could return null and if malloc returns null and ID reference it boom I get a segmentation fault again right so I might have an error in here where if my program actually like if my computer runs out of memory this program's just going to crash and I might want to try and handle it a bit better than just a good old segmentation fault so now we get to actually say to see that we are done with that memory and if creating some new memory is called allocating while saying you're done with it it's called deallocating so previously we didn't have to do this because when a function returns all the variables disappear that basically means that all the variables were deallocated for us so that is part of what C does for you so they're no longer valid that like C can go ahead and reuse a memory that you used for your variables in the function automatically you don't have to do anything special so when we say the memory's deallocated that means you're done using it it's not valid anymore you shouldn't touch it it can be used for other purposes and you don't know what those purposes are going to be so if you touch it well you're going to have a very very very hard time trying to debug it so for memory allocated with malloc I have since I requested it well C does not know when I am done with it so I have to tell it when I am done with it so we have to deallocate it ourselves and how we do that is there's a function for that and it is called free so it's function prototype it's also in the C standard library it's just free it takes one argument which is a pointer and the rule is that pointer argument needs to be the one that malloc returned to you and afterwards if I call free on that pointer well then all that space is given back to your operating system and it can be reused for other purposes and afterwards just like what we had before it is now invalid to use that memory again so that memory pointed to by pointer is now no longer valid and free does not return anything and yes void star means just an arbitrary pointer because C doesn't really care what you use the memory for that's up to you yeah all right so with free so oh also a nice thing nice thing about free is if the value of pointer is none so if the first argument is just null then free does nothing so there's no worry about like dereferencing null or anything with free if you try and free null that just means I'm trying to free nothing so C smart enough to know that oh okay well I don't have to do anything the function called does nothing and yeah some other questions if I forget to free space will my RAM just never be able to use that memory ever again and the answer to that is well what happens with Chrome it just grows bigger and bigger and bigger and you're not allowed to use that memory again so you have the same issue right so as long as your program is running and it has allocated memory for it you cannot take it away so your operating system will get rid of memory your program is using when it's done executing but other than that it has to keep it around and if you just malloc over and over again you can go ahead and just waste all the memory on your machine and spoiler alert you know when you submit your lab and then the servers went down something so some masters student malloc a lot of space and their program didn't finish and then the computer ran out of memory yay so that is a thing that can happen so what we should do is we should deallocate memory whenever we're no whenever we no longer need to use it anymore and it is up to you to make that judgment call the compiler see can't really help you here so in that same case well in foo I malloc and then I returned that pointer back and then in main I use that pointer to actually read whatever the value was and then that is the last time I actually need that memory so technically I should free it right when I'm done so I just free it I'm done with it and now I can no longer de-reference P again without getting some weird result if I did so let's assume that we did so here I could be like okay free P that's good so now I freed my memory but now if I try to use it again now I'm using memory that is now no longer valid so well we might get a random value we might get a segmentation fault we don't actually know what we're going to get so if we go ahead and run that we get negative a gigantic number and that negative gigantic number seems to change every time I execute it so we are no longer and now allowed to use that and then question can you re-explain what it means when returning automatically de-references so returning does not automatically de-references returning like this variable P in foo automatically de-allocates not de-references so like this local variable P in foo whenever this function returns I'm now no longer allowed to use it I can't if I return a pointer to it like what we had before when we return the address of X X only exists as long as foo exists so it was not valid to actually use a pointer to it here alright any other questions yeah is there a reason that after you um yeah so the question is is there a reason why I got a negative number as opposed to segmentation fault there is a reason for it but I cannot explain it to you until third year basically that memory is still sitting around and we can reuse it but it just wrote some random stuff there for the meantime so segmentation fault means like you were like wildly off on your address and you've never used it before this is I've used it before but I gave it back and they just wrote some random stuff it was used for something else so I have no idea what the value would be yeah okay any other questions with that so this bad news do not use memory after you free it for the same reason that we shouldn't use you know the address of X whenever X no longer exists anymore alright so forgetting to deallocate memory that has a name that name is called a memory leak so this is like the web browser problem so your program uses more memory than it actually needs to function it's just wasting space it's costing you money um and you might run out of memory sooner than you would like so this is a large problem when your program runs for a long time so anything you write in this course while it doesn't take that long to actually run all the memory goes back to the operating system whenever it's done running so it's not a big deal but later if your program runs for a web browser how many people have had their web browser open for days months weeks like years so that is just running constantly and if they even make a little mistake you know even if they forget to free a few bytes here and there well if you run something for like months without restarting it then it's going to eventually run out of memory might slow down other programs might prevent you from actually running something so these things are notoriously hard to figure out and identify so luckily I can show you a little tool that will help you when you are writing programs so there is a tool called Valgrind to help detect some memory issues so if you normally run your program on a terminal like here I did build build valid pointer so to use valgrind all I have to do is type valgrind in front of it and then it will go ahead and analyze my program for me while it is running for memory errors so if I go back to this so let's go back to the version where I just didn't free my memory I just malocked I used it I didn't free it at the end and if I run it you know doesn't look like anything's bad and it's 42 I have no issues whatsoever but if I go ahead and I run valgrind in front of it it tells me that there are some issues so here it has a leak summary so that's basically memory that your program has malocked but you haven't freed yet so it will actually analyze your program to make sure that you've freed everything by the time your program is done so here it says leak summary definitely lost which means I have leaked some memory I forgot to free something so so it gives me a bit of information here and it says rerun with leak check equals full to see details of leaked memory so if I go ahead and I run it what that means is it wants you to run it like this so we do valgrind and then dash dash leak dash check equals full and then our program it will give us some more information to help us identify why we had a memory leak so we run it and then we see here four blocks or four bytes and one blocks are definitely lost in record some things we don't really have to care about and here it will show us here's some memory addresses and then some functions but what really matters is we start from the bottom and then it tells you what function called what and that is the malloc that was never freed so this is saying in main at line 11 so this line right here so this is like file name and then colon and then line number so 11 11 so it's saying main was executing at line 11 and then it called foo from there so it was doing this and it says in foo on line five this is the malloc that you never freed so now I know that oh crap well this gives me a nice little hint that it was this malloc that had the problem so okay I can't free it here because well I'm going to use it later so I should probably use a free here so in this example doesn't help too much because there's only one malloc so there's only one possible thing it could be but if you write a more complicated program with mallocs all over the place then it will actually save you a lot a lot of time and in the output you might have noticed some number there don't worry about that number is basically to identify your program you don't need to know it you can just ignore it so only thing that is really important is in the leak summary if there's something that says definitely lost it means you malloc something and you forgot to free it so here is just so you have it on the slides if we wanted more information about the memory leaks so like I said this tells you what malloc you forgot to free and then like I said this means that main called foo and then foo called malloc this line number doesn't matter because I don't know where this file is so therefore all we really care is that our malloc at like five our program is the one that leaked then we have a question does malloc affect efficiency what if I choose to use malloc instead of the stack so malloc is technically a little bit slower and it's also harder to get right because we also have to remember how to free it and everything like that so if you don't need to use malloc do not use malloc use if you can just use you know variables in a function just use those you don't have to remember to free them or anything like that and they are technically also a bit faster so here's our example so we also forgot to do another thing so we did not check the value of malloc like what malloc returned because it could have returned null right it could have returned null that means we are out of memory so instead of just letting that null go in our program until we eventually seg fault good practice is to check if it's null and then we can use this new function called exit so this new function called exit will stop our program immediately and it's pretty much it's exactly like returning from main so main returns an int this int tells the operating system what happened to our program usually it's exit success that means all good but now we have a case where it is not good so we can exit and then we can give it the integer exit failure that means something bad happened so don't expect the don't expect that my program actually ran all the way it failed in some way so the exit function immediately ends your program it is also in the C standard library the other sections may not go over this so we don't you shouldn't actually need to know this for the exam but it is a handy thing to know so exit just takes an int status exactly like what main returns so it behaves exactly the same way as returning from main except you can put it anywhere in your program you would like stops your program from running and then that status tells the operating system if there is an issue with your program for this course if you have like an exit it would typically only have what we had here which is exit exit failure I ran out of memory I don't know how to proceed now like the next line doesn't even make sense if I don't have any memory and then for this course mostly we just use exit success or exit failure and then we have a question what really is the difference if I put exit failure at the end of main so if I put exit failure and instead of main that tells the operating system that hey my program probably didn't work as you expect it to but we don't really know how to use that or get that information out of the operating system so likely what will happen is a big pile of nothing let's see if I can show the difference so if I want to do exit failure instead whoops I can spell feel so if I look at it exit failure is just the number one oh whoops all right if I do exit failure instead of exit success exit failure is just the number one if I compile my program doesn't really look any different if I run it doesn't really look any different the only difference here is see this one that's where that one comes up so that's all it tells you but it's up to you to know that if you see this one you should expect that this program didn't actually work and there's this one right in the bottom right corner that you probably don't see but that's all it really does and it's up to you and your operating system to decide what to do with that information but as you get more experience during this and go in other courses you'll actually be able to use that information again probably not until the operating system course all right so like I said before so we saw this example we shouldn't use memory after we free it we just got a random negative value so what was happening was well we malocked so we got a new address that points to some unknown value on the heap but it is currently pointing to valid memory I can dereference it set the value equal to 14 and then free it after I free it that memory is no longer valid just poof disappears gets reused for something else but that pointer is still pointing to it and we saw when we read it we got just some random negative value and then well we would print off some random value exit and then we'd be done so the value it's another thing that is undefined so on my machine I got large negative values that were slightly different every time when you run it you might get something different it's also possible the segmentation fault depending on the operating system but probably pretty rare so that issue is called use after free so I'm trying to use memory malock gave me after I freed it so you might also hear that p is what's called a dangling pointer so it's a pointer just to some random invalid place in memory so a good practice to have just to save yourself is after you free a pointer you can just set it equal to null and that way well if you try and use it you'll get a segmentation fault which will be easier to debug than just having a random value so but that's about the best you can do in that case so you see a segmentation fault instead of an undefined value not the best but it could be worse so some other bad things to do you are also not allowed to call free twice on the same pointer so if I call free p free p again well I get a runtime error like free double free detected in tcache 2 what the hell does that mean don't worry about it it's some weird implementation detail all you have to worry about is double free happened you are not allowed to do that so luckily valgrind can actually help you also debug the previous two issues so it will tell you about use after free and it will tell you about double freeze as well which is nice and useful so if we had something like this where we free the memory and then we try and use it well if we go ahead and we try and use it we get like that random negative value again but if I go ahead and I'm trying to debug it I have no idea what's going on my program is complicated well I could use valgrind and then it will actually give me some handy information that might be a bit hard to read but it's better than nothing so it gives us a whole bunch of information so it tells you what happened to the memory so I tried to read a value in memory it tells me the line number that I tried to read it so it was line 8 and the read basically refers to this dereferencing so I'm like accessing the memory I'm reading it I'm trying to access it is what that means so it says invalid read so that basically means I was not allowed to dereference this it is not pointing to valid memory it is invalid and then it tells me that the address so this is the address that's stored in p so it says the address is zero bytes a.k.a. I freed it inside of a block that I freed and it tells me where I freed it so it tells me where the free function is but this tells me where I freed it so it tells me that hey you jerk you freed it on line 7 so why did you use it on line 8 and then it also tells me where I malocked it so it says I malocked it on line 5 so it says you malocked it on line 5 and then you got rid of it on line 7 and then you used it on line 8 so it gives you a whole bunch of information but it's just a bit hard to read but that's better than just seeing a random negative value and going what the hell so it will help you a little bit I hope all right so any questions about that so it'll also help with double freeze but double freeze are a bit more obvious because you get an error anyways but I'll leave it to you you can run it with double freeze it'll tell you what two free calls happened all right any questions so far before we do a more complicated example all right then let's ramp it up a little bit so let's just define some functions that work on arrays we'll do some more review so let's say I write a function so it takes a pointer to something that I want to represent an array and then I have an array length so I just iterate over every single element of the array and just assign it a random value in this case between 0 and 100 then I write another function to go ahead and print an array so I just print array and then just print all the digits so everyone okay with these two functions they should be okay but now we have the fun thing of using malloc so before remember when I had grades and I had to like the best I could do was give c five numbers and then it could go ahead and you know figure out the size of the array for me well what would I have to do if the user inputs the size of the array so if the user inputs the size of the array I can't tell c has no idea how big it's going to be I don't know how many elements it actually needs to contain beforehand and yeah it's one to a hundred I think I said that if I didn't I'm bad but yeah this will be one to a hundred all right so if I want to go ahead and ask the user for an array of any size well remember in an array all of the ints are contiguous and malloc gives me a contiguous block of memory so before when I had like five ints well when we did size of the array in the function it was defined in well each int is four bytes and if I had five of them I had 20 bytes and they were all in a row so there is no reason I can't just ask malloc for 20 bytes if I want to and then use that as an array so what I can do is I can dynamically allocate an array I don't need to tell c what the length is ahead of time there's no way for it to figure out because it's going to depend on user input in this case so here I'll just declare a variable called array length and I will allow the user to set it I'll make sure that it is greater than zero and then here in my array I can malloc and then well I can do some math inside of it so if I'm using if I'm creating an array of integers well I have to take the size of an integer so the size of each individual element times the length of the array so if I input five well I need five integers or 20 bytes if I input six well then I need 24 and then my math is terrible pass end and then I can check hey is the array is the pointer I got back from malloc equal to null if it is then I ran out of memory so I could just return exit failure because I'm currently in main so that will end my program otherwise well I can initialize the array by just assigning it to random values and then print the array and then after I'm done with printing the array I'm no longer going to use it so I can free it and then I can do my good practice of setting it to null even though it's the last line it doesn't really matter better to be safe than sorry and just get in the habit of it so if I go back and I run this now so here is that same program if I go ahead and run it I can just input the length of the array five and then it prints me five integers that are randomly assigned yep yep yeah so malloc always gives you contiguous bytes in a row so same as arrays which is why I can use it as an array and it's the same same idea yeah so the question is do I need to cast the void pointer returned by malloc to an int pointer like here so you can do that it turns out that the void pointer rules in C is you're it will automatically cast it to any other type of pointer so I could write that if I wanted to but turns out C will do that for me automatically because well avoid pointer is kind of useless and the rule is it'll automatically cast it to anything else so in here yeah I could just ask now I can ask for like 10 elements gives me 10 elements and I'll get the same order because I did not set the seed in this function but here I could even ask for 100 if I asked for 100 elements that's 400 bytes well still works just gives me 400 bytes next question is like oh yeah how much memory can I use well it's like 10,000 well fine gives me 10,000 doesn't matter it can use any number we want as long as we don't run out of memory you can do the math gigabytes of memory is a lot of memory so 10,000 actually isn't that much so turns out it works all right any quick questions before we wrap up all right then let's wrap up so dynamic memory useful but you should only use it when you need it because it is tricky to get right in fact it is so tricky to get right that's why I was talking about before the white house actually discourages this type of programming so good to know how it works but best to avoid it whenever possible because if we do it we have to remember a lot of rules we have to remember to free the memory when we're done using it otherwise it's a memory leak we have to make sure we don't try to use the memory after we free it that's a use after free we have to make sure we don't call free twice that is a double free and we should remember we should only use it when we absolutely have to so the only main two conditions when we actually absolutely have to use it is when your function needs to return a pointer to valid memory that did not exist before the function and also if you just don't know how many memory how much memory you need at compile time well then you can only figure it out at runtime and you have to use a dynamic allocation because well you just don't know ahead of time so with that just remember pulling for you we're all in this together