[MUSIC PLAYING] DAVID MALAN: Hello, everyone. This is CS50's supersection. Assigned Sections will not start for another week. And so today, I'm here with-- MARIA: Maria. DAVID MALAN: --to actually take a look at problem set one, the course's first weeks of material, get you oriented with CS50 IDE, a bit of Linux, the operating system that's running on IDE, as well as look at some of the transition from Scratch to C leading up to problem set one. So without further ado, in problem set one, you're going to be introduced to CS50 IDE, which is this web-based programming environment that we use in order to write programs. It's been designed to look very reminiscent of a typical computer system running an operating system called Linux. But it's in the so-called cloud, which means everyone in the class can actually have his or her own account and use it, as well. So most of you probably have never used a Linux environment before or perhaps even a command line environment. And a command line environment is different. It's all textual. It's all keyboard commands. And it's no mousing, no icons, no dialogue windows, no menus. It's purely text. So at first, it kind of feels like a step backwards in terms of sophistication. But it ends up being a lot more powerful, certainly, for a computer scientist, ultimately. So let's take a look. Here I am at CS50.io, via which you can log into CS50 IDE. And much like in Scratch, there's three primary areas to this screen. So on the left-hand side, we have what will be the file browser. And there's this folder at top, which is right now empty since I got rid of all my files before supersection. And that's where we'll save C files that we write. At the top right, we have a place where all of our code's going to get written. And indeed, if I click this plus, this is going to let me choose New File. And here I can start writing C code or, really, any number of other languages. And then at the bottom where it says jharvard@ide50-- and yours will say something a little different-- what was this called? Terminal window. Yeah. So the terminal window is the so-called command line interface via which you can interact with the underlying operating system. And for now, we're going to make very little use of this-- just to compile, to look at error messages that we see, and to run our programs. But ultimately, we're going to do so much more, as well. And you can even install software and administer your workspace within CS50 IDE, as well. But more on that some other time. So let's go ahead and write a very simple program just to go through a warm-up of hello.c, which is perhaps the simplest program we can write. I've already opened up a new tab. I'm going to go ahead and say include standard io.h. Then int main(void). And then printf ("hello, world" backslash n, close quote, close parentheses, and semicolon. All right. So now notice my window is untitled. So I'm very quickly going to go up to File, Save. And it's important that I call this not "hello." So a very common mistake, especially in problem set one, is to accidentally just call your program "water" or "greedy" or "Mario" or "credit" or the like. But you actually want to make sure you have the file extension because this is the only way that the compiler and also the code editor knows that you're actually writing C code. So let me go ahead and click Save. And now, too, what CS50 IDE has done for us is it's also syntax highlighted everything. So it's made everything very colorful. And the whole purpose of that isn't functional. It's just to draw my eyes to the conceptually different pieces of this program. So let's go ahead and compile this. And I can compile this in a couple of ways. And in week one, the old-school way we did it was literally at the command line-- "clang hello.c." And then I hit Enter. And nothing seems to happen in the terminal window. But what did change in the IDE? Where, again, IDE just means Integrated Development Environment. It's a fancy way of saying this integrated development environment for developing software. So what did change in the UI? What did you notice that's different, Maria? MARIA: I noticed something under the IDE50 folder up here. DAVID MALAN: Yeah. So up here, not only do we have "hello.c." We also have "a.out," which is kind of a dumb name for a program. But indeed, it's the default name for a program when you just compile your code and don't tell the compiler what file to output. So if I want to run this, I need to tell the compiler-- or rather, I need to tell the workspace that I want to run the program called "a.out." Enter. And there's "hello, world." now the "./". is actually important. Even though normally we only write the names of commands, when it's a program you've written, you do want to say "./" because that explicitly tells Linux that you want to run a program called "a.out" that's in this, where dot means this directory that I'm currently in, which happens to be called workspace, "a.out. Because if I just said "a.out," Enter, I'm going to get "a.out command not found" because the computer-- because I invented "a.out;" it didn't come with the computer-- doesn't know where to look for it, even though it's right under my nose, so to speak. OK. So we could change this to be "clang -o hello hello.c." And if I hit Enter, what program is this going to output for me? What's the name of the file? Yeah, in back. That's right. "Hello." So "hello" is going to be the name of the program because we've used a so-called command line argument, which is just a way of changing the behavior of the compiler to actually output a specific file name. And indeed, if I zoom out and look up here, now I have not only "a.out" and "hello.c" but also "hello," as well. So now I can do "./hello," Enter. And there's "hello, world." But lastly-- and this will now be the convention we use throughout the semester, typically-- is you can also just say "make hello." And indeed, it's saying it's up to date because it already exists. Let me go ahead and remove, with the rm command, both "a.out"-- and say "remove regular file a.out?" That just means, are you sure you want to delete it? I'm going to say yes. And then I'm going to remove "hello" but not "hello.c." I'm going to say "yes" explicitly, but "y" is sufficient, as well. And now notice if I type ls-- which, recall, means list-- it lists all of the files in my folder. And indeed, if I zoom out and look at top left, it confirms that what's in this folder, even though it's labeled as IDE50 up here and not workspace, it's just "hello.c." So now down here, if I do "make hello," Enter, now I see a much longer command but a more sophisticated command that's going to be useful in the weeks to come. And now I can say "./hello." So let's take a quick tour some other Linux commands. Then why don't we take a step back and actually look at C more generally, transitioning from Scratch to C, and then conclude with a look at the first problem set in C. All right. So I'm going to go ahead and just clean up my workspace with Control-L just to keep the screen neat. But that has no functional impact otherwise. Recall that we've seen a few commands now. So we've seen clang, which generally you won't have to execute manually anymore. We'll instead use make. But we also saw ls, which shows a listing of the files in my directory. And now why is there-- there's two files now, "hello" and "hello.c." Why is there a star or an asterisk after "hello"? What did that signify, based on what we saw in week one? What do you think? What does the star signify? MARIA: For-- the program "hello"? DAVID MALAN: "Hello*". Yeah. Oh, yeah? Oh, executable. That's right. So that means that "hello" is executable. So indeed, that's why I can do "./hello." All right. So what else can I do in here? Well, it turns out I can also create directories. So let me go ahead and create, for instance, a "pset1" directory. And the problem set specification will have you do exactly this, so you don't have to remember today. But "mkdir pset1" seems to have no impact. But again, no error message is generally a good thing. So if I type "ls" now-- ah, now I have an executable file called "hello," a C file called "hello.c." And then the trailing slash, so to speak, means that this is a directory. So indeed, now I want to open it. And I don't double click on it like in a GUI, a graphical environment. I instead say "cd pset1." Enter. Nothing interesting seems to have happened except my little prompt here-- this is Linux's way of reminding me where I am, so what folder is open. It's just telling me explicitly as opposed to graphically. And if I type "ls," why do I see another prompt immediately, do you think, when I list the contents of pset1? MARIA: You probably don't have anything in there. DAVID MALAN: Yeah. So then we haven't obviously created anything in there because I just created the directory. Now, if I wanted to create a file-- for instance, I could create a new file. And then I could go to Save and save it as, like, "mario.c" if you're doing the standard edition of pset one. And then, like any Mac or PC, just choose the folder "pset1, Save. And now the file is empty. But let's zoom in again for a second. Let's do ls here. Now we see "mario.c". So there's a few other commands that are worth keeping in mind over time-- clear, or Control-L is what I've been hitting; mkdir we've seen; rm we've seen, as well, which is for removing or deleting a file. Beware you can also-- and if you look at online tutorials, you'll rm -rf is a very common way of saying delete a folder that has stuff in it. Just be super, super careful. -rf means recursively delete whatever it is you're trying to delete and forcibly delete it. So recursive means if it's a folder with a folder with a folder with a folder, delete all of them. And forcibly means don't even ask me yes or no, am I sure? So it's a super dangerous way of deleting lots of stuff quickly. But beware-- too often does an intrepid student accidentally delete, say, pset one, for instance. MARIA: And if they just do -r, they're going to ask them about every single file. DAVID MALAN: Which is moderately annoying. MARIA: Yeah. DAVID MALAN: So that's why so many of us, self included, am in the habit of using -rf. But it's dangerous. So buyer beware. And then mv is kind of interestingly named. So this is the move command, which feels a little weird because you can indeed use it to move files from one place to another. For instance, suppose that I messed up. Suppose that I created a new file for the pset. And I saved it as "greedy.c." But suppose I accidentally save it in IDE50-- so in my workspace itself and not in pset1. You can see as much at top left. There's "greedy.c." And there's a few solutions. So one, I can use the super user-friendly way of just dragging and dropping it. And that would actually fix this problem. But today, we're trying to look at the more arcane but powerful ways of doing this. So let me take "ls" in pset1. And I only see "mario.c." Let me go ahead and do "cd ..". So CD again is change directory. ".." means what, though? Last time I said "cd pset1" to go into pset1. So when I say "cd ..", what am I doing? Backwards. Yeah. So it's going to the so-called parent. Go one level up, like exiting out of a folder. So Enter. And indeed, look what it did. It moved me just into workspace instead of into pset1, which is in workspace. And now if I type "ls", there's a whole bunch of stuff. In there is "greedy.c". So now let me use mv to literally move "greedy.c" into pset1. And so a lot of Linux commands work exactly like this. They take no arguments or they take one argument or they take two command line arguments and so forth. And in this case, it's literally doing what it says, albeit succinctly-- move greedy.c into pset1. Enter. Nothing seems to happen. But if I do a ls again, greedy is gone. And if I do "cd pset1", Enter, and then ls again, now it's in the right place. As an aside, if for some reason-- especially if you have intermittent network connectivity or you're walking around campus with your laptop lid closed and then open it up again and your workspace seems somewhat out of sync, no big deal. Just reload your browser window, and it should resync so that the left-hand file browser looks exactly like the terminal window. Not to worry. When in doubt, reload the page, so long as you've saved the files already. OK. So mv can also be used to rename files. And let's take a look at this final command here. So suppose-- and this is super common, too, early on. Some students occasionally create a file called, let's say-- what's another one? Like "WATER.C." So I'll just yell, for no reason, in all caps. But this is not the correct name for the file if only because our problem set specification did not tell you to save the file as all caps "WATER.C." Instead, we expect "water.c" in lowercase. And, in fact, this is problematic because check50, a program you're going to meet in problem set one that automatically tests the correctness of your code is going to yell at you if it can't find "water.c" in all lowercase. So I need to fix this. So many different ways to do this, the first of which would be to Control-click or right-click the file name and just change Rename. Totally fine to do that. But again, today, let's do it a little fancier. Let's use mv to change "WATER.C" to "water.c." So you can also use the first argument to rename it to the second argument if the second argument is not, in fact, a folder or a directory name. All right. And lastly, a little trick-- so I'm in my workspace directory at the moment. If I want to get into pset one, I can certainly type "cd pset1." But it's so tedious to type "pset1" or longer file names or directory names still. So very often in Linux, what you can do is start typing "pse" and just get bored, hit Tab, and let the computer figure it out for you. Super helpful to get into that habit. The only catch is if you have multiple files or folders starting with the letter "p" or "ps," you might have to type a few more before the computer knows what to do. MARIA: We like shortcuts. DAVID MALAN: This will save you so much time. And also, as we said in lecture, you can scroll up in history, up and down, to find recently executed commands, as well. All right. So now, let's turn our attention back to a simple program, hello world. So we've compiled this exactly. And now why don't we take a look at the data types and then transition from some corresponding Scratch blocks to C. MARIA: Awesome. So now that you've started writing programs in C, we're going to start talking about data types and variables. So some data types that you would want to know starting now are the ones that are highlighted in blue. So we have int first, which stands for integer. And that holds integers, as you might have guessed-- so 1, 2, 3, and any other integers that you can think of. DAVID MALAN: And also negative. MARIA: And also negative ones, yep. And 0. Then we have floats, which are floating point numbers. So that's all the real numbers that have decimal points. So 5.0, 5.2, and even more digits after the decimal point, as well, and also negative ones. Then we have char which is a character. So I think we talked about this in lecture today. But we have letters, for example-- A, B, C-- that can be stored as a char. But then we have a lot more symbols that can be stored as a char. And those are stored as ASCII. And then we have bool, which are Booleans. And those evaluate to True or False or 1 and 0, respectively. DAVID MALAN: And recall that bool comes from the CS50 library. So it's not built into C, but it's super useful to have the notion of true and false. And even though you might think-- fun fact. A bool technically needs how many bits, truly, to represent True versus False? How many bits do you think you would need, maximally? Yeah, just one. So it turns out that C can't give you just one bit. The smallest unit of measure you can get is eight. So it's a little wasteful they you're using an entire byte, or eight bits, to represent True or False. But that's just the way it's implemented in C by the CS50 library. MARIA: And then the ones that we're not going to talk about as extensively right now-- double, that's for bigger floats. Long long and short are also for integers. DAVID MALAN: Indeed. In hacker edition of pset one, we actually use long long. But for the standard edition, it should not be necessary. MARIA: Cool. OK. So operators-- you should be probably familiar with most of these. Addition, +; subtraction, -. For multiplication, we have the *. So not the X that we usually use. Division, we have the backslash. And modulo is our last operator that we are going to talk about right now. It's an operator that allows us to take the remainder of a division. So if we have 4 % 2, 4 divided by 2 is 2 with a remainder of 0. So 4 % 2 is 0. 4 % 3 is 1. 4 % 5 is 4, as you could have guessed. And remember when using all of these operators to use the PEMDAS rules. DAVID MALAN: So to be clear, if you do 4 % 2, why is that 0, exactly? MARIA: Because 4 divided by 2 is 2 with a remainder of 0. So modulo gives us that remainder as opposed to the result of the division. DAVID MALAN: And indeed, what we'll find this helpful for is that in some problems that's not necessarily one, if you want to have the effect of restricting yourself to a range of numbers like 0 through something, you can use modulo to wrap around earlier than like the 2 billion or the 4 billion value that we've talked about in lecture. MARIA: Yeah. And even in "greedy" we might. DAVID MALAN: Yes, in problem set one, as well. MARIA: Yeah, nice. DAVID MALAN: Good hint. MARIA: Sorry. Boolean expressions-- so for Boolean operators, we are going to talk about all of these that you see here. So right now, we have two equal signs listed for equals. So those are for comparison. So far, we've only seen one equals sign. That's when we assign a value to a variable. So if we've seen int n=5, then we've assigned 5 to the variable n. But if we want to use == for comparison, we can check if n == 5. And if n == 5, then that's true. So Boolean operators allow us, basically, to evaluate Boolean expressions to True or False. So not equals-- we have the exclamation mark and equals. So we could also check if n doesn't equal 5-- so n != 5. Less than, less than or equal to, greater than, greater than or equal to, and then we have the logical AND and the logical OR. And those allow us to evaluate multiple Boolean expressions together to basically come together as one whole Boolean expression. So if we want to find a number, say, that is greater than 5 but less than 15 at the same time, we would use the logical AND operator to see if n is greater than 5 && n less than 15. DAVID MALAN: And here, too, it's really easy early on to accidentally use just a single ampersand or a single vertical bar. And hopefully the compiler will yell at you because they actually have a very different meaning. For those curious, they're used for bitwise operations, operating on individual bits. But you do want the pair of them here. And super important is that first one, the equal sign, which is the equality operator as opposed to the assignment operator. MARIA: And the vertical bar is located between the Delete and Return. DAVID MALAN: Yes. On a typical US keyboard. MARIA: Yep. So let's jump right into conditional statements. In Scratch, you've already seen, probably, if statements that allow you to check if something is true, then do something else. So you might have wanted to check if your sprite is touching some other sprite or the border of your screen. And then you might have wanted to end the game or do something else. So the syntax for that is "if (condition)." So if your sprite is touching something, then do is inside the curly braces. Then we have if-else statements. Else allows us to do something if the condition that we check for in the beginning is not true. So if the sprite is touching the border do this, else do something else. So otherwise do something else. Then we have a short example for this. So if (military_time < 12), we want to printf "Good morning!" Else we're going to printf "Good evening!" Basic example. DAVID MALAN: Good. MARIA: Cool. So now we have switch statements. Switch statements in general can allow us to do a lot of the same thing that we just talked about with if statements. For example, right now we have the general form of the switch statement that allows us to take a variable called n and compare it to a lot of different values, which here we have called constant1, constant2. We may have a lot more. And those are called cases. So if we have a switch statement-- and this works only for integers-- we have a variable in this case that's n. If the variable n is equal to constant1, we will execute some snippet of code or something that we want to do. And then we would break. So the break means that the switch statement will stop executing if n is equal to constant1, and then your program will continue. It will exit out of the switch statement and it'll continue to do something else. If, however, n does not equal constant1, then case for constant2 will be checked. So if n equals constant2, that other snippet of code will be executed. And then it'll break if that is equal to it. And then we can have also-- not necessarily, though-- a default case, which will happen if n does not equal any of the cases that you have listed. And in the default case, we also don't need a break necessarily because the switch statement will know that it needs to end after the default case if that's the case. DAVID MALAN: But stylistically, we always put it in there. MARIA: Yeah. DAVID MALAN: Yeah. So especially when starting out, especially if among those less comfortable, I would personally just recommend stick with the ifs and ifs-elses and if-else-if-elses and so forth if only because they're a little more straightforward. This is a nice optimization, or sometimes even aesthetically it makes the code more readable. And in fact, probably mid-semester we'll see a problem set where it just looks better and easier to read for the humans by using a switch statement. But don't worry about clinging to this too early. MARIA: Yeah. If you have a lot of if statements, it might just not be very readable. It might not be very fast for you to go through it. So switch statements can be very useful, as well. And also, don't remember-- don't forget to put the breaks in there. DAVID MALAN: Don't remember this. MARIA: Because then you might fall through from one case to another. So let's say that case constant1 didn't have a break statement in it. Then we might fall through inside case constant2. And we don't want to do that if we've already reached case constant1 and it's equal to n. So, for example, if we have a variable n that contains a class number, and we want to see what that class is-- if n equals 50, we're going to print "CS50 is Introduction to Computer Science I." Then we're going to break. And that's it. If, however, n is equal to 51, we're going to print "CS51 is Introduction to Computer Science II." Then, again, we're going to break. However, if then we put 124, 61, any other number that you might think of, or program is not going to recognize that. So it's going to say, "Sorry, I'm not familiar with that class." And it's going to break. DAVID MALAN: So you can really see the if, else if, else idea here. It's just different syntax for expressing the exact same idea. MARIA: Exactly. Now we have our ternary operators. So ternary operators have three parts-- a condition, something to do if that condition is true, and then something to do if that condition is false. So you see, basically, the syntax of that here. We have the question mark, and then the-- what do we call this? DAVID MALAN: The colon. MARIA: Colon. Thank you. Sorry. So let's look at our example to see if we can make sense of this-- class_num == 50. So here we see our Boolean operator == that compares the variable class_num to 50. So class_num stores an integer. And if that integer equals 50, then we're going to store "David Malan" inside the string professor. If class number does not equal 50, "not David Malan" is going to be the professor. DAVID MALAN: Thank you. And so this seems equivalent to what, would you say, at first glance? MARIA: To me it seems like if-else statements. DAVID MALAN: Yeah. And in fact, this is kind of a pretty one liner, so to speak, for implementing exactly the logic of if-else but doing everything in one step. MARIA: Exactly. Yeah. So if-else statements might take up a lot of space. They might be too long for something as simple as this. So this can be very succinct and very nice. So now we're going into looking at executing something again and again, so checking for a condition multiple times and then continuing to do something while that condition is true. So this brings us nicely into while loops. To the left, we have our first while loop. So while something is true, do something again and again. So make sure to notice that our condition here is validated at the top. Whereas with our second loop-- we call that a do-while loop-- we do something, then we check for a condition. And if that condition continues to be true, we go back and do the thing again. So the main difference is where the condition is checked for. And the code may never be executed if the condition is not true with the while loop. Whereas with the do-while loop, we have the code that is always executed at least once. And then while the condition continues to be true, we can go back and iterate again inside. So why do you think we would use a do-while loop over a while loop? Right. So if we want to prompt the user for some sort of input, if we want to ask them to enter their name, we want to at least ask them once. And if they do enter that name, we're not going to ask them again because we already know it. But if they don't enter their name, or if they enter something that's obviously not a name, we still want to continue asking them on for their name. DAVID MALAN: And in lecture we had one like this with the get positive int example, where there's nothing to check at first because you haven't even gotten an int. So we want to do this-- get an int from the user-- then check it, perhaps, again and again and again. MARIA: Exactly. For loops-- OK. For loops can allow us to do almost the exact same thing, as well. It's actually the exact same thing. So there's nothing that you can do with for loops that you would not be able to do with while loops. But for loops may seem a little bit more complicated syntactically because they have three parts inside what was before just the condition with while loops. So the first part that you sea, the left-most, we have "int dwarves = 0." So this is where we initialize our variable. Then we have a semicolon and "dwarves < 7." So this is where out condition actually is. So that is what we would have put just in the while loop-- "while dwarves < 7." Here, that goes in the middle of our for loop. So "dwaves < 7." And then our last part is "dwarves ++," which is where we update our variable. So the important thing to realize is that this is going to go through this for loop seven times and execute seven times. So we have seven dwarves, and they're all going to say, "I'm here to help you, Snow White" because they are ready to help Snow White. With while loops, we would have done the initialization and the updating not inside the condition, again, but either before or inside the while loop to make sure that we-- because we always need those parts. So to make sure that we have them, we would've still added them on, just not inside the parentheses. DAVID MALAN: And so it looks like-- in the lecture, for instance, I almost always use, like, i and n and pretty boring variables. It looks like you can use more cleverly named variables, too. MARIA: Yeah, it's actually very nice to use a bit more descriptive variables because especially if someone else is reading your code-- maybe you're grader or if you're collaborating with somebody-- you want to make sure that they understand what you're doing. OK. So this is something very funky-- for loop inside a for loop. I don't know if we've seen this before. Probably not. But we can actually have this-- so loops instead of loops. So does anyone want to maybe walk me through what's going on here? DAVID MALAN: I'll take a stab. MARIA: Cool. DAVID MALAN: OK. So, spoiler-- we want to print the stuff that's in the bottom right-hand corner there. MARIA: Right. Yeah, yeah. DAVID MALAN: So we've just put that sample output there. So I can infer from the topmost loop that you're iterating over rows the outermost loop, so to speak. And you're iterating over columns with the innermost loop. And intuitively, this should hopefully makes sense because by nature of every program we've seen before, printf, which is the function we're using, ultimately, has the ability to print stuff out essentially line by line. Like, once you've outputted a new line, there's no doubling back and printing something higher in the screen, at least not using printf like this. And so in that regard, it makes sense that the outermost loop should be referring to the rows because for each given row, you're going to want to print out XXXXX, and then move on to the next row, XXXXX. So rows come first. And then within each row, you print columns. If you tried to do it the opposite, it would probably not come out as you intend. MARIA: Yeah. We just could not go back to the previous row with printf. DAVID MALAN: And what's interesting per today's chat about scope, actually, is that row is an int that's declared in the topmost loop. But notice that it is still inside of, so to speak, the curly braces that immediately follow, even though it's not technically within those curly braces. So row is in scope for the entirety of the snippet of code, both inside of the outer for loop and inside of the inner for loop. But by contrast, where is column in scope? The variable column? Yeah, only in the inside loop. And that's OK because we don't access it outside of its curly braces. All we do is print out a new line at the very end there. So that in fact is OK. So this has the effect, it looks like, of doing three rows and four columns. MARIA: Right. So first we go through our first row. And just in our first row, we do the four columns inside the first row. So we print out four X's. And then we can exit the for loop, since we've already printed out four X's. And we print a new line. And then we go through the same process for two more rows to make a total of three. DAVID MALAN: And it's worth noting it's just an artifact of the font, the fact that the sample output seem so much taller, as though there's more rows than columns. But it's just because the X is taller than it is wide. That's all that's happening there, plus the white space between lines. MARIA: Right. Cool. DAVID MALAN: All right. So a quick look at problem set one, take any questions, and then adjourn? All right. So in problem set one, there's three primary challenges, ultimately. But first, you'll find that the problem set specification, as with many the psets this fall, is going to walk you through a few warm-up exercises, point you out a few resources that you may or may not have seen already. For instance, CS50 has a suite of shorts, which are short videos, not unlike this, but that are very topic specific-- maybe five minutes, 10 minutes in length on loops or on conditions or on algorithms or later on more advanced topics, as well. And we generally embed those into the problem sets so that students have a resource with which to review material that might have already come up in lecture or section. But this way it's more focused and more at their fingertips. We also tend to embed in problem sets things called walkthroughs. So almost all of the examples I do in lecture, on stage here, we also have shot on camera in advance a more slower, a more intimate walkthrough by me on my laptop of that code, line by line so that in class, we'll often skim through something or someone will interject with an answer to a question. But it doesn't necessarily sink in for everyone in the audience. So you'll find code walkthroughs for most of the examples that we do here in lecture so that you can walk through it at your own pace and rewind or fast forward or skip altogether, if you'd like. There's often a few warm-up questions that ask you to sort of reinforce this material and make sure that you're comfy before you proceed with the rest of the pset. And then, of course, there's the pset itself. And one of the things we very deliberately do in CS50 is almost every uninteresting or intellectually uninteresting mechanical step that you might have to do is almost always very well documented. Over the course of the term, we'll start to ask more rhetorical questions like remember how to do this or that? But generally, you'll find that the problem sets get you through the mechanics of something so that the interesting, intellectual challenges are ultimately left to you the student. With that said, Zamyla, to whom we kept referring today in lecture, is one of our longtime staff member who also holds walkthroughs on specific pset problems like mario and greedy, though not water this year. And it's in those walkthroughs that she often offers some tips and tricks for how to proceed, never telling you exactly what to do, but rather-- like a condition, if you will-- giving you at least a couple of ideas so that it's up to you, ultimately, to decide how to approach them. MARIA: Sort of like a high-level understanding of the logic of what we are asking you to do. DAVID MALAN: Exactly. And, in fact, Zamyla's walkthroughs are meant to answer the frequently asked question of where do I began, especially when these long specifications are a little daunting given all the text and imagery that they have in them. So water.c, you'll find after you've completed it, is actually relatively straightforward. Absolutely are a bunch of you going to bang your heads against the wall trying to figure out why it's not compiling or why it's not running correctly. But once you're done with it and once you've spent some time wrestling with any of the bugs that you might have, you'll find that it's a very short program. It can be done in just a few lines of code, most of which we've seen here in lecture already, if you assemble the right building blocks. And as we suggest here, it's going to ask you to specify how many minutes someone is taking a shower on campus. We specify in the problem set the rate of flow of water in, like, a low-flow shower head, much like the Seinfeld clip we saw yesterday or the opposite thereof. And then you just have to do a bit of math, really-- arithmetic using C to tell us how many, roughly, bottles of water is that equivalent to if we're taking an n-minute shower. Now, in mario.c, this is going to be a slightly longer program. It's still not going to be this long. Just a few lines longer than water.c. But it's going to be opportunity to recreate the old school Mario pyramid from Super Mario Brothers or some follow-on. It's not going to look as prettier or as colorful as that one there. We're just going to use little hashtags like we have here on the screen using ASCII text. But it will approximate the same idea. And it's going to be an exercise that at first glance seems pretty simple-- just print a simple pyramid. But there's a couple characteristics here that are interesting. Notice that the rightmost edge of the pyramid actually has width two. So there's two equal height columns, which makes it require a little bit of thought to make sure you get that exactly right, as opposed to just a perfectly angled line. So that's a bit of a corner case but matches the actual game. And it's also non-obvious at first glance how to print the white space. So when I look at the sample output here-- and it's also in the spec-- it kind of looks like a rectangle, but a diagonal of the rectangle has been chopped off, and it's just white spaces, so to speak. And so a frequently asked question here is always, well, how do I move the hashtags over to the right? Or how do I print the blank spaces? And it's actually easier than most students think. Right? You can approximate it visually by just hitting the space bar once or twice or three times. And so even though with printf we almost always print out a string or an int or a word like "hello, world" or series of of words, you can also just print quote, space, unquote. And that will actually give you a white space there. So keep that in mind and don't overthink this. You really have to decide row by row by row, not unlike your example a moment ago, how many of those columns should be white spaces and how many of them should be hashtags. It will take a bit of time, but it's ultimately a logic puzzle of sorts. MARIA: Yeah. But the logic of going row by row is going to be very useful here. DAVID MALAN: Yeah. I think the sample code you gave-- even though it wasn't a complete program. You still need int and main and void and #include stdio.h, a lot of the stuff from lecture. But the building blocks seem to be there. And then lastly is something a little more algorithmic. So it turns out that any time you go into CVS or any convenience store and someone hands you at the cashier bills or coins as change, it turns out that they, humans, whether or not they know it or not, are probably using what's called a greedy algorithm, whereby if you're owed, say, $21 in change because for some reason you bought something very inexpensive with a very big bill at CVS, it would be really annoying if the cashier gave you 21 singles or, worse yet, a whole lot of coins. Rather, what a reasonable person is probably going to do is they're going to grab a $20- and then a $1-bill, and hand you just two bills in that case. MARIA: So they're seeking to minimize the change that they give back to you. DAVID MALAN: Exactly. And same deal with coins, as well. If you're owed, say, $0.50, hopefully you don't want 50 pennies. You instead want two quarters, for instance. Now, this does assume that the cashier has enough of every denomination that he or she might want to give you. But we do allow you to assume as much in the problem. And the goal, ultimately, is to implement in C code a greedy algorithm. So the user is allowed to type in how much change he or she is owed with dollars and cents, some kind of floating point value probably. And then you have to do the math and figure out algorithmically, well, how many coins can I give you minimally to give you exactly that amount of change. But there's going to be a few tricky parts here, right? Like there's the whole imprecision issue. MARIA: Exactly. So floating point values have imprecision. Did we talk about this in lecture today? DAVID MALAN: We did the last time in lecture. We talked about imprecision. And you don't want to cheat the user of how much change he or she is owed. And so the walkthrough, in the problem set specification, give some thought, ultimately, as to how you can mitigate those imprecision errors, potentially. It is avoidable, certainly, for the inputs we're talking about. And, in fact, pennies-- maybe we'll defer to Zamyla, I think, for the tricks there. So ultimately, you'll find a progression of problems this week, the first of which is pretty small, then medium, then a little larger. But all of them use the building blocks from this past week, from this supersection, problem set specification puts you at innumerable resources. But still, if at all struggling, especially among those less comfortable with no prior background, come to office hours on Monday and Tuesday and Wednesday and Thursday. Go to CS50 Discuss via the course's website, via which you can chat with staff and classmates. But ultimately, I think the best advice is just start early. It's not the kind of class that you should be starting psets on Wednesday night, or worse Thursday night. MARIA: My best advice is to have started by Monday. DAVID MALAN: Monday. So if you haven't started already-- no. But even if not Monday, then Tuesday. The earlier the better. And that's the reason the course has so many late days is to give you a bit of a psychological pressure to start earlier but still let things slip when things take longer than you expect. MARIA: And you want to make use of office hours as much as you can, too. DAVID MALAN: Any questions? All right. Well, why don't we adjourn here?