字幕列表 影片播放 列印英文字幕 DAVID MALAN: All right. This is CS50 and this is lecture 1. And you'll recall, of course, that just a few days ago, we introduced programming and some fundamentals of computing and computational thinking, so to speak. And today, we're going to build on those ideas but begin to transition to a more cryptic looking but nonetheless much more powerful language-- transitioning ultimately from Scratch. So odds are by now, you had an opportunity with problem set zero to experiment with Scratch and drag and drop puzzle pieces and recall that the real point of Scratch, beyond having a bit of fun in showing off, which you can do with something like that, is to explore ideas like loops and functions and conditions. Maybe some Boolean expressions or events. Really depends on how you pull those ingredients together. But today, we introduce a language that's been around for quite awhile longer-- decades-- called C. And it's an older language and frankly, after CS50, odds are you're not likely to use this language all that much, if ever. But it's been a foundation for a lot of the more modern languages that have come in. So roughly mid-semester when we transition to another language-- Python and then thereafter SQL and then thereafter JavaScript-- you'll see a lot of those same origins and syntax and ideas. And indeed, everything we did last week in Scratch, you're going to see permeates all of these various languages. Because at the end of the day, you're not learning C in CS50. You're not learning Scratch or Python or JavaScript. You're learning the fundamentals of computer science and ultimately, the tool of programming. So today, let's begin to translate some of last times ideas into more cryptic looking but nonetheless fundamentally identical ideas as follows. So this was a super simple program that simply displayed on the screen out of the mouth of a cat by default, hello world. Well, let's begin to translate this to something textual as most programming languages actually are, by first focusing on just this block. This purple puzzle piece-- we called an example of what kind of programming construct? It was like a function. A verb or an action, do something in Scratch. MIT decided to make them purple but that was just arbitrary but they're consistent in the program because they're all very similar in spirit. Now in C, starting today and for several weeks hereafter, that same purple puzzle piece is going to start to look like this. And we saw a glimpse of this last time-- printf, hello, world. But notice there's a few salient characteristics beyond just the words, hello world. There's printf and we'll see what the f stands for today. There's a parenthesis and a closed parenthesis over here. And that kind of balance is going to be important, not intellectually, but just syntactically because the computer is going to expect you to be super precise. The quote and unquote, we'll see, surround words that you write in a program. So whereas last time in Scratch, you simply typed a word in a white box, now you're going to do the same thing on your keyboard but surrounding it with quotes. And then lastly, there's going to be this nuisance, this semi-colon, which a lot of languages have which simply says, end of thought. It's like the programmer's equivalent of a period in an English sentence. And you'll find that among the frustrations that new programmers experience, myself included back in the day, is you don't really notice these things from the get go. And you might type out all of your logic and feel good about your program try to run it and the thing doesn't work because of something stupid like you forgot this. So the key takeaway for today especially is don't get frustrated by the stupid stuff. You're absolutely going to bump against walls, not quite seeing what someone like I might see after all these years of practice. But in just a few weeks time, you'll start to notice patterns. And the mistakes you might make in the first week are going to be much more obvious to you in the second and third and beyond. So this then would be a function in C. Let's combine it as a complete program, which we did see a glimpse of last time. So if you were to implement this same program, hello, world in C, these are the several lines you would have to type. You can't just type printf. You have to sort of set up the program. Now why is that? Well, we can tease this apart by looking at just a few of the keywords in this example here. So highlighted now in yellow is main. And some humans, years ago, just decided, you know what, when another human is writing a program, he or she has just got to call their function, as we'll soon see, main. They could have called it anything they want but main is kind of a nice word for it the main part of your program. So this is the equivalent of our when green flag clicked in the language called C. Meanwhile, if we highlight another key word printf, this is going to be the C equivalent of the say block in purple. So printf is just going to print something on the screen. Meanwhile, in yellow here now is what we're going to start calling a string. A string is just a technical word for sequence of characters or words, phrases, paragraphs, whatever it is. So that is a string highlighted now in yellow. And notice that it's sort of being supplied, as we'll see, to printf. If it's immediately coming after the word printf just like hello, world in the white box immediately came after the word say. And now things get a little more arcane now highlighted in yellow is stdio.h. Definitely the most cryptic of the key word so far. This happens the stand for standard inputs and outputs. And that's just a fancy way of saying this file, as we'll soon see, is somehow related to printing and somehow, which is output, and somehow related to keyboards, which is input. So somewhere in that file, we'll see is this sort of functionality that you would hope a computer would have. Outputting stuff and taking input. And so we'll see that that's where we get that kind of standard functionality. Scratch does not have an equivalent. It just all kind of works, which is nice in Scratch. Meanwhile, this keyword, include, we're going to see, is literally just saying that. Hey computer, please include standard input and output functionality so that I can do something interesting with my program. And without that line of code, you couldn't do as much in this language, C. Now let's look quickly at a few other puzzle pieces, a few concepts that intuitively are probably pretty straightforward. And then we'll transition partway through today to actually writing code and lots of actual examples and running the code as well. But last time, you might have implemented an infinite loop, one that just goes forever, with a forever block. And in Scratch, you would then have a say block or something else on the inside. Starting today, that same puzzle piece is going to look a little weird. It's going to look like this. While (true) printf hello, world. And frankly, there's a bunch of different ways you could implement this. I'm just sort of choosing the simplest, relatively speaking, or most canonical. But why is this the same? Well, I've highlighted in yellow the first line, while true. And while-- it's kind of a nice word in English and so far, it just kind of intuitively suggests like, while something is happening-- that's kind of loop like. And meanwhile in parentheses, this is a Boolean expression Scratch had these by dragging and dropping those puzzle pieces on the equivalent block when you had conditions. But in this case here, we're just saying while (true). So (true). (true) is like yes. And the other day, we said yes is kind of like the number 1 whereas no is like false or the number 0. And that's great because if we have a true, false world or a yes, no world, or 1, 0 world that wonderful [INAUDIBLE] to the hardware we all have on our laps and in our pockets, which is a computer based on transistors and electricity and all of that we're going to now abstract away from. Don't care how electricity works today and I don't care how 1's and 0's. I just know that I can represent 1's or 0's, 1's or 0's. Or equivalently (true). So while this lamp is on or while this lamp is (true), printf hello, world. So the reason, logically, that the code you have on the screen there prints hello, world forever is because it's as though we've never turned the light bulb off. It's just while it's on. Keep doing this doing this doing this doing this again and again and again, just like in Scratch. Meanwhile, we might also do the following after a number of iterations of that. We might have a finite number of iterations with this repeat block. This one says, of course, repeat the following 50 times. Now this one is going to look a little uglier, for sure. This is probably the most conventional way to translate this Scratch block to C. Now it looks like a lot all at once but again, after a couple of days, couple of weeks, you'll start to see the patterns. Let me highlight some of the features of this code. So highlighted in yellow here is what we're just going to call an initialization. This says, hey computer, give me a variable, call it i, just because. I could have called it anything. And initialize it to 0. So again, just like an algebra, you might have x equals 0 or y equals 0 this is just equal 0. And even though we haven't talked about this, you might be able to guess what does this keyword, int, perhaps mean? Integer. That's right. I mean, we didn't have the same idea in Scratch. In Scratch, if you want a number, you just type it. If you want a word, you just type it. But in C, you have to be a little more uptight. You have to actually tell the computer what type of value you're putting in your variables. They're not just going to be numbers, integers. Turns out we can put strings, we can put trues and falses, we can put other things as well down the road. So this is just saying, hey computer, give me a variable that's going to store an integer, a number, like negative 1, 0, 1, and so forth, but initialize it to 0. Make it the number 0 by default. And that's it. Succinct, if cryptic way of saying it. Then this block of code says the following. Hey computer, just to be safe, is i less than 50? That's a Boolean expression, true or false? So is i less than 50 at this moment in time? Obviously, because it's 0. That's of course, less than 50. So the computer then does the following. printf hello, world. So it initializes the variable. It checks that it is less than a certain number, 50 in this case. And then if that condition is true, it proceeds to print hello, world. And even if you've never seen code before, perhaps by process of elimination, what step is probably going to come next? What am I next probably going to highlight on the screen? Yeah, the i plus plus. Not obvious what it does quite yet but you can perhaps guess i plus plus is a conventional way in this language to just say, you know what, go ahead and change i's value by 1. So if 0 becomes 1, 1 is going to become 2, 2 is going to become 3 and so forth. But for now, we're just changing 0 to 1. So at this point in the story, i is 1. What does the computer do? Now, it just kind of repeats things bunches of times. It's going to check again, hey, is i less than 50? Simple question. i is 1, so is i less than 50 now? Obviously so. And so it's going to print hello, world again. Then it's going to increment i. So Now it's 2. It's going to double check that condition. Is 2 less than 50? Obviously, yes. And then it's going to print hello, world. It's then going to implement i again, which is going to become 3. It's going to double check that condition. Is 3 less than 50? Obviously. And then it's going to print hello, world. And it's going to continue that process, take a guess, how many times? 50 in total because eventually-- and we won't bore ourselves with the whole story-- i is going to equal 50 because of a whole bunch of plus pluses. And at that point in the story, the computer's going to ask the question, is 50 less than 50. No, obviously not. And at that point, the code stops executing. And whatever is below it in your program-- like lower in your file-- that's what's going to happen next, even though there's nothing pictured there. So again, cryptic. But it follows this pattern. And once you sort of get comfortable with that pattern, you're going be able to bang this out on a keyboard and just know what it's supposed to do without even having to think about it so methodically. Now the other day, this was perhaps the biggest set of puzzle pieces we played with in person, even though it's probably just a small piece of some of your own Scratch projects now. But it actually maps pretty nicely to C code. It's not colorful in the same way. But you'll see that the other day when we asked is x less than y, in code, it actually looks pretty identical. In fact, it might be a little simpler to look at. We just have some parentheses. We have the less than sign. And of course, x and y, which in this context, are assumed to be variables-- like x and y in algebra. Where do they come from? I have no idea. In this context, we're just assuming this is part of a bigger program. So if x is less than y, print out x is less than y. Else if x is greater than y, print out x is greater than y. Else print x is equal to y. And so just like this yellow puzzle pieces kind of are embracing the purple puzzle pieces, similarly do you have these curly braces, which maybe you have never actually had occasion to use on your keyboard. But odds are, they're, probably around your Enter key on a US keyboard. These are like sort of wrapping the lines of code that you want to actually execute. Now there's a curiosity I haven't called out just yet and we'll come back to this-- this this weird backslash n. We'll see why that is there in just a moment. So let me pause for just a moment because that was already a mouthful. Any questions on functions or on loops or on conditions as we begin to translate them from Scratch to C? Anything at all? Yeah? AUDIENCE: Why are there two plus signs and not just one? DAVID MALAN: Good question. Why are there two plus signs and not just one? If you have just one plus sign-- and we'll actually see this in a bit in an example-- that literally means add one number on the left to one number on the right. So in this case, it's just because is kind of the trite answer. It's because if we want to have this special operation where there is no number on the right, you're just adding 1 to the number on the left. Humans, years ago, just decided plus plus is pretty succinct and it's not used for other purposes yet. So that's all. Yeah? Yeah, right there. AUDIENCE: [INAUDIBLE] DAVID MALAN: Correct. I wouldn't start thinking about it as having a loop inside of it because we'll eventually see that you can literally put another for loop, as it's called with the key word for, inside of another by indenting it inside. So think of when you're looking at a for loop-- like the one we just saw a moment ago-- the loop as really being all four of these lines. And like something is just kind of happening cyclically around the whole body of that code, so to speak. Other questions? Yeah? AUDIENCE: Why do we in for the main method? DAVID MALAN: Why do we use int for the main method? Let me take the fifth on that for just a moment. What you're alluding to, just to be clear, is this example here whereby in our most canonical sort of simplest, relatively speaking, but program that does the least amount of work possible, we also mentioned int here. We also mentioned this curiosity here, void. Let me just defer that answer for a little bit until we have a vocabulary with which to answer that. All right. So we've looked then it functions, at loops, and conditions. But there are a couple of other puzzle pieces that we looked at before. But for now, we're going to take those as our sole translations, just to kind of give you a taste of the fact that even though the syntax is different, you might have never heard of typed these characters on your keyboard before, the ideas today are exactly the same as last time. But of course, even as we humans begin to write code-- code is just characters on the screen like this-- the problem is per our first lecture computers don't speak pseudo code. They don't speak English, per se. And they don't even speak code, per se. What's the only language we claim computers understand? 1's and 0's or binary. At the end of the day, they only understand 0's and 1's and they can do a whole lot with those 0's and 1's. But somehow, if me, the human, am going to type stuff like this on my screen before my Mac or PC can understand it, unfortunately, I'm going to have to literally convert it to 0's and 1's. And back in the day-- back even on this campus years ago-- you might have heard of punch cards growing up or in a history book or the like which effectively captures symbologies like this, people did way back in the day program in binary, at least early on. Then they invented other languages that were a little nicer to use and then they invented other languages that were yet nicer to use. But at the end of the day, our computers, Intel Inside, still just understands this. But thankfully, we the humans don't need to worry about why those 0's and 1's actually mean, hey computer, print hello, world on the screen because of the following. We henceforth are going to write source code. And that's technically what you did with Scratch. Even though you dragged and dropped puzzle pieces, you were writing source code. Sort of human like syntax that's just more digestible for us. But we ultimately need to convert source code to what's called machine code-- 0's and 1's that Intel CPUs or other CPUs actually understand. Thankfully, humans have come before us have invented software, generally called compilers, whose sole purpose in life is to translate source code like we've been seeing on the screen into machine code 0's and 1's. And in fact, this is a whole research area in computer science as to how to do this well, how to do it quickly, especially for really big programs. This is a tool that we'll use as a tool in the CS50 so as to not worry about how those translations actually happen. And to do that, we're generally going to use all the same environment-- something called CS50 IDE. IDE stands for integrated development environment, which is just a fancy way of saying a computing environment that's identical for all of us. Because frankly, especially when getting into programming, one of the easy frustrations can be following a whole bunch of directions on one's Mac or on one's PC just to get your environment to be identical to someone next to you, but invariably, some of us have different browser versions, some of us have different versions of Mac OS or Windows. And it's just a massive headache trying to get everyone onto the same page. And so increasingly in industry, it's very common, even within companies, for everyone to have kind of a uniform development environment, even if they don't all have the same computers. And so what you'll begin to have access to today and even after the course ends is an environment that looks like this. It's web based, this integrated development environment. And those of you who did take some CS before, it's similar in spirit to Eclipse or NetBeans or Visual Studio or tools like that. But if you're not familiar, you can just think of it as a web application. A site that you're going to have usernames and passwords on that's going to allow you to log in and see, essentially, an environment like this that has a big window here where you can write code, like we've been seeing on the screen thus far. It's going to have what's called a terminal window at the bottom where just like we're about to do today, you can type some lower level commands and tell the computer what to do, even without using a mouse. And then much like Mac OS and Windows have, you'll be able to see all of your files and folders. This is in the cloud though, so to speak. And so you have some number of gigabytes in the cloud and you have only access or you or your teaching fellow, if you grant him or her access, will have access to this environment. And you can, of course, then access it anywhere on the internet. And frankly, even if you don't have good internet on a vacation or while traveling for school or for sports, you can also download an offline version as well of the same environment. So there's also night mode too, if you're that type. But let's see actually how we use this environment. But really, at the end of the day, how we program. So I have logged in in advance already to see CS50 IDE. I put myself in night mode here. The address is CS50.io and you can follow along here if you'd like. But probably better to do this at a slower pace on your own, whether for problem set one or later on today. And so let me go ahead and write my very first program. I don't really care about what's going on the left because I have no files and folders yet except for this folder up here. By default, all of you will have your own workspace folder and that's where all of your problem sets and files can go. But I'm going to go ahead and hide that by clicking this folder icon, just to kind of simplify what we're looking at. And now there's two parts to the screen. The code editor up here where you can write code-- not that. And then this so-called terminal window down here. So let me go ahead and write my first program. I'm going to go ahead first and do File, Save, just like on a Mac or PC. And I'll call this hello.c. By convention, any program you write in this language called C is supposed to end in .c. Just like in Scratch, somewhat oddly, it ends in .sb2, if you noticed on your Mac or PC. With C, it's literally just C. And by convention, always use lowercase. And by convention, don't use spaces. Use underscores or hyphens-- something like that when making files. Otherwise, it just gets harder to find things in your workspace. So now I have a file or a tab called hello.c. I can do this pretty quickly because I've done it before. But I'm going to go ahead and type out that program we keep seeing. Quote, unquote "hello, world", semi-colon, and save. Now you'll notice that somehow, my code is all very colorful, even though I just kind of typed that out on my Mac's keyboard. You would see the same thing on your PC. That's just because a lot of IDEs, integrated development environments, just color code your source code for you to kind of draw your attention to the functions, to draw your attention to other key words. It has no meaning and it's not stored in the file. This is just kind of a graphical user interface feature that you get automatically. But how do I run this program? Like on your Mac or PC, how do you typically run a program? AUDIENCE: You click on it. DAVID MALAN: Yeah, you click on it. You probably double click an icon. On Android or iOS, you just tap an icon. But with programming environments, you can make that possible. And on Macs and PCs, you can absolutely write software as simple as this, save it, and then double click on an icon. But the reality is, for aspiring computer scientists or data scientists, or really, just anyone who wants to do more powerful things with computers, you can actually do a lot more with your keyboard, even if you don't type all that quickly. Because nothing we type at the keyboard is going to be all that long or verbose. But you'll find it's just a lot easier and more flexible because you can do more than today's graphical environments do. So this is all to say that if I want to run this program now, I need to actually compile it. Recall that compiling meant taking something that looks like this in code and converting it to that. So I somehow need to run my source code through a compiler in order to get machine code. And there's a few ways to do that. The first way I'm going to do that is as follows. I'm going to click in the blue part of my screen, which henceforth, I'm just going to call a terminal window. It's an old school term just describing a prompt where you can type words and commands. Zoom in here. And I'm going to do the following. clang, for C language-- it's a compiler for the C language-- and then I'm going to type literally, hello.c. And you might not be in the habit of doing this on Macs and PCs these days, but if you grew up with Dos or with Linux or some operating system, you might have. But now I'm going to hit Enter. And nothing seems to happen. And in this programming environment and CS50 IDE is running an operating system called Ubuntu Linux, which is sort of different but similar in spirit to Windows and Mac OS, nothing happening apparently is generally a good thing. Because if you don't see an error message, it means the computer has nothing to complain about. So what can I do next. Well, notice the following. If I open up my file browser up here, a couple of things have since appeared. A couple of minutes ago, there was nothing except my workspace. It makes sense, probably, that hello.c now exists because I made that. I went to File, Save. But what do you think a.out is? It seems to be another file but I did not type this word. Yeah? AUDIENCE: [INAUDIBLE] DAVID MALAN: Say again? AUDIENCE: [INAUDIBLE]? DAVID MALAN: Another file? AUDIENCE: Executable file. DAVID MALAN: It's what I can execute, exactly. So when I ran the compiler called Clang on my source code, I promised in the slide a moment ago, that's going to output machine code-- 0's and 1's. It would be a little annoying if it literally just spit out 0's and 1's on the screen because that's not useful for me and the computer doesn't need to see it on the screen. So all those 0's and 1's got saved in a file called a.out, just by convention. a is the first letter of the alphabet and out is output. Though the origins are a little fancier than that. But that's all-- just the default filename. So how do I run this? Well, on a Mac or PC, I would generally click it. But that's not how I'm going to do this in a command line environment. And that word-- command line environment or CLI is the acronym-- I literally have to do everything at the command line-- by typing commands with my keyboard. And the way I do this is the following ./a.out. So dot means look in my current directory, wherever I am, like my workspace. Slash is just a separator that you've probably seen on Macs and PCs to separate folder names. a.out is the name of the program. And so now when I hit Enter, it's as though I just double clicked on an icon on a more modern graphical interface, like Mac OS or Windows. But I would argue this program is a little bit buggy, right? My screen, beyond just looking sort of new to most people here, it also looks a little stupid at the moment. Why? Aesthetically. Yeah? AUDIENCE: It's on the same line as hello, world [INAUDIBLE] workspace. DAVID MALAN: Yeah. I mean, hello, world in white is on the same line is that workspace keyword. And the workspace is just reminding me every line where I am. Because again, it's not graphical right now, it's textual. So I'm literally seeing in blue where I am, what folder I'm in. And frankly, this just kind of bothers me. I'm a little sort of anal and I don't like how this looks. And arguably, it's a bug. But why is that? Well, it's simply because the computer took me literally. In my source code up here, notice I deliberately made this mistake or inconsistency with what we saw a moment ago. I omitted something from this line. What was that? Yeah, the backslash n. So what role is that clearly serving? Well, backslash n is an explicit way of saying, hey computer, put a new line here. Hit the Enter key here. And it's explicitly written as backslash n only because doing this-- it's just feels messy and kind of non-obvious what's supposed to happen. So programmers, years ago, decided, you know what, we're going to express the notion of hitting Enter symbolically with backslash n. That's all. So now, if I go ahead and save the file, which I can do with command s or control s or you can be more explicit and go to File, Save, just like on your own computer, and now I go ahead and run ./a.out, Enter-- damn it. What's wrong? Yeah, I have to recompile. So again, this is a process. I saved the file. My source code is now correct. But my machine code is outdated because I haven't recompiled it. Again, the computer is a pretty dumb device at the end of the day. Fast though it may be, it's only going to do what I tell it to do. So down here, I had better do clang hello.c again. Nothing seems to happen. But odds are, that changed a.out. So indeed, if I do ./a.out, now I see hello, world. It puts a seemingly invisible line break on the screen. But now, everything looks a little cleaner. But clang hello.c of course, yields a pretty stupid file name. It would be nice if I could actually name my program hello or hello, world or something like that. And we can do this in a couple of ways. So let me go ahead and zoom in down here again. I'm going to clear the screen just to keep things neat. And it turns out I can supply commands like clang and others we'll eventually see with things called command line arguments. I can actually specify, you know what, clang, instead of just taking hello.c as your input, also do this. Output a file name called hello. And this varies by program. clang is not the only program we're going to see in this blue terminal window. This is now saying, hey clang, output a file called hello and take as input, that same files before, hello.c. Why? Well, humans years ago decided O is the first letter of the word outputs. Dash o is a nice way of saying output. So dash o hello means output a file called hello instead of your default, a.out. Again, nothing seems to happen but if I zoom out, look in my file browser, you'll notice now I have the old a.out and hello in addition to my source code. So just intuitively, how do I go ahead and run this new version called hello? It's ./ because dot means here. Slash just separates here from the file name. Hello, enter-- same exact thing. Now I keep opening the file browser and closing it just so we can kind of see things graphically. But even that's not necessary. It turns out that in a command line environment, you have a whole bunch of commands. For instance, I can type ls, which is a succinct way of saying list. Hey computer, list all of the files in the current folder. The current folder is called workspace. That's why I keep getting reminded of in blue. And now you'll see three things-- a.out with a star, hello with a star, and hello.c. And they're also color coded. It turns out that in most text environments, if you configure them this way, any program is highlighted in green and it has a little star next to it, which means it's executable. You can run it. Not by double clicking but by doing dot slash program name. Anything in white here is just a text file, like hello.c. I only have one of those. And it turns out if I had folders, I would actually see their names as well. And I can create folders just like in Mac OS and Windows in a couple of different ways. I can actually go with my mouse up to my file browser up here. I can Control click or right click on there and I can scroll down to the bottom and say, New Folder. And when I do that and zoom out, you'll see new folder. And maybe I want to do this for pset1 one, problem set one. And hit Enter. And now I have a folder called pset1. I can see this in my command line environment by typing ls again, Enter. And now notice, I have those same two executables programs that same text file, hello.c. And now a directory in blue called pset1. And the trailing slash just indicates, hey, , human I am a folder. So how can I open pset1? Well, in Mac OS and Windows, you would, of course, just double click and things would expand and show you what's inside. But this is again, a textual environment. So let's put that away, go down here, and change into pset1 as follows. CD is another command in a Linux environment. And again, Linux is just another operating system like Mac OS or windows that we are running in the cloud for you. And if I do CD pset1, with or without the slash, doesn't matter, and hit Enter, my prompt just changed. And my prompt is just literally the words on the screen just reminding me where I am. In blue, it previously said workspace. Now it says workspace/pset1 because I have done the equivalent with my keyboard of double clicking on pset1 and opening it up and going into it. So just a guess now. If I type ls inside of my pset1 directory and hit Enter, what should I see? Hopefully, nothing because it'd be a little weird if all I did was create a folder and suddenly, there's stuff in it. And indeed, there is nothing in it. Hitting ls and then Enter just shows me nothing, which means nothing is in it. Meanwhile, if I decide this was a mistake, I'm getting ahead of myself, I can go back. And this might be a little non-obvious, but cd space dot dot means go back one directory or technically go into your parent. You can actually think of your Mac or PC folder structure and the IDEs as this tree. Like a family tree. And I just went down into the child of workspace called pset1. So cd dot dot Takes you back if you prefer that mindset or takes you up if you prefer the family tree mental model. If I hit Enter now, my prompt changes back to workspace. If I type ls, I'm comfortable again, I see the things I know. And if I want to remove that directory, I can just type rmdir, for remove directory, pset1. And it's gone. And I can confirm is much with ls. So in short, this is the textual way of doing things that you've probably been doing for years on your Mac or PC or even phone these days. OK. So none of that is sort of intellectually interesting. Like we learned how to make files and folders. Let's now actually dive in deeper to some of the code and the ideas with which we actually solve problems. This first program didn't do all that much but it did kind of express an idea. And we're going to start to take for granted even more so what a function actually is. And maybe just to make this point clear, let me go ahead and do this. Let me change the screen to just a blank canvas. That's all the circles I was drawing earlier. Get one volunteer, maybe exchange for a stress ball? OK, very quickly, come on up. What is your name? AUDIENCE: Sam. DAVID MALAN: All right. So Sam, we have a name tag here for you. But instead of calling you Sam, we're going to call you for the moment printf. So if you don't mind, hello, my name is printf. AUDIENCE: Hello, my name is printf. DAVID MALAN: OK, thank you. Put that wherever. All right, you can stay there for just a moment. I, for the moment, am the programmer on my computer here. And my goal is to simply print out onto the screen hello, world. Now I've been programming for years. I have different monitors over the course of the years. And I don't really care how the words I type in my program actually get on the screen. I kind of want to delegate that functionality to someone or something else. And thankfully, Sam has been programming for some time. He knows how to talk to computer screens or print things out on the screen. And so I can literally kind of outsource functionality that I want to use. But I don't want to care about how it is implemented or how Sam implemented it by just kind of calling Sam over and asking him to do something. So in this case, Sam, you are now actually printf. I'm going to go ahead on a piece of paper and I'm just going to tell you, if you don't mind, by passing you input, I'm going to hand Sam a slip of paper that literally says, hello, world. And if you don't mind, can you go print this on the screen since you are indeed, printf. And you can do so just with your finger on the screen. So here I am, the computer program. I have no idea how print is working. I just know that I wrote a line of code. I ran the program. printf is in motion. It's doing its thing. And perfect. Sam, come back to me. And now Sam is done executing, if you would. Thank you very much. And that was ridiculously belabored way of making the point that functions aren't intellectually all that interesting. It really is just this packaging up of functionality that I don't necessarily need to know or care how it works. But I want to get the job done. And in fact, we can do one more job. If you don't mind changing your name for just a moment. How about in exchange for two stress balls? So now I'm actually going to call you or rename you get_string Because it turns out that in the computing world-- technically, it doesn't add all that much to put this on, but that's OK. So in the computing world, there's a whole bunch of other functionality that you can use, some of which is CS50 specific. But most of which, is not. And so in fact, if I go ahead and open up here this list, some of the functions we're about to start using and taking for granted are these. get_char or get me a character. get_int for get me an integer. get_string for get me a string or a sentence. get_float for something even different. And still, I don't know how those work. I don't really know how keyboards work or where the input comes from. But thankfully, someone else did. Sam, in this case, he implemented get_string. And so now, if you wouldn't mind, Sam, I'm going to write another program with you right there. And it's going to look instead like this. I'm going to go ahead and create a new file called string.c. I'm going to go ahead and do include stdio.h. Int main void, which is just copy and paste from before. But instead of just typing out hello, world, I'm going to do this string s get_string name. And then I'm going to do printf quote, unquote, hello comma percent s backslash n s semi-colon. Now what is going on? We'll come back to line 6 in a moment. But line 5 is now doing two things on the left hand side, it's declaring a variable called s that's going to store, apparently, what type of data? A string, which is like a word or sentence or paragraph or whatever. It's characters from the keyboard. And what's going to go inside of s? When we talked about variables earlier, we put inside of another variable called i, the number 0. Here on the right hand side of the equal sign, we're instead putting the name of a function, which is kind of interesting. Because before, when Sam was a function called printf he just did something and he came back to me but he didn't hand me anything. I just sort of thanked him and moved on. But in this case, I actually want Sam, if you would, just go into the audience for a moment with this pen and piece of paper, just go literally get me a string. Get me the name of someone, if you could. Anyone you want. So again, I have no idea how this is implemented. It might have taken Sam five lines of code, 20 lines of code, 100 in order to support the process of getting input from a human. But what's different in this case of this function is he's going to now come back to me and not just be done executing. He's going to actually bring something back to me and we're going to start calling this-- thank you, Sam-- a return value, the name of which is Katrina. And so he's literally handed me what we're going to call a return value. I'm now going to go ahead and do something with that. And how do I plug that into my string? I do that with this line 6 here. I say printf, not just hello but, hello comma percent s. Percent s is just a cryptic way of saying put some string here. What string do I want to put? Well immediately after the comma, notice that I've mentioned the name of the very variable, s, into which I stored whatever it was Sam handed me. And so we're not, for every function we write, use an actual volunteer. But that's all that's happening. I have no idea who Sam was going out to reach out to. I have no idea whether he was going to write in cursive or in non-cursive writing on the screen. I just know that he was capable of doing that. So if we could, maybe just a quick round of applause for Sam here. Thank you. So suffice it to say, there are other functions, not just get_string. But if you want to get an int, there's another function for that. If you want to get a single character, get_char is another function for that. But there are other things here too. Double and float and long_long and whatever those actually mean. Well, it turns out that computers, especially with languages like C, you do need to be super precise as to what types of data you're actually storing in them. And so you have to specify in advance, is it a string, is it an int, is it something with like a decimal point, not just an integer. So let's actually go ahead and do a different example here as follows, this time using an integer. I'm going to go back into the IDE. I'm going to go ahead and create myself a new file called int.c. and I'm going to go ahead and start the files before, include stdio.h. Int main void. And then here, I'm going to do this time, int i get_string integer semi-colon. And then printf. How about just hello percent-- not s, because s is for string-- but percent i, for integer, backslash n and then semi-colon. This looks like a complete program, even though we've not used-- sorry, bug-- get_int. So it looks like a complete program, even though a lot of the syntax might be new to you. So let's go ahead and try to run it. How do I run this program? I can't run it yet. What's step one? Yeah, I have to compile it first. And how do I compile it? Yeah, so clang. I can do dash o. I can call this int because if I want the name of the program to be int. Frankly, this is just annoying. I don't want to have to constantly type clang, dash o, name a file. I just want to make the program. I won't have to care about this. And it turns out there are ways to do that. Because installed in the IDE for you is a very popular command literally called make. And make allows you to type literally just this-- make int. You don't specify .c. You just specify the start of the file's name. So if it's int.c, you say int. If it's hello.c, so you say hello. And you literally just write make int. And make is a different program. It's not technically not a compiler. But it's a program that knows how to use a compiler. And when you hit Enter, notice the crazy long output that it spits out. It mentions the words clang but then it mentions all of these other command line arguments that you would never want to try to remember or let alone type out yourself. It would be incredibly tedious. But that's simply because we, the staff, pre-configured the IDE to just configure clang in a certain way to give it certain features without you having to enable these features yourself all the time. But unfortunately, even though I tried to compile my code, this cannot possibly be good. Seeing three errors in a program that is barely three lines long. This is not very promising. Well, turns out you needn't get overwhelmed when you see bunches of errors on the screen after writing a program because sometimes, the computer just gets confused. And the most important error is probably the very first one that the computer noticed because the others might just be dependencies sort of resulting from that first error. So don't get overwhelmed by the number of errors. Instead, look at the very first and you'll see this. Implicit declaration of function get_int is invalid in C99 and then some other cryptic stuff. And then I see one line of my code as the third line of that output. I really don't know what that means offhand. But it does seem to be an error somehow related to get_int. Now why is that? Well, turns out that get_int does not come with C. It's sort of a training wheel that we use for the first few weeks of the class before removing those training wheels just to make it easier in C to get input. In Scratch, you just already have a lot of puzzle pieces that make it easy to do things. In C, you don't. If you simply want to get input from the user, you actually have to jump through a few hoops, so to speak, and write more lines of code than might be ideal. So we the staff wrote what's called a library, a collection of functions-- like a whole bunch of Sam's-- that know how to do very specific things. And we gave them names like get_int and get_string and so forth. But the catch is that therefore, because CS50 made them, they're not in the standard input and output library. They're in the CS50 library. So if I want to use some of this functionality in the course's first week, I actually have to add one more inclusion. I have to say, hey computer, also include not just the standard input and output library where libraries are just a collection of someone else's code and in this case, used to contain just printf. But now the CS50 library also contains get_int and get_string and other pieces of functionality. So let me go ahead and save the file, go back down to my terminal window here. And now rerun make int. Crossing my fingers, Enter. Dammit. What actually happened here? It's my second bug but it's progress. Now I'm down to two red errors. And this time it says, error, more percent conversions than data arguments. I can kind of wrap my mind around that. But notice, I haven't practiced what I preached a moment ago. What is missing from line 7 that I've highlighted? AUDIENCE: You have to put a comma after the string and then include the variable. DAVID MALAN: Yeah, exactly. I have this placeholder, percent i, says put an integer here. But I didn't finish the thought. Like some Scratch puzzle pieces have multiple white boxes into which to type or drag other puzzle pieces. So I haven't finished the thought. I need to actually say what value do I want to plug into this string. And you do that in C by separating your inputs with commas. And in fact, these inputs to functions are called parameters or arguments, depending on the context. And so what argument do I want to pass in? Well, I want to pass in i as a second white box in a scratch puzzle piece that somehow influences the first input, otherwise known as an argument. And now, if I really cross my fingers after saving the file and rerun make int, I get no errors. And no errors is good. And now if I type ls, what file should I hopefully see among my others? Hopefully a program called int. And indeed, there it is in green with a star after it meaning, I can do dot slash int, integer. Give me a number. 3, I heard first. Hello, 3. Let's run it again. I heard 6 earlier. Hello, 6. And we can do this all day long unless I get a little random and type monkey. But the program is going to notice that. And that is some of the functionality you get from library code. We took the time, staff, to implement get_int in such a way that if you, the human, don't give us an int, we're just going reprompt you, reprompt you, reprompt you. So in this case, typing a word doesn't work. Typing something like 1.23 doesn't work because that's not an integer. That's what we're going to call a real number. But really, a floating point number, where there's literally a point in it. But if I do type something like 42, then I get my hello 42. Let me pause there because that was a lot and it was a lot lower level for any questions. Yeah? AUDIENCE: So I get that you all made a library for us to use. But when you just a hashtag [INAUDIBLE] library, where is it getting it from? DAVID MALAN: Really good question. So when you just put that one line of code at the very top of the program, where is the code? It has been pre-installed somewhere in the cloud, literally in some folder in your CS50 IDE. And because we have installed industry standard software, that software, like Clang, literally just knows where to look on the hard drive to which you have access. So we have a file that we wrote in the past called CS50.c that literally has all of the C code that implements it. In CS50.h, there's really just a summary. A .h, we'll soon see, is called a header file. And it literally just has a succinct summary of the functionality to which you have access so that you simply have to write one line and therefore, you get access to the whole toolbox of functionality in CS50's library, in the standard I/O library, or in something else. That's what you get. Yeah? AUDIENCE: [INAUDIBLE] and then like, hey, [INAUDIBLE].. DAVID MALAN: Exactly. You can use any of these functions. get_int, get_float, get_string. And we haven't even talked about what some of those are. But so long as you store it in the right type of variable, changing into to string or string to something else, then yes, you can use any of those to just get input from the user so that your programs are actually dynamic. They're not going to involve mouse clicks and so forth. But at least you can take textual input from the user. Let me go ahead now and open up a program that I wrote in advance. Let me go ahead and grab this here. And it's called ints, plural. And I'm going to go ahead and open this as follows. So this is code that's already on the course's web site too, so you can take a look at it at any time. But it's a little more complicated. But it looks as follows. So at the top of the file, notice it starts with slash slash. Turns out that programming languages like C support what are called comments. Comments are not code, they're just kind of sticky notes to yourself that remind you or someone you're working with or your teaching fellow what the program is supposed to do. And in this case, I want to demonstrate integer arithmetic, whatever that soon means. Now I have a couple of includes and I've clustered them. I put some blank lines but that's just kind enough to keep everything neat and tidy. It's not strictly necessary. Here, I have main and we'll come back next time most likely to tease apart why we have ints and why we have void. But for today, let's just assume that that is the equivalent of when green flag clicked. And now we have a few lines of code here. I have two comments which literally tell you what's going on-- prompt the user for x and prompt the user for y. Beneath each of those comments is the actual lines of code that do that. And how do you think about this line of code? It's pretty similar to what we just saw, albeit with different names. On the left hand side of line 9. We're saying, hey computer, give me a variable called x and plan to store what type of data in it. int, an integer like a number. Then then on the right hand side, it literally calls get_int, which is like another version of Sam that goes off and gets an integer from the user where the user, he or she types it at the keyboard, hits Enter, and then get_int returns it to the program. And because that get_int is on the right hand side of an equal sign, that value, just like Sam handed me a piece of paper, is going to get transferred from right to left and stored in the variable on the left hand side. So if I type in the number 1, x is going to contain the number one. Meanwhile, if the next number I type is the number 2, the variable y is going to store the number 2 from right to left. And now this is a little overwhelming at first glance but it's just a copy paste of some of the same ideas. Perform arithmetic. So I wanted to demonstrate in this program a few arithmetic operations that C supports. You can add numbers, subtract numbers, multiply, divide. Might not be obvious what symbol to use and that's why we see this. On line 15, we see the following example. We have the string here, which says plug in some value, then literally say that word plus, then plug in some value, then literally say the word "is", then say the third value. All of these values are integers, because after this highlighted string, I have three additional inputs to this printf function. Three additional values to plug in: x literally, y literally. And it turns out if you want to do math in C, you literally just type x plus 1 and that will return 1 plus 2 or whatever the values actually are. And again, there are three values separated by commas here because there are three placeholders on the left hand side. Meanwhile, the rest of this is just like copy paste of that but with different words and operators. So something minus something is something. And how do I get that output, x and y and then x minus y. So minus is what you would expect it to be. x something times something is something. Well, that's x comma y comma x star y. So the asterisk in C represents multiplication. And then x something divided by something is something x y and then x slash y gives you division. And then the last one is probably the only weird one or one that you've never like typed out on a keyboard. The remainder of something when divided by something is something. And that character is the percent sign. So you have probably never written that as a command unless you've done modular arithmetic but you've thought about it in grade school, probably. Divide one number by another, what's the remainder? This percent sign is how you express that same idea. So let me go ahead and compile this program. And again, to recap, what's the most succinct way for me to compile a program that's in a file called int.c? Make ints. And again, we're abstracting away all those details. And this is going to be a pattern. Just when things seem really detailed and really nitty gritty, we sort of layer on top of it a simpler way of doing things and just take for granted that we know that something is happening underneath the hood. Make ints seems to have worked because no error messages. So ./int Enter. X will be say, 1. Let's actually do this. Let's do 2. 2 and 2, enter. All right, 2 plus 2 is 4. 2 minus 2 is 0. 2 times 2 is 4. 2 divided by 2 is 1. Remainder of 2 divided by 2 is 0. I think all of those actually do check out. But-- but, but, but-- I am a little curious that proof by example is not really a proof. So let's try it at least once more. 1 for x. 2 for y. OK, 1 plus 2 is 3. 1 minus 2 is negative 1. 1 times 2 was 2. 1 divided by 2 is 0? What should it be? Probably 0.5, right? Like 1/2. 1 divided by 2 is not zero mathematically. But remainder of 1 divided by 2 is 1. So for some reason, division is broken. Like, my computer does not apparently do division correctly. But why is that? Well, you can probably guess, even if it's not obvious, like why might this be? What is going on? Yeah? AUDIENCE: Looking for integer. DAVID MALAN: Looking for an integer. So divided 1 by 2 . And if the output has to be an integer because of the percent s, you kind of have to pick one way or the other. And so what a computer program does is it throws away everything at the decimal point. If you are using ints and ints should not have decimal points-- those would be real numbers instead, irrational numbers-- we're just going to throw away everything after the decimal point and we're left, of course, then with zero. Because 1 divided by 2 is technically 0.5. So we lose everything after the dot. So how do we fix this? Well, it turns out we can fix this in a couple of ways. But perhaps the simplest is to do the following. Let me go ahead and grab one other example that I wrote in advance. This one is called float.c And float is an allusion to floating point arithmetic. Floating point literally is referring to a period that can move left and right depending on what value you're trying to express. And in this case, notice I've pretty much just changed the program to use not ints anymore but literally, floats. So a third data type. We had string. We had int. And we had float. And float allows our numbers to have periods in them. And so now, if I do some arithmetic here, just one line of it, this is the same line of code as before. But now I'm using percent f instead of percent i to print a floating point value. Let's go ahead and make float-- Enter. ./floats. And let's try it again. 1, 2. And now I get the answer I actually expect. So that's kind of interesting. Now I just have to be ever more precise as to what's going on. So we have strings, we have ints, we have floats. Let me pause here to any questions now on what are generally called data types-- types of variables. Yeah? AUDIENCE: How do you increase the number of decimal points? DAVID MALAN: Oh, really good question. How do you increase the number of decimal points? So we can do this in a very specific way. So right now, we have one, two, three, four, five, six values printing by default. Let's say we want to do 10 instead. It's a little cryptic but I can literally do .10, which is just a official way of saying give me 10 numbers after the decimal point. And frankly, I forget these kinds of details all the time. You just Google and you can kind of pull that kind of information up. Let's go ahead and try it. make floats. And now ./floats. 1, 2. And now I get even more 0's after the decimal point. And you can go the other direction to sort of do implicit rounding as well. Yeah, question. AUDIENCE: Can you have the first two integers [INAUDIBLE]?? DAVID MALAN: Ah, good question. Can you make the first two integers and make the last two a float? So could I do int x, get int. int y, get int. And then change these, of course, to i, i, but leave this as just float. That's a good question. And frankly, not to be trite here, any time you have these kinds of questions, when you're on your own and not in an environment like this, literally just try it. And so make floats again. And that's not good but the compiler noticed that I was doing something that isn't legitimate to do. The compiler-- it's always a little cryptic, these error messages. But format specifies type double. Double, turns out, is a floating point value but with even more capacity for numbers after the decimal point. Long story short, float generally uses 32 bits, which gives you that many 0's and 1's with which to represent a floating point value or a real number. If you use a double instead, you get 64 bits, which per our conversation in the first lecture, just means you have even more range of values, or more precision. So we specify type double but the argument has type int. So the compiler caught it and we just can't do it. We could turn off this warning and we could try to do it but we might get unexpected behavior. Great question. And was there another question here before? No? OK. All right, so that's then a different type of value. But let's introduce now a few of those logical constructs that we promised were coming. Let me go ahead and do this. Let me go ahead and grab a file-- and all of these, again, are on the course's website-- called conditions.c. So here too is a program I wrote in advance that does a bit of logic. I again, am kind of following a pattern. So that each program kind of introduces just one or two new ideas. So I have get_int twice, storing the values in x and y. And then I'm just doing some logical operations. So this is really just copy and paste from what we saw before. But this, in code, is how I might compare two variables. Earlier I said, I have no idea where x and y came from, right? We looked at the example out of context. Now we have context. The few lines above we're calling get_int twice, storing the values in x and y respectively. So now, x and y actually exist in my program. So here on down, I'm just doing the exact same thing that really big collection of Scratch puzzle pieces did so if I compile and run this program, conditions.c, let's go ahead and see what happens. make conditions and now let's do ./conditions. 1 and I'll type in 2 and logically, what should this actually print? Hopefully, x is less than y. And indeed, that's exactly what the program does. If I run it again with 2 and 1, x is greater than y. And if I run it with 1 and 1, x is equal to y. So again, I've just translating to Scratch puzzle pieces in this case to see, to give me something a little different. But what if I don't want to just compare one thing? Very quickly in Scratch did you probably kind of construct scenarios where you want to check multiple things at once or you want to ask multiple questions, perhaps. Or even if not, odds are you'll cross that bridge before long. So let me go ahead and do another example. This one will do from scratch. I'm going to call this noswitch.c for reasons that will become clear in a moment. And I'm going to go ahead and include the CS50 library. I'm going to go ahead and include the standard library so that I can get input and print output. int main void, which is the one line we'll just take for granted today. And then here, I'm going to do the following. char c, get_char. And I just want this to be the user's answer. char is a single character, not a string, which might be a whole phrase or paragraph. And then I'm going to do the following. If c equals equals quote, unquote "y", then I'm going to go ahead and print out yes. else if c equals equals quote, unquote, "n", I'm going to go ahead and print out quote, unquote, "no" semi-colon. And that's it. So what's this program doing? Well, if you've ever run a program that has like a yes no button to click or maybe it is a command line program or you're using your keyboard and you have to type, yes, I agree to the terms and conditions or no, I do not, this is kind of like a super simple way of checking did the human type y for yes or n for no. So let's run this and then come back to why it's implemented in the way it is. So make noswitch. And again, I'll come back to why the name is what it is. Let me go ahead now and run .slash noswitch. Enter. And my answer shall be y for yes. It's buggy. what. Was I expecting? Yeah, I was kind of expecting if I hit y, then print yes. But let's think about what my code is asking. Wherein lies the bug? Why did my program not print Y-E-S? Yeah? AUDIENCE: It's not capitals? DAVID MALAN: Yeah, it's as simple as that. It's not capitalized. So here too, precision-- super important. I wrote a program that says if c, if the char the user has typed in equals capital Y, print this. Else, if it equals capital N, print that. I didn't do either of that. So the program is not broken per se. It's just missing a feature, if you will. It's lacking support for lowercase. But if I do do an uppercase Y, that, of course, works. So why is this written in the way it is? Well, there's a couple of details here. And this may be a question you would have based on your comment earlier. Why is it equals equals and not just equals, like in math? Seems a little weird. Yeah? AUDIENCE: One equals is for assigning values [INAUDIBLE].. DAVID MALAN: Yeah, it's the same kind of answer. Humans already used up the equal sign for a different purpose-- for assignment, as it's called. Move a value from the right to the left. So when they realized, oh shoot, we kind of painted ourselves into a corner, how do we now check for equality like in arithmetic? Well, you need a different symbol so the computer knows the difference. So equals equals means, unfortunately, equals. And equals means assignments. And that's all. And once you kind of remember that, it's all pretty straightforward but that's why. There's another thing I did a little differently. And this is an annoying detail. Why did I suddenly switch, do you think, to single characters-- dammit. Why, all of a sudden, did I switch to single apostrophes instead of double quotes, like I did before? AUDIENCE: Single quotes only work for characters. DAVID MALAN: Why, yes. How astute. Yes, so that's exactly it. Single quotes, as I just wrote, are literally meant for when you have single characters, like y or n in this case. Double quotes are used when you have multiple characters for proper strings. And we'll tease apart why that is on before long. But for now, that's literally the reason. If you're checking one character, it's literally single quotes. If it's more than one character, you absolutely need double quotes for multiple characters. But there's a way to fix this. I could certainly just kind of cheat, be like, OK, I fixed my program. So now I can do make noswitch. Now I can run noswitch again. And now I can type in y and it works. Unfortunately, now I can't type capital Y so this is all kind of dumb. So what would be a better fix, do you think, to the program up here? AUDIENCE: [INAUDIBLE] both of them. DAVID MALAN: Accept both of them somehow. So how would you do that in Scratch, for instance? What would you do? What kind of puzzle piece would you try again? AUDIENCE: Use an or. DAVID MALAN: OK, we can use an or. Exactly. So there's an or puzzle piece, which you may or may not have used. And I would like to be able to just type the word or but computers are generally a little cryptic, although some languages-- Python-- will literally introduce the word or again. In C, it's two vertical bars. And you just have to remember that. Two vertical bars allows you to say, if c equals equals capital Y and down here, I can say, if c equals equals capital N, now I can ask two questions at once. And so now if I zoom out and recompile this, make noswitch, Enter. And then go ahead and run next here dot slash noswitch. And now I can do lower case y, I can do capital Y, I can do lowercase n, I can do capital N. But I can't do like a question mark because there's no support for that. s doesn't work either. It wasn't one character and the last was not y or n. There's another way it could have done this. How else could I have implemented this, especially if I didn't even know that these two vertical bars existed? What other puzzle piece or a block of code could I use? AUDIENCE: [INAUDIBLE] DAVID MALAN: Yeah, exactly. I could just have another else if. I could say if the character equals y, just as it was a moment ago. But I could also do this. else if c equals equals capital Y, then go ahead and print out quote, unquote, "yes" as well. And then I could do the same for no. So how do you choose between these two options? Because this is just the first of many times where you're going to have to make a decision as to how to implement something. Someone like to argue in favor or against either of these? Little farther back? Yeah. AUDIENCE: [INAUDIBLE]. DAVID MALAN: Yeah, the first one used fewer lines of code and frankly, that's a good thing. Because the fewer lines of code, frankly the less likely you are to have mistakes, perhaps, in your program. Because you've written less code, fewer places to make mistakes. And there's another argument I think in favor of the first one. Not just fewer lines of code, but what else? AUDIENCE: [INAUDIBLE]. DAVID MALAN: Exactly. The second one is also redundant in so far as I'm literally saying, printf yes twice. And that's just kind of seems unnecessary, right? We saw examples in Scratch where why do things multiple times if you have a loop. Well, same here with conditions. Why do things multiple times if you can combine them into one? Because plus, if you decide later on that you want to change the output to yes exclamation point, it could have updated it in half as many places if there were only one block instead of two. Now you might disagree and a reasonable person could make the case that no, this is cleaner because it's just super explicit now what I'm checking for. And this is what's going to boil down in a class like this to something called design. There's going to be correctness, which is your code working as prescribed. But is it well designed? Like, would a reasonable person kind of vote in your favor that yes, you did a good job implementing this. The equivalent of someone evaluating an essay. Like yes, you expressed your thoughts but they were all over the place. And you also have a third axis of evaluation style. You'll notice that all of my code to date has been very nicely indented and I have comments in the files that I wrote in advance. That's a matter of good style, which means you have sort of pretty looking code that's just easier to read than if you just wrote everything out onto one line. But more on those in just a bit. So let me go ahead and open up one alternative and not do this one from scratch. Let me go ahead and open up a file called switch.c, just to introduce one other idea or one other feature. Whoops. OK, accidental but good takeaway. What did I just do and why is this looking the way it is? I misclicked. AUDIENCE: You opened the compiled file. DAVID MALAN: Yeah, I opened the compiled file, the program, not the source code. So what I'm looking at is machine code. And because my browser doesn't know it's machine code, 0's and 1's, it's kind of misinterpreting the 0's and 1's as though they are ASCII characters. Recall that ASCII was like capital A is 65, capital B is 66. The IDE is trying to interpret the 0's and 1's in my programs machine code as though it's characters. But it's not actually English or English like syntax. It's just random 0's and 1's in a sense. And so that's why we're seeing the crazy characters and colors. Because it's being misinterpreted as colors or characters that I didn't myself type. So no worries. Ignore the problem and close it. And then open up instead switch.c. So this is not a feature that Scratch had but it's just to demonstrate-- and even in C, there's even more ways of implementing the same idea. Let me scroll up ever so slightly. And you'll see that up toward the top of this file, I have main as before. I prompt the user for a char. But this time, I'm not using if's and else's. Notice I'm using a new keyword that we didn't have in Scratch called switch. It takes between parentheses, a variable that you want to look at and a variable or value on which you want to make decisions-- on the basis of which you want to make decisions. So you have four cases, it seems here, which are kind of nice in that they kind of say what they are. What does this program do when run? Even though we've never actually looked at the switch statement before. What does it seem to do? What's that? AUDIENCE: Different cases, different options. DAVID MALAN: Yeah, different cases, different options. So if I type in a capital Y to this program when it's run, what is it going to do? It's going to print yes. If I type in a capital N? AUDIENCE: [INAUDIBLE]. DAVID MALAN: Lowercase n? AUDIENCE: [INAUDIBLE]. DAVID MALAN: And so forth. It's actually the exact same program. It's just written with a different feature so there's different ways of expressing yourself, just like if two people are writing the same position on a court case paper. They might have the same opinions but they're going express themselves differently in English. So in C, you can write the same program, behaves exactly the same, but you're using a different approach and you're using different constructs like switches. And so in this case, case capital Y, case lowercase y just means that if either of these two cases apply, do the indented code beneath them. But then break. Breaks make sure that you don't keep executing everything below it. Because if I didn't have the break, the program would keep executing lines of code below it. And actually, if I typed y, it might incorrectly say yes, no because I didn't break out. You get the breakages for free in a sense with if conditions because you have those curly braces. The switch does not use curly braces on the inside, it uses a slightly different syntax. Which one is better? It kind of depends. Sometimes, it just looks better [INAUDIBLE] the switch in some sense, a reasonable person could say [INAUDIBLE] a better version of the program we just wrote. Because it's just so much more compact, right? It's just easier to digest visually. I typed fewer characters. But maybe someone else would disagree and say, I rarely use switches, I never remember how they work. This is actually less readable to me. So again, it's sort of to each his or her own in cases like this when it comes to design. All right. So let's introduce one other idea one other building block that we've seen before, but we haven't done ourselves I'm going to go ahead and do the following. I'm going to create a program here called return.c so that I can kind of implement the idea that Sam acted out for us. I'm going to go ahead and include the CS50 library. Then I'm going to go ahead and include the standard library. And then I'm going to do this-- int main void, as before. And then down here, I'm going to do int x gets get_int. And I'm just going to prompt the user with the x. And then I'm going to say printf percent i backslash n. And now I want to square x. So x times itself will give me x squared. Now that's straightforward. This is not a hard program to write, especially once you know multiplication. And this would seem to do exactly that. If you type in 2, give me 2 squared, like four and so forth. But you know, squaring maybe is a function that I like to use a lot, right? It's kind of a mathematical operation. And yes, it's obviously trivial to implement it with x times x. But it would be nice to abstract that away and just literally say the word square. Well, if your programming language doesn't come with a function called square, no big deal. We can implement it ourselves. We can do it as follows. Down here, I'm going to do the following. int square open bracket int n. And then here, return n times n. So what have I just done? You might not have done this in your own Scratch programs, but you might recall from last lecture, we did briefly have a cough example with a custom puzzle piece that was a purple puzzle piece. Coughing was not a block that existed when my team made scratch but we made it. Squaring might not exist in C, the libraries that we're using. So we're going to make it. How do you do it? Well, now we can begin to address in part the question that came up earlier about int and void, though only partially today. This is the name of my function. It's my custom puzzle piece, if you will. It takes as input, per the parentheses, one value that I'm arbitrarily calling n. I could call it m or o or p or anything I want. But n stands for number, so I went with n, as a computer scientist tends to. And all it does is execute one line of code. n times n. But then it returns the value. And this special keyword highlighted here is just like when Sam handed me back a slip of paper. He literally returned to me a value, a slip of paper. Here, I'm literally returning n times n. And that implies that what type of data is this custom function returning to whoever uses it? It's an integer because n is an integer. And it stands to reason the n times n is an integer. And so that is why I have also specified int here. It turns out that functions, to be clear, can take input and they can return output. If they take input, it's in between the parentheses, just like I've highlighted on line 10 here. And it's one input in this case, a variable called n of type int. But this function also, just like Sam's implementation of get_string returns a value-- not a string but an integer. So I have to tell the computer, hey, this custom function I just wrote is going to return to whoever uses it, an integer. And it's this line of code, line 12 that actually implements the functionality from which you get the value you care about. So now I don't need to do this anymore and reinvent the wheel. I can now use square as a keyword in all of my programs. But how do I call it? Thus far, any time I've called functions, I've done like this. Like int squared value I could do. And then I could do square of x semi-colon. Now I'm just kind of doing this intuitively, right? I don't know if this is best but it does follow a pattern. On the left hand side, I've declared a variable called squared value, though that's a little verbose. We could probably do better. But squared value and it's a type integer. On the right hand side, I'm calling square by just calling its name, open parenthesis. And then the value I'm passing in is input just like I handed Sam a slip of paper with input on it. And then I'm returning from the right to the left, that value. And using the assignment operator, the single equal sign. So how can I improve line 8 to finish that thought? Instead of typing x times x, what can I simply type here? Squared value, which is again, a little dumb in that now I've typed more characters and really achieved the exact same thing. But I don't need this intermediate value and here's an opportunity for better design. If I'm only declaring a variable on line 7 and then immediately using it in line 8, kind of doesn't need to exist. Because you can nest blocks of code as follows. I can just take the square of x, which I know returns the square of x. I can delete line 7 altogether. And I can more elegantly just do this, much like you can nest puzzle pieces. And this will be better designed arguably because it's fewer lines of code. It just says what it does. And you don't have some random temporary variable just there to go from one line to the next. Maybe it's less readable-- again, to each his or her own-- but now I've at least done this. But there's one problem. Even if all of this makes sense, even if it's super new to many of you, I do have an error. I do have an error. And how can I go about resolving this? Implicit declaration of a function square is invalid in C99. C99 means the 1999 version of a language called C. Implicit declaration of function square. Well, turns out-- and I haven't said this explicitly yet-- C is kind of dumb. It only does what you tell it to do. And unfortunately-- and this is a bug-- on line 7, I'm calling the square function by mentioning its name. Unfortunately, on what line of code do I teach the computer that square even exists? Not until a few lines later-- line 10 onward. So it's too late. I tried to use square even before it existed. So I could fix this in a couple of ways. I could take this block of code and just move it up here and then save it again. And run make return and that works. But that's kind of a cat and mouse game. Eventually, you're going to find, when your programs get complicated enough, you can't move every function above every other function. At some point, you'll construct a scenario where every function can't be above every other function. But that's OK. Because what we could also do is undo this and put square at the bottom and keep main at the top, which is better practice. It's nicer to keep main at the top because that is the default function that the human is going to care about. And I can actually just be a little bit redundant. But it's OK in this case. I can just give the compiler, clang in this case, a hint as to what's to come. I don't have to tell it how it's implemented. But on line 4, I can use what's called a prototype. A little teaser like a movie trailer of a function that eventually is going to get implemented. All clang needs to know from the get go though is what its inputs and its outputs are. The actual implementation between curly braces can come later. So if I now do make return again, now the program seems to compile successfully and I can do return. And then if I want to type in x is 3, x squared it's going to be 9 in this case. And we can do this kind of abstraction in many different contexts by implementing some idea like squaring, thereafter calling it by its name square but actually not worrying about how it's actually implemented. But unfortunately, we're going to bump up against some limits. We're going to bump up against some limits as follows. Let me go ahead and remind us of a visual you might not have seen inside of your computer. But that's this. In fact, inside of your Mac or PC or laptop or even phones are things like this. These are sticks of RAM or memory. When you say my computer has a gigabyte of memory or two gigabytes of memory, it's generally got one or more of these things. And it might be slightly different shapes. This, for instance, is from a laptop there. And there's other things inside of your computer which have limits too. But for now, we just care about this. This is a physical device. It stores 0's and 1's while your computer is running. When you double click an icon on Mac OS or Windows and you load a program or do some math or write an essay, it is stored in this physical hardware as 0's and 1's. Unfortunately, the ram, the memory you and I have in our computers, is finite. This is literally only some number of inches by some number of inches. It literally only store some number of millions or billions of bits and that's it. So you have a fixed amount of memory. That's not a good thing when it comes to writing programs that don't know in advance how big the numbers are that the humans are going to type in. Or how long of an essay that the human is going to type in. You could certainly contrive a scenario where your essay is just so damn wordy, it does not fit in your computer's memory. Or your number just has so many digits, it does not fit inside of your computer's memory because it's fixed. You only have a finite amount. And this has very real implications for two problems at least. There's something fairly arcane called integer overflow and you can actually spot this from time to time in the media as a real world issue. Here, for instance, are 8 bits. Last time we looked at just three but here's eight. And notice, this is pretty high number. It's a lot of 1's. And this happens-- if you do the math per last time-- to represent 254. What happens if I increment this number by 1? Which bit changes based on last time's lesson? Yeah, the rightmost one. The 0 becomes a 1. And then this whole thing becomes all 1's, which happens to be, if you do out the math with the places, 255. If you add one more 1 to this, what's going to happen? In the human world, we'd ideally just get like a marker or chalk and write one more number. But in the computer world, if you only have a fixed amount of memory-- hopefully it's more than 8 bits-- there could be millions or billions-- but at some point, you'll run out. And indeed, all of the data types we talked about today like int and char and float literally use a finite number of bits. It's usually 8 or 16 or 32 or 64. It's a power of two but it's fixed, which means with a computer program using ints and chars and floats, you can only count so high, even though we humans can theoretically count toward infinity. And the problem is if you take a number like this that's already as big as it can be with all 1 bits, all the light bulbs on, if you add one more to it-- and you can't just write down a new one-- it's as though all those values suddenly became 0. And your integers overflow. You get to number 255 and guess what comes after 255 if you only have 8 bits. Zero, apparently, because all the little 1's flip over and become 0's. So a computer therefore can only count so high using an int, using a float, using a double. And at some point, if you try to add one more to it, the numbers kind of can overflow and end up being something you don't expect it to be. Maybe it's positive, maybe it's negative, or maybe it's 0 itself. And we can actually see this. Let me open up one quick program here called Overflow, which is also available online, that literally just does this if I run it. Make overflow. ./overflow. As I run this program, it's just going to keep counting up from 1 to 2 to 4 to 8 to 16. I simply wrote a program that just doubles the number every iteration of the loop. And I also used another function called sleep just so that this wouldn't fly by the screen. I wanted to pause, just like in Scratch. You can wait. It's getting bigger and bigger and this is exponential. So it's going to get bigger and bigger faster, which is nice because it's not going to take us forever to get to a really big number. But I'm using an int. And with an int, you can only count up to roughly 4 billion and technically only to 2 billion if you want negative numbers as well. If you want half as many negative and half as many positives. And there it is. Eventually, if I talk long enough, I will double this integer so many times that it just doesn't fit in 32 bits and the computer notices and has a runtime error. And then weird stuff happens. Now I'm stuck at 0. And so you can actually see this for real. But there's one other issue too and this is perhaps a super simple program that you wouldn't think has an opportunity for error but it does. I'm going to go ahead and write a really quick program here, including the standard library. Int main void as before. I'm going to go ahead and save this as imprecision, a different problem, dot c. And I'm going to simply do this. I'm going to print out quote, unquote, percent f backslash n 1.0 divided by 10.0. Now based on grade school, what should that answer be? AUDIENCE: 0.1. DAVID MALAN: 0.1. That's 10%. 0.1. And let me go ahead and run ./imprecision. And it's indeed .10000, which is the same thing. But I am willing to wager at least like a dollar that we've all been lied to. That this 1 divided by 10 is not actually 0.1. Anyone want to go in on this? I should have made that claim before I took out the $1. Sorry, I showed my hand. So I make this claim because of the following. Maybe I'm just not looking far enough into the number. When you asked earlier how we can show more decimal digits-- you know what, let me see 10 of them. Let me just get some comfort here. Let me recompile the program. Let me rerun it. Losing the dollar. Let me go ahead and change to like 55 possible digits. Let's really look deeply into the number. imprecision. Interesting. So if someone else played this, I would take the dollar back at this point. And now, we see that 1 divided by 10 is not in fact 0.10000, like our grade school teachers told us-- that those 0's should go out to infinity. It's imprecise. And why might this be? Why is 1 divided by 10, at least on my Mac or in CS50 IDE here, not actually 0.1? What's the intuition? Well, if you only have a finite amount of this stuff, you can only represent a finite number of numbers, right? If you only have like 32 bits or 64 bits, however many bits you have, you can only permute them in a finite number of ways. Eventually, you run out of patterns of 0's and 1's. And it turns out that 1 divided by 10, at least in this computer, cannot be represented precisely because we don't have an infinite number of patterns of 0's and 1's to represent all possible real numbers, a.k.a. Floating point values. Because of course, there's infinitely many of those and only a finite amount of memory. And to conclude-- and this has very real world implications as follows-- one, if you ever played Lego Star Wars too long, you might notice that the largest number of coins you can collect is four billion. And they rounded it a little bit. Technically, you can count a little higher but 4 billion-- and that's probably because what data type was Lego using to store the number of coins? Integers, which are 32 bits. Meanwhile, that's all fine and good. Like, they actually anticipated that and thought about that. Here is a Boeing 787. Or actually, there's a funny story here. Well, here is a Boeing 787 that actually ended up having documentation associated with it that says you need to reboot your plane every 248 days. Specifically, this model 787 airplane that has been powered continuously for 248 days, if not rebooted, can lose all of its alternating current-- electrical power-- due to the computer simultaneously going into fail safe mode. This condition is caused by a software counter internal to the computer that will overflow after 248 days of continuous power. So literally, a company like Boeing did not realize that if you leave your plane on long enough and you only use an integer or 32 bits or whatnot those numbers might creep up big enough that it's going to roll over and have catastrophic consequences like the plane turning off in this case. And a little less frightening but nonetheless real-- there's one final tale before we wrap up here and it involves civilization or Gandhi in this case here. So if you actually in the game of civilization choose the character Gandhi, who was a very peaceful character by definition in the game, he had an aggressiveness level of just one, which just mean very unaggressive. But the authors of this game, Civilization, only used 8 bits, which means you can only count as high as 255. So 255 would be like a lot of aggression. So 1 is not much aggression at all. But there is a feature in the game whereby if Gandhi, in his civilization adopted democracy, there was a line of code that said any time a civilization adopts democracy, decrease their aggressiveness by two because they are content people. Unfortunately, if your aggressiveness level starts at 1 and you subtract 2, just as though you can overflow, you can also underflow such that 1 minus 2 is not negative 1. That is actually 255. And so it looked back to the ludicrously high figure of 255, making Gandhi as aggressive as a civilization could possibly be. So there are very real world design decisions here. And what we will do in next lecture on Friday and beyond is actually explore these issues, start solving problems with them. Until then, problems set one is online. Orientation meeting is today and tomorrow. Stick around if you have any one on one questions. And we will see you next on Friday.
B1 中級 美國腔 CS50 2017--閱讀1--C (CS50 2017 - Lecture 1 - C) 130 9 王秉民 發佈於 2021 年 01 月 14 日 更多分享 分享 收藏 回報 影片單字