Download as txt, pdf, or txt
Download as txt, pdf, or txt
You are on page 1of 19

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 computing [INAUDIBLE] the 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 0's and 1'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 [INAUDIBLE] a third [INAUDIBLE] are integers. Because after this
highlighted string, I have three additional inputs to this printf function. Three
additional very 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 y 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 look, it's 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 [INAUDIBLE]
and guess what comes after 255 [INAUDIBLE] 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.

You might also like