CS50 Video Player
    • 🧁

    • 🍭

    • 🍉

    • 🍿
    • 0:00:02YULIIA ZHUKOVETS: Hi, everyone.
    • 0:00:03My name is Yuliia, and this is CS50 Week 4 sections.
    • 0:00:06And today, we're talking about all things memory.
    • 0:00:10I am a preceptor here on Harvard campus, and it is very lovely
    • 0:00:15to see you all here in the room.
    • 0:00:17So today, we're talking all things memory.
    • 0:00:20And that includes pointers, file I/O. We're
    • 0:00:23going to get some practice with how to operate these weird pointers things,
    • 0:00:28and also, some practice with how to open files, write into them,
    • 0:00:33and read information from them.
    • 0:00:34That should really help you on this week's problem set.
    • 0:00:37So let's jump right ahead and let's talk about pointers first.
    • 0:00:42So you might recall from week 1, we talked about a phone book, right?
    • 0:00:46We set it up with different variables, such as calls
    • 0:00:50that we try to keep track of, for example, how many times
    • 0:00:54your mom or your friend called you.
    • 0:00:56So let's just get a quick refresher on that.
    • 0:00:58So as in week 1, we had our variable called int calls.
    • 0:01:04That is of type int.
    • 0:01:06And the store is a value 4, for example.
    • 0:01:09And you can visualize it as a sort of box.
    • 0:01:13We're going back to our boxes for visualizing these diagrams again.
    • 0:01:17So for example, our value was 4.
    • 0:01:21Well, recall now that every variable also has an address.
    • 0:01:26And here, we came up with a fake one, and will certainly look different
    • 0:01:29in your system, but every variable has an address, and so using this address,
    • 0:01:35we can now create a pointer.
    • 0:01:37And so what are these pointer things?
    • 0:01:41Well, the setup is, again, very similar, where
    • 0:01:43we have a name of our variable, which is p, short for pointer.
    • 0:01:48But again, it can be anything you want.
    • 0:01:50What the type is, a pointer to an integer.
    • 0:01:55And the way that we define that is by having int
    • 0:01:58come very first to define this data type that our variable is going to point to.
    • 0:02:03And the asterisk right next to p is what makes this variable a pointer.
    • 0:02:08And what do these pointers store?
    • 0:02:10Well, they store addresses.
    • 0:02:12You can now imagine this second box that now stores an address of variable calls.
    • 0:02:21Note, too, that every variable has an address.
    • 0:02:26Variable p will also has an address-- will also have an address, although we
    • 0:02:31rarely use them.
    • 0:02:34It is just important to emphasize that it exists out there.
    • 0:02:38So just to reiterate again, what happened here is we had variable calls
    • 0:02:44storing a value of 4.
    • 0:02:46We then created another variable.
    • 0:02:47And you can imagine it by visualizing a second box
    • 0:02:50right next to it that is now pointing to our previous variable,
    • 0:02:56but it's storing, essentially, the address.
    • 0:02:59And so let's go back again one by one actually
    • 0:03:02defining what each of the values are.
    • 0:03:05So the value of calls is 4.
    • 0:03:08That's what we had before.
    • 0:03:10That's what we learned during week 1.
    • 0:03:12It is inbt calls equal 4.
    • 0:03:14Therefore, the value is 4.
    • 0:03:17The value of p is, in turn, the address of calls.
    • 0:03:22Pointers store addresses of the variables they point to.
    • 0:03:29The address of calls is, again, this hexadecimal value
    • 0:03:33that we have under our box.
    • 0:03:35And we can access it using the ampersand symbol.
    • 0:03:38In turn p, our pointer also has its own address.
    • 0:03:43And although we might not be using it as much throughout the class
    • 0:03:47and in general, every variable still has an address,
    • 0:03:50and it's important to mention that.
    • 0:03:53Well, how do p and calls combine?
    • 0:03:57Using *p, you're essentially telling your computer to go to the value
    • 0:04:04at the address stored in p.
    • 0:04:06And so this is where our two boxes come back together.
    • 0:04:11On the left-hand side, you have your p variable
    • 0:04:16that is storing the address of calls.
    • 0:04:18Calls itself is its own variable.
    • 0:04:21It's storing value of 4, and has an address of 0x1A.
    • 0:04:24And when we use *p or *p, what is going on is this arrow situation.
    • 0:04:32Like, we're grabbing the value from calls by referencing this variable.
    • 0:04:39And let's go over some of that syntax, some of these operators
    • 0:04:45that I've been using.
    • 0:04:46So type star is a pointer that stores the address of a type.
    • 0:04:52So today, we'll be using a lot of int star,
    • 0:04:55but it can also be char star, which is where this week, we sort of uncovered
    • 0:05:01what has been sort of hiding from you.
    • 0:05:03And recall that in the previous weeks, I said,
    • 0:05:05well, strings actually don't exist sort of.
    • 0:05:08And char star is actually the correct way of defining it.
    • 0:05:14Asterisk x takes that pointer--
    • 0:05:17takes a pointer of x and goes to the address that's-- sorry.
    • 0:05:22Star x takes a pointer x and goes to the address stored in that pointer.
    • 0:05:27So for example, here we had p that was storing the address of calls,
    • 0:05:34and then knowing this address, it can find where the calls
    • 0:05:38variable is located very easily.
    • 0:05:40It knows exactly what cell to go to, and then it
    • 0:05:44can access the value located there.
    • 0:05:48And lastly, we have &x that takes x and gets its address.
    • 0:05:54So that was important when we're defining our pointers
    • 0:05:57in the very beginning.
    • 0:05:58Like we want to make sure we're grabbing that address from the variable
    • 0:06:02that we're interested in so that we can store it in the pointer afterwards.
    • 0:06:08And I know this week has been like another firehose of information-- a lot
    • 0:06:15of new symbols like visualizing memory now
    • 0:06:18becoming more difficult because it becomes this like more abstract thing.
    • 0:06:21And hopefully, through the next exercise and as you're
    • 0:06:25working through these problems on your own,
    • 0:06:27you can get a better grasp of what's going on.
    • 0:06:30And again, it would be really helpful to visualize it on paper or the whiteboard,
    • 0:06:37like drawing it out and really connecting the cells and the arrows
    • 0:06:41together.
    • 0:06:43But before we jump to our next exercise, what questions
    • 0:06:46do we have so far about pointers?
    • 0:06:52Going to look at the chat here.
    • 0:06:55Someone said, is the variable name stored somewhere,
    • 0:06:57or it's just the value?
    • 0:06:59So you can imagine it's like a box that stores the value.
    • 0:07:02But then the way that we access the box is using the variable name
    • 0:07:06that we defined.
    • 0:07:10Let's see.
    • 0:07:22What's the danger of using pointers?
    • 0:07:27I think here again, we're like, we're entering this, like, land of memory.
    • 0:07:31Like it is becoming a little bit more abstract,
    • 0:07:33and it is like almost like a less controlled environment.
    • 0:07:36So like with the pointers and with malloc
    • 0:07:39that Professor Miller introduced this week as well, we are more prone to,
    • 0:07:43for example, segmentation faults or like memory leaks and those kind of errors.
    • 0:07:49But in turn, pointers really empower us to do more complicated things
    • 0:07:54that we could not have done before.
    • 0:07:56And as we'll see in the end of this section, one of those things
    • 0:07:59is like accessing the files and working with them.
    • 0:08:05So someone asked what exactly are memory leaks?
    • 0:08:08It's a great question.
    • 0:08:09It's essentially when you access something that you're not supposed to
    • 0:08:13or when you forgot to free the memory that you use
    • 0:08:17or close a file that you used.
    • 0:08:19And if it not, it doesn't really come up with running the wrong once or twice.
    • 0:08:24If you don't follow exactly the steps or for example, allocating the memory,
    • 0:08:28but also giving it back to the computer afterwards,
    • 0:08:30you might run into these kind of issues.
    • 0:08:34All right.
    • 0:08:35Let's keep moving for the sake of time.
    • 0:08:37But our next activity is really getting practice with pointers
    • 0:08:41and understanding how to correspond these things all together.
    • 0:08:44So let's consider this variable x that we're setting equal to 4.
    • 0:08:50And so as before, we can visualize it.
    • 0:08:53We're creating this new box that has value 4 and some address
    • 0:08:58for the sake of this exercise.
    • 0:09:00I came up with a fake one, but it'll certainly
    • 0:09:01look different when you're trying to print out addresses in your computer.
    • 0:09:07Next, let's create a pointer.
    • 0:09:09So as before, the way that we define it is using int star p equals address of x.
    • 0:09:16And as before, you can visualize this box that stores the address of x.
    • 0:09:21Notice how the two values correlate.
    • 0:09:26Next, let's print out something.
    • 0:09:29So this is where this magical connection comes in.
    • 0:09:33So as I said before, when we use--
    • 0:09:37when we use star p, that means that we're
    • 0:09:40grabbing the address that is stored in our pointer
    • 0:09:42and then accessing the value stored in that address.
    • 0:09:46And so consequently, what we'll see in the terminal is--
    • 0:09:50and you can type in the chat--
    • 0:09:52if I'm printing out printf quote unquote percent I comma star p.
    • 0:10:00Yes.
    • 0:10:01So in our terminal, we will see 4 because as I just
    • 0:10:05said, what is happening is we're grabbing that address.
    • 0:10:09We're going to the location of that address
    • 0:10:13and grabbing the value stored in that cell.
    • 0:10:17OK, so this was sort of like an exercise that we could
    • 0:10:22have done with the previous slides.
    • 0:10:24But let's push it a little further.
    • 0:10:26So consider I want to change my value.
    • 0:10:30So one way to do it is certainly just changing
    • 0:10:33the value of x, but now that I have my pointers, I could also do it in this way
    • 0:10:39by using star p and setting it to two.
    • 0:10:43what is going to happen is I'm going to change the value of x.
    • 0:10:48And now it is going to be equal to 2 because as before was the line 3.
    • 0:10:55When we printed out the value, we used star p
    • 0:11:00to grab that value in the same way we can access that value once again
    • 0:11:04and change it.
    • 0:11:06OK, so now our x is equal to 2.
    • 0:11:10That is the value that's stored there.
    • 0:11:13Now if we wanted to printf star p minus 2, what would that be?
    • 0:11:22What is the value that we're going to see in the terminal now?
    • 0:11:26Exactly-- it will be 0.
    • 0:11:28Because the new value that I have in x is 2.
    • 0:11:33I'm subtracting two.
    • 0:11:34So I'm printing out 0 in the terminal.
    • 0:11:37But won't that change my value of x?
    • 0:11:41Like, am I subtracting x minus 2, and now the value of x is 0 as well?
    • 0:11:49So someone on the chat said, no.
    • 0:11:51I'm not explicitly changing x, or even star p,
    • 0:11:55I'm just printing that value out.
    • 0:12:00OK, so let's keep moving.
    • 0:12:01And what we're going to print out last is x.
    • 0:12:07So now that we've changed that value to 2, what we're going
    • 0:12:13to see in the terminal exactly is two.
    • 0:12:16So using these pointers and the connection
    • 0:12:21that we have between the addresses, we can now manipulate things even better.
    • 0:12:28I don't have to explicitly change values in my variables.
    • 0:12:33I can reference them using pointers and then
    • 0:12:36access that information through the addresses that connect the two.
    • 0:12:39So before we jump to file I/O and switch gears a little bit,
    • 0:12:47what questions do we have about this exercise and pointers?
    • 0:12:52Yeah, so someone asked to explain the code.
    • 0:12:55So let's walk through it line by line again.
    • 0:12:58So in the very beginning, we have x int x equals 4.
    • 0:13:02That is creating this new variable.
    • 0:13:06Then we need to set up our pointer.
    • 0:13:08And as we just talked about, pointers to our addresses.
    • 0:13:12So using the ampersand, we're grabbing that address of x.
    • 0:13:15Like we're grabbing this hex value that is like signifying the address of x.
    • 0:13:21Then our printf line, like we've seen it a dozen of times so far.
    • 0:13:26And to achieve the same result, I could have just said printf percent I x,
    • 0:13:32but I'm using the power of pointers to just reference that value
    • 0:13:36and print it out here on line 3.
    • 0:13:38Again, harnessing the power of pointers and being able to reference the value
    • 0:13:44explicitly changing them.
    • 0:13:45Well, in this case, we are.
    • 0:13:46But on the fourth line, where we're using
    • 0:13:49star p equals 2 is where we're changing the value of x.
    • 0:13:55And now it is two.
    • 0:13:56And then again on those last two printf lines,
    • 0:13:59we are just printing out different things
    • 0:14:02just for practice to see what we actually see in the terminal
    • 0:14:06combined to what is actually is stored in those variable cells.
    • 0:14:11So let me go back to the chat again and see if there are any questions there.
    • 0:14:19So someone else that's changing the value of the pointer
    • 0:14:21change the value of the variable permanently So in this case,
    • 0:14:26Yes, because we went explicitly to the location of this variable,
    • 0:14:32and we changed the value to 2, for example, online, what is it, 5?
    • 0:14:38When we print it out, star p minus 2, we just use that value.
    • 0:14:43And subtracted 2.
    • 0:14:49OK, so why didn't the last value change from 0 to 2?
    • 0:14:58So on line 5, where we printing out star p minus 2,
    • 0:15:03we're not explicitly changing the value of x.
    • 0:15:06We are just using that value by referencing the pointer
    • 0:15:10and subtracting 2 from it.
    • 0:15:14OK, let's keep moving forward for the sake of time,
    • 0:15:18but I'll try to get some other questions in the end of the session--
    • 0:15:24file.io I/O. So this is where why we need pointers comes in.
    • 0:15:32So the things I just talked about, you could
    • 0:15:35try to do that with just the variables that we knew, but with the files,
    • 0:15:40this is where the pointers come really in handy,
    • 0:15:43and this is what will enable us to do more complicated things that frankly, we
    • 0:15:48could do before.
    • 0:15:50So to get us started, here are two of the key functions
    • 0:15:55that we will use in the beginning.
    • 0:15:56So the first one is fopen.
    • 0:15:59This will allow us to open a file to either read or write into it.
    • 0:16:05As I mentioned briefly just a few minutes ago,
    • 0:16:08it is really important to close those files.
    • 0:16:11So if we fopen anything, like a file called input or a file called output,
    • 0:16:17we must close it after we're done with it.
    • 0:16:20So this is a really good practice to get into anything you have open,
    • 0:16:26make sure you close it because again, we're
    • 0:16:29going to run into these memory issues and weird errors that
    • 0:16:34might be difficult to solve.
    • 0:16:36So making sure that you have this very explicit approach of how
    • 0:16:43you handle the code is very important.
    • 0:16:46OK.
    • 0:16:47Yeah.
    • 0:16:47Someone's mentioning malloc in the chat.
    • 0:16:49So this is, again, where all these errors come in.
    • 0:16:53So we're now going to talk about malloc function a lot during this section,
    • 0:16:57but malloc can be used to create memory, like if we want
    • 0:17:03to allocate some memory for us to use.
    • 0:17:05But it's really important to free that memory that you allocated
    • 0:17:09and use to go back to the computer so that we
    • 0:17:11don't run into any memory errors.
    • 0:17:13So let's consider this file.
    • 0:17:15So for example, I have a TXT file that has "hi"
    • 0:17:20in it and it is stored at some address.
    • 0:17:23Well, how could I use it?
    • 0:17:26How can I open it?
    • 0:17:27How can I read from it or write into it?
    • 0:17:30I can use my function called fopen.
    • 0:17:34And again, it's like, whoa.
    • 0:17:36Like things escalated really quickly.
    • 0:17:37There is like so much stuff going on--
    • 0:17:40the stars, the capitalization, like all the other arguments.
    • 0:17:43So let's parse it one by one.
    • 0:17:46So the first thing that we have is the name of the variable.
    • 0:17:50Again, variable names can be anything that you want.
    • 0:17:53So in this case, I chose input, but it could also be file or text or word.
    • 0:18:01It is up to you as a programmer what variable names you want to use.
    • 0:18:05Then with every variable definition comes the type.
    • 0:18:11So in this case, our type is a pointer to file.
    • 0:18:17So we've seen n star.
    • 0:18:20We've seen char star.
    • 0:18:21File star is, again, very similar, but someone just
    • 0:18:25like went ahead and defined what like file is and is literally
    • 0:18:29these TXT files or any other files.
    • 0:18:31And so as before, our pointers store the address.
    • 0:18:36So on the bottom of my TXT file right here, I have its address.
    • 0:18:43So what the input is actually going to store is the address of this file.
    • 0:18:49And the way I could get that address is by using the fopen function.
    • 0:18:53So if when I use fopen, what it will return is the address of the file
    • 0:19:00that I am trying to access.
    • 0:19:04Well, let's parse fopen one by one as well.
    • 0:19:10First argument is the file name.
    • 0:19:12So hi txt or test PDF.
    • 0:19:17It can be whatever file you want to use.
    • 0:19:20Then the next argument is the mode.
    • 0:19:23So in this case, what we want to do is just read from the file that we opened.
    • 0:19:29So we're using R, short for read.
    • 0:19:32If we want to modify the file or write something into it, the mode we can use
    • 0:19:39is w.
    • 0:19:41And I believe in this week's lecture, Professor Malan
    • 0:19:44also defined something that Rb and WB.
    • 0:19:49That is for reading or writing binary files--
    • 0:19:53explicitly saying that the bits or the pieces of data that you'll be reading
    • 0:20:01are binary.
    • 0:20:02So like no need to try to interpret it or understand what it is.
    • 0:20:07So we have this set up, we've opened our file.
    • 0:20:13We now have the address of our TXT.
    • 0:20:17What is going on next?
    • 0:20:19Well, as before, there's an arrow.
    • 0:20:22So again, we're going back to these diagrams, and we're drawing things.
    • 0:20:27But essentially, what the input does, it is
    • 0:20:30a pointer to the address where this TXT file is stored.
    • 0:20:33So you can imagine again the arrow that points to it.
    • 0:20:38Now that we've opened our file.
    • 0:20:41What can we do with it?
    • 0:20:43So two key functions that we'll talk about today, and this week in general,
    • 0:20:48is fread that will read data from a file, fwrite that will write data
    • 0:20:56from a buffer to a file.
    • 0:20:59And what is a buffer?
    • 0:21:01And we're going to talk about in just a second.
    • 0:21:03But you can imagine it is just a chunk of memory that can temporarily share--
    • 0:21:08store some data from the file.
    • 0:21:10And there's a little hint of the question
    • 0:21:13I'm going to ask you in just in two minutes.
    • 0:21:15So you might think already about it already.
    • 0:21:17But why do we need the buffer?
    • 0:21:19Why do we want to use it?
    • 0:21:22So let's go back to our setup.
    • 0:21:24We have this TXT file that is storing "hi" or any other text.
    • 0:21:33What it actually is just collection of some pieces of data--
    • 0:21:37so collection of some bytes.
    • 0:21:43So how do we actually read from it?
    • 0:21:47In this case, this is what we're going to do.
    • 0:21:49But there is a very methodic approach of how you want to read your data.
    • 0:21:54Let's start from the end.
    • 0:21:56So the very last argument in our fread function is location to read from.
    • 0:22:02So this is the new file that you open, like the file
    • 0:22:05where you want to grab the information from and read it from there.
    • 0:22:11So you can imagine it almost like a little dot
    • 0:22:14or like a cursor there showing you where this file is.
    • 0:22:18Then next two parts is the size of blocks to read in bytes.
    • 0:22:25And the in bytes part is important because in this case,
    • 0:22:28I'm just reading size of one byte.
    • 0:22:31But if you want to read something different, for example,
    • 0:22:35if it is more than one byte and maybe you don't know exactly
    • 0:22:38is that variable like two bytes or three bytes, a handy function to use
    • 0:22:44is size of because also depending on what machine you're using, for example,
    • 0:22:49integer can be actually different size depending on the machine.
    • 0:22:53And by using the size of function, you can always get the precise number.
    • 0:22:59Next component of our fread function is how many blocks we want to read.
    • 0:23:05So in this case, I want to read four blocks of one byte.
    • 0:23:13So four blocks on one byte and you can again--
    • 0:23:20once again visualize it by like allocating or highlighting
    • 0:23:25these four squares in our text file.
    • 0:23:29And lastly, is the location to store blocks in.
    • 0:23:32So in this case, it is buffer.
    • 0:23:35And we're going to grab these 4 bytes from our input file, from hi.txt,
    • 0:23:42and then store it in the buffer variable.
    • 0:23:47And because I know that I'm going to read four blocks of size of 1 byte,
    • 0:23:55I can pre-allocate that memory and have my buffer
    • 0:23:58be ready to accept those bytes.
    • 0:24:01So once again, this is the fread function that we'll use in this case
    • 0:24:08and to have an algorithm to it, this is how you can visualize it.
    • 0:24:13So if we have fread, our function, the first argument
    • 0:24:18will be store to where into buffer or whatever other variable
    • 0:24:24name you come up with.
    • 0:24:25Again, this is arbitrary.
    • 0:24:28How many blocks and on what size?
    • 0:24:31So four blocks of size 1.
    • 0:24:33And here I am flipping it a little bit from what we saw before,
    • 0:24:37but it is essentially size of 1 byte, four times almost.
    • 0:24:43And then from where?
    • 0:24:45From the input file or again, whatever name
    • 0:24:50you chose to give to your input file.
    • 0:24:54So again, to where, how many and on what size, and then from where--
    • 0:24:59this is how we put our fread function together.
    • 0:25:03And this is how we can visualize it in the end.
    • 0:25:06We had our pointer input to the file that we were interested in.
    • 0:25:11We grabbed 4 bytes from there, and then we stored it into buffer.
    • 0:25:16So now input is pointing to the next bytes in our TXT file.
    • 0:25:24So this was reading information.
    • 0:25:32OK, that was reading information.
    • 0:25:34But why were we using buffer in the first place?
    • 0:25:36I promised you to come back to that question, and now we're back to it.
    • 0:25:42Why were we using buffer in the first place?
    • 0:25:44Why could I not have just done like fread from input to output
    • 0:25:49and be done with it?
    • 0:25:50Why it is important to use buffer?
    • 0:26:00Why do we want to use buffer, in this case?
    • 0:26:03Anyone want to type their suggestions or thoughts?
    • 0:26:11OK, so just store it.
    • 0:26:12Yeah, we want to store something in buffer.
    • 0:26:15Temporary storage of data--
    • 0:26:17OK.
    • 0:26:18Memory is a big consideration.
    • 0:26:22There is one more thing.
    • 0:26:29Yeah someone said it's like a third glass from the lecture.
    • 0:26:32So it's like our temporary variable that we're creating.
    • 0:26:40So often, we don't know where the data ends.
    • 0:26:44So I can't say like read 200 bytes.
    • 0:26:47What if there are more bytes, or what if they're not as many bytes?
    • 0:26:51And by ensuring that we're doing just like little bits at a time, maybe
    • 0:26:56like 4 bytes at a time, even one byte at a time
    • 0:26:59until we reach the end is why a buffer is important.
    • 0:27:04Like we're using this like third glass, as we talked about in lecture.
    • 0:27:08We're swapping variables.
    • 0:27:09Like we're using this third glass, third variable
    • 0:27:11to be a temporary storage as we're sort of moving things alone.
    • 0:27:17So that's why buffer is important.
    • 0:27:21That's why you will find using--
    • 0:27:23well, we will find using buffer a lot this coming week
    • 0:27:26to temporarily store information.
    • 0:27:30But now that we have learned how to fread, let's talk about fwrite.
    • 0:27:35So we're not only just want to open information,
    • 0:27:37we also want to make sure we know how to modify it.
    • 0:27:40So the syntax is, again, very similar, but just slightly different.
    • 0:27:45And let's go through it one by one.
    • 0:27:47So with fwrite, the first argument that I have is from where.
    • 0:27:54So contrary to fread, we're sort of like flipping things here.
    • 0:27:58So first, from where.
    • 0:28:00I want to write from buffer--
    • 0:28:02again, how many and what size?
    • 0:28:05Well, in this case, four blocks of size 1.
    • 0:28:07And then the last bit is to where.
    • 0:28:11To my output file or once again whatever variable you choose to have.
    • 0:28:14So flipping things a little bit compared to fread, but still the same idea.
    • 0:28:20I want to read from buffer.
    • 0:28:23I want to write from buffer for blocks of size 1,
    • 0:28:27and I want to store them or write them into the output file.
    • 0:28:34And so this is how we can visualize it again.
    • 0:28:38So if I have these four bytes in storing in my buffer, what a fright would do
    • 0:28:45is just copy them over to output.
    • 0:28:51So now my output file has those bytes.
    • 0:28:57So let's take a pause here.
    • 0:29:03I'm going to spend some time answering questions before we
    • 0:29:05go to the last activity of the day.
    • 0:29:07What questions do we have about fread or fwrite
    • 0:29:11or how we were handling these pieces?
    • 0:29:16Yeah, so someone asked to explain exactly what the blocks are.
    • 0:29:19So if you open like a PDF file or a text file, you see text on the page.
    • 0:29:25That is what's visible to the humans.
    • 0:29:27But what is going on behind is like some sequence of bytes.
    • 0:29:31So this is how we handle these documents on like a micro level.
    • 0:29:36We like go a level further, and we say, OK, we want to read one byte at a time.
    • 0:29:40It might be like, I don't know, a character or just
    • 0:29:42like looking at the image.
    • 0:29:46It will be something different.
    • 0:29:47But it will be one byte at a time.
    • 0:29:50And again, by splitting the problem in these smaller pieces,
    • 0:29:53we can ensure that we're actually, A, getting through the entire file
    • 0:29:57versus just like, let's read 200 bytes.
    • 0:30:01Like maybe that's too much.
    • 0:30:02Maybe that's not enough.
    • 0:30:03We want to make sure we're handling it bit wise.
    • 0:30:10OK, let's see.
    • 0:30:16Yeah, so someone said fread is like copying some bytes from another file
    • 0:30:19and transferring it to another file-- exactly by using fread,
    • 0:30:23I'm not changing my hi.txt.
    • 0:30:25It is staying the same.
    • 0:30:27Like I'm not taking things away, I'm just copying it
    • 0:30:30or like referencing that file to read things into buffer.
    • 0:30:34So if I go back a little--
    • 0:30:39back on my slides.
    • 0:30:40So I moved my arrow four blocks forward, but they didn't necessarily disappear.
    • 0:30:47Like those four blocks are still contained,
    • 0:30:51and my TXT file is just for the purposes of this program.
    • 0:30:54Like I'm moving forward.
    • 0:30:56Like I read those 4 bytes, so I can go on to read the next ones.
    • 0:31:15OK, so someone asked to see the fwrite slide again.
    • 0:31:20And I can go back to that.
    • 0:31:25OK, it's right here.
    • 0:31:27So right, this is fright syntax.
    • 0:31:30But let's go ahead and get some practice with these guys.
    • 0:31:34So fread, fwrite, and working with the files.
    • 0:31:37So on the menu today is the activity.
    • 0:31:43So on the menu today is the activity that will allow us to detect PDF files.
    • 0:31:49So what we're going to do is we're going to create a program called PDF.c.
    • 0:31:55And again, you're welcome to follow along with me
    • 0:31:58or reference it after this, but we will write a program that will read the file.
    • 0:32:06And then we'll try to understand if it's a PDF or not.
    • 0:32:10A helpful hint here is that all PDFs begin with a specific 4 byte sequence,
    • 0:32:16and if you do some math and manipulation,
    • 0:32:19you're welcome to figure out what exactly that is.
    • 0:32:22But the example usage of the program is that when we run this PDF program
    • 0:32:28and we plug in a specific file name, it should let--
    • 0:32:32specific file, it should let us know if it's a PDF or not.
    • 0:32:40So let's move to cs50.dev and I already started it a little bit.
    • 0:32:51OK, I need to go to my directory first.
    • 0:32:55All right.
    • 0:33:00All right, here it is.
    • 0:33:02So I already prewrote some code just to help myself move along.
    • 0:33:08So let's walk through it together, line by line of all the todos
    • 0:33:12that we need to do.
    • 0:33:15And I gave a little hint here.
    • 0:33:17OK, let's leave this here, but I will show why it is important.
    • 0:33:22So first thing we're going to do is check usage.
    • 0:33:24Like we're again, making sure that we are writing
    • 0:33:27our programs in a very defensive way.
    • 0:33:30We are telling you there's exactly how many--
    • 0:33:33how many CLAs we're expecting from them and exactly what we want to see.
    • 0:33:37Next, we're going to open that file that the user gave us.
    • 0:33:41We're going to create buffer for that file.
    • 0:33:44So again, we want to store just a little bit of it.
    • 0:33:49We're going to create an array of signature bytes.
    • 0:33:52So the signature bytes is exactly the 4 byte signature or sequence
    • 0:33:57that we're looking for in our PDFs.
    • 0:34:00We're going to match them up.
    • 0:34:03So looking at the 4 bytes, first 4 bytes of our file,
    • 0:34:07and then add the four signature bytes that we define in our array.
    • 0:34:12We're going to compare them.
    • 0:34:14And then if they all match up, then it is indeed a PDF.
    • 0:34:18And if not, it's not a PDF file.
    • 0:34:21And in the end, a very important thing we're going to do
    • 0:34:24is we're going to close the file because we opened it in the very beginning,
    • 0:34:29and we want to make sure that we close it back again.
    • 0:34:33OK, so let's get started.
    • 0:34:36And I'm going to skip this comment just a second
    • 0:34:39to show what happens if you don't check for CLAs.
    • 0:34:41But let's start writing some code.
    • 0:34:45So as we just saw in the slides, the way that we open file--
    • 0:34:51we can use files is by using the pointers.
    • 0:34:54So the type that we're going to point to is file.
    • 0:34:58This asterisk is what gives us a pointer,
    • 0:35:02and I'm going to call my file input.
    • 0:35:05I'm going to use fopen and inside of fopen,
    • 0:35:08I'm going to use my command-line arguments to access the file name.
    • 0:35:18So per usage right here, what we want to see from the user is ./pdf to run
    • 0:35:26the program, but then the file name, which will be our second command line
    • 0:35:32argument.
    • 0:35:32And I'm opening it in mode read because I don't want to modify anything in it.
    • 0:35:37I just want to make sure I'm grabbing the information that I need,
    • 0:35:41and that is it.
    • 0:35:43Next, I'm going to create buffer for that file for the little bits
    • 0:35:49of information that I'm going to read.
    • 0:35:52And so I'm going to introduce something new, and it is uint8_t buffer.
    • 0:36:03So the tricky thing in this whole line is just this guy.
    • 0:36:09Buffer is just the variable name that I picked.
    • 0:36:11Four-- it is just defining that we will have four little cells in our array.
    • 0:36:16But what is uint8_t?
    • 0:36:22Does anyone know what that is?
    • 0:36:24And it's OK if you don't.
    • 0:36:26But yeah, so very close.
    • 0:36:32Someone says I believe it's a byte.
    • 0:36:34Very close.
    • 0:36:35It is a size of byte, but it is actually is an unsigned integer.
    • 0:36:40So first of all, it is making sure that we only have non-negative values,
    • 0:36:45but it's also making sure that it's exactly one byte.
    • 0:36:48As I mentioned before, depending on what machine you're using,
    • 0:36:52integers can actually be bigger or smaller.
    • 0:36:55But by using uint8_t, we're always ensuring that it is of size byte.
    • 0:37:05Now let's create another array where we're
    • 0:37:08going to store our signature bytes.
    • 0:37:11So this is what is going to help us identify if it is a PDF.
    • 0:37:17And I have the signature bytes pre-written,
    • 0:37:23so I'm just going to copy them over.
    • 0:37:30OK, so this will help us identify if it's a PDF.
    • 0:37:36So it is just the four bytes that are always
    • 0:37:41contained in the beginning of each PDF.
    • 0:37:43And so by comparing what it will actually read from the file,
    • 0:37:47we will be able to identify that.
    • 0:37:51So this is where the tricky part comes in.
    • 0:37:56All of these things that we knew, how to define arrays, fopen
    • 0:37:59was a little bit new to us.
    • 0:38:02But now is the interesting part.
    • 0:38:05Like we want to read first 4 bytes from the file.
    • 0:38:08And by looking at this keyword right here, I see that--
    • 0:38:12I'll just probably use fread.
    • 0:38:14And I mentioned at the beginning that we don't want to modify anything,
    • 0:38:17but can y'all help me out?
    • 0:38:19So what four arguments do I want to put inside of my fread function?
    • 0:38:27What was the structure of our arguments inside of fread?
    • 0:38:36OK, so I want to read to buffer.
    • 0:38:44That is my first part.
    • 0:38:46Then I already also have a hint to myself from the comments.
    • 0:38:51Read first 4 bytes.
    • 0:38:53So I remember that my second argument in fread is the size.
    • 0:38:58So I can say one because I know that uint8_t is always 1 byte.
    • 0:39:07Or I could be more diligent and use the size of function
    • 0:39:11that I was telling you about.
    • 0:39:13So by using size of, I can ensure that no matter what machine I'm using,
    • 0:39:19I always get the exact size of this variable of this type.
    • 0:39:26And then after the two location and the size comes the number of blocks.
    • 0:39:35So I want to read four of those.
    • 0:39:40And then where am I reading them from?
    • 0:39:43What is the last argument?
    • 0:39:47So people already typed in the chat.
    • 0:39:50Yeah, it's input-- exactly.
    • 0:39:52So I'm going to read it from input.
    • 0:39:57OK, let's make sure it compiles before we go any further.
    • 0:40:02So make PDF, and this is where I'm going to show you why CLA is that important.
    • 0:40:06So, for example, if I try to do, I get this error--
    • 0:40:12segmentation fault. Why is that the case?
    • 0:40:17Like, why did I get an error?
    • 0:40:27OK, so someone is saying fclose.
    • 0:40:32No.
    • 0:40:33Yeah.
    • 0:40:34So I need a value for argv[1].
    • 0:40:36I didn't pass anything in.
    • 0:40:38I only have ./pdf, but I don't actually have the file name.
    • 0:40:42So when my computer gladly does what I told him to do, it gets to line 10,
    • 0:40:48and it tries to open the file.
    • 0:40:49But I never told him what that file was.
    • 0:40:52I never gave it in the command line argument.
    • 0:40:55So it is really important to make sure you're error checking.
    • 0:40:58You program correctly.
    • 0:41:00And you're being a defensive programmer.
    • 0:41:02Like you're telling your user exactly what you expect from them.
    • 0:41:06So to write my if statement, how many--
    • 0:41:10what should be my value of argc?
    • 0:41:12Like how many arguments am I expecting?
    • 0:41:15What condition can I set here?
    • 0:41:18Two-- OK, so I can say something like if argc does not equal to 2,
    • 0:41:24if they provided me with too many arguments or not enough,
    • 0:41:28I want to give them a message.
    • 0:41:31Please provide only one file name.
    • 0:41:39And I want to quit.
    • 0:41:43So I don't want to be going further because once again, I
    • 0:41:47hit this line, line 14 now.
    • 0:41:49My computer will try to open the file, but it can't because I
    • 0:41:53never told him what this file was.
    • 0:41:56All right, so let's try.
    • 0:41:59Let's compile this.
    • 0:42:01Make sure we update it, and let's run it again.
    • 0:42:04And now, I don't get any segmentation fault errors.
    • 0:42:10And it is instead just telling me that I need to provide file name.
    • 0:42:20All right, so we had some bytes, and now let's check them.
    • 0:42:27So essentially, what I will have is the buffer array with 4
    • 0:42:34bytes of some information from my file.
    • 0:42:37I also have my signature array of the bytes that I want to cross-check.
    • 0:42:45How would I go about it?
    • 0:42:47I want to compare these 4 bytes.
    • 0:42:50Could I write something like if buffer equals to signature,
    • 0:42:58then everything went well?
    • 0:43:05Is that something that I could do?
    • 0:43:12OK, so yeah, people are suggesting to use a loop,
    • 0:43:16and that is exactly the intuition behind it.
    • 0:43:19I want to go comparing one byte at a time.
    • 0:43:23So as we've seen these past weeks, we're going to set up a very simple for loop
    • 0:43:28where I'm going to go until 4 because I'm only looking at the first four
    • 0:43:33bytes.
    • 0:43:34And inside my for loop, I'm just going to compare the values
    • 0:43:39in each of the array one by one.
    • 0:43:41So I could do signature i like indexing into the spot that I'm interested in.
    • 0:43:50If it is not equal to the bytes that I have in buffer, what do I want to do?
    • 0:44:00And I messed up the syntax here.
    • 0:44:03OK, so if I'm looking at the first value in the signature array
    • 0:44:09and I'm comparing to the first value in the buffer array,
    • 0:44:13if they don't match up, we do I want to do?
    • 0:44:16Exactly-- I want to quit.
    • 0:44:18So if the very first bytes don't match up or the second or the third,
    • 0:44:22I don't want to go until the very end to find that out.
    • 0:44:25I might as well just quit right away and tell my user it's not a PDF.
    • 0:44:29So I can say something like this is not a PDF new line semicolon and return
    • 0:44:41zero.
    • 0:44:42OK, so let's make this again.
    • 0:44:57oh typo.
    • 0:44:59All right, let's make this again--
    • 0:45:01make PDF.
    • 0:45:05OK, let's try running it.
    • 0:45:09And I already preimported some test files,
    • 0:45:15so I have test.jpg and test PDF right here.
    • 0:45:19So I'm going to use test PDF.
    • 0:45:24OK, I don't get anything.
    • 0:45:25And I would say that's a good sign.
    • 0:45:27But if I try to do pdf test.jpg, it is telling me this is not a PDF.
    • 0:45:34So seems like our algorithm is indeed working as we intended.
    • 0:45:40And it is telling us if it's a PDF or not.
    • 0:45:43I'd argue it's also nice to know if it is a PDF.
    • 0:45:46So if I get through my entire for loop and I don't quit, I know it is a PDF
    • 0:45:51so I can just return this message here.
    • 0:45:55It is a PDF new line.
    • 0:45:59And then lastly, I want to close my file.
    • 0:46:02So even though I'm not necessarily seeing any errors right now
    • 0:46:06in the terminal, when I run this program,
    • 0:46:08odds are something might come up later, but I just want to avoid that.
    • 0:46:12So I'm just going to close the file that I opened earlier
    • 0:46:18and also return 0 to tell the program that we're done.
    • 0:46:23So let's make PDF again, and let me expand this.
    • 0:46:28Let me clear this first.
    • 0:46:30So make PDF.
    • 0:46:32OK, let's run PDF on test PDF--
    • 0:46:36OK, nice.
    • 0:46:37And then let's run it again on test JPG.
    • 0:46:42This is not a PDF--
    • 0:46:44OK.
    • 0:46:47OK, this was a lot.
    • 0:46:48So let's recap this one more time now with the code that we have.
    • 0:46:54So let's actually go back to the line number five.
    • 0:46:58We actually never talked about.
    • 0:47:00By defining this line, we are making sure
    • 0:47:04that we can accept those command-line arguments.
    • 0:47:06This is our definition for doing that.
    • 0:47:08Our next step is making sure that we have exactly
    • 0:47:11the two command-line arguments we were looking for.
    • 0:47:14And you can go even a little further, trying to figure out if they actually
    • 0:47:18gave you a file name or something else.
    • 0:47:20But this is pretty good for now.
    • 0:47:22So I'm making sure that my user gives me two command line
    • 0:47:26arguments, one for the program name and second for the file name.
    • 0:47:30If it's not, indeed two, I want to return.
    • 0:47:33I want to quit.
    • 0:47:34I want to end my program and tell the user
    • 0:47:36that they must provide me one filename.
    • 0:47:40My next step is now opening this file.
    • 0:47:43This is the equivalent of double-clicking on your file
    • 0:47:47and opening it in Adobe or your web browser.
    • 0:47:50And we're opening the file with the file name that the user gave us.
    • 0:47:56So this is where the command line argument comes in,
    • 0:47:59and we're grabbing that second command line argument at index one
    • 0:48:06to use it as a file name to open our file.
    • 0:48:10The second argument in the F open function
    • 0:48:12is quote unquote r, which stands for read write.
    • 0:48:17We just want to open that file, read information from it,
    • 0:48:21not modifying anything, just reading it.
    • 0:48:24So this will set us up to have that file opened.
    • 0:48:29Next, I'm going to create the buffer for the file.
    • 0:48:32And so we just talked about this new data type that is unsigned int.
    • 0:48:38This gives us an option to have exactly one byte
    • 0:48:41for each of those cells in our arrays.
    • 0:48:44It's a buffer that is expecting 4 bytes.
    • 0:48:48Our next step is creating the array of signature bytes,
    • 0:48:51and I will give away what these hexadecimals are.
    • 0:48:57But the 0 x value that you see in the array are four hexadecimals,
    • 0:49:02and 0 x is telling us that they are hexadecimals.
    • 0:49:06If you do some conversions, what they stand for is percent PDF.
    • 0:49:13So actually, there are these hidden traces in the files
    • 0:49:17that tell us exactly what they are.
    • 0:49:20So really, what we're doing here is something very simple.
    • 0:49:23We're looking at the file sort of like on the micro level,
    • 0:49:27literally looking at it byte by byte, and just by knowing this information
    • 0:49:32from the internet, I know that the 4 bytes will look exactly like that.
    • 0:49:36And so I can do something relatively fancy.
    • 0:49:40Like, I don't know.
    • 0:49:40If you try to open a PDF file with PowerPoint,
    • 0:49:47you won't be able to do that because it just doesn't support, or maybe it does.
    • 0:49:52Anyway, let me go back on that.
    • 0:49:53If you tried to open the file, write it with some program
    • 0:49:56that simply doesn't support that, one way
    • 0:49:58that they can do that is by simply checking the signature.
    • 0:50:01And if it is exactly the file that they can't indeed support,
    • 0:50:05they will return an error message, which is what we're doing in this program.
    • 0:50:10So line 24 is where our juicy stuff happens.
    • 0:50:15So this is where we're reading those 4 bytes of information at a time.
    • 0:50:19And we're using our new functions that we just learned.
    • 0:50:24So again, fread is structured in such a way that we want to read to buffer.
    • 0:50:32We want to read four blocks of size byte and we want to read it from input.
    • 0:50:41So just some order and like algorithm to it once again, you need to get used to.
    • 0:50:48And then our last piece where like our matching up is happening.
    • 0:50:53It's actually quite simple.
    • 0:50:54Like we've seen for loops before.
    • 0:50:56We've done the if statements.
    • 0:50:57It is just making sure that we're comparing this information correctly.
    • 0:51:01We want to go one--
    • 0:51:04again, one index at a time, comparing one cell at a time
    • 0:51:08at each of our arrays.
    • 0:51:10I can do if signature equals buffer.
    • 0:51:13Like he just can't compare things like that.
    • 0:51:15And if they're indeed not equal at any point, I want to make sure I'm telling,
    • 0:51:20A, my user about that and, B, that I'm quitting the program.
    • 0:51:25If my very first byte doesn't match up between the two arrays,
    • 0:51:30there is no reason to go all the way through.
    • 0:51:33I want to make sure they just quit right away, tell my user, and end my program.
    • 0:51:39But if I indeed got through the entire for loop and I didn't quit
    • 0:51:43and I didn't tell my user something like that is not a PDF,
    • 0:51:46I can safely say that it was a success that my file is indeed a PDF.
    • 0:51:51And this is where some of the people might end this program.
    • 0:51:54I completed my goal.
    • 0:51:57I either said that it was a PDF or that it wasn't.
    • 0:52:01But an important step that we must take is closing the files that we opened.
    • 0:52:07If you're coding the program similar to this
    • 0:52:11or the one that uses fopen, literally just say OK, I have one fopen here.
    • 0:52:16I must have an fclose.
    • 0:52:18And it is common practice to just do it in the end.
    • 0:52:21But I could have also closed my f input on line 25
    • 0:52:27right here because I technically am not using it further down in my program,
    • 0:52:34but I kept it open just in case.
    • 0:52:36Like what if I want to access it again?
    • 0:52:38But once I reached to the very, very end,
    • 0:52:40literally right before I'm returning and quitting the program,
    • 0:52:45I just want to close the file to make sure I am not messing with any memory
    • 0:52:50that I am not supposed to be messing with.
    • 0:52:53OK, all right.
    • 0:52:57What questions do we have about this program,
    • 0:53:02about pointer's memory, before we break for the day?
    • 0:53:10So someone said, could we use malloc for buffer?
    • 0:53:12And we indeed can.
    • 0:53:14We can use malloc to allocate the same amount of memory, in this case,
    • 0:53:19like creating an array just because I know exactly what size it needs to be.
    • 0:53:23That works as well.
    • 0:53:26OK, let's see.
    • 0:53:31Someone says, does fread remember the position where it stopped the last time?
    • 0:53:35Yeah, so my pointer is sort of moving every time I fread, and this
    • 0:53:39is something that will be really helpful for you, cover, for example--
    • 0:53:42Like every time you read some piece of information,
    • 0:53:45your error just keeps moving forward, and you're
    • 0:53:47able to read the consequent one.
    • 0:53:49So someone said, can we use char star?
    • 0:53:52Yeah, we sure can.
    • 0:53:54So this is sort of like would be taking our training wheels off,
    • 0:53:57and we could do char star RGB.
    • 0:54:03That is just the string.
    • 0:54:05But I'll keep this just for now.
    • 0:54:09OK, let me see.
    • 0:54:10There's so many questions.
    • 0:54:13Can I point to point to pointer?
    • 0:54:15Yes, it can.
    • 0:54:16I think someone already answered that in the chat.
    • 0:54:18It will just be like creating this string of things.
    • 0:54:20There is no reason to do that unless you really
    • 0:54:22need to because pointers take up space.
    • 0:54:27When we use pointers, we're almost like doubling, if not more,
    • 0:54:30the memory that we're using.
    • 0:54:32So again, we want to use them exactly in the situations when we need to.
    • 0:54:38So do fread and fwrite write only work in bytes?
    • 0:54:41That's a good question.
    • 0:54:42So actually, let me show an example.
    • 0:54:46So if I go into manual pages--
    • 0:54:51yeah, so let me show an example.
    • 0:54:53If we go into manual pages and I open fread,
    • 0:54:59I can read the description where under the size--
    • 0:55:04and let me zoom in here a little bit.
    • 0:55:06So under the size component, it says, which
    • 0:55:11is the size in bytes of the data of type of data to read?
    • 0:55:15So this is just how fread is set up.
    • 0:55:18And you will actually find that the two, the size and the number,
    • 0:55:22can be interchangeable depending on the situation.
    • 0:55:26But yeah, we want to make sure we're specifying it in bytes.
    • 0:55:29And the easiest way to go about it is just using the size of function.
    • 0:55:32That will always return exactly the size of the data type
    • 0:55:37that we are looking for.
    • 0:55:40OK, let's see.
    • 0:55:41There are so many more questions.
    • 0:55:45Can we close the file input inside the loop?
    • 0:55:48Yeah, we sure can.
    • 0:55:49But consider the case if we don't get to this part.
    • 0:55:55If we try to fclose here, we might never like, if it is exactly a PDF,
    • 0:55:59we might never reach that point.
    • 0:56:02So you're always want to make sure that you're
    • 0:56:04closing the file like not inside the if statement
    • 0:56:07or somewhere where your code might not reach.
    • 0:56:10But just doing it in the very end is a good habit to get into.
    • 0:56:16So the usage for the program--
    • 0:56:23someone asked in the chat--
    • 0:56:24is ./pdf and then the name of the file.
    • 0:56:30So in this case, I use test.pdf.
    • 0:56:33And you just want to make sure you have those files in your environment
    • 0:56:38before you try to access them.
    • 0:56:39Because obviously, if you don't have it, you'll also get an error.
    • 0:56:45OK let's see.
    • 0:56:51So why do we return 0 when we're already closed the file?
    • 0:56:56So this is going back to the previous week
    • 0:56:59where we talked about the main function a little bit.
    • 0:57:02So in my definition of the main function, I say int main
    • 0:57:07and then whatever arguments I am accepting.
    • 0:57:09By saying int main, I am specifying that the return type of my main function
    • 0:57:14has to be like a number, an integer.
    • 0:57:17So in this case, as I am like returning one when I want to terminate on line 11,
    • 0:57:22if I didn't, in fact, get the correct number of arguments,
    • 0:57:26or here I am also returning zero and returning zero here.
    • 0:57:31You could again write different numbers.
    • 0:57:33It doesn't really matter.
    • 0:57:35I could write 4, but 0 is for a successful program.
    • 0:57:39And even if it's not a PDF, like our program was still successful.
    • 0:57:43It identified what kind of file it is, or rather if it was a PDF or not.
    • 0:57:49So it was still a success.
    • 0:57:51So we can return 0 here and then 0 in the very end.
    • 0:57:59All righty.
    • 0:58:00So let's go back to our slides.
    • 0:58:03And again, this week and even the last week
    • 0:58:06has been escalating really, really fast.
    • 0:58:09So definitely make sure you're taking the time
    • 0:58:12to go through the section slides, go through the recordings of the lecture,
    • 0:58:16and even writing out things on paper and drawing those diagrams, like we just
    • 0:58:20did today, would be really helpful.
    • 0:58:23But this was it for today.
    • 0:58:24My name is Yulia.
    • 0:58:26This was week four of CS50.
    • 0:58:28Thank you so much for joining our section.
    • 0:58:30And I see you again later.
  • CS50.ai
Shortcuts
Before using a shortcut, click at least once on the video itself (to give it "focus") after closing this window.
Play/Pause spacebar or k
Rewind 10 seconds left arrow or j
Fast forward 10 seconds right arrow or l
Previous frame (while paused) ,
Next frame (while paused) .
Decrease playback rate <
Increase playback rate >
Toggle captions on/off c
Toggle mute m
Toggle full screen f or double-click video