[MUSIC PLAYING] DAVID J. MALAN: All right. This is CS50. This is week one, because of course, last week was week zero. And this is the week where we'll actually start programming in a much more traditional way, that programming language we promised called C. Of course, we started with this. And hopefully by now, with problem set 1, you've had a little bit of fun, even if you've played with it before. And the goals of Scratch, beyond making things feel very accessible and user friendly is really to elucidate some of the fundamental concepts that we'll see again today, and really every week subsequently, like functions and conditionals and loops and variables and so much more. And in fact, among the goals of Scratch is, again, to plant these visuals in your mind. So even as today onward feels all the more like a fire hose, especially when it comes to really weird, cryptic textual syntax, the ideas are still going to be the same. So today, this program, Hello, world, becomes this instead. And in fact, just to color code things temporarily, I dare say that what I've color coded here in orange, which looks probably, to those of you who've never programmed, pretty cryptic is the equivalent of when green flag clicked orange puzzle piece like this. What remains is just one line in purple with a bit of white, which is what ultimately is going to get the screen today to say, Hello, world on the screen. And of course, we had a name for something in purple. In fact, if we rewind to week zero, this block in purple represented what type of functionality? AUDIENCE: [INAUDIBLE]. DAVID J. MALAN: A function itself, an action, a verb that gets the computer to do something. So what looked like this last week is about to look like this. Let's take away the color coding and focus really on what we're going to now start calling source code. So this is what programmers do in the real world. This is what software developers, software engineers do in the real world. They write code that looks like this. And clearly, it's a little English-like, but it's not English in the way you would compose an essay or an email. Clearly, there's some patterns and some special syntax to it that will highlight ultimately today. The problem is, though, that computers, of course, don't understand source code. They only, per last week, understand zeros and ones. That is it, the so-called binary system. So somehow, we've got to get what already looks cryptic into something that looks at a glance even more cryptic, the zeros and ones that computers do understand. And for today's purposes, just know that built into your Macs, PCs and phones, there is a built in understanding of what these patterns mean. Maybe it means a number, maybe it means a letter. But today, maybe it means an instruction, like print something on the screen, or save something, or load something. That is to say, computers use patterns of bits not only to represent all the stuff we talked about last week-- numbers, letters, colors, images, sounds, and all of that, they also use patterns of bits to represent fundamental functionality. Print things, play things, much like those same scratch blocks. But no computer scientist really, unless they take out a paper pencil or write a program or use a website to convert this can read this and know what's going on. That's why we humans are actually going to use not machine code, as it is called, the zeros and ones that computers understand, we are going to start writing source code. And last week you already wrote source code, but in the form of dragging and dropping those puzzle pieces. So this too is going to be the paradigm that sort of guides us through the entire semester. Problem solving programming is really about input becoming output. And we'll focus today then on a certain type of input becoming output. Someone has to get the source code, that's written in a language like C, into the machine code, the zeros and ones that the computer actually understands. So source code today is going to be our input. Machine code is going to be our output. And we're going to give you today a special program called a compiler, whose purpose in life is to translate one to the other. And there's compilers for different languages in the world. We're going to focus on one that supports today's language, known as C. And here, as promised, is the programming environment we are going to use. It's tailored to CS50, which is to say, we've pre-installed certain software that you might find useful during the term. But for all intents and purposes, the tool you will use for CS50 problem sets henceforth is a very popular industry standard tool called Visual Studio Code, or VS Code for short. We are using a cloud based version of it that lives at literally this URL, cs50.dev. You can sign in to that so long as you have a free GitHub account, for which you signed up presumably already. And that will give you access to not only an industry standard programming environment, but again, an environment that has some CS50 specific things pre-installed. And at the end of the semester, or even in the middle, if you so you're so inclined, you can actually download for free VS Code onto your Mac, PC. You can disconnect from the internet and you can actually program on your own computer. Caveat, though, is that you tend to hit technical support headaches in the very beginning of the term, so we suggest you do that later in the term once you're already comfortable with this cloud based environment here. And here it is. This is what programming shall look like, whether we're using C now or Python in a few weeks or JavaScript or SQL thereafter. So here is what looks-- what is VS Code configured as follows. At the top right, you'll generally have one or more tabs for code, much like tabs in a browser. And this is where you'll write code that looks a little something like this. And in fact, this is exactly the code that you saw a moment ago. What VS Code does, among other things, is it actually highlights your code for you. It colorizes it in what's generally an illuminating way. So I did not choose to make this red. I did not choose to make this blue and this purple. The computer sort of automatically does that for you, as we'll soon see to draw your attention to different ideas in the program itself that all happens automatically. At the bottom here, you're going to use a more advanced interface today onward, known as a command line interface in the form of a terminal window. So you can still use your mouse or trackpad and click and drag and do things like that in this environment. But you'll find, and many programmers prefer that it's much more efficient ultimately to use your keyboard more often than the mouse or the trackpad. So we'll introduce you to that text based terminal window there. Up here at top left, you'll have a File Explorer. So what's nice about VS Code is that not only will you have textual commands, with which you'll get comfy, you also have a normal Mac or PC or phone nowadays, like literally files and folders will visually appear to you so you can play with or manipulate them there. And then, lastly, this is sort of like the menu, the so-called activity bar that just has icons for various features, including CS50's duck. So in fact, if you poke around, you'll see ultimately a duck icon when you log in, which is your own CS50 specific chat bot of which you can ask questions throughout the process. So now that we've got VS Code here, let's go ahead and actually consider what it represents. So this is generally, for jargon sake, a graphical user interface, which means buttons and icons and menus and all of that. We all take that for granted on most any device nowadays. That's abbreviated, just so you know, as GUI, G-U-I. But built into VS Code, again, is what's not only the terminal window by name, but conceptually this is a command line interface. So not a graphical user interface, but a command line interface, whereby there aren't icons to click on or double click on. Rather, if you want to run a program, you use the command line interface, or CLI, to type the name of the program that you want to run. And so this will feel like a step backwards initially today, because we all tap and point and double click on things nowadays. But again, it's going to give us more power, more efficiency ultimately beyond this. So with that said, let's go ahead and actually use it for just a moment. During class, you're welcome to follow along. But suffice it to say, we'll generally go somewhat quickly. Really, you're going to learn how to program by way of the problem sets each week. I'll introduce and focus on the concepts, the ideas, the sort of primitives that will get you started, but only through actually doing the problem sets is the muscle memory and practice going to come. So not to worry if it doesn't all go down easily the first time around. So here is the code that I claim is equivalent to last week's Hello, world program. Let's actually go ahead and do this in the programming environment. So I'm going to go ahead and switch over to VS Code itself, which is now running on my Mac here. It's not just a screenshot. And I'm going to go ahead and do the following to get started with programming. I'm going to write literally in my terminal window, the word code, and I might have to give it focus by clicking down in that quadrant of the screen. And then I'm going to give the name of the file that I want to code. And in this case, I'm going to propose that we call it hello.c. In the world of Scratch, when you downloaded it, you might have noticed the files are all called like SB3 or some such file extension. When writing code in C, you literally name the file something dot C by convention. But notice some other details. Especially if I zoom in, everything I've typed thus far is lowercase. There's no spaces. And so this is going to be important. And unfortunately, computers are not forgiving. And odds are one of the first stupid mistakes you'll do is miscapitalize something, misspell something, add too many spaces or the like. Not to worry. In time, that kind of muscle memory will come with practice. So let me zoom out. Let me now just hit Enter and you'll see at top right the Code tab that I promised. So I'm going to go ahead and type out this program pretty quickly, because I've done it before. Include stdio.h, int main void, and then some curly braces, as they're called, and then printf quote unquote. Hello, comma, world, backslash n, close quote, semicolon. All right. So that's a lot. But that too will come in time with practice. But this is the exact same code that we saw just a moment ago. Indeed, if I zoom in, it's color coded just as in the screenshot, and thus I have written my first program. VS Code will automatically save for you, but you can also hit control or Command S to ensure that it's saved. But notice what's happened at top left. Not only do you see my code over here, you see a visual icon, just like on a Mac or PC that, yes, this file now exists in your account. And that too is what you're getting with VS Code for CS50. You're getting your own sort of server in the cloud. It's called a container nowadays. So there's some virtual disk space somewhere in the cloud, ala iCloud or Google Drive, that's going to store all of your files. And at the moment, because I refreshed my account before class, I only have one file in my own account. What's this? What's this? Well, this is like my ID number for GitHub. Not really a big deal. That's just randomly generated by GitHub. Urban Adventure is the name of my programming environment today, otherwise known as a code space. This is just a GitHub thing which is, again, one of these cloud companies. Instead of choosing random letters and numbers to uniquely identify all of our programming environments, it's popular in the tech industry nowadays to just put together random English words that sometimes sound kind of cool. But it's just by coincidence, not something I chose. Yours will be different. All right, so I've written some code. I created hello.c. I typed in all of that code. I confirmed visually at left that it was created. I'm going to hide my File Explorer henceforth, just so that we can focus on the code. How do I actually run this program? Well, on a Mac or a PC, we would be in the habit of like opening the folder and double clicking on it. Or on your phone, you would take it out and tap on an icon. But not here. Here, we're focusing primarily on the command line interface within this whole environment. So I'm actually going to have to introduce a few commands. You saw already the code command, which for our purposes is VS Code specific, that just creates a new file called hello.c in this case. But I need two other commands to actually run this program. The first nicely is called make, and then I specify what program I want to make. And then a little weirdly, I have to type dot slash hello. But just to take a step back, make hello. If this is about to be my second command that I type, what does that step represent, perhaps? Given what I said just a minute or so ago. AUDIENCE: That's going to translate your source code into ones and zeroes. DAVID J. MALAN: Perfect. So make represents the compiler, so to speak, the program that converts source code to machine code. I have to do that for now manually by running make hello. Now, make is kind of smart, and even though I'm saying make hello, not make hello.c, make it smart, and it's going to say, if you want to make a program called hello, I'm going to assume that there is somewhere in this folder a file called hello.c. So you should not type make hello.c. You just type make hello. And then this third command, even more cryptic, what might it do? If this is step three of three. That's going to run the machine code. It's going to tell the computer in this folder, the dot implies this current folder, and dot slash just means something in this current folder. Run the program called Hello. So that's it. Like there's three steps to writing a program in C. You create the file, as with the code command. But there are other ways to do that too. And you don't even have to use VS Code. You can use dozens of other alternative programs in the world. You run the compiler, which, in this case, is called make. Little white lie, make's not actually the compiler, but more on that next week. But make is going to trigger compilation of this code. And the last step three is to execute, or run the program called Hello. So let me go back to VS Code here. And you'll see that my code is still at the top. My terminal window is at the bottom. I hid my File Explorer, just because it's not that interesting anymore. And I'm going to do what you proposed, which was M-A-K-E space hello. All lowercase. Enter. And ironically, thankfully, nothing happened. And that's actually a good thing in this environment. If nothing seems to happen you probably did, good. If anything does seem to happen on the screen, you probably screwed up and you've made some mistake. So seeing nothing is generally a good thing. But what has happened? Well, let me actually go back and open up my File Explorer. And notice, there's not only hello.c, but there's a second file now. Hello, which is the name of the program. So Hello is the program I want to run. I'm going to go back to my terminal here and to run this program, I'm going to do dot slash H-E-L-L-O. I'm going to cross my fingers, as I'll often now do, and voila, my very first program in C. How else can we see this file? Well, down here in my terminal window. Let me zoom in. You keep seeing dollar sign. That has nothing to do with currency. It's just a weird, geeky convention that your prompt at a terminal window, like where you type commands, generally starts with a dollar sign. Sometimes it's a hash symbol. Sometimes it's an angled bracket. It depends on the system you're on. But dollar sign is very common. It just means type your commands here. Well, I've typed code, I've typed make, and I've typed dot slash hello. But I can type other things too. And more on these later. Like ls, which doesn't actually spell something, but is short for list, L-I-S-T. Programmers tend to just be as succinct as they can, so most commands are not full words. They're often abbreviations. If I hit Enter now, you'll see also two things. You'll see hello.c. And you'll see in green, just to draw attention to it, hello as well. The asterisk here just means in the programming environment, this program is executable. Like you can actually run this by doing dot slash hello. The fact that this is just white here, that just means it's some text file. It's in fact source code. So in other words, ls lists the file in my current folder. Or you can use your human eyes in the File Explorer at top left and just look at what files exist. These are one and the same. One is a GUI one, is a CLI. Graphical command line. And so forth. And we'll start to take these kinds of paradigms soon for granted. But let me pause here and see thus far, now that we've written our first of many C programs, any questions? Or confusion we can clear up? It's OK if you don't understand most of the lines of code. That's what today is about. Yeah. AUDIENCE: I don't fully understand the difference between hello and hello.c. DAVID J. MALAN: What's the difference between hello and hello.c? So hello.c is literally my source code. It is a file that exists somewhere in the cloud that contains all of the code I myself wrote. The hello file is the file that the compiler created for me by converting the source code to the machine code. So inside of hello, theoretically, is a whole bunch of zeros and ones. We can't quite see them. But if I do this, let me zoom out. Let me click on hello. And notice that VS Code is going to yell at me. This file-- the file is not displayed in the text editor because it is either binary-- that is zeros and ones-- or uses an unsupported text encoding, whatever that means. If I do open it anyway, but I don't recommend this. Like heed these warnings. You won't see zeros and ones, but you will see sort of nonsense. And this is because VS Code is trying to interpret those zeros and ones incorrectly, as ASCII text, like English text. But it's not. They're instructions for the computer. So as soon as you see scary red stuff like this, like undo, close whatever tab you open, because odds are you can only break the program you just created. It's not a huge deal. You can recreate it. But that's what's inside of those files. Yeah. AUDIENCE: What if [? you don't ?] [INAUDIBLE]? DAVID J. MALAN: Really good question. What if we don't type dot slash hello we, just type hello. Well, let me do this. Let me hide my File Explorer again because it's not that interesting here on out. I'm going to clear my terminal window by hitting Control L, just to be neat and tidy in class. Or you can literally type clear and it will clear it. But again, that's just to keep things tidy. Your TFs might do that in section 2. If I just type Hello, enter. I'm going to get this, weirdly. Bash, hello, command not found. So more on bash down the line. But this just means literally the command hello is not found because you need to tell the computer where it is. So dot slash hello means run the hello program that is, in fact, right here. By contrast, you don't run dot slash for code, for make, or other commands that we'll soon see, like ls, because why? Those are installed in the system for everyone, not just in your individual folder. So that's the difference. Any programs we write, it'll be dot slash something. All right, so let's tease apart what is actually going on here and see if we can lean heavily today on Scratch, especially as the syntax gets weird, perhaps a little overwhelming. Still the same idea. So this last time, of course, was our Scratch program that just said Hello, world. I claim today that this is the nearest equivalent that any programmer can convert Scratch into C. If we color coded it accordingly, indeed, this sort of lines up with when green flag clicked is the orange. And then the purple is just the equivalent of the say block. So the say block, we said earlier, was a function. So let's compare these things side by side because there's actually some rhyme and reason to what MIT did with Scratch, as to why these shapes look like they do and so forth. So in Scratch, there's a function called say. Recall that it takes an input, otherwise known as an argument, or a parameter is another name. And that's always provided in these white ovals, zero or more white ovals. In C, we've already seen, but let's do it a little more pedantically, the equivalent say is essentially the word print. Why did MIT say you say? Just because it's a little more kid friendly. But print is the idea in our environment. It's actually not print, it's printf, because we're going to be able to format our text in interesting ways. More on that in a moment. But notice, the opening parentheses and closing parentheses here conjure up the idea of that white oval. So that's kind of intentional on MIT's part. What, though, in C goes between these parentheses? Well, literally the input or the argument you want to pass to the function, like Hello, world. But in C, you have to be a little more pedantic because you don't have a nice little graphic like this purple block with the white oval. You have to surround everything in double quotes. Those of you with prior programming experience, in C, you need double quotes, not single quotes in this context. And then there's this arcane detail here, backslash n, which we'll come back to in just a moment. But that's essentially what's going on, line by line from Scratch to C, there's kind of an equality between those two, even though, of course, look a little bit different. Well, let's see what that backslash n is doing, just to highlight some details here. So let me actually zoom in a little bit here and let me go up to my code. And let me just recklessly delete the backslash n. I'm going to let it auto save. I'll zoom out. In my terminal window now, I'm going to run make hello to recompile the code from source code to machine code, because I changed the source code. Nothing seems to happen. That's good. Now I'm going to type dot slash hello, enter. And there's a subtle bug. Since I made that change. What looks wrong to your eye now? AUDIENCE: The dollar sign [INAUDIBLE]. DAVID J. MALAN: Yeah, the dollar sign, our so-called prompt is at the end of the line instead of on its new line. I mean, this isn't really a deal breaker. Like the code works, and you can still type a new command. But it just looks a little stupid. Like this was not the intent of the program. It's sort of good practice to move the prompt to the next line, and that's because the backslash n is what we're going to call an escape sequence. So it turns out in programming, you have to tell the computer exactly what you want it to do. So if you want a new line, the equivalent of hitting Enter on the screen, you have to tell the computer to put a new line there. What you do not do is this. If I zoom out and I go into my code here, and I'll zoom in on the code-- if you want to put a new line, you don't do this. Why? It's just confusing for the computer. Like, wait a minute, is that a typo? Did your lines just wrap. Do you want to put a new line there. It just looks stupid. And it makes it less line based, the code itself. So humans decided years ago, if you want an actual line break, don't just naively hit the Enter key. Literally tell the computer, put a new line here. If you want to move two lines down, just do two of those. If you want three, just do three of those. Well, why the backslash? Again, these are what are called escape sequences. And you don't literally want an n, let alone [? an ?] n n. What you want is a new line, which is represented in code as simply backslash n. Now, for the mathematicians among you, what we're doing now by writing, using functions like printf is just sort of like f of x notation, if you recall that from high school or prior, where f is a function, x is an argument or an input thereto, and we're using parentheses in code, just like mathematicians would, to write functions like these. And the types of functions we're using right now still follow this model. You've got input, you want output. In this case, the input to printf, for instance, just like the say block, is what's called an argument. The output, though, of the function printf is what we call a side effect. And the easiest way to think about that is a side effect is just something that sort of happens on the screen, visually, [? audibly. ?] It just sort of happens. And there's that effect on the screen. And we'll contrast this with other types of outputs from functions. But for now, we're focusing on just this, which is reminiscent, of course, of what we did last week, which is if you type Hello, world into the white oval, use the say puzzle piece, you get out the side effect of the cat appearing to have said hello, world. Now, as for those escape sequences in C, there's bunches of them, but very few of them will we actually use in practice. Backslash n is a new line. Backslash r is a little more subtle and it's kind of a feature of yesteryear. It moves the cursor not to the new line, but to the beginning of the line. Kind of like an old timey typewriter, if you've seen how those work. Sometimes, though, you might want to print out an actual double quote. But there's a problem, of course. If this is my code here, and I'm already using double quotes as sort of special symbols to surround the text, I want printf to say it would probably be a little-- like if you wanted to say hello, world, with sort of finger quotes, why might this not be a good idea? If you think about this from the computer's perspective. Why is this probably not the right way to do this? Yeah? AUDIENCE: [INAUDIBLE]. DAVID J. MALAN: Exactly. The computer is indeed going to read your code top to bottom, left to right. And when it sees the first open quote, OK, that's fine. It understands that. But when it gets to the second quote, it's going to assume, oh, wait a minute. Maybe you only want me to say hello comma, and then it's going to keep reading and be like, wait a minute, why is there the word world here. And then wait a minute, now there's two more quotes. It's just confusing. It's ambiguous. And computers need you to be, again, very precise. So if you want a quotation mark to literally be displayed on the screen, you would escape it, so to speak, which looks a little weird and takes some getting into the habit of. But this just solves that kind of problem. And similarly, might you use single quotes in other contexts? More on that soon. And if you really want to bend your mind, how do you actually print a literal backslash, if you ever care to? It's not that common a character to type, but if you ever want it on the screen, it seems that we're using backslash as a special character that says, hey, give me a new line or give me a carriage return or give me a double quote. Weirdly, in programming, if you want to type a literal backslash on the screen, you literally do backslash backslash. But that's it for sort of weirdness for now. But this is to say, humans tripped over these same problems years ago. They came up with solutions, and now we indeed have these conventions in code. All right. So let's tease apart some other features of this in every program we're going to write, namely what's at the top of this file. So at the very top of this file, there is this cryptic looking hash include, or pound include standard io.h in angle bracket. So this is a little weird. We'll talk more about this next week, too. But this is what's called a header file. Any file that ends in dot h is not a source-- well, any file that ends in dot h is what we're going to call a header file. And inside of that header file is functionality that maybe came with the system, came with the programming language itself. So for instance, I'm going to do this. I'm going to go back to my code here and I'm going to make a very common mistake that you yourselves might make in the coming days, where I just forget that line because I don't even understand it in the first place so I certainly didn't think to type it here. Now, if I go back to my terminal window after clearing it and I run make hello, because I want to recompile it because I've changed the source code, I'm going to see a fairly cryptic error. I mean, there's more error on the green than there is code up here, but you'll get the hang of reading it to try to figure out what's going on. And I'm seeing this. Hello.c, line 3, character 5. So that just means line 3, colon, character 5. From left to right, it's sort of a visual cue as to where the problem is. Call to undeclared library function printf with type dot dot dot. And then the rest kind of overwhelms me visually at this point. But that's a hint. If you do not include that header file at the top of the code you've written, you do not have access to what's generally called a library. A library is a collection of code that someone else wrote for you. Maybe it was MIT, maybe it was the authors of the C language itself years ago. Maybe it was CS50 if we wrote some code for you. A library is a collection of code that someone else wrote for you and you access it, again, by including header files that those same people wrote for you. So if I go back to my code now-- let me clear my terminal window just to be less overwhelmed. Let me undo what I just did and put that file back. Can you perhaps infer, just functionally, what is inside of standard io.h that, again, someone else wrote? What must be inside? Printf. So whoever invented printf decades ago probably put that code in this file. And so by including it, so to speak, in my code, I now have access to printf functionality. So that's all. And again, C is lower level than scratch. It's obviously text based, which means you have to be a little more pedantic yourself as to what you want the computer to do for you. And if you want to use someone else's code, you indeed have to include it. Scratch didn't bother with this, but we indeed do need to do this in the context of C. As an aside, just to preempt some unnecessary headaches, this word is not studio.h. Every year, a non-zero number of people can't understand why their code is not working because studio.h is not found. It's standard io, stdio.h. That's one of the first frequently made mistakes otherwise. All right, so remember that. Let me undo now the unnecessary quotes I added here. And let me propose that we show you where you can learn more. So all of these libraries generally are documented. People wrote instructions for how to use them. So you don't just have to listen and pay attention only in class. You don't have to pull up a book. There tends to be online documentation as well. For instance, for the standard I/O header file. And the documentation in the world of programming for C specifically are called manual pages or man pages for short. Unfortunately, they're really written decades ago for the more comfortable among you, those who have an eye already for programming. And so what CS50 has done at this URL, manual.cs50.io, is we essentially have more user friendly versions of the documentation for this header file and others. So for instance, if I pull up manual.cs50.io, you'll see a web page like this. And if I just scroll quickly, you'll see a whole bunch of header files, .h files, and a whole bunch of functions beneath them. And there's only a couple of dozen or so here. And indeed, per this checkbox at the top frequently used in CS50, we have highlighted the functions that odds are over the next month and a half like you will probably want to use. If I turn off that less comfortable mode, there's actually hundreds of functions that come with C. And like no programmer knows all of these functions. What they do is they read the manual when they want to find some new piece of functionality. So I'm going to simplify this. I'm going to scroll down, though, to stdio.h, for instance here, and you'll see more functions that we'll eventually get to. But if I click on printf, you'll see hopefully some fairly user friendly instructions for how this thing works. For instance, under synopsis, you'll see that we tell you what header file you should include in order to use it. Below that is something called a prototype. More on that later. But below that is a description. And here is where the CS50 staff have written in layperson's terms explanations of how this function works, how to use it, and so forth. But if you'd rather see what the real world uses, you can turn off that mode and you'll see much more arcanely the original language. So in short, these are sort of training wheels that you can turn on and off at your leisure. But ultimately, this is real world documentation as well. So if we want to see something else, for instance, let me go back to the main menu. And as we'll see today, there are actually functions in a header file called cs50.h that for a few weeks, we're going to lean on heavily. Long story short, it's actually kind of hard. It's annoying in C to get user input, ironically, to get the human to type in a word or a number. You have to jump through some technical hoops to make that happen. And we'll show you how to do it like the real way in a few weeks. But for now, among the first training wheels is a CS50 library code that we wrote that will just make your life easier. And indeed, we're going to give you access to functions that simplify the process of actually getting input from the user. So case in point, we're going to give you access to functions like get_string, when you want to get a string of text from the user-- a string is just text. So if you want to get one character, one word, one sentence, one paragraph, you can call a function called get_string. We're going to give you another one called get_int. When you want to get an integer from the user, like 1 or 0 or negative 1 or anything else, you can use that function as well. And we'll see today too there's other functions you can use from CS50's library. In a weeks' time, we'll take these away once you don't need them anymore. And you'll see what those library functions have been doing all along for you. But for now, let's focus on this. Perhaps the most useful of them, get_string, and solve a problem that we did already pretty easily in Scratch. So recall in Scratch, this was a program that used two functions. Three, in fact. Ask, to ask a question of the user. Say, to actually display something on the screen. And join, to combine the default of apple, banana. Or in this case, Hello, and whatever the human's answer was. So this made our Hello program a little more interactive last time. How can we actually translate this into a similar paradigm now? So input and output is the story, as always. In this case, we have arguments going into those functions. But now we're going to introduce not side effects, which is stuff that happens visually. We're going to revisit that blue circle called answer, or the blue oval called answer, that represented last week what we called a return value. And this is what many functions will actually do for us. They're not just going to display something presumptuously on the screen or play a sound or a video or something like that. They're going to hand you back virtually a value-- text or integers or sounds or images that you can then do with what you see fit. So the paradigm we'll now have is much like in Scratch. If the input is what's your name and the function is ask, and you get back a return value of answer, we want to actually do this now in C. So side by side, what code like this in Scratch is going to look like today onward is this. Instead of using the Ask block, you literally use CS50's function called get_string. It takes input. So we put the parentheses on the left and the right to conjure the idea of this white oval. Inside of that string, you can put a prompt, so to speak, like, what do you want the human to be asked, in this case. And I'm missing something still. Per the placeholders here, what's missing? So quotation marks, so literally quotation marks on the left and the right. And I'm going to be a little anal here. I'm going to put a space at the end. Because I don't want to-- I could, but I don't want the cursor to go to the next line. Hence, no backslash n. If I want the cursor just to sit there kind of blinking, waiting for the user after the question mark, I'm just going to put a space. So it will stay there for me. But this is just an aesthetic detail using the same idea as before. So that is the analog of this block. But how do I get access to the so-called return value? MIT just plopped it on the screen for us automatically. In C, we have to write a little more code to get access to that return value. And the way we do this is on the left hand side of this line of code, we come up with a name for the return value. You can call it anything you want. But answer is a nice equivalent to what MIT did. You could more generically call it x or y or z. But that's not really useful. And so computer scientists, unlike mathematicians, will tend to use variables that are a little more verbose, like the word "answer." But in C, it's, again, a little lower level. You have to tell the computer what type of variable this is going to be. So I'm kind of conflating "variable" and "return value," but they're being used in an intertwined way. The get_string function, just like the ask block, returns a value. If you want to do something with it, you need to put it in something called a variable, which is denoted in text here. But again, per last week, the computer doesn't know if it's looking at numbers or characters or images or sounds. You have to tell it, as the programmer, that the zeros and ones that are somehow involved here underneath the computer's hood are, in fact, to be treated as text, a.k.a. string. Now, there's one stupid subtlety still missing from this line of code. Does anyone know, especially if you've programmed-- OK, all of you have program before. Yes? AUDIENCE: Semicolon. DAVID J. MALAN: Semicolon. So one of the headaches of C and a lot of languages is you actually have to finish your thought explicitly so the computer knows that that line of code is done. And it's not a period, like in English. It's, in fact, a semicolon. Now, you don't use these everywhere. We'll see where you use them. But that, too, is a very common mistake, to overlook something simple. But again, in the coming weeks, even though this might look very cryptic, with muscle memory and practice, you'll start to see these things instantly, even if, for a few days, you sort of bang your head against the screen, so to speak, not seeing what the TFs and I much more readily see. So let's go ahead and do this. Let me go back over to VS Code here. Let me zoom in just a little bit. And let me go ahead and do this. I'm going to get rid of my single use of printf. And I'm going to say the exact same thing-- string answer equals get string, quote, unquote, "What's your name?" question mark, space, closed quote, semicolon. And now I want to print out that answer. Well, let me do this incorrectly, deliberately, for the moment. Let me just say printf, quote, unquote, "hello, answer," if I want to plug in "answer" and I want to add a new line at the end, semicolon. So let me try this. But there's multiple mistakes now in my code. Let's trip over them deliberately. Let me go down to my terminal window by clicking at the bottom of the screen. Let me run "make hello" again. Enter. And, oh, my god, there's even more errors now than there were before, but not a problem. Let me click on this little triangle here, which is just going to zoom in on the terminal window. So it takes up my full screen. And just generally, all you have to do is find a few keywords visually that give you a clue as to what's going on. Or, as before, you can always ask the CS50 Duck. So here's the command I ran, "make hello." Somehow that induced all of these errors. Always read them top to bottom, not bottom up. So from top to bottom, there's a problem on line 5, character 5-- use of undeclared identifier string. Did I mean standard in? No, no, no, I didn't there. And then, also, two errors generated. Too many errors [? are made. ?] What did I do wrong? Well, it turns out what I do need to do at the top of this file-- let me click the triangle to zoom back out-- if I want to use the get_string function to get a string, I actually need to include another header file, which is probably called "include cs50.h." Technically, any order is fine. I tend to alphabetize because I just know, therefore, where to look alphabetically for a certain header file. Now that that's in place, let me again run "make hello." Enter. And now we're back in business. No error message. So even though you might have more errors than you have code, odds are it's just the computer is confused. And it could be something simple and an easy fix like that. So just to be clear, standard io.h, because I'm including it, I can use printf. cs50.h, I can use get_string because the people who invented C and the people who invented CS50 wrote those two files, so to speak, respectively. All right, unfortunately, even though the program compiles, that doesn't mean it's correct. It just means it's syntactically valid. It's valid C code. If I go ahead and run "./hello" and hit Enter now, I'm going to be prompted for my name. So I'll type it-- D-A-V-I-D. And notice there's a space to the right of the question mark, as promised. Enter. But it just says "hello, answer," which, of course, is not the intent. I want it to say "hello, David." So how can we do this? Well, in Scratch, it took a couple of puzzle pieces. But it was pretty straightforward. If I wanted to say the combination of two phrases, "hello" and something else, I joined those two and then passed that output to the input of say. In C, it's going to be a little different here just because it's an old language and this is how it's done. Still use printf because that's the same thing as say. I got my parentheses. I got my semicolon. Good to go. But inside of that, this is where printf is different. If you want to say something followed by something else, in the world of C, you tend to use placeholders. So you don't just join things together as we will do in Python and other languages. You say to the compiler, give me the word "hello," comma, and then something else. And the percent s means, put another string here. It's sort of like leaving a placeholder in your code or a template where you'll actually plug in some values. Now, if this is what I want to display, I still use my quotes, as before. And I might, in fact, have a backslash n if I want to move the cursor to the next line. But this is where printf is a little different. Unlike say, which took one input, printf is kind of like join. It can take two or more inputs if you so choose. You just have to separate them with a comma. So much like the join block has two ovals here that are initially white-- apple and banana-- until we dragged and dropped answer on top of it, printf-- and really any function in C-- if you want to pass in multiple inputs, that's fine if they're supported. Just separate them with commas. There's no multiple parentheses. There's no multiple ovals. Just separate them with commas. And now notice a potential point of confusion. What's different about this comma and this one, just instinctively? Sort of minor detail, but important. Yeah? AUDIENCE: Inside and outside. DAVID J. MALAN: So one is inside, one is outside. So the one that's inside the quotes is literally the English grammatical comma that you want the human to see. The one out here is a C thing that's separating the first input to this function printf from the second. Strictly speaking, you don't need a space there. But it's a good practice, stylistically, to separate your arguments with single spaces, just as I've done there. So let me go ahead and now do something with this. Let me go back to my C code here. I'm going to clear my terminal window just to get rid of that distraction. And now I'm going to change answer to percent s. And then outside of the double quotes on line 7, I'm going to do comma "answer." And then, after it auto-saves, I'm going to go back to my terminal window. And just to make another deliberate mistake, "./hello." Enter. "What's your name? David." Enter. It's still broken. But why? I still have to recompile it. So again, you just get into the habit, when you change your code, you have to recompile so you get new machine code in the file "hello." So let's do it again. "make hello." No errors is good. "./hello." Enter. "What's your name?" again. D-A-V-I-D. And now, "hello, David." So again, a lot of this is still cryptic. But it's going to start to follow patterns like this. Functions like in math class, f of x, are written function name, parentheses, input, comma, input, comma, input, however many you have. They're going to follow these patterns. But notice, too, on lines 6 and 7, I have finished each of my thoughts with a semicolon. So what are the other commands that you can run in your terminal window besides something like ls? Well, it turns out there's a whole bunch of them. ls, of course, was simply short for list, which shows you the files in your current folder. But there's also cd for change directory, which is the command equivalent of double-clicking on a folder to open it up in a graphical environment. There's cp, which is short for copy, which allows you to make a copy of a file or folder. There's make dir, "mkdir," which is short for make directory, which is how you could make a new folder. There's mv, which is short for move, which would allow you to move one file or folder from one place to another or simply rename one of those to a different name. There's rm, which is short for remove. And there's "rmdir," which is short for remove directory. So, in fact, let's play around with a couple of these. Let me go back to VS Code here. Let me go ahead and open up my File Explorer. And recall that at this point I've got two files, hello.c, which contains my source code, and then hello, which contains my machine code, the executable program that I previously generated by running make. Well, let me go ahead and propose that I'd like to prepare to keep all of my files and folders very orderly. So for every program I write or for every problem on a problem set I write, maybe I want to store my relevant files in a specific folder for that problem. So suppose then that I want to put hello.c in a folder, otherwise known as a directory, called hello. Well, I can't do that quite yet because I already have a program called hello. So let me use one of those new commands. rm space hello will delete or remove hello from my current directory. So I'm going to hit Enter. I'm going to be prompted to confirm with y for yes or n for no. "Remove regular file 'hello'?" I'm going to hit y and enter. And as I hit Enter, watch the top left of my screen as the hello file would seem to disappear. Voila, it's now gone. So now I'm going to go ahead and use a different command. Let me go ahead and do mkdir for make directory. I'm going to call the directory itself hello. And watch again, at top left, what happens. Enter. Now I have not a file but a folder called hello. And in this GUI, the fact that it's a folder is indicated, one, by its icon and, two, by that little right-facing triangle, which means I can expand it to see what's inside. And in fact, if I do that, I'll see, of course, that nothing's in it because we literally just created it. All right, well, what if I want to move hello.c into the new hello folder? Well, I could, just like on macOS or Windows. I could, actually in my File Explorer, click and drag one into the other. But let's do this entirely within the terminal window. So let me do this. Let me move, or mv for short, my file called hello.c into a new destination folder, hello. And I can, optionally, put at slash the end of "hello" just to make super clear that it's a directory. But that's not strictly necessary. But if I say mv hello.c hello, with spaces in between, assuming hello exists as a folder, watch what happens at top left now. It's a little more subtle, but hello.c is going to move inside of the hello folder right now. And indeed, it's only slightly more indented. But notice if I collapse the hello folder, notice that it seems to be gone because hello.c is now inside of that folder. Of course, if I expand that, I'll see it again. If I go back to my terminal window and type ls for list, now I don't see hello.c. And I don't see an executable program anymore. But I do see hello. And the slash there just makes super clear to me, the user, that it's indeed a folder. So how do I change into that folder? Well, I can obviously use the graphical interface at left and click and expand and see what's going on. But there's no direct connection between the File Explorer at top left and my terminal window at bottom right. Rather, those are just two different ways to explore the underlying system. So if I want to change my terminal window into this new directory, I can do cd for change directory, hello, and then Enter. And now notice my terminal window's prompt changes slightly. There's still a dollar sign, which indicates, type my commands here. But before that dollar sign, just so that I have a reminder, sort of breadcrumbs that visually remind me what folder I am now in, I see that I'm inside of hello. If I now type ls, I should see the file I expect to be in there, which is indeed hello.c. Now, suppose I want to try out some of those other commands. And suppose I want to maybe rename this file. I really want this file to be called something else. So maybe I might do something like this, mv hello.c space, and now a new name for the file. Well, maybe I want to make-- say this is an old version of my code, because I want to just start fresh with something new. So I could do something like this, mv hello.c old.c. And watch what happens at top left. hello.c, of course, gets renamed via the move command. So I can use move to move a file into a folder. Or I can use it to rename a file or folder, as I've just done here. Now, suppose I want to undo that. Well, I can't just type undo. I can't just hit Control C. But I can do the opposite, in effect. mv old.c hello.c will now, per top left, change it back into that file. If I want to make a copy of this file, maybe as an actual backup because I'm really happy with this version and I'm worried about breaking it, well, I could do cp for short. I can then do hello.c. And then I can do something like backup.c, or any other file name. I'm taking care to use the same file extension so that if I do open this file later, it still opens and gets highlighted and colorized in the same way. But watch what happens now at top left. When I type Enter, I now have two files in this hello folder. And indeed, if I type ls now, I can see exactly the same. So long story short, there's this whole list of commands, and even more than these, that allow you to manipulate the underlying system in exactly the same way that you and I have probably done for years by using a mouse and pointing and clicking and double-clicking. But for now, let's undo all of this because I haven't really written that many programs today. And I'm going to keep things simple today and keep everything in my same folder. So let's undo all of this. Let me go ahead and now remove backup.c because I don't particularly care about that. I'm going to be prompted to confirm as much. Then let me go ahead and move hello.c out of this folder and into the original folder. And, conceptually, the original folder is what we would call the parent folder, the folder that contains this hello folder. And the way you can specify the parent folder, like back up from whence you came, is with dot dot. So a single dot, as we've actually seen "./hello", "./a.out" means execute a program in this directory, dot. But dot dot refers to your parent directory. So watch what happens at top left when I move this hello.c file out of this folder. It shifts a little bit to the left to indicate that it's no longer in that folder. I'm going to go ahead and type cd dot dot, which will bring me back to my parent folder. Or, even more useful, especially if you get confused or lost somewhere within your folders, you can actually just type cd and nothing, and that will whisk you back to that original folder no matter where you are. So it's a nice shortcut. And it's a nice way of undoing any confusion you might have caused for yourself. Lastly, let's go ahead and get rid of the hello directory with rmdir hello, Enter. And that now disappears at top left, as well. Now, what I was hinting at here whereby I had my hello.c file in a folder and I was moving things around and renaming things and backing things up isn't strictly necessary because there's actually other features still inside of VS Code that you're welcome and encouraged to play around with. In fact, if I go to my so-called timeline at the bottom of my File Explorer here, you can actually see that there's been automatic backups made over time of this file. So if you click, click, click through those backups, you can actually see different versions of this same file slightly in the past, which might save you the trouble of having to manually create files. And in fact, in the world of software development and industry, there's actually standard tools, very similar in spirit to what we've been using GitHub for, that allow you manually to make different versions of your code so that you can proactively keep track of all the changes you've made without manually renaming things as you might typically on your own Mac or PC. All right, let me clear my terminal window and ask if there are any questions. Yes, over here. AUDIENCE: What if you had a type other than [INAUDIBLE]? DAVID J. MALAN: Yeah, really good question. If we had something other than a string of text, if we had an integer, would you still use percent s? No, you would use something else. And, indeed, percent i is what we're going to use. And we're going to actually do that-- perfect segue-- to other types that C actually has. So up until now, we've been calling a string of text literally a string. And this is common in many programming languages, including Python and JavaScript. "Strings" in the programming world just mean text, whether it's zero or more characters thereof. But C does have other data types, just a few of which we'll dabble with today but you'll use more over time. We've already seen string, for instance, which is indeed a string of text. But let's focus, as well, on an integer. As an aside, there's other types, too. There's Boolean values, like true or false. There's chars, which are single characters instead of full phrases or sentences. There's doubles and floats, which are real numbers, something with a decimal point, the equivalent of fractions. And there's longs, which are integers but longer integers, even bigger integers than you might type by default. So let's focus on an int because so many computer programs of course manipulate numbers in some way. So what can we do with this? Well, if we want to be able to get an integer, lucky enough, CS50's library comes not just with get_string but also get_int. So that's going to be a third function we now use in C. And we need to know what are generally called format codes. So that placeholder I called before, percent s, is indeed for a string. If we want to place an integer inside of something we're printing to the screen, we are, in fact, going to use percent i instead. So let's now actually use these building blocks, get_int and percent i to actually get numbers in some way to solve a problem. Well, what problem could we solve? Let's introduce another concept from scratch and programming more generally known as conditionals, like those proverbial forks in the road. If something is true, do this. Else, maybe do this other thing. So in Scratch, we might have had a set of puzzle pieces that looked like this. If x is less than y, then say, or have the cat say, x is less than y. So sort of stupid program. But it just demonstrates how we have two variables, x and y. In the context of Scratch, we're comparing them with a Boolean expression. We're using a conditional to then conditionally say or not say this phrase here, depending on whether this question has an answer of true or false, yes or no. In C, it doesn't look all that different. It's a little more cryptic. But you say literally "if." You use parentheses, similar to functions. But confusingly, by convention, you put a space after the word "if." So you don't put spaces after function names. You do put spaces after words like "if." And you use the parentheses to conjure up this weird trapezoidal-like shape. So there's no real keys that conjure that. So C uses parentheses, like most languages. And then there's these weird curly braces, which, at least in English, we don't use all that often. But they're there on your keyboard, English or otherwise. And they essentially allow us to create this hugging shape to the puzzle piece. Anything inside of those curly braces is going to be equivalent to anything inside of this yellow hug that's sort of grabbing one or more pieces inside. So what do we put inside? Well, this part is straightforward-- printf, quote, unquote, "x is less than y" backslash n semicolon. So nothing new here. The only bit of new code is this if construct instead. What if you have an if-else, so a two-way fork in the road? This is what that looked like in Scratch. Same question-- if x is less than y, then say x is less than y. Else, say x is not less than y. In C, the code is going to be set up initially like this, so two sets of curly braces to represent this pair of yellow bars and this pair of yellow bars. And what's inside of them-- indented, no less, just like our pseudocode last week-- is two printfs-- x is less than y, x is not less than y. So that's it. So the only new stuff here really is now the else keyword, which does not need parentheses because you're just saying, else, do this other thing. But what if it's a three-way fork in the road? And we'll stop after that. Here's a three-way fork in the road in Scratch. If x is less than y, then say this. Else, if x is greater than y, say this. Else, if x equals y, then say this. So this is a little more precise because now we're handling equality, not just greater than or the opposite. In C, it's going to look similar to before. But we're adding this element here. And at first glance, especially if you've never programmed before, it looks like I'm an idiot and I made a typo. What looks wrong? There's two equal signs-- not a typo. So it turns out, recall from earlier, when we use the equal sign the first time around, we used it in the context of getting a return value back from a function, like the get_string function handed me back the user's answer. So unfortunately, because humans decades ago decided, hey, let's use the equal sign to assign a return value from the right-hand side of a line of code to the left-hand side, we sort of painted ourselves into a corner and like, oh, shoot, what do we do when we actually want to test for equality of two values on the left and right? So what most languages, including C, do, is use double equal signs. So you say double equals or equals equals or whatever. But it is, in fact, syntactically correct. What's inside of these three sets of curly braces? Same idea-- printf, printf, printf based on what English phrase you want to print out. So this code, both in Scratch and C, I'll claim is correct. It won't run because we still need the other stuff, the equivalent of the when green, flag clicked. But out of context, this code is correct. But there's a subtle weakness in design. And we'll talk a lot about this this week and beyond. "Correctness" just means the code does what it's supposed to do. Design is more subjective. How well have you written your argument in an English paper, how well have you written your code, is design. This code is not designed as well as it could be because I'm doing more work than I need to. Yeah, in the back. AUDIENCE: You don't need the [INAUDIBLE]. DAVID J. MALAN: Yeah, I don't need the x equals equals y. But why, logically? AUDIENCE: Because [INAUDIBLE] [? there's no need. ?] [INAUDIBLE]. DAVID J. MALAN: Exactly, that's just a math thing. Either x is less than y, or it's greater than y. Or the third and final option is they must be equal. So it's subtle, but why would you bother wasting time writing a line of code and expecting the computer to run a line of code that is just going to answer a question that logically you could have concluded already? Because if x is not less than y and x is not greater than y, then, my god, just print out x is equal to y because you know, at that point, logically it's true. You don't need to waste your time or the computer's asking a third question unnecessarily. In reality, it's not a huge deal. No one's going to notice in the real world on a Mac or PC that there's this extra line of code. But it's a bad habit. Keep it simple. Don't write code that doesn't need to be there if, logically, you can conclude otherwise. So in fact, let's clean this up both in Scratch and in C. I can tighten this up, so to speak, use less code here, less code here. And honestly, if only statistically, the less code I write, the less likely I am going to make mistakes. So that, too, is probably a net positive overall. Writing less code is generally better than writing more code, not unlike English essays too, perhaps. All right, questions about this feature of C, conditionals and this syntax? Yeah? AUDIENCE: [INAUDIBLE] DAVID J. MALAN: Oh, a really good question. And, yes, jumping the gun. There are alternative ways to solve problems like these. And the question was, to summarize, when to use "if, else, if, else" versus what's called a switch statement. More on those another time. But this is going to be true, in general, in programming, not just C, not just in Scratch, but every language. There are going to be several, dozens, hundreds, an infinite number of ways to solve problems. Among the things we're going to teach you, though, is indeed how to do things well or better than you might otherwise. And we're going to introduce you eventually to another feature of the language that can even simplify this code, too. So for now, let's actually use this then. So let me go over to VS Code again. I'm going to go ahead now and clear my terminal window down here. I'm going to go ahead and close the hello.c tab just so that it-- we're going to create a new program. And let's just do something a little simple using some operator, so to speak. And I haven't used this word by name. But it turns out that there's lots of operators that come with C, just like a lot of operators that came with Scratch, for doing assignment or less than or less than or equal to, greater than, greater than or equal to, actually equal to, not equal to. Now, some of these are a little cryptic. But there's no easily-found key on your US English keyboard, at least, where you can do less than or equals or greater than or equals. So what most programming languages do is you don't use a special symbol where there's an angled bracket and then a line below it. You actually just use two characters. So greater than or equal is literally this, this. Less than or equal is literally this, this. We already saw that equals is this, this. And not equals is to use an exclamation point. So this, too, is a thing in programming. Using the exclamation point, pronounced bang, is how you invert, logically, certain things. So "bang equals" or "not equals" is how you would express exactly that idea. It's just a symbol on the keyboard that some human decided, let's use this one to invert the idea. But we're going to need one other thing for this program, specifically variables, which we've used already because, in Scratch, we got one for free. We had that answer variable that stored the return value of the ask block. But let's consider, in general, how you can-- and probably did for problem set 0-- use a variable of your own, like keeping track of a counter or a score or the like. In Scratch, if you want to create a variable called counter, you can set it equal to some initial value, like 0. In C, that code is going to look similar. You literally just write whatever name you want to give the variable, then an equal sign, and then the value you want to give that variable. And because the equal sign is the assignment operator, it will behave essentially right to left and copy the 0 into counter. But this isn't enough for C. Remember that you, the programmer, have to tell the computer, is this indeed a number? Is it a letter? Is it an image? Is it a sound? You have to tell the computer that this is an integer, otherwise written as "int" for short in C. But there's one other stupid detail that's missing, which is now-- semicolon to finish the thought here. But this then is equivalent to this in Scratch. Let's do another. In Scratch, if you wanted to increment the counter, that is add 1 to it, you could literally use this puzzle piece here and specify you want to add 1. In C, it's going to look like this-- counter equals counter plus 1 semicolon. Now, at a glance, this seems like a paradox of sorts. How can counter equal counter plus 1? I can't make that math expression true. But it's not math in this case. The single equal sign is assignment. So this means take the current value of counter, whatever it is, add 1 to it, and then copy that value from right to left into the same variable, thereby changing it from 1 to 2, 2 to 3, and so forth. This, though, is so common in programming, to be able to increment or even decrement numbers by one or two or more, is that you can tighten it like this. This is the exact same thing-- a little faster to type, saves you keystrokes, maybe less chance for error. Counter plus equals 1 semicolon is the exact same idea. Better still, this is so common in C and C++ and Java that there's a third way to do this, to my comment earlier about solving problems in different ways. The most canonical, the most popular way is probably just to say counter++ semicolon, which literally, automatically, adds 1 to that value. It only works for 1. If you want to do 2 or 3 or some other increment, you have to use one of the other approaches. But this simply does the same thing as this. And if you want to invert it to negative 1, you change the plus plus to a minus minus instead. So again, just little things that we'll see and pick up over time. Invariably, you'll have to look them up or check the notes or look back at the lecture slides. But in time, this will get familiar if you are not already familiar. So let's consider just logically how we might implement this in code. Let's go back to VS Code here. And let me propose that we create a program called compare.c whose purpose in life is just to compare a couple of values. I'm going to go ahead and proactively, based on the previous chat, include CS50's library from the get go. I'm going to include standard io.h from the get go. So I can use get_int and printf respectively. I'm going to just, on faith, type int main(void). And today, we won't explain what that does. More on that to come. For now, just assume it's like, when green, flag clicked. But in this program, let's do a couple of things. Let's declare an integer called x and assign it the return value of get_int. And let's just keep it simple. Let's ask the user not what's their name, but "What's x?," question mark, semicolon. Now, so that we have something to compare, let's do it again but with y. int y equals get_int, quote, unquote, "What's y?", question mark. And I'm leaving again a space just visually so the cursor nudges over a bit, followed by a semicolon. At this point in the story, my users will be prompted for x and y respectively. Let's do something with those values. How about if x is less than y, then go ahead and print out, quote, unquote, "x is less than y" backslash n, close quote, semicolon. All right, and let me hide my terminal window for just a moment. This is a 13-line program at the moment. But really, it's five or six interesting lines. The rest has been copy/paste from previous programs. Notice a few details. One, I've indeed used my curly braces here. And notice, if you highlight lines, you'll actually see little dots that can help you make sure, oh, there are indeed four spaces there. I've been indenting just like we did last week with pseudocode. Strictly speaking, it's not necessary. But it's going to be way easier to read your code if you do at all of this whitespace, so to speak, than if you write and then submit to us, as homework, a program that looks sort of godawful like this, which is going to make it much, much harder for the human to read it, for you to read it, your colleagues in the real world to read it. But the computer is actually not going to care. In fact, as an aside, one of the tools we have built into VS Code for CS50 is this button at top called style50. This is a program that we indeed wrote that will give you suggestions on how to improve the style of your code so it looks like the right way that programmers would generally write it. As an aside, the computer world is fraught with religious debate, so to speak, as to what code should look like. And people in the real world will have really stupid arguments over how many spaces to use for indentation and what lines code should go on and so forth. Generally, in the real world or in a class, there's an official style guide that someone autocratically declares this is how everyone should write their code so that just everyone's code in the company or course looks the same. But you'll find, in the real world, reasonable people will disagree. When you click style50, it will be formatted as we ourselves recommend in CS50. And in fact, let me zoom out here. And this looks a little cryptic at first glance. But on the left is the code that I just wrote and made a mess of by deleting all that whitespace. On the right is the way the code should look if it is well styled. So whereas correctness is all about, does the code work the way it's supposed to, design is about, how well have you written that code? Is it efficient? Did you make good decisions? Style is purely aesthetic. Is it readable? Does it follow a standard? Can another human easily skim it top to bottom, left to right, and understand what's going on? So these green highlights are saying, please add white space there. And so I can actually change my code to match. On the left-hand side here, if I realize, oh, my code is looking pretty ugly, watch on line 6 at left. As I hit the space bar two-- oops, sorry-- on the left, 1, 2, 3, 4, notice that the right-hand side is starting to be happier with my code by getting rid of the green indicators. And I can do 1, 2, 3, 4. That fixed that. Over here, I can do 1, 2, 3, 4. I can move this onto its own line by hitting Enter. And you know what, if it's taking too long, once you get into the habit of things, you can just Apply Changes. It will give you the suggestions automatically. And we're done and on our way. But for practice's sake, I would get into the habit of doing things manually until it gets boring and tedious, at which point, you might as well automate the process with a single click. All right, so let's actually run this code. I'm going to go ahead and open my terminal window again and clear it for clarity. I'm going to run make compare and hope that I didn't make any mistakes. I don't seem to have yet-- "./compare." And now notice I'm prompted for x. Let's type 1. For y, let's type 2. Enter. And x is less than y. Let's do a little sanity check, so to speak. Let's rerun it-- c What's x? Let's do 2 this time; 1 for y. And this time, it said nothing. So that's to be expected because I didn't have a two-way or a three-way fork in the road. The only time this code should say anything is if, indeed, x is less than y. So for those of you who might be more visual when it comes to learning, here's a flow chart that represents this same exact program. If you read it top to bottom, you start the program with "./compare." You are then prompted for x and y. And you're asked this, is x less than y? And the fact that this is a diamond means this is a Boolean expression, a question that the computer is asking itself. If the answer to that question is true, then, quote, unquote, "x is less than y" gets printed. And the program stops. Else, if x is not less than y, as in the second scenario, the answer is, of course, false, and nothing more happens. But we can build out this tree, so to speak, by adding a bit more code. So let's make it look like the second Scratch example. If I go back here, it's not hard to just say, else, if x is not less than y, let's say that. "x is not less than y" backslash n, close quote, semicolon. Let me now go ahead and rerun make compare. Enter. "./compare," Enter. And again, I'll do the second example-- 2, which is bigger, and 1, which is smaller. And this time, I will see x is not less than y. If, then, we were to look not at this flow chart but a slightly bigger one, you can visualize it this way. Everything in the left-hand side of this picture is the same. But if it's not true that x is less than y, the answer is thus false. This time we say, quote, unquote, "x is not less than y." And we can do this obviously one final time just to bring the point home. If I go back to my code and I even more pedantically compare these three values, let me go ahead and do this. So, else-- hm, I don't want an else actually. So let's go ahead and do this-- else if x is greater than y, let's then say "x is greater than y" in English. And then, finally, have an else that says printf "x is equal to y," close quote, or rather backslash n, close quote, semicolon. So just to show this all on the screen at once, this is identical Now to that Scratch version. It's well designed because I'm not asking the equals equals question unnecessarily. If I go back to my terminal window here, clear the screen, run make compare, Enter, and then "./compare" again. Enter. "What's x?" Let's do 1. Let's do 2. "x is less than y." Let's run it again-- "./compare." "What's"-- 2 and 1. "x is greater than y." One more time-- "./compare." "What's x?" 1. "What's y?" 1. And now x is equal to y. As an aside, if I seem to be typing fairly fast, you can actually cheat with your keyboard. If you go up or down, you can scroll through all of the past commands that you've typed. So it's actually very useful. If you just hit up, it will pre-write the previous command for you, at which point you can just say Enter. Or there's other fancy features built into this programming environment. If you do dot slash C-O-M and then get bored with typing out the whole English word, you can hit Tab for tab completion like in a web browser. And it, too, will autocomplete if it finds a file that starts with those letters. So little efficiencies here. Questions then on the code here? Yeah? AUDIENCE: I have a question about libraries. DAVID J. MALAN: Sure. AUDIENCE: [INAUDIBLE] is there any downside to putting in all the libraries? DAVID J. MALAN: A good question. Is there any downside to just putting in all of the libraries like we saw in the manual pages a moment ago? Performance. So generally speaking, C is meant to be a very efficient language, so much so that, even though it's decades old, still used omnipresently nowadays because it's so fast. It therefore minimizes time. It minimizes energy use. So it's still being used heavily. You would slow things down if you told the compiler, by the way, give me all of these other functions that I'm never going to use. So in short, just don't do that because it's unnecessary. But a good question. Other questions on what we've done here? Yeah, in front. AUDIENCE: [? Just to follow up, ?] [? why is it C? ?] DAVID J. MALAN: What is it-- oh, why is C faster? Why is C faster than other languages, let me answer that in more detail in week 6, when you'll see how much easier it is to write code in other languages because someone else is doing a lot of the work for you. So as an introductory course, we're teaching you bottom up, like how do you write code? How does the computer understand code? Eventually, this kind of stuff, certainly after five, six weeks of this, it's going to get tedious doing some of these things. We're going to switch to another language that takes away the tedium and allows us to really focus on the problems to be solved once we've graduated to that point. Yeah? AUDIENCE: [INAUDIBLE] shortcuts? DAVID J. MALAN: Sure. To repeat the keyboard shortcuts, you can just go up, up, up, up, up. And that will go through all of your previous commands, at which point you can just hit Enter. Or you can use Tab completion. So you can start typing a word like "code." And C-O-D tab will finish the thought. Or dot slash C-O-M Tab will finish that thought just to save yourself some keystrokes. And clearing the screen is Control L, which has no functional purpose other than keeping things neat and tidy in class. So a design question. So this code, I dare say, is correct. Let me zoom in a little bit here. Let me change the code to just do this, even though we already saw from Scratch that we probably shouldn't do this. Why should we not do this if, especially, I'm just more comfortable asking three separate questions, like if x is less than y, if x is greater than y, if x equals y, do this? It's a nice world to live in. Just ask your questions. You don't have to worry about else, else-if, else-if, forks in the road. You can just ask three questions. But let's put a finger on, why is this correct, yes, but not well designed? Yeah, in back again? AUDIENCE: [INAUDIBLE] DAVID J. MALAN: OK, there could be cases that are potentially outside of these three. Because this is relatively simple math, comparing numbers, we don't have to worry about that here. But, yes, in general, you might miss a scenario without using a catchall like else. AUDIENCE: Maybe more than one of them would be evaluated as true. DAVID J. MALAN: Yeah, so maybe more than one of them could be evaluated as true-- not going to happen here. But, yes, you could accidentally create a situation where two things print or three things print because you didn't really think about the boundaries among these questions that you're asking. Again, not applicable here but, in general, a good concern. AUDIENCE: You're forcing the computer to have a condition that doesn't need to be checked if I slow it down. DAVID J. MALAN: Really good. Really, what's concerning here in this example is you're slowing the computer down by wasting its time, having it do work that is logically unnecessary, even more so than the Scratch in the first C example. Why? Suppose that I type in 1 for x and 1 for y. Because I wrote this code top to bottom, this question is going to be asked no matter what. The answer is going to be false. This question is going to be asked no matter what. The answer is going to be false. This question is going to be asked. And no matter what, the answer is going to be true. We're OK there because we had to ask all three questions. But suppose I did the first thing, x is 1, y is 2. Then this first question is going to be true because x is less than y. 1 is less than 2. So this is going to print. And yet, then I'm wasting everyone's time asking, hm, is x greater than y, even though it obviously isn't. Is x equal to y? Hm, it obviously isn't. You're doing three times as much work in that particular case. It's just not good design. And again, for those of you who think a little more visually, we can actually make this picture to match. Here is a final flowchart for bad code, bad design. Why? Because no matter what, when you start the program and you want to stop the program, you're going through all three of those darn questions no matter what, whereas the previous flowcharts got us to the Stop bubble faster by taking alternative arrows based on true or false answers. So in short, still correct but bad design. And so again, even for problem set 1, when we start writing C code, consider not just getting the job done but how you might get the job done better than you might otherwise. All right, let's add a few other features into the mix. Here we have those same data types that are supported by C. Let's focus for a moment on something a little simpler, just chars, single characters. Unfortunately, for better or for worse, in C, the language makes a distinction between strings of text, which are generally words, phrases. They can, confusingly, be single characters or even zero characters if you don't type anything in between the quotes. But more on that another time. But when you know from the get go that you only want to get a single character back from the user, like "y" for yes, "n" for no, for instance, which is super common in programs, you can get that using a char and CS50's own function, get_char. So how might we use this? Well, let's go back to VS Code here. I'm going to close compare.c. And let's write a third program altogether. Let's call this one agree.c. And this is meant to represent like terms and conditions, where you have to check a box yes or no or something like that. In this program, I'm going to go ahead and do the following. I'm going to go ahead and, as before, include cs50.h, so we've got it, include standard io.h so that we've got it, int main(void) because we have to do that for now. More on that another time. And now let's ask the user a question. Do they agree? So I'm going to call get_char and then pass in a prompt of, "Do you agree?", question mark, with a space, semicolon. But as before with get_string and get_int, those functions return a value. So I want to assign that value from right to left to a variable, which I could call "answer again." But honestly, this program is so short, we're just going to use the letter c, which is conventional. So "c" for char, "i" for int, or "n" for number are very common. But one more thing. What's still missing for my variable here? The type. I need to say, this shall be a char, not an int, not a string, a single char. All right, now what do I want to do? I can ask a question. If c equals equals lowercase y, then go ahead and print out, just so we see something on the screen, "Agreed" period, backslash n, as though they agreed to the terms and conditions. Else, if c equals equals lowercase n, go ahead and print out, for instance, "Not agreed" just so we see something on the screen. So let me hide my terminal window and focus on the code. There's a couple of details here that are a little interesting. So, one, what did I do on line 7 and 11 that is not consistent with what I've done before? Subtle. So I'm using apostrophes or single quotes now instead of double quotes. Why? It's a C thing. When you're using strings, you use double quotes. When you use single chars, you use single quotes. So the argument to get char, that's still a string. It's a whole sentence that I'm passing in. So that is just like get_int, just like get_string. But when I get the answer back, the return value, and put it in this variable and I want to check, what is that one char, I have to surround the char I'm comparing against in single quotes or apostrophes, both for the y and for the n. So this program is not super well designed because it's not going to handle uppercase. It's not going to handle weird inputs very well. But let me open my terminal window. Make agree, Enter. The code compiles OK-- "./agree." Do I agree? Let's try it. y for yes. OK, let's try it again-- "./agree." n for no. "Not agreed." Let's do it one more time. Let's very enthusiastically say "YES" in all caps, and it just kind of ignores me. But why? Well, this is a feature of CS50's get_char function. If you tell us you want to get a char, we're not going to tolerate a whole string of text from the user. We're going to prompt them again and again and again until they give us just one char. So "YES," is three times too long. So let's actually just do a single capital Y and see what happens. Return. The program ignores me altogether. So all right, this is kind of a poorly designed program. It's a little annoying that we'll just ignore humans even if they type in Y or N that just happens to be uppercase. So let's improve this. Let me go ahead and add a couple more conditions. Else if c equals equals uppercase Y, then go ahead and print out "Agreed," same as before. And then, down here, else if C equals equals capital N, then let's go ahead and print out, again, "Not agreed." So this is now more correct. It's still going to ignore bogus input that makes no sense, if it's just the word-- if it's a different letter altogether. But this, too, code, while correct in some sense, is still poorly designed. Even if you've never programmed before, what rubs you the wrong way about this code now? Be critical. Yeah? AUDIENCE: [INAUDIBLE] uppercase and lowercase Y's together [INAUDIBLE]. DAVID J. MALAN: Yeah, it'd be nice to just merge the lowercase and the uppercase Y together, the same thing for the lowercase and the uppercase N. Why? If only because literally lines 9 and 12 are identical. Lines 17 and 21 are identical. And while not a huge deal, if I go in and I change this sentence, odds are, over the course of my lifetime programming, I'm going to forget to change this one even though I changed this one. Or I'm going to forget to change this one and this one. So you don't want the code to get out of sync potentially. And you certainly don't want to repeat yourself. So "don't repeat yourself" is a tenet of programming, too. If you can avoid that by somehow factoring out some commonality, you should do so, similar in spirit to math when you factor out variables or the like. So let me tighten this up, so to speak. Let me get rid of what we just did so that it's a little shorter as before. And let me express myself with two conditions using the following syntax. I want to check if c equals equals lowercase y or c equals equals uppercase Y. So you can actually use what's called a logical operator, two vertical bars, which means "or." And we can do this down here, or c equals equals capital N. So same exact functionality. But to your point, we've now eliminated, what, like another one-- it was, like, 1, 4-- it's eight lines of code now are gone, which is eight fewer lines that I might screw up in this program. Less opportunity for mistakes or bugs, probably a good thing. So now, if I run this, let me open my terminal window. Let me run make agree, Enter. "./agree," Enter. Do I agree? Capital Y. Now it seems to be handling both of those situations. So just a little tighter. As an aside-- we won't use it here-- but if you want to say "and," which would be nonsensical, it, a little confusingly, is two ampersands, means a logical "and," whereby the left thing has to be true and the right thing has to be true. So it's two Boolean expressions at once. This one makes no logical sense, though, because a character cannot be simultaneously lowercase and uppercase. It's got to be one or the other. So two vertical bars is logically correct. That represents our notion here of "or." Question? No? Yeah. AUDIENCE: Would you not be able to write or? Does it recognize that? DAVID J. MALAN: You could not write "or." So I'm saying "or" just because that's a little more normal. But this is incorrect. However-- sneak preview-- in the language of Python, you actually will literally say "or," among other things, which gets a little more user friendly. Other questions on this here? Searching. Yes, in back. AUDIENCE: Is there an easier way to-- DAVID J. MALAN: Is there an easier way to handle a case sensitivity? Yes, and we'll show you that next week, in fact. So we can combine this code to be even tighter. All right, let's do one final set of examples before taking a cookie break, if we could. But let's go ahead and close agree.c here. Let me open my terminal window. And let's go ahead and implement a virtual cat as we did last week. I'm going to code up a file called cat.c. And I'm going to implement this in a few different ways, the first of them pretty foolish. So here, I'm going to include standard io.h. No need for CS50 dot yet-- just yet. int main(void). Inside of these curly braces, let's go ahead and do printf "meow" to get the cat to meow. And then, to save time, I'm going to copy/paste that two more times. So this cat shall meow three times in total. All right, I'm going to go ahead and make the cat, so to speak. All good. "./cat," Enter. And it meows three times, just like our Scratch cat last time. I'll stipulate, this is correct. This is a really well implemented cat correctness-wise. But why is it bad design intuitively, just like last week? AUDIENCE: [INAUDIBLE] [? out. ?] DAVID J. MALAN: Sorry? AUDIENCE: Repeating the code. DAVID J. MALAN: Sorry. AUDIENCE: You keep repeating the code. DAVID J. MALAN: I keep repeating the code. I mean, I literally copied and pasted, which is your first obvious sign. I'm probably doing something wrong if I'm copying and pasting because I'm literally repeating myself. So to spoil it, odds are a loop is probably going to be our friend here. And so, in fact, in C, we have those features as well. So in the world of C, we can implement some of last week's same ideas in a few different ways. These are a little more mechanical. But suppose we want to repeat something literally three times. Scratch gives us a repeat, a block with an input-- so easy. C and a lot of languages, it's going to be a little more mechanical. And it's going to look ugly at first. It will take some getting used to. But it is a paradigm you will use again and again and again. This will become very rote memory before long. Well, the most direct translation of this Scratch code to C is probably something that looks a little something like this, whereby I initialize a variable, here called i, and set it equal to 3. That's the code equivalent in C of putting up three fingers. Then what I want to do is, while i is greater than 0, that is to say while I have at least one finger up, go ahead and do the following. And then once I've done that, for instance say "meow" on the screen, I want to go ahead and decrement i and then do this whole thing again. Now, I could have called this variable "counter," for consistency with earlier. But it turns out it's conventional when you've only got one variable involved in your code and all it's doing is something simple like counting, you can go ahead and call the variable i for integer, for instance. But it would not be wrong to instead call i "counter." But notice, too, that in this so-called while loop, as we'll start to call it, there is this parenthetical. And that parenthetical is actually itself a Boolean expression. But unlike an if statement, whereby the Boolean expression is evaluated just once and if the answer is true, or yes, you do that thing, the Boolean expression in a while loop here in C is evaluated again and again and again every time you go through the loop to check if you should keep going through the loop. So for instance, if the goal at hand is to say "meow," well, of course, the comparable C function is going to be printf. And I want to print out on the screen "meow," followed by a new line. Well, what's going on? Well, again, I initialize i to 3. I then check, is i greater than 0? And of course it is because effectively, in the computer's memory, three fingers are up. I go ahead and print out "meow." I decrement i, which means to put down one of those fingers. And then I check the Boolean expression again. Is 2 greater than 0? Of course it is. So I print out "meow." And then I decrement i, putting down one more finger. Then I check the expression again. Is 1 greater than 0? Of course it is. I print out "meow." And then I decrement i. And now I'm down to 0. I check again. Is 0 greater than 0? Well, no. And so the loop will automatically, by the definition of how this C code works, terminate for me and proceed to any other lines if there are more lines of code that I've written. So how do we actually implement this then in code and get it running? Well, it's going to be pretty much the same idea. Let me go back to VS Code here. I'm going to get rid of all of this copy/paste. And inside of my main function, I'm going to do exactly what we saw-- int i equals 3, semicolon. while i is greater than 0, then go ahead and print out with printf "meow" backslash n. And then be sure you decrement i. And notice that lines 8 and 9 are not only indented, they are inside of that while loop, so to speak, which means they will both happen again and again and again because what's happening in code here is those curly braces are kind of like the yellow pieces that are hugging the other puzzle pieces in Scratch. It will keep doing this, this, this. But every time, through that loop or cycle, this Boolean expression will be checked again and again and again until the answer is false, at which point the computer is going to jump to the last line. And if there's nothing left, that's it for the program, no more to be done. So same exact idea in Scratch, even though it's a little more mechanical. So that's how we might implement this. And you can think of it, these variables-- this is perhaps a little gratuitous, but let's do this. So if you have a variable inside of a computer's memory-- and that's a detail we'll get to in more detail before long-- you can really think of it just as like a container that stores value. So for instance, this clear plastic bowl, it can be thought of as a variable. It just stores values. And right now, there's obviously three stress balls in it. So it represents the number 3. So what's really happening in code like this is we've initialized i to 3, which is this bowl. We're then checking the question on line 6. Is i greater than 0? Obviously. So we proceed inside of the curly braces. And we print out "meow." We then decrement i. So for the sake of unnecessary drama, that's decrementing the variable. So what's being stored in this container now is one less. We do it again, check the count. Nope, 2 is greater than 0. So we keep going-- "meow." Decrement i. Check the variable. 1 is greater than 0, so we print "meow." Decrement i. We check the condition again. i is not greater than 0 because 0 is not greater than 0. And so the rest of the code stops executing. I'm not sure if that was any more effective than fingers on my hand. But we had the bowl. We had the balls. So same exact idea. Variables are just storing some value. And incrementing and decrementing would just be adding or subtracting stress balls in this case. But there's other ways we could do this. In fact, let me zoom in on my code here. And it's not really conventional in programming to count down-- nothing wrong with it, it's just not really a thing. We would typically count up. So we could alternatively do this-- set i equal to 1 initially. So we count 1, 2, 3, like a normal person. And we can change our condition. If I'm going to count from 1 to 3, what should my comparison be in my Boolean expression here? i is less than 3? Less than or equal to 3, I think. So if i is initialized to 1, we're going to go through this one time, two times, three times. i is going to eventually get incremented to 4. But at that point, 4 is not less than or equal to 3. So it's only going to execute a total of three times. But there's still a bug in this code. What other line needs to change? AUDIENCE: Plus plus. DAVID J. MALAN: Yeah, so line 9 needs to become plus plus. So this code is just as correct. And honestly, you could-- reasonable people will disagree. Your TF might say do it this way and not this way. But this is still correct. But it's not the most conventional way. As per last week, computer scientists and programmers generally, actually, start counting from 0 by convention for reasons we'll soon see. So the better way, the more conventional way arguably, would be always start counting from 0. Count up to but not through the number you care about. And so this form of the code is probably the most popular way to do it. Start at 0, count up to 3 but not through 3, as with less than or equals than. All three are correct. Can't really do counting up as easily with the bowl without picking up the balls. But the exact same logic applies. And in fact, this version of the code is so commonly done that there's a different way to implement it all-- there's a similar way to implement it all together. In fact, this code here-- same exact thing, repeating three times-- because it's so commonly done that you want to initialize something to 0 and keep doing something until the value 3, you can actually use a different preposition, for, which is another keyword in C. And it looks a little more cryptic. But it just tightens things up. This is what's called a for loop. Previous is what's called a while loop. And honestly, even though it, probably to the newbie, still looks just as cryptic, it's just a little tighter because you're expressing all of these ideas on one line. You specify the variable you want to create and initialize. You specify the Boolean expression you want to check again and again. You specify what increment or decrements you want to happen. And confusingly, you do use semicolons here, not commas. You do not put a semicolon here. You, of course, don't put them after these things. You generally only put them after functions thus far. So we do have one semicolon here. But in short, this you'll get more comfortable with. This is how I, for instance, almost always write a loop. But it's doing the exact same thing mechanically as this, same thing as counting on your fingers, same thing as counting the stress balls. There's just different ways to express the exact same idea. But there are ways to screw up. So in fact, let me go ahead and do this. Suppose that the cat-- we'd like the cat to live as long as possible. And we don't want it to stop meowing after just three or a finite number of times. How can you do something forever, again and again and again? Well, let me go back into VS Code here. Let me delete all of the code from earlier. And let me go ahead and say, while something is true-- I'll come back to that-- let's just go ahead and print out "meow" backslash n ideally forever. But what do I want to put in here? Well, if I want to do something forever, I could do something kind of stupid, like while 1 is less than 2, which is always going to be the case, or while 50 is less than 51, which is always going to be-- I could just ask an arbitrary question. But arbitrary-- not good in general. You should have meaning behind your code. So if you want the expression to be true all of the time, just say "while true," because true is not changing anytime soon. If it's literally true, it's always going to be true. The only caveat is to use this trick. For now, you will need to include the CS50 library, which for today's purposes makes that possible. But there's a problem, of course. If the cat's going to live forever, if I do make cat, "./cat," Enter, you can very quickly lose control over your terminal window. And you can see the meows are flying across the screen, at least based on the bottom from what we're seeing. This cat will never stop meowing. And this is either a feature or a bug, so to speak, depending on how long the cat here should live virtually. But how do you terminate a program that is out of control like this, infinitely? So one of the takeaways for today is Control-C is your friend for cancel or interrupt the program. If you ever lose control over a program because you've got intentionally or unintentionally an infinite loop, you can go into your terminal window, hit Control-C, sometimes multiple times if it's ignoring you. And that will break out of the program and just essentially force-quit it, like in Macs or PCs. But let's make one improvement here still. The last thing we did with our cat in Scratch before now-- we'll take a break in a moment-- was we defined our own functions. And recall that we did that to abstract away the idea of meowing because Scratch didn't come with a meow puzzle piece. C definitely does not come with a meow function. We have to implement it ourselves. So quickly, toward the end of week 0, we did this-- define a function called meow that just plays the meow sound. And now we have a meow puzzle piece we can use and reuse. In C, we're about to do this. And this is going to look a little cryptic. But it's going to lay the foundation for future weeks when we do this even more. I've got a meow function, weird mentions of void. That just means there's no input and there's no output for this function. It just does one thing simply. And that one thing is printf, "meow." So how do I use this here code? Here, in Scratch, is how we used it last week. When the green flag is clicked, repeat three times the meow function. In C, it's going to look like this-- int main(void) and all of that. And I can use a for loop, a while loop. I'm copying and pasting for loop version of the code. Set i equal to 0. Make sure it stays below 3. Increment it on each iteration, or cycle. And just call meow. So what's nice here is that we have, fairly simply, a way in C to create our own functions called meow or anything else that lines up perfectly with what we did in Scratch. We'll take some time to get comfy with the syntax and remember it, have to look it up frequently for reference. But let's go ahead and actually do this. If I go back to VS Code, clear my screen-- let me hide my terminal window temporarily. Let me go ahead and invent this meow function. Per the code earlier, I'm going to go ahead and do this-- void meow(void). And again, the two voids mean no input, no output. It just does one thing well. printf, quote, unquote, "meow" backslash n. And now, down here, I can use a for loop. So for-- and I know this from memory-- int i equals 0; i less than 3; i plus plus. And then, inside of curly braces, I'm going to go ahead and call the meow function. Notice, when I'm creating the function up here, I explicitly, pedantically, say void void, no input, no output. When I use the function on line 13, you just say open parentheses, close parentheses. That's the equivalent of a Scratch puzzle piece without a white oval. You just put nothing there. You don't put the word "void." So that's it. Let me open my terminal window. Let me run make cat to recompile-- "./cat." And I think I have a working cat. Now, this is correct. The only thing I don't love about this version, if I hide my terminal window, is that when I start writing bigger and bigger programs, it'd be nice if my main function, which I told you to take on faith for today, is at the top of the file, if only because literally the name "main" means this is the main part of my program. It'd be nice if it's the first thing I see, which is to say, just to be pedantic, it's very common to put any functions you write at the bottom of your file, maybe alphabetically, maybe organized some other way. But you put main first by convention, just like the "when the green flag clicked." It was the first thing you always started with last week. But watch what happens now. If I go into my terminal window-- and Command-- or Control-J is hiding and showing it, if you are curious. But probably, you'll just leave it open on your own all the time. Let me do make cat again. And, huh, I've screwed up somehow. All I did was move the meow function from top to bottom. And I'm getting "call to undeclared function 'meow,'" something, something, something. Well, what's going on? Well, C is pretty naive and simplistic. It's only going to do what you tell it to do. And it's only going to do things top to bottom, left to right. And unfortunately, on line 8, you are telling C, call a function called meow. But that does not exist in CS50's header file. That does not exist in standard io's header file. It exists at the bottom of my file, at which point it's too late because I'm trying to use it before it exists. So I could just undo that and put this meow function at the top of the file. But you're going to eventually get into a perverse scenario where you can't put all of your functions above all of your functions. You've got to pick a lane at some point. So the solution to this, albeit a little weird-- and the one time in CS50, in programming, that it is encouraged and necessary to copy/paste-- is what you can do at the top of your code, above main, is just copy/paste the first line of your own function. This is the so-called prototype of the function. And it simply describes how to use the function. And funny enough, we actually saw this earlier. But I kind of swept it under the rug. A moment ago, or a bit ago, when we looked at standard io.h and we looked at the printf function in the manual pages, I highlighted the header file. But I also glossed over the so-called prototype, which is-- sorry-- the first line of the printf function, just as this is the first line of my meow function. This is like a little clue. This is like saying to C, hey, there's going to be a function called meow that takes no input, has no input-- takes no input, has no output. Just know that it exists eventually. And that will satisfy the compiler because if I go back to my terminal, rerun make cat, it now knows on faith, per line 4, this function will eventually exist. And indeed, once it gets to the bottom of my code, line 14 onward, there it, in fact, is. So you just copy the one-and-only first line of your function's code to the top, called a prototype. And now if I do "./cat," I get, finally, "meow," "meow," "meow" yet again in this case. Questions on these here cats? No? All right, then the last flourish before-- I keep promising cookies. And I promise they exist. So last flourish-- just as we did in Scratch-- so in Scratch, recall that we parameterized our meow function by letting us tell meow how many times to meow so that we didn't need to use our loop inside of our "when green flag clicked" block. In other words, if I want to actually have the cat meow a specific number of times, I can actually go ahead and do that proactively with some of my own code such as this here in Scratch. When I edited my meow function last week in Scratch, I specified that I want it now to take an input called n, which represents some number of times. And I changed my repeat block not to be 3 perpetually, but to actually have n generally baked in there instead. Or actually, instead of just saying play sound "meow," I had a repeat block using n as the placeholder instead of a hard coded 3. So how can I now use this in C? In C, It's almost the same. It's still void at the beginning of my function name, which means no output still. It only has side effects. But what did change vis-á-vis the previous version of meow? What has changed? AUDIENCE: [INAUDIBLE] DAVID J. MALAN: Exactly. Instead of saying "void" a second time in parentheses, it literally says "int n" inside of those parentheses, which means, in C, this function called meow takes input. It means the exact same thing as the pink on the left. And again, this is why we keep emphasizing the Scratch blocks. Like, no new ideas with a lot of these features. It's just different syntax that you'll get used to over time. So if I go back into VS Code here and I change this function, let's do that. Let's change my prototype to be int n, where n represents some number of times. Let's change the actual function on line 14 to also have int n here. And let's actually move the for loop from main into the meow function such that I now have my curly braces here. I have my print statement inside of those curly braces. And now, in main, I can get rid of all of that code. Just say "meow" any number of times, like three. And just like I did with Scratch, let me hit Enter an arbitrary number of times. Sort of out of sight, out of mind. Now the essence of my program is one real line of code-- "meow" three times-- because I've abstracted away the idea of meowing and told the cat, instead, exactly how many times to meow by way of that function. OK, I can't keep stringing along cookies so long. Let's go ahead and take a 10-minute break here. And when we come back, more cats, more code. All right. So we are back. And I want to add one final flourish to this program because now, more so than a lot of the examples, now the programs are starting to grow in length. And indeed, soon there'll be a few dozen lines of code, which is not uncommon. But let's suppose that we want to stop hard-coding 3 everywhere and actually prompt the user for some number of meows here. Well, let me do this. In VS Code, I'm going to go ahead and get rid of this one line for now. And let's do something like this. Let's ask the user for an integer. So int, maybe n for number, equals get_int. And we'll say something like just "Number" to give a number of meows. And then we'll go ahead and actually call meow, passing in not 3 this time, but passing in n. So we are using the return value of get_int to store it in a variable called n on line 8. And then we are passing n as the input, or argument, to the function called meow on line 9. And again, the actual implementation of meow on line 22 onward, who cares? Out of sight, out of mind. Once it exists, we can abstract it away mentally. But I'll keep it up tight here anyway. All right, so let me go ahead and open my terminal window-- make cat, "./cat," "Number"-- I can still type in 3, and it works. Or I can go ahead and type in 5. "Meow," "meow," "meow." But, hm, it's not actually meowing five times. Why? [WHISPERS] I didn't realize this either, but there's a bug. AUDIENCE: [INAUDIBLE] DAVID J. MALAN: Yeah, exactly. So the for loop, when I copy/pasted it before, before break, I actually got lazy and I forgot to change the 3 to an n so that it matches the name of the argument that's being passed into meow. So that was a bug-- unintentional on my part. But we have now fixed it here. And now we are passing this in from main to meow. So if I make cat, "./cat", and type 5 this time, I indeed get five meows. But it's worth noting there's some subtleties here in my code in that I've used n a couple of times. So this is actually deliberate, that I've used n twice in this way, to induce a bit of confusion. But it turns out this n is actually not the same as this n, nor this one. So what's going on here? Well, it turns out, in programming, there's often this idea of scope. And long story short, generally speaking, variables only exist in the scope in which you create them. More down to Earth, variables only exist inside of the curly braces in which you define them. So for instance, suppose I got a little sloppy and suppose I didn't bother giving meow an input and I didn't bother giving its prototype an input and I just used n on line 14 because, why? Well, I already defined n on line 8. So this is just an alternate universe in which I'm not changing meow to take input. I'm just using n in two different functions, in main on line 8 and 9-- actually, I don't even need that-- on line 8 and 9 and also again on line 14. This code will not work. The compiler will not like this. Why? Because n does not exist inside of meow. Why? Per the heuristic I offered, n exists only inside of the curly braces in which it was defined, namely these curly braces here. So n is in scope in main, so to speak. But it is not in scope in meow. And that's why we have to jump through these hoops and use inputs and outputs and inputs and outputs and pass things around among functions without sharing things across functions instead. Now, I could clarify this and maybe change my argument here from n to times. If I want to make clear that, oh, this is the number of times I want meow to be said, I don't have to use n for both. But just realize that, if you do, it's just a coincidence. They are not usable in two different scopes. All right, let's do one other thing, though. Let's not only prompt the user for the number here, let's make sure that it makes sense what number they give us. So if I do make cat-- just to clean things up-- "./cat," suppose I type 0, OK, I suppose that's correct. If I say meow 0 times and it doesn't meow at all, that's arguably correct. But if I type in something like negative 5, it ignores me, which I guess is better than crashing or freezing or something. But ideally, it might be nice to handle this situation. And if they give me a negative number, prompt them again for a positive number. Prompt them again for a positive number. Make the program make sense. So how could we do that? Well, a couple of ways. If I go back into my code here, I could do this. I could maybe do something like a loop or-- let's see. So if I get n, so if n is less than 1, then it makes no sense. So what do I want to do if n is less than 1? Well, I could just prompt the user again. And I say, OK, let's get n again. And then I can say, if n is less than 1, what do I want to do? I guess we could ask the user again. And then if n is less than 1, I could just, again-- I can give them three tries, four tries to get this right. This is obviously stupid. I'm copying and pasting. I'm repeating myself. There's no end in sight. I can't do this forever, surely. So this just feels like the wrong solution. So there are different ways to solve this problem. And funny enough, a while loop is not really the best way. A do while loop is-- agh-- a while loop is not the best way. A for loop is not the best way. It turns out there's one other type of loop that we want to introduce that's super useful for getting user input, potentially, again and again and again so that the user cooperates. Specifically, what I'm going to do is this. I'm going to literally say, do the following while something is true. So it's more of a mouthful. I'm spreading it out over multiple lines. But what am I going to put inside of the do block here? I'm going to say int n equals get_int and ask for that number as before, closed quote, semicolon. And I'm going to keep asking while-- sorry, accidental Enter-- while n is less than 1, semicolon. So notice the semantics of this. Even though it's a little weird-looking, it does read, in English, do the following. Get an int stored in n. And keep doing that while n is less than 1. But this code as written is not quite going to work yet. Let me try opening my terminal window. Make cat, Enter. Ugh, damn it-- "Use of undeclared identifier 'n.'" Well, here's where the line number is helpful. The line number is indicated here, 12. And it's repeated here, 12. So I clearly screwed up at line 12. But there's not that much going on at line 12. Why is n "undeclared" in line 12 even though I literally just declared it in line 10? AUDIENCE: Because it's [INAUDIBLE] inside of the [INAUDIBLE] line 10, not outside. DAVID J. MALAN: Exactly, because I declared n inside the scope of the do block, so to speak, inside the curly braces on lines 9 and 11. That variable n no longer exists by the time we get to line 12. It'd be great if it did, but it doesn't because it violates that heuristic I proposed, which is that variables only exist in the scope of the curly braces in which they were defined. So how do I fix this? Well, it turns out you can declare a variable in advance outside of one scope but then define it, that is initialize it, elsewhere. So the solution here is actually this. Inside of the loop, just set an equal to the return value of get_int. But per the heuristic, you've got to declare n, make it exist inside of the outermost scope of this function. So it's a little weird. And we're kind of breaking this down into two steps. But this is valid, recommended, correct C code. You declare a variable without giving it any value initially. And then, in line 11, you proceed to give it a value, potentially again and again and again. Now, what's useful about a do while loop? So a do while loop, as the name implies, will do something no matter what. But it will potentially do it again and again and again while some question is true, like n being less than 1 in this case. As an aside, why did we not do a while loop? Well, let's think about that. While n is less than 1-- but wait a minute. n doesn't have a value. OK, so I guess we have to go back to doing get_int, number, colon, semicolon. OK. But while n is less than 1, we're back to the same problem where we have to repeat ourselves again. So this is why for loops, while loops, not the right solution when you want to do something at least once but potentially again and again. So the right solution here, again, is this new and final looping construct-- I'm just hitting Control-Z a lot-- whereby we've done it as follows. All right, let's try this. Clear the screen. make cat, Enter. "./cat." Let's type in 5. Still works. Let's type in negative 5. And notice it doesn't just ignore me. It prompts me again and again and again. Even if I type in 0, I've got to at least give it a positive integer. Well, this actually seems kind of a common paradigm. What if we want to prompt the user for a positive number in other programs too? We're nearing the point already, even after just week 1, where it'd be nice to write our own reusable functions that solve common problems. And eventually, maybe we can put them in header files as well. But for now, let's go ahead and do this. I'm going to actually copy all of this code. And I'm going to create one more function in this file below main called get_positive_int, for integer. And I'm going to specify that it doesn't need any input because the only thing this function is going to do is that exact same thing. So notice that I've just moved my code from main into a function that's name describes what it does, "get_positive_int." I'm declaring n here. I'm doing this again and again. And I'm doing that while n is less than 1. And what am I going to do up here? I can do something like this. Give me a variable called times for, how many times do you want to meow? And just call get_positive_int semicolon. So now, again, we've abstracted things away. And just like in Scratch, our final example-- which, recall, looked a little something like this, where we just called a function to meow three times-- now we're calling a function to get text. If I hit Enter an arbitrary dramatic number of times, out of sight, out of mind, I now have two functions in this world, get_positive_int and meow that are collectively implementing this entire program. But it's not quite correct. There's one mistake here still. Notice that get_positive_int is written slightly differently from the meow function. And just to be clear, too, let me copy its prototype to the top of the file just so we don't make that same mistake I made earlier where I didn't put the prototype at top so C didn't know what it was. What is different about these two prototypes at a glance? Yeah. AUDIENCE: get_positive_int should be returning int. DAVID J. MALAN: OK, so get_positive_int apparently-- and we've not talked much about this-- apparently does have an output of type integer. It's supposed to return an int, hand me back an int. It doesn't have any input. That's what the "void" in parentheses meant. No input, but yes output. And meow, funny enough, is the opposite-- yes input, no output. Why? Because it has a side effect, the visual thing, where it prints something to the screen but doesn't hand me any useful value back like the ask function or the ask puzzle piece did. So these are opposite in functionality, which means I actually need to return an integer from this function to whatever function wants to use it. So if I want the assignment operator to work here on line 9, I need to do what, all this time, get_int, get_string, and other CS50 functions have been doing. I need to, in my own function, return that value literally with a new keyword called return. And this is why I keep sticking out my hand. When you want a function to hand you back a value, you literally use "return" and then that value. That's why we have "return" value as a term of art, literally the "return" keyword. So if I open my terminal window now, make cat, Enter-- huh, I did screw up accidentally. How? Yeah. AUDIENCE: [INAUDIBLE] DAVID J. MALAN: Yeah, so on lines 9 and 10, I made a quick change. I changed my variable to times. But I stupidly didn't change this. So that's fine. That's why n was undeclared in that context. Let me clear my terminal, make cat once more. OK, that worked. "./cat." Let's type in 5. And it's still working. So again, even though the code feels like it's-- sorry-- even though the code is growing and growing and growing, it's the exact same program we wrote super simply before break. But now we're sort of modularizing it. We're creating reusable functions. And this is why functions like get_string exists, get_int exists. Like, CS50 wrote those years ago. And we realized, why are we copying and pasting these functions in all of these different CS50 programs? Let's factor out that functionality into a function of our own-- get_int, get_string. Just like here, I'm proposing to factor out this functionality, get a positive integer that gives you even more precise functionality so theoretically you could use and reuse it in other programs too. By not even just putting it here, we could go put it in a file of your own name and include it in future programs as well. That's all a library is. Someone realized, jeez, other people, including myself, might find this function useful again and again. Let's package it up in our own custom functions, just like our custom meow puzzle piece last week, so we can indeed use it again and again. And the takeaways for now is that unlike Scratch, which was a little more user friendly, in C, you have to specify if you want your functions to have inputs. And you must specify if you want them to have outputs as well. But more on that syntax to come. So where does that bring us? So after all this discussion of code, at the end of the day, this is what's important in the world of programming. Not surprisingly, it's like, what's important when it comes to grading and evaluating the quality of code? One, and first and foremost, is correctness. If the code does not do what it's supposed to do, what was the point of writing the code? So correctness sort of goes without saying. Design, again, is much more qualitative. It's like getting feedback, again, on an English essay, where reasonable people might disagree. You can make your argument better. You can structure the paper better. You can structure the code better in the case of programming. And style is purely aesthetic. Does it look good? Is it pretty printed, so to speak? Can other people, colleagues future and classmates present, actually read and understand it? That's what we mean by style. Nicely enough, within CS50's programming environment, you will have tools to evaluate the quality of all three of these axes, so to speak. So in problem set 1 onward, you'll be introduced to a command line tool that you type its name at the prompt called check50 that will check for you the correctness of your code-- not necessarily exhaustively. There might be mistakes you've made that we don't catch, which doesn't make your code correct. But it is a tool for finding many of the mistakes in your code. In the real world, you would have colleagues or yourself, would write tests for code you wrote or someone else wrote. So testing code is not just a grading thing. It is a real-world thing to ensure that systems are designed correctly. We saw the style50 tool in VS Code already. You click the "style50" button. There is now, thanks to the Duck, a "design50" button too, also in that top right-hand corner, whereby once your code is correct and working, like several of my programs have been, you can click "design50," and the Duck will not just quack but give you qualitative advice, if it can, on how you can make that code even better even before you submit. And of course, there's all of us humans in the room and online that you can ask these same questions of as well. So let's now solve some real-world but still simple problems as opposed to emphasizing small bite-size as we have thus far. So the first of these programs falls into this category of having side effects. So let's implement one or more functions that takes an argument's inputs and, as its output, produces these visual side effects. We'll draw inspiration from Super Mario Brothers-- not surprisingly, perhaps, here-- the original one, which was very two-dimensional, side-scroller, left to right. Mario or Luigi move from left to right and generally have to jump over things like pyramids or other shapes on the screen. So how might we go about implementing some of the screens from Super Mario Brothers, albeit textually? Well, we'll make it a little black and white and ASCII art, so to speak, here using just our keyboard. But suppose we want to write a program called mario.c that just prints out four question marks. It's not going to be nearly as pretty as what's on the screen here. But the logic is going to be the exact same as what Nintendo presumably did years ago. So let me open VS Code, my terminal window. Let's code a program called mario.c. In mario.c, I'm going to start with some boilerplate-- I know I want to print. So even if I don't know how to do this yet, I'm going to include standard io.h. For today's purposes, I'm going to copy/paste or type out that same line again and again-- int meow(void). And inside of my main function, akin to the green flag being clicked, I want to go ahead and print out four question marks. Well, honestly, the simplest way I can think of doing this is with printf question mark, question mark, question mark, question mark. Maybe a backslash n to move the cursor, and that's it. So that is arguably correct. So let's do make mario in the terminal, "./mario." And it's not quite as pretty as the game version of it. But it is, in fact, the exact same idea. But here, sort of an opportunity, a stepping stone to do better design. This game changes over time. And not all of the screens have just four question marks. It might be five, six, or even more. So what's the right programming construct with which we could generalize how many question marks are printing here? What feature of C do we want? A loop, like a for loop, a while loop, or something like that. And there's different ways to do this. But honestly, I've proposed earlier that we get into the habit of reaching for for loops as just very conventional. So let's do that. for int i equals 0; i less than 4-- because that's how many I want for the moment-- i++. And then inside of my curly braces there, let's go ahead and print out, quote, unquote, a single question mark, but no new line. Let me now go ahead and make mario. And can you anticipate an arguably aesthetic bug when I hit Enter? It's not going to move the cursor to the next line. But the solution here is a little non-obvious. I don't think this helps me. If I put the backslash n there and I do make mario again and "./mario," what is this output going to look like instead? AUDIENCE: [INAUDIBLE] DAVID J. MALAN: Yeah, like a vertical column of question marks, which, while nice enough, is not the goal at hand. The goal is these horizontal ones. So someone else, what's the fix here, if clearly putting the backslash n inside of line 7 is wrong? AUDIENCE: [INAUDIBLE] DAVID J. MALAN: Yeah, so put it after the loop, and not after the printf line, specifically after and thus outside of the loop so that after that loop is finished executing three total times, it's totally fine to just print nothing other than a backslash n so long as we now recompile the code, make mario, "./mario." And, voila, now we have four in a row. It's a little generalized. OK, so we've sort of plucked off a fairly easy problem. Well, let's go back to the world of Mario and try something that is, in fact, vertical, like this. So this is another scene with three bricks here. Instead of using question marks, we'll use hash symbols to represent bricks. This actually is the incarnation of my mistake a moment ago. So let me undo this by getting rid of that printf. Let me change the inside one from a question mark to a hash symbol, which looks the most similar in ASCII to a brick. And let's go ahead and put a backslash n after that. If I do go ahead and do make mario, "./mario", it's not that interesting. But-- and it's actually not that correct because I wanted three. So no big deal. I can, of course, go back to my code and change the 4 to a 3. Or better yet, I could use get_int or my new get_positive_int function and just generalize this further so that I can print out any number of them. But for now "./mario" gives me three. All right, so we've plucked off the second of two problems. Let's now let things escalate a bit. So it turns out, once you get to World 2 and beyond, there are some underground parts of Mario where you actually have bigger, more solid bricks like these here. And just by eyeballing it, this is a 3-by-3 grid of bricks, like nine of them total, we'll conjecture. So how can I go about implementing this? Well, now is where the program gets a little more interesting. And the not-- well, the poorly designed way to do this would be like printf hash, hash, hash, backslash n, semicolon, and then maybe printf, printf. That's correct but not well designed. So make mario, "./mario." It doesn't look like a square, just because these hashes are more vertical than they are horizontal. But it is correct, this example. But it's not very generalizable. And this is literally hard coding. I copy/pasted. I'm just doing a lot of bad practices here. So what could I do instead? Well, it turns out we can combine today's ideas, including loops, to do things again and again. So what is this grid of bricks? It's a 3-by-3. So it's like a row and a row and a row. And then within each row, there's column, column, column. So it, too, is like an old-timey typewriter that prints one line, then the next line, then the next line, and so forth. So how can we conjure that in code? Well, let me go ahead and do this. I think a print approach would work like this. For int i equals 0, i less than 3, i plus plus, because I know I want to do something three times-- but what do I want to do three times? This loop kind of represents, in my mind's eye, row, row, row. So in fact, I could be more pedantic. If I want my i to mean something beyond int, I could say row equals 0, row less than 3, row plus plus, just to help me think about it. And then what do I want to do on each row? What do I want to print? Column, column, column, so brick, brick, brick. So how do I print three bricks or any number of bricks? Well, I could cheat and just do printf hash, hash, hash, backslash n. But again, I can't generalize. I can't take an input from the user and print four or five or six bricks. So that's going to get me into trouble eventually. So maybe I could use a loop. So I could do for int i equals 0, i less than 3, i plus plus inside of my loop. And then in here, I could print out one hash. And that's kind of on the right direction, the right path, because now I'm just using the simple building block, or brick, but reusing it again and again. And it's totally fine to have nested these columns in this way. I used i out of habit. But what would a better name be? Well, maybe "column," or maybe just C-O-L, "col" for short, so that my code is saying what it does for me. And I don't have to use "row" or "column" explicitly. I don't need to print them. But I am using them as counters one after the other. So let me go ahead and run make Mario, "./mario." And I'm feeling good about this, but-- ugh. Damn it, there's nine bricks. But they're not really laid out. Why? What's the fix? Yeah. AUDIENCE: You never went to a new line. DAVID J. MALAN: Yeah, I never went to a new line. And let me do what I think you're not going to suggest I do. Let me just go to the obvious place. All right, well, let's put one right after the brick. But, of course, if I do make mario, "./mario," I'm making the same mistake as before. I'm printing out too many new lines. So in between what lines do I actually want to print a new line? Between, yeah? AUDIENCE: 10 and 11. DAVID J. MALAN: Yeah, so 10 and 11. So outside of the inner loop but inside of the outer loop so it happens again and again. So let's just print out, as before, a single backslash n, semicolon. Now let's do make mario, "./mario," Enter. Ah, now it's generalized as I see fit. And if I really wanted to dwell on this, I could go in and I could prompt the user with get_int or with get_positive_int, figure out what row and/or column should be. We can make any size brick that we want. But now we have a nice starting point. But there's another way to think about this because I dare say, especially for your first CS50 problem set, if you're trying to print bricks and the world of Mario in this way, it's probably not going to be obvious to come up with loops like this and just magically get it working after 45 seconds in total. It'll be a struggle at first. But there are some patterns to follow. So one, it's pretty conventional nonetheless to use just i and then j and then k and then l. And if you've got nested, nested, nested, nested for loops, at some point nesting, you're probably writing bad code. It's not well designed. But one or two or maybe three nestings could be an OK thing. But you cannot use and reuse i again and again. Why? Because if you're counting i here, but then you're changing i here to do your columns left to right, you're going to get all of your math out of sync. So you need two separate variables. i and j are conventional. Or row and column would work too. But if we go back to this idea of rows and columns, well, let me actually factor something out here. And this might help you instead. Suppose that you set out on this problem. You know you want to do something three times. But you don't quite understand how to print those rows. Well, take a baby step, a bite out of the problem, and maybe do this. Create a function with no output, just a side effect whose purpose in life is to print a row. And how many rows? Well, maybe n for some number of rows-- for some number of bricks, rather. How do you print a row of bricks? Well, let me just think about this in isolation. How do I print a single row of bricks? That's easy-- for int i equals 0, i is less than n-- if I'm generalizing-- i++, and then-- whoops, i++. And then, inside of my curly braces, go ahead and just print out a single hash. And at the end, as you suggested, print out a single new line. In other words, abstract away the idea of printing a single row. And in fact, at this point in the story, especially if you're struggling to get started, you don't even need to start with main. Take a bite out of the problem that makes sense to you that's smaller than the whole problem, printing a single row because then you can come in and iterate. Then you can go in and say, OK, now let's write my actual main function. So int meow(void), as always. And now what do I want to do? I want to print out a whole bunch of rows. How do I print out a whole bunch of rows? Oh, my god, it's like the same idea-- for int i equals 0, i is less than, let's call it 3 for now-- but we can generalize that-- i++. And what do I want to do on each iteration of this loop? My gosh, just print row with three bricks. And then we're sort of done. Again, out of sight, out of mind, this function can go away and never be seen before because once print_row exists, that's what it in fact does for me. Now, this isn't 100% correct. I still need my prototype because if I've made my own function, I need to tell C in advance that it shall exist. So I need to copy and paste that one line of code. If I were really being pedantic, this is bad design. In general, when you have the same number in multiple places in a program, a programmer would call this a "magic number." Like, how is that working? Just honor system, that you're using the same number again and again. So a better solution here, even if you're not going to take user input, would be to do this-- int n equals 3. And then use n here. And then use n here. Or you could call it anything you want. But now you've specified 3 in one and only one place. And we can go one step further. It turns out, in C and in other languages, you can protect yourself against yourself. If you know that a variable should never change its value, it should always stay 3 in this case, you can use what's called a constant, where you can specifically say, I don't want just n to be an int. I want it to be a const int, "const" for short for "constant." And this means even if I try to change n in my code, the compiler will not let me. So I can protect myself from myself, or in the real world, you can use a variable that none of your colleagues can foolishly change on you without you realizing that it has happened. So a lot of programming, honestly, is just not trusting yourself the next morning when you've forgotten what code you wrote, let alone the next month, the next year when you're writing code in the real world. So constants just give us a feature to defend against ourselves. There's another feature that's useful too, especially when you wake up the next day and you're like, oh, my god, how does this code work? What does it do? Well, there's comments in code. And some of you might have used this in Scratch. You could add little yellow sticky notes in Scratch for "comments." In code, you can do something like this. You can, if you want to put an English reminder to yourself, or if you speak some other human language-- a comment in Spanish or any other human language-- you can write it with a slash slash at the start of the line. And then you can say something like, print n rows. And then this tells you, in a comment, what those subsequent lines of code are doing. It's sort of a note-to-self. It has no functionality for the computer's sake. It just is a note to yourself. Or you can say something like this, like never change n, because you're making clear that it's indeed constant. But that, too, is a little pedantic since const says the same. But comments are notes to self to help you remember what something is doing or why you did it this way. Questions now on any of these Mario problems that we have solved? No? All right, so one final set of examples that push the limit of what computers can actually do. Thus far, we've solved every problem I've proposed. But that's because I've kind of been skirting some of the underlying challenges. So it turns out that we have not only functions that give us side effects visually on the screen. We again have functions that have return values. So let's focus on those and where things can go wrong. And let's use a bunch of other operators as well. Suffice it to say, computers got their start by being really good calculators. So computers support addition, subtraction, multiplication, division, remainder operators, represented by the percent sign here, which says take the remainder of something over something else. And there's even more operators than this. So let's go ahead and implement our own calculator of sorts that actually has some bugs along the way. Let me go back over to VS Code here. I'll close mario.c, open my terminal, and code up one final file called calculator.c. And in this calculator file, let's go ahead and do something super simple initially. Let's go ahead and include CS50.h. Let's include standard io.h. Let's do int meow(void), as always-- all boilerplate thus far. And now let's do something more interesting-- int x equals get_int. And we'll prompt the user for an x value. int y-- prompt the user for a y value, as we've done previously for comparing numbers. And let's just do something super simple. Let's give myself another variable, int z equals x plus y. And then let's print out the sum. So printf, quote, unquote-- and I don't percent s here. If I want to print out a number-- someone said it earlier-- we want percent s for string but percent i for integer. Backslash n, and print out the value of z. So it's a little silly, this calculator. It just adds two numbers together. But it's going to demonstrate some points. So make calculator, Enter. So far, so good-- "./calculator." Let's just say x is 1, y is 2, z is going to be 3. This code is correct, simple though it is. Is there an opportunity for marginally better design? Could we tighten this up, make it shorter? Fewer lines means lower probability of bugs, probably. Yeah. AUDIENCE: You don't need to provide a separate variable z. DAVID J. MALAN: Yeah, we don't really need a separate variable z. I mean, it's fine if it's clearer to you, if it's clearer to your TF, if it's clearer to your colleagues. But honestly, this is so relatively simple, I think we just get rid of z and just say something like x plus y here, which is totally reasonable as well. But you don't want to take this to an extreme. Heck, if we don't need z, do we really need x and y? Well, we could do something like this. Let me actually-- whoops-- let me actually delete these lines of code and claim-- we can do this all in one very pretty one-liner. We could do, say, get_int x plus get_int y. And notice now, like the join example last time, I'm calling get_int once, get_int twice. Both of them return a value, which is going to be 1 and 2 respectively based on what I typed earlier. Then I'm doing 1 plus 2. That's going into printf as the second argument. This is actually correct and will work. This is just stupid. Don't do this. We've crossed some ill-defined line where this is just harder now to read. And so even though the variables aren't strictly necessary, I would argue, and I think most programmers would argue, this is just much more readable. Each line is doing a little bit less work. There's less chance for error. It just makes a little more sense. But reasonable people will disagree. So therefore, this is to say, over time, too, you and your TF might disagree. You and your colleagues might disagree. And at that point is when the religious debates kick in as to which way is the right way. All right, so that's one calculator. Let's do something else that maybe just doubles a number here. So let me change this to just get one integer from the user. Let's just call it x. And let's just double it quite simply. So printf, percent i, backslash n, x times 2. We'll quite simply double it. The star operator is indeed multiplication in this case. So that's going to go ahead and double my number. So make calculator again, "./calculator." Enter. And let's go ahead and type in 1. And I get back 2. Let's run it again. Type in 2, I get back 4. Type it again. Let's type in 3. I get back 6, and so forth. All right, so that's not bad in this case here. But what if we actually want to write a proper program here? In fact, yeah, let's see. This is sort of a meme that comes and goes. Let me see if you recognize this. I'm going to go ahead and say another variable-- not x. Let's be more specific, like int dollars equals 1. And then let me deliberately induce an infinite loop. Sometimes it is useful to induce an infinite loop so long as you eventually break out of it somehow if you don't want the program to run forever. I'm going to ask the user a question asking them for a char c using get_char. And I'm going to ask them, quote, unquote, "Here's percent i." Period. "Double it and give it to the next person?" Question mark. This is ringing a bell. And then we can pass in to get_char the dollars value there. So actually, this looks a little cryptic already. I'm going to put a dollar sign in front of it as though we're actually dealing with US currency. And what do we want to do? How about if the user says y for yes-- double it and give it to the next person-- then let's go ahead and do dollars. And let's double "dollar." So I can do dollars equals dollars times 2. Or recall the trick for plus and minus. I can also do times equals 2, which just doubles it in one line as well. Just a little syntactic sugar, as programmers call it, that just tighten up your code even though it's the exact same thing. But what if the user does not type y and they want to keep the money? Well, we have an else condition. At that point, you don't want to keep asking, asking, asking them with get_char. Let's just break out of this loop instead. So break is another keyword that if you're inside of a for loop, a while loop, a do-while loop, you can forcibly break out of the loop early if and when you want to. And so this satisfies the goal of making sure that this doesn't run forever, but it is going to run again and again and again while we keep prompting the user with this question. So let's see now what happens except, at the end, let's go ahead and make sure the user knows how much money they're walking away with. Here's dollar sign, percent i, backslash n, dollars. So we will see, at the end of this, whatever dollar amount the person ends up with. Make calculator, Enter. "./calculator." And let me increase my terminal window size. So here we go. "Here's $1. Double it and give it to the next person?" Yes. "Here's $2. Double it and give it to the next person?" Yes, yes, yes, yes, yes. So the Instagram Reels aren't that long. But if you keep doubling it again and again, this is called exponentiation, which will make you quite wealthy quite quickly because, notice, we're already in the thousands of dollars by just saying yes and yes and yes. It's an interesting societal question as to what dollar amount you would keep the money and no longer double it and pass it on. But for now, we'll just keep doubling it because this is just getting bigger and bigger, seemingly infinitely large And the C program-- but, oh, my god, apparently the Instagram Reels cut off the meme too short because eventually it goes negative and then 0. What's actually going on here? The code is actually correct. But we're bumping up against a different kind of problem. Any instinct for what is actually going wrong here? It's not doubling forever. Yeah. AUDIENCE: There's not enough bits to store. DAVID J. MALAN: Yeah, there's not enough bits to store bigger and bigger numbers. Recall, with 32 bits, which happens to be how big most ints are, you can count as high as 4 billion if you start at 0 or roughly as high as 2 billion if you want to handle negative numbers as well, negative 2 billion to positive 2 billion. So eventually, once I get to $2 billion, or $1 billion, it goes negative. And then it just goes to 0 altogether. This is because of something called integer overflow, whereby if you only have a finite number of bits and you keep incrementing them, incrementing them, incrementing them, eventually you can't just carry the 1 because there's no 33rd bit. So all of the other bits wrap around from ones to zeros. And it looks like all 32 of your bits are 0 because the 33rd bit was supposed to be the 1, but it's not there. They don't have enough memory. So this is a fundamental problem with computers whereby if you count high enough, things will just start to break, at least if you're using C or C++ or certain other languages that don't anticipate this. And there's a very real implication of this. So here's a photograph of something we'll look at more in time to come of memory inside of your computer or phone or any electronic device. Suffice it to say, there's only a finite amount of memory. And if you're only using 32 bits then, or heck even three bits, you will eventually overflow. We used three bits last week. So here's an example. In binary, if you're only using three bits, per the white digits here-- I've put in gray the fourth just to show you what carry we might want to have-- here's 0, 1, 2, 3, 4, 5, 4, 7, just like last week. And just like last week, someone said, how do we get to 8? We need another bit. But if that bit is grayed out because it doesn't exist, we've just overflowed this tiny integer and gotten back to 0, just like my money went to $0 instead. So how do we actually avoid that? One way to do this is this. Let me hit Control-C to break out of the program. Or I could just type "no." Let me shrink my terminal window and clear it here. I could actually do this. It turns out that ints use 32 bits typically. But there's another data type that was on the slide before called long, which is a longer version of an int, which is 64 bits, which is crazy big. There's not that many dollars in the world. But it's still finite, even though I can't pronounce a number that big. But if we change all of our ints to longs and we change our placeholder from percent i to percent li, for long int, I can actually count higher and higher. So case in point, let me actually go back to my terminal-- make calculator, Enter. Make it larger again-- "./calculator." And I'm just going to keep saying yes but faster this time. The sequence is exactly the same. But recall that once we got into the billions, it started to wrap to negative and then 0. This is a lot of money now. Longs are indeed longer. And I could do this probably all day long. Oh, interesting. I shouldn't have said that. Can't do this all day long because eventually a long, too, will overflow. [WHISPERS] I just didn't think it was going to happen that fast. So a long, too, will overflow because we'll need a 65th bit, but the computer has not allocated it. So that, too, becomes an issue of overflow. To read an excerpt, these are very real world issues. And in fact, here's a photograph of a Boeing 787 years ago that actually had issues beyond the most recent issues with Boeing airplanes, whereby after 248 days, the Boeing 787, years ago, can lose all of its electrical power due to the generator control units simultaneously going into failsafe mode, whatever that means. But if you dig into this, it turns out that there was a software counter in these airplanes years ago that would overflow after 248 days of continuous power. 248 days, why? Well, Boeing was using a 32-bit integer. And they were using it to count tenths of seconds. And it turns out, if you do the math, after 248 days, you have used too many tenths such that you overflow the size of a 32-bit integer. The plane would essentially have this integer, this tiny, stupid little variable, overflow. But generally speaking, when your numbers suddenly go negative or 0, bad things happen. The plane could literally lose its power mid-flight or on the ground. And if you can believe it, anyone want to guess what Boeing's workaround was till they fixed the actual software? AUDIENCE: [INAUDIBLE] What's that? AUDIENCE: [? It's for ?] [INAUDIBLE]. DAVID J. MALAN: Not even-- reboot the plane. They were told, every few days, certainly every 248 days, turn the power off, turn it back on, which, stupidly, is what all of us have been told for years with our Macs and PCs and phones. Why? Because sometimes, because of bugs and software, computers get into funky states, which is a colloquial way of saying some programmer made a mistake and some counter overflowed or some condition wasn't handled and just weird, unexpected things happen. So rebooting just resets all of your variables back to their original values and gives you more time, more runway in this case, no pun intended. There are others. In fact, one of the most famous ones from the 1980s was the original Pac-Man game-- only had support for 255 levels. Why? They were using 8 bits. Recall that 8 bits gives you 256. But if you start counting at 0, you can only go to 255. So the crazy kids who were so good at Pac-Man that they got to level 256, the makers of Pac-Man did not anticipate that anyone was going to win that many levels. And just weird stuff happened on the screen. All of the fruit started overwriting everything because they didn't have enough memory allocated to the level, nor did they have a condition that says, if level equals equals 255, "you win." There was just nothing handling that corner case, so to speak. So these things abound even these days. Thankfully, in some languages, there are better solutions where you can use big integers. And you'll just use 64, maybe 128, maybe 256 bits. But you need to use a language or a library that allows you to grow and shrink the amount of memory being used. And many, if not most languages, do not do that for us. So there's a few final problems to see that we've been taking for granted thus far. And they also involve numbers and memory. So let's go back into our calculator. Let's throw away all of this meme code here. And instead, let's go ahead and do something simple again. int x equals get_int. And prompt the user for a variable x. int y equals get_int, prompt the user for a variable y. And this time, instead of addition, instead of doubling, let's do division. So printf, quote, unquote, percent i backslash n. And then plug in x divided by y. So you use a single forward slash for division. Let me go ahead and, make calculator down here, "./calculator." And let's go ahead and do 1 divided by 3, which should, in fact, be-- it's not really 0. It's like 0.333. Let's try this again. How about "./calculator" 3 divided by 2? Should be 1.5. Nope, computer thinks it's 1. Well, what's happening here? Well, it turns out, when you're using integers in a program, you are vulnerable to what's called truncation. An integer plus an integer gives you an integer. An integer divided by an integer, funny enough, gives you an integer. So even if the answer is supposed to be 0.333 or 1.5, everything in the world of integers throws away the decimal point onward. And you only get the integer part of the value. So it's not even rounding. It's truncating everything after the decimal. So this program is just not correct. But there are solutions potentially. For instance, if I go back into my code here and I use a different format code we haven't used yet-- we had s for string, i for int. There's also f for float. And a float was like a real number, something with a decimal point in it by definition. We just haven't used it yet. I could tell the computer to print this as a float. So let me do make calculator again. And now, hm, it's specifying type double. There's an error here. The problem is that I can't just tell the computer to format this number as a float. I need to convert the number, x divided by y, to a float. And I can do this in a couple of ways. One, I could literally change all of this to floats and just avoid the problem altogether. Use float, use get_float, use percent f, and I'm done. But if I want to use ints for whatever reason-- because I want the user to type in integers, but I want to show them real numbers with decimal points for correct math-- I can do what's called casting a value. I can, in parentheses-- which is a weird new use of parentheses-- I can say, hey, computer, please treat the following integer as a float instead, thereby avoiding truncation. Do not truncate for me. So if I now run make calculator again, "./calculator," and type in, for instance, 1 for x, 3 for y, now I get an actual floating point value. I'm formatting it as such. And I'm telling the computer to actually arithmetically calculate it as such as well. But here, too, I'm kind of cheating you of a reality. It turns out-- let me clear this screen here. And it turns out that there are fancy ways in printf to tell it how many digits to show you, how many significant digits. And the syntax is very weird. I have to look it up constantly. But instead of just saying percent f, you literally put some numbers in between there. And you say point 5. And that will say-- it's weird syntax-- hey, printf, format this to five digits instead. So let me go ahead and do make calculator again, "./calculator." And let's do 1 divided by 3. And indeed, I get five significant digits there. But suppose I get a little crazy and I want 50 significant digits. Well, according to grade school, I should just see more 3's. But watch this. Make calculator, "./calculator." And it turns out that whoever taught you grade-school math was kind of telling you some white lies because if you really do it with a powerful Mac or PC or phone, one third is actually 0.3333333334326744079-- [SIGHS] who's right? Mr. and Mrs. So-and-so from grade school or the internet? What's going on here? What explains this? It all comes down somehow to [? weak ?] zeros and ones. Why is this floating point number imprecise, so to speak? What's the intuition? Yeah. AUDIENCE: Is this similar to what happened earlier where there was an overflow? DAVID J. MALAN: Yeah, similar in spirit. Just as ints only use 32 bits, floats also use only 32 bits. If you want more, just as int has long, floats have something called "double." So I could avoid some of the problem by switching to double. But that's still going to be finite. And if you think about this intuitively, if you're using a finite number of bits, be it 32 or 64, you can only represent literally so many patterns and thus so many floating point values, so many real numbers. But how many real numbers are there in the world? Literally infinitely many, is the challenge of real numbers. You can just keep adding numbers after the digit. So how could a computer, Mac, PC, or otherwise, possibly represent every floating point value super precisely if there's not enough patterns to represent every number in the world? Moreover, the way that computers use to represent numbers sometimes do not allow them to represent numbers so precisely. We can get more significant digits maybe, but not 100% perfection or precision. So floating point precision, too, is a fundamental problem with computers today. And unless, again, you're using a specialized language or library that understands, for scientific computing, the implications of overflow or imprecision, your code will have mistakes, much like Boeing discovered, much like Pac-Man discovered as well. And in fact, just to end on a gloom-and-doom note, it turns out there's another problem like this on the horizon already. So back in my day, everyone was really worried about the Y2K problem, the Year 2000 problem. Why? Because for decades, when computers were invented, most systems were using just two digits-- independent of bits-- two digits to represent years. Why? Computers came out a few decades ago. Who'd think that a computer is still going to be running decades later? Turns out they were, especially in government and corporations and the like. But if you're only using two digits to represent years and the millennium comes around and it's 1999 about to roll over, about to roll over, what comes after 1999? Well, if you're only using two digits, ideally 2000. But if you're only using two digits, the year 0 comes after the year 1999. And the whole world, truly-- you can look it up nowadays on Wikipedia-- was freaking out because there was so much old software in the world that could have had this mistake. And who knows? Planes falling out of the sky, computers rebooting, freezing. No one really knew because this was an unhandled situation in code. So thankfully, the world actually got its act together. The world did not end in the year 2000. And most systems were updated in time without crazy horror stories. But we're going to have this happen again because it turns out just a few years from now, at this point, computers for years have been using 32-bit integers to keep track of time in the sense of what time of day it is. And the point in time they decided years ago was, like, hey everyone, let's just keep track of how many seconds have passed since January 1, 1970. And we can relatively compute time any time thereafter. So that's great. That gives us a lot of decades' worth. But 32 bits eventually maxes out at, like, 4 billion positive, or 2 billion if you want negative and positive. And it turns out, if you count the number of seconds between 1970 on up, on the day January 19, 2038, the world might again end because all of these clocks are going to overflow. And we're going to end up in the year 0 or negative something. Now, what's the solution there? I mean, my god, it's the exact same thing. Stop using so few bits. Use more bits. But bits and memory and computers used to be expensive. Nowadays, storage is so much more available. But among the things we'll discuss then is how you can throw both hardware and software at this problem. But for now, maybe set a Google Calendar reminder for January 19, 2038. And hopefully we'll see you next week. [APPLAUSE] [CLASSICAL MUSIC]