SPEAKER 1: This is CS50, and this is week 1.
And by the end of the day, you will know how
to create programs that look like this.
So this, of course, is binary.
This is the only language that machines ultimately understand.
But thankfully, per last week, there's so many abstractions
and there are so many humans that have come before us that we don't actually
have to write anything at this level.
We can abstract way above it like we did with Scratch already
and like we will starting today with C.
But does anyone nonetheless want to take a guess
at what that program, when fed to your Mac or PC, actually does?
Anyone recognize?
Anyone want to hazard a guess?
It's perhaps the simplest program you could write.
Indeed, it does, when fed to the brain of your computer,
the so-called CPU simply prints that.
So how do we actually get to that point?
Well, recall where we started this conversation last time
talking about computer science more generally
and problem solving-- we proposed could be distilled really is this.
You've got some inputs.
You want some outputs.
And somewhere in the middle, you need to do something with those inputs.
And to get to that point, though, we had to represent those inputs and outputs.
We just had to decide as humans, how are we going to represent all of the inputs
to our problem when it comes time to have a computer actually process them.
And at the end of the day, all of the phones and the computers that we're all
using only at the end of the day plug into the wall
to get their physical resource, electricity,
and they might store that temporarily in a battery.
But that really is our only input.
It's either plugged in or it's not.
It's either a 1 or a 0, true or false.
So the world really reduces to those two states, so to speak.
And so you can think of those states then as just being like a light bulb,
on or off.
I pulled up my cell phone last time to turn the flashlight on or off,
1 or 0, true or false.
Now of course, if you only have one light bulb,
you can only count from 0 to 1.
But if you start to have a bunch of them back to back to back to back,
you can permute them like I did my finger--
0, 1, 2, 3, and so forth.
And so we started talking about binary more generally.
And so here for instance were three sequences
of 0's and 1's and each of those represented something,
but we don't need to think about the world at that level.
We can abstract on top of that.
All of us are so much more familiar with decimal of course,
and indeed recall that this was just 72, 73, and 33, which if anyone recalls,
when you use ASCII--
which is this global standard for mapping numbers
to letters-- we got what message?
Yeah, it was just high, capital H capital I exclamation point.
And so that's an abstraction on top of those otherwise binary numbers.
But we don't have to model just text using numbers.
At the end of the day, our only resource is still that electricity,
and the only way we think about it digitally is still zeros and ones.
But if we take the same value--
72, 73, 33-- and treat them in the context of Photoshop
or a photo program or a graphics program,
we can instead interpret them as like some amount
of red, some amount of green, some amount of blue,
which gave us last time, recall, this yellowish color.
So now we had another abstraction on top of binary colors,
and this is just one pixel.
What can you do once you have more than one pixel?
What can you represent next?
Yeah, right, images.
So we're continuing the conversation up and up and up,
and we could represents something like a graphical emoji on the screen, which
has more than just one yellow dot.
It's got a whole bunch of yellow dots and other colors as well.
And recall that, if we want to animate things,
whether it's through silly things like animojis on a phone or just more proper
videos and movies, well, those are just sequences
of images flying past your human eyes really quite quickly.
So that's where we kind of left off last time starting at the base level
and abstracting away so that we could stipulate thereafter we
can represent inputs, and we can represent
outputs, whatever those happen to be.
And here on out, we don't need to think at that level.
We can just assume we all know how to do this.
And even if it eventually becomes kind of a distant memory,
we know that someone can indeed do this.
And that's the value of abstraction.
But inside of this black box are so-called algorithms,
the secret sauce--
this is where the problems are actually solved.
And we not only talked about what these algorithms are, but for instance,
how efficient they were.
So recall that this red line represented a very simple algorithm just turning
the phone book page by page one at a time.
And the reason that it's a straight line is because there's a one to one
correspondence between how many pages there are in the book
and how many page turns there are-- one page, one more page, one more
turn, and so forth.
If I fly through it at twice the speed--
2, 4, 6, 8--
I can do better.
And so that yellow line now, recall, was lower on the graph.
If you just look at any two points, yellow and red,
yellow is below red, saying it takes less time.
But it was not quite correct.
There was one bug when I was looking for Mike two pages at a time.
What was that issue?
Yeah, I might miss him.
He might accidentally get sandwiched in between two pages-- not a huge deal
because I could fix it, but I have to fix it.
I have to apply that additional logic and double back
at least a page if I go too fast.
But of course the final algorithm-- and frankly all of our initial intuition
probably-- was the dividing and conquer, open it roughly to the middle,
look down, and then go left, and go right,
and just repeat that process as the problem gets
this big to this big to this big to this big to just one page left.
So that was all about efficiency.
But to get to that point we needed to express ourselves more precisely.
And so we introduced pseudo code.
There's no formal definition.
It can be English, English like.
It's just meant to be succinct and get the point across.
And recall that, along the way, we introduced a whole bunch of concepts,
many of which you probably experimented with Scratch, like loops
and conditions, Boolean expressions, variables, and so forth.
And those were building blocks that came out of this kind of demonstration here.
But honestly, even in this demonstration, in this pseudo code,
there were a whole bunch of assumptions.
If you read these instructions one at a time
and you're holding the phone book yourself,
odds are you can execute this pseudocode, this algorithm.
But what does it really mean to, say, open to the middle of the phone book?
All of us have an intuitive understanding of what that means.
But honestly, if you were explaining that
to a kid or someone who's learning English or whatever language
for the first time, open to the middle of the phone book,
you should probably sets forth some assumptions.
OK, this thing in front of you has 1,000 pages, pieces of paper.
Turn to the 500th page, and let's call that the middle.
This would very quickly get tedious if all of us humans
are talking at that level of detail.
And so we abstract away with more sweeping
statements like open to the middle of the phone book,
but that's an abstraction.
And it's not quite as precise as is probably ideal,
especially feeding this algorithm to a newbie or to a robot or a computer.
But it's useful because we can then make a 12 step program instead of a 20 step
program by elaborating too much.
And for instance, throughout here too we had our loops and conditions
and so forth, but even call Mike.
What does that mean?
Well, if you imagine that the human knows how to use the phone,
then it goes without saying.
But if he or she also needs to be programmed to use the phone,
you've got to explain-- pick it up, hit this button, type
this sequence of buttons, and so forth.
So call Mike is also an abstraction.
So these abstractions are useful, but they can sometimes get in the way,
especially if you're not precise enough to program the computer correctly.
And to paint this picture, I thought we could begin a little heartedly here.
I brought some breakfast, if you didn't quite make it next door or beyond.
Just need a couple of volunteers if you're
comfortable appearing on stage and on the internet here.
Let me kind of-- there's a lot of lights here.
How about over there on the left and over here in the front?
Yeah, right there.
I think your hand was up.
Come on down.
And Brian, do you mind lending us a hand here, too?
Come on down.
If you want to take control here, let you go ahead
and switch over to another program for you.
What's your name?
JEAN: Jean.
DAVID: Jean, David.
Nice to meet you.
Have a seat on the far left.
And your name?
ABBY: Hi, I'm Abby.
Nice to meet you as well.
On the far right if you could.
So Jean and Abby, do you want to say a little something about yourselves
quickly?
JEAN: I'm Jean.
I'm a Massachusetts native, and I'm taking CS for the first.
It's my first coding or anything.
Or I'm doing and I'm enjoying it.
DAVID: Nice, glad to have you with us.
And Abby?
ABBY: Hi, I'm Abby.
I'm taking this as a sophomore, and I know nothing
about computers or computer science.
So I'm probably taking it stat on stat.
DAVID: OK, well, nice to have you as well.
So in front of us is a whole bunch of ingredients,
and hopefully we can start this semester off gently.
And if we're successful, we'll actually have a quick bite here.
But we thought we'd defer to the audience here,
and Brian's going to scribe as we go.
And all we want to do this morning is just
make a peanut butter and jelly sandwich, one instruction at a time.
And each of us will just execute what we hear.
How does that sound?
All right, if someone could volunteer with the first instruction and Brian
will type it down.
AUDIENCE: Open bread.
DAVID: Open bread we heard.
Open bread is the first instruction.
So each of you would like to execute open bread.
No, don't look at me.
All right, so we're kind of on our way.
I think Abby did it better certainly, but we did it correctly arguably.
So let's move on to step 2 and see if we can't improve.
Take out bread.
Welcome to the team now.
Nice, all right, step three.
Yeah.
AUDIENCE: Place two pieces of bread on the table.
DAVID: Place two pieces of bread on the table.
Never mind the plates.
OK, step four.
AUDIENCE: Twist cover of jelly till it opens.
DAVID: Twist cover of jelly till it opens.
Thank you.
Step five?
Yeah?
AUDIENCE: Place the lid to the side.
DAVID: Thank you.
Place the lid to the side.
I took some liberties myself.
AUDIENCE: Take the knife.
DAVID: Take the knife.
Peel off the cover of the jelly.
No covers on ours.
Stick knife into the bottle?
From the top.
Stick-- step nine.
AUDIENCE: Rotate hands so jelly ends up on.
DAVID: Rotate hands so jelly ends up on--
OK, step-- quickly--
10.
Yes, step 10?
AUDIENCE: Pull out knife.
DAVID: Pull out knife.
OK, step 11.
Jelly side down on bread.
All right, step 12.
Step 12, anyone?
Yes.
Thank you.
Step 13.
Pour jelly on bread.
JEAN: Pour jelly--
DAVID: Pour jelly, jelly.
All of it?
OK, now you're just messing with us.
Step 14.
AUDIENCE: Put jelly down.
DAVID: Put jelly down.
Thank you.
15?
Pick up peanut butter.
AUDIENCE: Take the lid off.
DAVID: Take lid off.
Thank you.
Peel off lid.
Thank you.
Step 18?
Pick up knife by blunt end, scoop.
Scoop.
Step 20?
Put peanut butter on bread?
21?
AUDIENCE: Move the knife left to right.
DAVID: Move-- move the knife left to right, please.
Left to right.
Step 22?
AUDIENCE: Put down knife.
DAVID: Thank you.
23?
AUDIENCE: Put down jar.
DAVID: 24.
What was that?
Eat sandwich.
OK, I think we're--
well, why don't each take a bite?
And a round of applause, if we could, for our volunteers.
Thank you.
ABBY: Mind if I take some for the row?
DAVID: You can take some for the row if you'd like.
Thank you.
So-- thank you, Brian.
OK, now I need a minute.
Thank you.
So suffice it to say, this obviously demonstrated even more so
than the phone book example where our certain assumptions are
and our abstractions are.
And honestly, almost all the time those are useful.
And of course, we kind of hammed things up.
And I think the instructions were kind of helping with that here.
But when it comes time to program with Scratch and certainly with C
starting this week, you can't really make as many of those assumptions
anymore because, if you don't handle these corner cases
and if you don't think about what that instruction means,
you're going to get the proverbial spinning beachball or the hourglass
that you're familiar with on your Mac or PC.
The program is going to crash, something's
going to go wrong just because you miss some specificity or precision.
Now we're full of peanut butter.
So over time, we're going to find that, much like in Scratch,
we were able to make our own building blocks.
You might recall the short examples we did with the cough example
where I had cough 0 and then cough 1 and cough 2
where I was making my own puzzle piece within Scratch.
That was useful because, after that example theoretically,
I never again need to think about or worry about how to implement cough.
I can just use that abstraction.
But someone has to implement them, and sometimes it's
going to be other people who have come before us.
And sometimes it's going to be us.
So this isn't to say that programming ends up being so tedious
that you have to point out every little thing,
but you or someone does have to do that level of precision at least once.
And nicely enough in Scratch, MIT did most of that legwork for you.
We all had the building blocks with which
to make our own animation or game or artwork or the like.
But even then, you probably had to connect several dozen puzzle pieces
or even more to get those fundamentals to do
what it is that you wanted it to do.
So today we're going to start to transition from Scratch,
this graphical programming language, that while targeted at younger
students, is typically representative of a lot
of the same concepts that are now going to be laced throughout the semester.
But we're going to introduce today an older, more traditional language that's
just text based.
And as such it's a lot more powerful.
But at first glance, it's actually going to look a lot more cryptic.
In fact, instead of writing zeros and ones starting today,
we're instead going to write something like this.
Now if you've never programmed before, odds are, at first glance,
this does look pretty cryptic, and there's
a lot of symbols within it, punctuation from the keyboard.
There's probably some familiar English like words.
And frankly, even after doing Scratch anyone, even with no prior background,
can probably hazard a guess as to what this program written
in this other language called C does when you run it.
It just prints hello world.
Now granted there's a decent amount of overhead syntactically.
There's a bunch of stuff you have to type to make
this program do what you want it to do.
But at the end of the day, that's all it's going to do.
And this is among the simplest of programs
we're going to add to our puzzle pieces, so
to speak, today and see some of those same concepts
that we saw last time as well.
So let's do this first though.
Let me take a moment to compare Scratch to C
because the most important takeaway for today
is going to be that, even if the syntax doesn't look so obvious--
and frankly, even if your first minutes or hours
with writing your own code in C is frustrating because, oh,
dammit, you left off a semi-colon or, oh,
I had a parenthesis in the wrong place.
There's a lot of these stupid syntactic hangups
that make you feel quite often that you really aren't getting it.
But that's not the important stuff.
A lot of the syntax is the least important.
That's not at all fundamentally intellectually interesting.
So try to see past that, and try to take comfort in the fact
that it's the principles that are going to be important.
And honestly, just muscle memory and practice, all of the other stuff
that at first is going to be an occasional frustration,
it just starts to go away as you start to see
this for what it is and not for the syntax
alone that you see on first glance.
So this is to say this program on the right in C
is equivalent to what we did just a week ago with two puzzle pieces in Scratch.
Now there isn't going to be a green flag on my Mac or my PC
as we move forward that you can just click.
We're going to run these programs in a little different way,
but that's all the code on the right is doing.
It's equivalent to the code on the left.
So let's do this again and again for just a few of those concepts
from last time, and then we'll start writing some of our own programs.
So this was an example, this purple block, of what concept in programming?
Yeah, a function.
So it was a verb.
It was an action, and we're going to call those generally functions.
They just have functionality built into them.
So how do we do this in C?
Well, you might remember from just a moment ago,
because one of the lines of code was representative of this,
it had some of this syntax.
So in fact, if I were to translate the block
on the left in Scratch to the equivalent code in this other text based
language called C, I'm going to start by writing print
and then open parenthesis and then close parenthesis.
And those parentheses represent the oval, the white oval on the left,
that we typed hello world into before.
Now in C, it's not quite as literal as that.
The function, or the verb, is actually not called print.
It's called printf, and the F stands for formatted.
And it just means that in C you can actually
format your text in different ways.
So we'll see that before long, and it turns out
that you don't just write hello world between those parentheses
like we did in Scratch.
You also actually have to surround them with double quotes in C.
Not such a big deal, but something you didn't have to do before.
But in C, you're also going to generally want
to be super specific to the computer.
And when you want the cursor the text on the screen
to move down to the next line, you need to tell the computer that
by literally typing backslash n.
The human is not going to see a backslash and an n.
He or she is actually going to see the cursor move
to the next line of the screen like in Google Docs
or in Microsoft Word or the like.
But this just speaks to the precision that you
need to have when talking to a computer at this level
and not just with the puzzle pieces.
And then one last thing-- and I alluded to it earlier
because it's the bane of a lot of programmers early on.
Most lines of code in C have to end in a semi-colon.
That's the sort of code equivalent of a period in an English
or some other languages sentence.
So that's it.
It took us a little while to build that up.
But that's all it is.
The idea on the left of saying something is the same in C
as printing something with this function called printf.
And before I forge ahead with some other comparisons,
any questions on just this translation?
AUDIENCE: How do you write backslash n?
DAVID: How do you write backslash n?
Good, so thinking ahead, this would seem to make it hard to literally show
the user backslash n.
Well, it turns out that this backslash, because it's not
a terribly common character, the programming world
uses it as what's called an escape character.
It's one that you use when you want to escape information and show it
in a slightly different way.
So the way you would show literally to the human
a actual backslash n is to actually in your code
do backslash backslash n because the second backslash is
like saying treat the next character special
and actually show it to the human.
And there's other such examples of that.
So how about this one?
This orange block was an example of one concept in Scratch?
Yeah, so this was a variable, like an x and y in algebra.
This was just a placeholder for data, and you could store numbers.
It turns out you can store words.
You can store other things too in other languages.
So in C, we're going to do this.
We're going to say, literally, the name of the variable we want-- for instance,
counter.
But we could call anything we want--
equals zero if we're setting it initially equal to zero.
But C is a little more pedantic.
You've also got to tell the computer, the type of variable I want
is specifically for an integer, otherwise abbreviated int.
So you have to tell the computer in advance what type of data
you're going to store on it.
And take a guess.
You've got to finish the thought ion C. What more do we need to add to the--
yeah, just a semi-colon.
And that's it.
It looks a little more cryptic, but the idea is fundamentally the same.
So what if we wanted to do this in Scratch?
Change counter by 1-- this was equivalent to incrementing or adding 1
to counter.
Well, let me go ahead and propose that you could literally just
do this in C. Set counter equal to whatever counter currently is plus 1.
That seems to be the right intuition.
And now notice, what's key to note here is
that this equal sign isn't saying that counter equals counter plus 1
because that just doesn't seem possible.
If you pick any value for counter, like the number 1,
well, one definitely does not equal 1 plus 1, which is 2.
And 1 does not equal 2, and you can come up
with an infinite number of worrisome incorrect comparisons.
So the equal sign in C, like a lot of languages we'll see in the class,
actually means assignment.
Copy the value on the right into the value on the left.
So set counter equal to whatever it is plus 1.
What?
We've got to finish the thought.
So we need a semi-colon.
I don't though need to remention int, and why might that be?
Yeah, I already told the computer it's an integer.
You don't need to repeat yourself by mentioning int again,
assuming in this context, even though we're looking at it just on the slide,
has actually been created before just like you did
with Scratch by saying make a variable.
So it turns out you can be a little more succinct in C and a lot of languages.
If you find this a little tedious to type-- and it's a little verbose.
It's a bunch of keystrokes.
You can actually abbreviate it with just this.
So plus equals is just syntactic sugar, as a programmer would say.
It's just a nice fancy feature that lets you write fewer words or characters
but do the same thing.
And frankly, we can do a little better.
And if you've taken a PCS, you might have seen this in Java as well.
You can also simplify this even more to just counter plus plus semi-colon.
So that's it-- all equivalent.
This is just a little more efficient.
And as you get more comfortable programming,
saving keystrokes just saves you time.
Now this of course was an example of what in Scratch by contrast?
Yeah, we called this a condition.
And it had a Boolean expression that we were asking a question of.
In this case, we're apparently asking in Scratch is x less than y and, if so,
say it on the screen.
So how might we translate this to see?
Well, it turns out we can quite simply translate this one pretty literally.
We've seen almost all of the building blocks thus far,
but we do have to introduce a little something new here.
Notice that the printf line is almost identical to what
I used earlier for just hello world.
I've obviously just changed the words in it, but I still have the backslash n.
I still have the quotes, still have the semi-colon.
So the rest of that is the same.
Now if is new, but this is a one to one translation.
Scratch calls it if.
C calls it if.
And the only additional thing you need in C
is parentheses around the Boolean expression.
So that's what takes the place of the little green block there.
And then assuming x and y are indeed variables
that we created earlier, you can just compare them like this
and you can use greater than and other symbols for comparison as well.
But there is something a little interesting, and most of us
don't often have occasion to even use these keys on our keyboard.
Curly braces, on a US keyboard they tend to be
over on the top right above your Enter key.
These are just C's equivalent of this shape.
Notice that most of the yellow blocks in Scratch
had this embracing or this embracing shape to them.
You can simulate that in C by having what's called an open curly brace
and then a closed curly brace.
So that's the same exact idea.
Now as an aside, you don't technically always need these curly braces.
If you just got a one liner like this, you
can omit them as you might see online or in textbooks.
But we'll just always draw them for consistency so that the C code always
looks like this.
What if you wanted to express this, though?
If x is less than y, then say x is less than y, else say x is not less than y.
Well, it turns out this is almost identical.
The first four lines, perfectly the same as before.
But it turns out in C, you can literally say else
after that closing curly brace.
And then just print out alternatively whatever it is you want to say.
So this is like the fork in the road.
If you go one way, say this.
If you go the other way, say this other thing.
Any questions on these comparisons thus far?
Yeah.
AUDIENCE: Should we put the first bracket on the same line as the if?
DAVID: Really good question.
Can you or do you put the curly brace on the same line is the if?
You can, and we're going to talk about this the next couple of weeks,
this matter of style.
There are different ways I could express this exact same code.
Frankly, I could write out all of this code with no spaces whatsoever.
In fact, just to make that point, if I go ahead and just open up a simple text
editor here--
not to actually program, but to just type something--
I could actually do something like this if x less than y.
Then go ahead and print out x is less than y backslash n semi-colon curly
brace else print and so forth--
completely unreadable at the end of the day or unmaintainable,
especially when the code gets complicated.
But whitespace does not tend to matter to the computer,
but it does matter to the human.
And as you're alluding to in some languages,
it's actually conventional to do this, where you actually
keep the curly brace on the same line.
And indeed, you might see textbooks do this as well.
Some people will even do this.
These are all long story short matters of style.
In CS50, in the earliest weeks of the class,
we're going to insist that everyone follow the same style so
that we have some basis for comparison.
But eventually, this is the kind of thing
that, like in your own English writing or whatever language you
tend to write in, you have your own stylistic or linguistic flair to it.
Code has that as well.
Other questions?
Yeah.
AUDIENCE: When you establish the counter-variable,
do you always have to say what it is equal to,
or can you just say int counter section?
DAVID: Really good question.
When you declare a variable, create a variable,
do you have to set it equal to something right away?
Short answer, no.
And we'll see examples of that before long, where you can actually
say give me a variable called counter, but don't actually
set it equal to some value.
Come back to that in a bit.
So what if we want to add this logic?
Frankly, in Scratch it's starting to look a little overwhelming.
But this is just a three way fork in the road.
If x is less than y, say so, else if x is greater than y,
say so, else if x equals y, then go ahead and say they're equal.
And in C, we can do this translation pretty directly as well.
In fact, now the first eight lines of code
are identical to before except this middle one
here where I'm adding a second Boolean expression.
Is x greater than y?
And then I have this third condition, else if x equals y.
But there seems to be a typo perhaps or something anomalous here.
So anything jump out?
Yeah.
I have a double equal sign, which maybe is just a typographical error
on my part, but turns out it's not.
This is deliberate.
But why?
This seems like our first example of where Scratch doesn't really
map perfectly to C?
AUDIENCE: Well, because the equal sign is like an assignment.
And so counting the equal sign actively sets it equal--
DAVID: Exactly.
We already a moment ago decided as humans-- or really, years ago-- equals
is actually in the context of C going to be assignment-- copy
the value from the right to the value on the left.
And so we kind of painted ourselves into a corner.
We still as humans, as programmers, want to be
able to express the notion of equality and comparing.
But if we've already used the equal sign for assignment,
we need another pattern of symbols to represent equality.
And as it turns out, humans just chose two equal signs instead--
so slightly different from Scratch.
The reason Scratch does it this way is because you don't really
want to have to get into those weeds certainly
when the target audience is 8-year-olds just
learning to program in the first place.
It's not important nor is it really important for us.
But for us there's going to be a logical difference
because, if we use the wrong one, the behavior is going to be wrong.
If we had just one equal sign, we would literally be changing x to equal y
rather than just comparing it.
Was there a hand in here?
Yeah.
AUDIENCE: Just a quick question.
So if you wanted to express greater than or equal to,
would you write equal and greater than?
DAVID: Good question.
If you wanted to express greater than or equal to, how might you do that?
It turns out there are ways to do that.
And if I go ahead and just give myself someplace to draw here for a moment,
you can actually indeed do less than or equal or greater than or equal.
There's no way on a typical keyboard to put them atop each other
like you might recall for math.
You just put them next to each other.
Well, it depends.
I want the double equal sign here because I
want to explicitly check this third case and say x is equal to y.
So that was my goal.
But logically, this is not necessary.
Let's make the program a little better designed.
How many possible cases are there when comparing two integers, x
and y, for greater than, less than, or equality?
Well, I kinda of just answered the question, didn't I?
Three.
Excellent!
There's three scenarios there-- x is either less than or greater than
or equal to.
And I'm hard pressed to think of a fourth.
So do I need this amount of specificity?
What could I do to give myself a slight optimization,
improve the code just a little bit just to save myself
a little bit of time writing it and maybe even the computer
a little time running it?
Yeah.
AUDIENCE: You don't need the last condition.
DAVID: Yeah, I don't need the last condition because,
if we all agree logically that either x is less than y or greater than y
or maybe equal to y, well, if there's only a third and final case that
can just be my so-called else.
Just make that be the so-called default case.
And in fact, even though this is what most people would
call an over optimization, you are saving the computer some time.
Because suppose that x does in fact equal y
and they're both the value number 1.
So is 1 less than 1 when this line of code is executed?
Yes or no?
No, obviously not.
1 is not less than 1.
So this code does not execute.
But the Boolean expression is evaluated, so to speak.
The question is asked.
Is 1 greater than 1?
No, and so this code is not executed, but this Boolean expression is.
So we just spent another step or second or however fast the computer is.
Is 1 equal to 1?
Yeah, it is.
So this actually prints.
But to your point, you don't need to ask that question.
And in fact, you just increased by a factor of 50%
how many questions you're asking.
So you just wasted a little bit of time.
Now as an aside, our Macs and PCs and phones
these days, I mean, again, they're operating at like a gigahertz
speed, one billion things per second.
So in practice, who cares if you're asking that third question?
And frankly, if it makes your code more readable or to your teaching fellow
or to a colleague or friend who's working on the program for you,
then that's great.
If it's more clear from the code what's going on, leave it that way.
But these are the kinds of design decisions that we'll now make.
And arguably this version of the scratch program and this version of the C code
is just a little better designed because why
write more code than you need to express the exact same idea.
So what about this?
This was a loop in Scratch.
This was an infinite loop because it was just forever saying hello world.
Now in C, this gets a little less directly translated.
It turns out c uses the key word while.
So there is no forever keyword in C, but there is the word while.
And of course, I'm going to use my curly braces--
curly braces, curly brackets to encompass the following lines of code.
The line of code I want in there is just another printf.
So that's the exact same as before, but it's not sufficient to just say while.
It turns out that while wants you to ask it a question every time
the loop executes.
And it's going to check that question.
And if the answer is yes, it's going to run the loop.
But if the answer being asked in C is ever no or false,
it's going to not execute the code and it's just
going to move on to any further lines of code lower down in the file.
So in C, you actually need a pair parentheses after the keyword while.
And then you need to ask a question.
You need to ask a question like, is x less than y
or a question like is x greater than y or is x equal to y.
But none of those scenarios apply because the whole purpose
of this Scratch block is literally to do something forever.
So what's a question we could ask to which the answer is surely true?
Does 1 equal 1?
We could contrive an arbitrary but very met mathematically correct scenario.
We can just say just 1 equal equal 1.
But it turns out you can be even more succinct because in C there's
a couple of keywords, one of which is true, one of which is false.
And the word true is by definition always true,
and the word false is by definition always false.
So you don't need to contrive some arbitrary but correct idea
of does 1 equal equal 1 or does 50 equal equal 50.
You don't need to just come up with some arbitrary solution.
You can literally just say true because that key word true never changes value.
So even though this is a little weird looking,
it's how you induce something to happen forever.
You asked the same question again and assume that the question always
has the same answer of true.
Any questions on that one?
Yeah, in the back.
AUDIENCE: Do spaces matter?
Can you take out the space between y and 0?
DAVID: Good question.
Do spaces matter?
Short answer, no, not in this case.
You can in fact delete all of the space here
except for the one in the English phrase,
and it would still be functionally correct.
You can even add spaces anywhere you want.
You can make this taller by hitting Enter a bunch of times,
tabs, spaces around the word true.
All of the examples I"ll show here today and you'll see in the coming weeks are
the better way to do things because they're more readable.
But again, as you get more comfortable with code
or if you're coming in with some prior experience,
you might already have your own opinions.
And frankly, this is just a religious debate
among programmers, which is the right way to write your code.
And that's fine.
Once you get comfy, so long as you're consistent is the most important thing.
You don't need to adhere to one person's or the other.
So how does this code work logically?
Well, the first thing the computer, your Mac or PC or your phone
or whatever is going to do, it's going to ask the question.
Well, true.
Well, true is always true.
So it's going to proceed to execute the line of code.
But after it does, because that's the entirety of the code that's
in between the curly braces, we could have more lines.
These are just short programs.
The computer is going to check, OK, is true still true.
Yes.
So it's going to execute it again.
Then it's going to ask the question again.
Is true still true?
Yes, so it's going to execute the code again,
and this is going to repeat literally forever.
But what if you don't want to repeat something forever?
What if you only want to repeat it 50 times?
Scratch doesn't make you think very hard about this.
People just figure out how to keep track of 1, 2, 3, 4, 5, and all the way
up to 50 and then stop.
That's nice.
It makes it easy to use the block.
C and a lot of languages aren't quite that user friendly.
You will see later in the semester that newer languages are
a little closer to what Scratch offers.
But in C, we need to be more explicit, but this
is a chance to use some of these more primitive building blocks.
In C, the equivalent of repeat is going to be the proposition for just because,
for now.
And then, just as before, if we want to do something
again and again within this loop, we're going
to use the curly braces, similar to the little orange block there.
And then what am I going to do?
I'm going to do this every time, 50 times hopefully, print out hello world.
So now I just need to figure out and see how to express
the number of times specifically 50.
So it turns out in C-- use parentheses again--
this is going to be a pretty common characteristic of a lot of the code
we write.
And then you need to do three things.
The burden is now going to be on us the programmer
to keep track of how many times we want to execute this code to how many times
we've already executed this code and then constantly make sure
that one does not exceed the other.
So we stop once we hit 50.
So what's the fundamental construct that we use to keep track of anything
in a program?
A counter, which was an example of a variable.
So we just need to use a variable.
Now it's actually going to be inside of the parentheses this time.
So it's not on its own as it was just a bit ago, but the syntax is the same.
I could call it counter, but the reality is that the convention in programming
is just to use shorter variables when you're just doing something mundane.
And if all you're doing is looping--
i stands for integer, is sort of many programmers' go-to variable name
rather than the more verbose but correct counter or whatever.
So this says, hey, computer, give me a variable called i.
Let me store integers or ints in it and set the initial value to 0.
Why?
Well, almost everyone in this room probably starts counting from 1.
Computers just tend to start counting from 0.
But why?
What's the rationale for starting to count from 0
perhaps based on last week?
Why does that kind of makes sense?
Yeah, what do you think?
AUDIENCE: Well, because it's ones and zeros, and it's binary.
DAVID: Yeah, it's just ones and zeros, and what's
the smallest number, negative values aside,
that you can represent in binary?
Well, it's just 0, 0, 0, a bunch of zeros.
So why would you waste that representation,
that permutation of bits?
Let's just start counting at 0 and then add to that.
So you can start counting from 1 in C, but the convention in most languages
is count from 0.
So we'll get off on that foot as well.
And you might recall even that in our PBJ, for the peanut butter and jelly--
not for the PDJ code--
for the phone pseudo code, I actually deliberately started
numbering the lines from 0 to 1 to 2 for that same intuition.
So here's how you then say to the computer check, if you would,
whether i is less than 50.
Now, initially it's obviously going to be less than 50
because zero is less than 50 but that same condition is
going to be checked again and again and again as this loop executes.
And then recall from before, we can just plus plus a variable to add 1 to it.
We can do this more verbosely.
We could say i equals i plus 1, but it's just
more conventional to write i plus plus just
to say the same thing more tersely.
So what happens next logically?
That's the code I've written.
What does the computer do with it?
Well, it initialises i to 0 and prepare to store integers in it.
It checks the condition just in case you initialized it too big of a value.
You might not want the loop to execute at all.
But obviously 0 is less than 50.
So this line of code executes.
Take a guess as to what happens next.
Yeah, you probably want to do i plus plus
because you're done executing all the lines of code
in between the curly braces, even though there's just one.
So let's go ahead and increment i.
So i is now 1.
Let's now make sure-- is 1 less than 50?
Obviously.
Execute the code.
I plus plus-- is 2 less than 50.
Obviously execute the code. i plus plus-- is 3 less than 50, obviously.
Now go ahead and execute the code, and again and again and again.
And at some point, we're going to get up to i equals 49, and is 49 less than 50?
Obviously.
So we print out hello world.
And then i plus plus kicks in, and then it's, is 50 less than 50.
No.
So wait that feels like a logical error, no?
Should I be checking if i is less than or equal to 50?
Yeah, because if I started from 0, I already
spent that one additional cycle.
So I can count from 0 through 49 which seems to work or from 1 through 50,
but the convention in programming honestly
is typically to start counting at some value
and then count up to but not through some value just because.
But logically, you can implement this in half a dozen different ways most
likely.
Let's look at one final example that allowed us
to actually get user input in Scratch.
Recall that we used this block to actually get
the name of someone in lecture, and we also
in the animation with the gingerbread house used it to get yes or no--
do you want the cupcake or the apple or the like.
So this is an example of a function in Scratch
that actually takes input like the sentence what's your name,
but it also returns a value, which in this case
was just hard coded in Scratch by MIT to be called answer.
So it's like a special variable called answer,
but effectively it's being handed back to the user.
So how might we think about this?
In C it turns out that you can express this line of code a little more
verbosely than before but using a new function called get string--
so get underscore string is the name of the function.
The underscore is convention in C. If you ever want to have a space,
you can't have spaces in the names of functions.
So people just started using underscores like you might in your own social media
user names and the like-- is a convention there as well.
Here's the sentence I want to display, and I'm
going to start calling this more formally a string.
A string in a programming language is just a sequence of characters.
It's a word, it's a phrase, it's a character, it's a paragraph.
This is a string.
Anything between double quotes is a string in C,
and the backslash n it's just end of line as before.
We still already have the semi-colon, but this
isn't quite a literal translation of what's going on just yet
because I also now need to do something with the answer.
So if get string is a function that actually gets input from the user,
as via his or her keyboard, just like the blue block in Scratch, in C
we need to be a little more explicit as to where
we're putting the return value from that function, what it is it's handing back.
And so I can store in a variable called answer.
I could call it anything I want.
But for consistency with Scratch, let's call it answer.
But recall what we have to do in C anytime we create a variable.
We have to be more precise.
Yeah.
AUDIENCE: Define its class as a string.
DAVID: We have to define its-- let me call it a type or class,
if you've taken a previous class.
It's type and it's not going to be an int because probably the words being
typed in are not numbers.
It's going to be this time what I just called it a string.
And so, indeed, we would declare the variable on the left
by saying give me a string, call it answer,
and assign to it whatever's on the right.
Well, what's on the right?
What is on the right is whatever this function
get string comes back with and gets stored from right to left.
So how do I now say this person's name?
Well, in Scratch I just say and then I drag and drop the answer variable,
and it's done.
What's the function in C with which we can say something, though,
on the screen?
So printf, print a formatted string, even though we haven't really seen
any formatting yet until now.
It turns out in C, You have to actually tell
d if you're not passing in a hard coded string or sentence,
you have to pass to printf what's called a format code or a format string--
this first input to printf.
Now printf apparently seems to take two things.
The first is this one before the comma.
The second is the thing after the comma.
And we've not seen this before yet in C. So printf
is being told, go ahead and print out a string that looks like this.
Percent S is a placeholder, and S stands for string.
And that literally is a placeholder saying,
printf, I'm going to give you a string to plug in to this first input.
What is that string?
Literally, the answer variable.
Now it feels like we're jumping through hoops here.
It would have been nice to just say printf, open parenthesis, answer,
close parenthesis, semi-colon, and be done with it.
That's just not the way printf works.
In older versions, you could maybe do something
a little more simple like that.
But honestly, we're not typically going to be printing out
just what the human typed in.
After all, this is kind of a stupid example at the moment.
I'm typing in a word.
You're just saying it on the screen.
We already decided in Scratch that's kind of lame.
It'd would be nice to at least have the program, not just
say David or whatever the name is-- but what did we do last time?
Like hello comma David.
But this would seem to give us that capability.
Right now I'm literally just printing out the human's name in C,
but let me change this ever so slightly just as we did in Scratch.
Recall that in C we did this green block of join where I literally
get past join two arguments.
The first one was hello comma space.
The second one was answer, and this concatenated.
This combined back to back those two strings.
Well, in C, thanks to printf, we can do that same thing.
It's just a different syntax.
Printf still gets one argument first, that is, the string you want to format,
ergo the F in printf.
But this time I'm going to literally say H-E-L-L-O comma space percent S
for string and then give printf a second argument,
which is its instruction to go ahead and plug in whatever this variable is
to whatever this placeholder is.
And so here we've now joined the two strings effectively and thus
was born our first formatted string.
Well, any questions then on that?
Yeah.
AUDIENCE: What if you wanted to say something extra after it?
DAVID: What if you want to say something extra after?
You could certainly continue the logic.
You don't have to end this quoted expression
with percent S. You could say, hello, comma percent S
comma, nice to meet you.
And then what printf will do is it's only
going to substitute that variable called answer where the percent S is.
And if you want to give 2% S's, you could just add another comma here
and pass in another variable and a third variable and even more,
thus formatting the string even more detailed.
Question over here.
Yeah.
Other questions?
Yeah, in the back.
AUDIENCE: How do you make a distinction between the placeholders
if you have different variables?
DAVID: How do you make a distinction between the placeholders
if you have different variables?
It's the ordering from left to right.
So in this case, it's a trivial example because there's
only one variable and one placeholder.
But if as you were hinting, I had multiple percent S something something
something, percent S something something something,
I would just make sure that I pass printf the first variable comma
the second variable comma the third variable and so forth left to right.
Other questions?
Yeah.
AUDIENCE: Why is there no backslash n?
DAVID: Oh, damn it.
Because I screwed up and didn't include that and I
was going to fix it after class quickly.
Bug, it's a bug.
Yeah.
AUDIENCE: What if you wanted to use the int twice in the string?
So you wanted to say, hello, David, hi, David.
DAVID: Sure, same exact thing--
comma answer, comma answer with 2% S. If you want to say the same variable twice
in two places for whatever reason, two placeholders and then answer comma
answer to plug that in twice.
Other que-- yeah.
AUDIENCE: Is percent a universal placeholder in terms of integers?
DAVID: No, and we're going to see some others in just a bit.
It turns out there's others.
It's percent i integer, and there's going
to be even more than that-- percent c for a single character and more.
Other questions?
Yeah.
AUDIENCE: Since the backslash n is a variable, would you put it after n?
So will you put it in the quotation?
DAVID: Good question.
If I did have correctly-- and if this weren't a PDF,
I would just edit it on the fly--
if I had the percent n, it always has to go in the formatted string,
in the first argument.
So the only thing that comes after printf's first argument
is optionally variable comma variable comma variable comma variable.
Other questions?
so Let's go ahead and actually do something with code.
I'm going to go ahead and open up another window,
and this is a tool called with CS50 Sandbox,
and this is a tool via the web by a which you can actually play with code.
And I'll show in just a moment how I get to this particular location,
but let me first explain the user interface much like we started off
our conversation with Scratch.
So I need a place to write code.
The reality is I could just use my own Mac.
I could just use my own PC.
Frankly, I could even use certain mobile devices these days.
But then we would have hundreds of other people in the class
all with slightly different configurations
on their Max and their PCs and their phones and the like.
And so everyone would have different software and different settings,
and they just never works very well.
So at the beginning of the course, we just
standardize everything by actually using a web based environment
just like Scratch is, whereby we'll all have access to the exact same computer
but virtualized in the so-called cloud.
If you've ever wondered what the cloud is,
it just means other people's server somewhere on the internet
that people can use for free or to rent and not
have to host those physical servers themselves.
So CS50 Sandbox, just like Scratch, is a cloud based application
that someone else wrote that's hosted on the internet,
and the user interface, at first glance, looks just like this.
There are only two components to it.
At the top of the user interface of CS50 Sandbox
is just a code editor, a very simple text editor
similar in spirit to Google Docs and Microsoft Word and so forth
but much simpler.
There's no formatting.
There's no bold facing and centering.
You can just type words of text.
Down here is the so-called terminal window,
but we'll come back to that in just a moment.
Let me go ahead and write my first program.
Let me go ahead and write include standard IO dot age
int main void open curly brace printf hello world backslash and semi-colon,
done.
Now few people in this room could probably whip up a apparent program
that quickly unless you do have prior background.
And if you did take APCS or something else, it looks kind of like Java
but not quite the same.
But this is my first program.
Now recall from earlier this was the black and white program
we saw on the slide just a little bit ago.
And even if you didn't quite appreciate what all the funky syntax is doing,
all of us probably had the intuition of what this program does,
which is just to print out the words at the end of the day hello world.
And we'll tease apart in just a bit what all these various lines are doing.
But the interesting part is what's highlighted in green here,
and this is just one of the features of CS50 Sandbox.
It will color code different concepts within your code
so that they just jump out at you.
The colors aren't actually there.
You don't have to color code things yourself.
It just does it automatically so you can see the different components
just like MIT colorizes is the various Scratch puzzle pieces the same.
So this is a program that I want to call hello.
It's in a file.
This is just a tab up top called hello dot C
because it turns out, when you write a program in C,
you save it in files by human convention whatever dot C as the file extension,
so to speak.
How do I run this program?
There's no green flag to click, which Scratch gave us.
So how do I actually run the program.
And frankly, moreover, the green flag seems to be the least of my concerns.
What is the language that any computer understands
whether it's my Mac here or the cloud server where this thing is?
Zeros and ones, right?
And we started with that overwhelming slide of a lots of 0's and 1's, and
that is the point we need to get to.
But hopefully, we ourselves don't have to write at that level of tedium.
So we need some way of converting this code
from C, which we'll start calling source code, which is the English like code we
see on the screen that's mildly pleasurable to write as opposed
to just zeros and ones.
But we nonetheless need to convert it somehow to zeros and ones.
And so the way we can do this is essentially as follows.
If we have what we'll start calling our source code, which can be written,
in our case, in C, but you can write source code in Java, in C++, in Python,
in dozens of other language.
Source code's a generic term.
That just means the code that we humans have written.
We need some way of converting it into zeros and ones, which
henceforth we're just going to call machine code, which
feels like a reasonable name.
It's the zeros and ones that a machine understands.
How does a machine know what zeros and ones to understand?
Well, that's the whole reasoning behind having CPU, Central Processing
Unit, the brains of a computer.
They are just hardwired at the factory, so
to speak, at Intel's factory to understand
certain patterns of zeros and ones.
But the point for us now is we need to take a source code, like the C program
I wrote a moment ago that's supposed to print hello world,
and somehow convert it to machine code.
So it turns out this is the step that humans who've come before us
have solved for us.
Other humans have already written programs
that we're going to start calling a compiler that allows us
to convert source code to machine code.
It's just one additional step.
This step did not exist in Scratch, but we're
going to run a program that's generally called a compiler that we pass
our program to as input, and we get as output machine code, thereby
perfectly bringing us full circle to what computer science is
is in now the context of programming-- input
source code, outputs machine code.
The algorithm or the special software we're going to use in just a moment is
called a compiler that just converts one to the other so that none of us have
to ever think about or write in 0's and 1's.
So it's a little old school how you do this.
In Scratch, you obviously just hit the green flag and MIT
and all those folks took care of it for you.
We have to be a little more manual about this,
and that's where the second piece of CS50 Sandbox user interface
comes into play.
Notice I have a blinking prompt here.
There's dollar sign at left, which is just a common convention.
A dollar sign tends to in these types of computers represent a prompt.
It's waiting for me to type something, and indeed it's literally blinking,
waiting for me to type something.
This is an example of a terminal window, and your own iMac and your own PC
actually has or can't have this exact same feature.
It's just all of us operate with graphical user interfaces these days.
So we've got buttons and menus and things
to drag and click, but back in the day--
and typically in programming-- you don't bother with these aesthetics.
You actually get your hands dirtier with just the keyboard alone typing
anything you want to do.
And at first, it might feel like a regression.
Like, why are we giving up all these beautiful amenities
of modern computers?
But it's more powerful, and it's more explicit.
It lets you do exactly what you want to do by sending commands to the computer.
So this is my terminal 1.
I can create others just to have multiple windows,
but this is giving me access to the underlying server that I now
have access to.
So if any of you, when it comes time to the first problem set,
log into the same tool, you don't all have the same environment.
You all have your own isolated copies of the same software but your own storage
space, so to speak.
So I need to somehow convert hello dot C to zeros and ones.
And the way I'm going to do this is like this--
clang, which stands for C language, hello dot C enter.
And the fact that I see nothing happening is actually an amazing thing
because there's an infinite number of things, frankly, that can go wrong,
and the computer will happily yell at you
with cryptic looking error messages if any of those things do go wrong.
So seeing nothing but another blinking prompt with the dollar
sign is actually a good thing.
My code has somehow been converted to zeros and ones.
Where are those zeros and ones?
Well, by convention, they are stored in a file that's weirdly
and historically just called a dot out, and we can see that.
If I click this folder icon up here, you'll
actually see my file hello dot C and another file now called a dot out.
It stands for assembly output, but for historical reasons.
Now let me close the folder icon because we're generally not going
to use the graphical user interface.
How do I run that program?
I couldn't just double click on the icon.
This isn't a Mac.
This isn't a PC.
This is a cloud based Linux environment.
Linux is a super popular operating system.
It happens to be used by lots of computer scientists, lots of websites,
lots of servers.
In fact, almost every website you visit these days is powered,
if not by Windows by Linux, and variations thereof
called Unix and other flavors still.
It's just a very popular and often free operating system
that CS50 Sandbox itself uses.
To run a file called a dot out that's in this folder, so to speak,
even though you don't see a graphical version of it.
You literally just type dot slash a dot out.
Completely non-obvious and kind of a stupid name for the program,
but this is the equivalent in your Mac or PC of double clicking on an icon.
Let me go ahead and hit enter.
And when I do, I should hopefully see what?
Hello world.
And here we go.
Wow, that's our first program.
It's not doing all that much, but it's at least
doing what we promised it would do.
And this is the equivalent in Scratch of just saying on the screen hello world.
Now to be fair, there were more steps involved,
and God knows there was more cryptic looking code to write.
But at the end of the day all we've done now
is re-implement last week's logic in this new language,
but we're now going to very quickly introduce new puzzle pieces but in C.
But first let's solve this minor headache.
I don't really want to tell friends like,
hey, everyone, come run my a dot out program.
Let's give it a real name.
Suppose I just want to call my program hello
like you might download from the App Store or Google Play Store.
Programs have names.
So how do I do that?
Well, it turns out in a terminal window, the so-called command line environment,
which is just a fancy way of saying you write lines of commands
with your keyboard, you can actually pass
in what are called command line arguments, additional inputs
to programs that are just words that you type at your keyboard that tell it
how to behave.
So instead of just running clang on hello dot
C, I'm actually going to be more explicit
and I'm going to tell clang please output--
as is implied by literally typing dash 0 for output--
a file called hello instead.
So it's a little more verbose--
hello dash O hello-- or, sorry clang dash O hello hello dot C.
But what this is going to do now is still convert
source code to machine code, but it's going
to save it in a file called hello.
And indeed now I have hello dot C a dot out and hello as
pictured in the little graphical folder there.
So now I can instead run dot slash hello.
What should it say?
Hopefully the same, enter.
So that's it.
Those are called command line arguments, and it's just
the old school way of telling a text based command
how to behave a little bit differently from its defaults.
But frankly, this is going to get tedious quickly.
We aren't going to want to write our code
and then every darn time we want to convert it to zeros and ones to run it
actually remember these magical incantations of commands.
And so humans have abstracted these away too.
It turns out that, if you want to make a program from source code
into machine code, there's another command you can use.
And you can literally type make hello, where
hello is the name of the program you want to make,
this program, whose name is make, will look for a file
by default called hello dot C, therefore saving you the time of specifying it.
Hit Enter now, and, oh my god, look what it just did.
It has even more configuration options that are baked into it,
and we as CS50 staff, configured CS50 sandbox to have these various features.
And even though we're not going to go into detail on them now,
I'm going to wave my hand at what they actually do.
They just make additional features possible that we'll eventually get to.
But this would be otherwise the command that you all
do have to type in just two or three or four weeks time,
and no one can ever remember that.
I certainly couldn't.
So Make just automates that for you.
But when you run Make, Make is not a compiler.
Make is not the thing in the middle here converting source code to machine code.
It's just a second program that some humans wrote years ago that use
clang in an automated way to achieve the same output.
Because people got tired of typing stuff like this.
So someone made a program called Make that does it for us.
Any questions?
Let's add a little bit then to this program.
Instead of this version of hello, let me get some user input
and actually do something with it.
Suppose I actually want to get the user's name and then print that out.
Well, we saw the spoiler for that just a moment ago,
but let me go ahead and add to this program here.
Now I have a second line of code, and I want to get a string from a user.
And with what function do I get a string from the user?
Get string was the one, and recall I can do get
underscore string open parenthesis.
And then I have to pass in an argument, so to speak, like give me your name--
or actually, what did we say before?
What is your name, I think was the prompt backslash n semi-colon.
Now it's not enough to just get the string.
What do I want to do with it?
Yes, store in a variable.
What type of variable?
A string.
So I just need to go on the left hand side of this line of code
and say, OK, well, give me a string.
I'll call it name, but I could call it x or y or anything.
But name feels like a good descriptor for it,
using a single equal sign to copy from right to left.
And now I've got that.
Now it's not sufficient to just store the value in the variable.
I need to print it out.
So let me start with this.
It autosaves, the Sandbox.
So I don't even have to go up to File, Save or anything.
Let me go ahead and do make hello now--
oh uh, oh my god, look at all these errors already.
So clearly something is wrong, as the computer is fond of telling me in red.
And frankly, this is where you very quickly
get derailed or kind of freaked out because,
oh my god, I only wrote two lines of code.
How do I have 20 lines of errors somehow?
So the computer is kind of as confused as you.
And the most important thing, when you face this kind of situation
where it's just cryptic, erroneous output, start at the top.
Even if your window's kind of small and therefore a whole bunch of stuff
scrolls on the screen quickly, scroll up to the top
because odds are there's one mistake up at the very top
and that one mistake just had a cascading effect on the compiler.
Then it just got really confused, and it just kept spitting out messages
because it got tripped up early.
So let's scroll back up to the top here.
And here is the very long command that I said make automates for you.
So that's not erroneous.
Here seems to be the first error, and it's a little cryptic still.
But let's glean some information.
Here's a familiar phrase--
hello dot C. Let me go ahead and zoom in on the bottom here.
So hello dot C recalls the name of my file.
Albeit not obviously, clang is telling me look at line 5 and then
your fifth character.
So this something colon something means line number character or column number
if you're looking from left to right.
Error means error.
And then this is where things get a little sophisticated.
Use of undeclared identifier string--
did you mean standard n?
No I didn't, but I do recognize standard n,
or rather it seems similar to standard I/O. But no, I didn't mean that.
I'm pretty sure this code is right.
Well, why am I getting this error?
It sounds like string, on line five, fifth character, right there,
that is wrong.
Well, it turns out, there is no such thing as a string.
C, the language, has integers, and it has Booleans, it turns out.
And it has characters and a few other things.
It actually doesn't have strings.
Strings is a word that's useful to describe sequences
of characters, paragraphs, words.
But string is not a type.
It's not a type of variable unless you make it so.
And in fact, this is one of the simplifications we do.
In just the first couple of weeks of the course to get us off the ground,
it turns out that we need to add one line of code here.
We need to do, not only include standard I/O-- which we'll explain in a moment--
but also CS50 so-called library.
So CS50 has a lot of humans involved with it, and over time we've decided,
you know what, we could make the first hour of CS50 a little easier
and the on ramp a little cleaner for folks with no background
by just inventing a few features ourselves such as the ability
to get strings from the user.
So it turns out get string is also not a function that
comes with C. That is a custom puzzle piece, so to speak, that CS50 made.
And where we created that function is essentially in a file
called CS50 dot age.
And so by including dot age, you now get access
to more puzzle pieces, if you will, that we have created for you.
And it turns out this line of code that has
been here before is also giving you features, too.
We're just doing what everyone does in programming,
which is solve a problem once and then let other people use that solution.
Take a guess.
What functionality is actually implemented
in a file called standard I/O input output dot h?
This is just a file somewhere on the server that actually does come with C,
and it provides you with handy features like what?
Say again.
Once more.
Printf.
It turns out that the means by which you are allowed to use a function
called printf here is you have to include
the file in which it is declared.
So some humans, years ago, literally wrote a function, a puzzle piece,
called printf, and they figured out how to actually draw
characters on the screen.
They then stored information about that function in a file
called standard IO dot age.
If I had not included that seemingly cryptic line of code
at the very top of my previous program, even that hello world program would not
have worked because clang, the compiler, wouldn't
have known what I'm talking about.
What is printf?
I don't know what that is unless you tell
it to also include this file that humans wrote years
ago in which printf has been created.
And now if I want to use get string, as well as the new keyword string,
I need to tell clang the compiler, also go ahead
and look in CS50.h for more functionality, such as string
and get string.
So let me go ahead now and try this again.
I'm going to clear my terminal here and just try that same command again--
make hello, enter, dammit.
Now I've got another error.
But, but, but, progress.
Well, no, just as many errors as before somehow, but different ones.
Notice now-- wait, that was before.
Oh, no, I'm sorry.
It has fewer errors.
Here's where I ran the command a moment ago,
and now I'm getting this error instead.
So progress.
Now my error is not on line 5.
It's on line 6, though fun fact, line 6 used to be line 5.
So it's apparently still involved in the problem.
So let's read the error message.
The problem is on line 6, which is no surprising is that one there.
But this time it's different-- error, unused variable name.
That one I kind of understand even without being a programmer.
What does that mean?
Yeah.
Maybe declare prior to using, but it turns out this is how you declare it.
But I'm actually-- yeah.
AUDIENCE: You're not actually using the variable you declared.
DAVID: Yeah, I'm just kind of wasting the computer's time.
I'm creating it.
So line 6 on the left is correct.
Hey, computer, give me a string variable,
and call it name and put a value in it.
But what's the point of that exercise if you're never,
as you say, doing anything with it.
And in fact, recall from the slide a moment ago,
how do I do something with it?
Well, this is not how you do something with it.
If I go ahead and run this program now successfully,
what would I actually see on the screen?
Literally hello name, H-E-L-L-O comma space N-A-M-E, obviously not correct.
So how do I plug in the variable?
What was the trick?
Yeah, percent S for string, a format code,
so to speak-- hence the name printf.
And then I need to pass a second argument to printf,
and I do that with a comma and then the name of the variable I want to plug in.
Now notice there are two commas in this line here.
If I zoom in, notice there's two commas, but there's only
two arguments or inputs to printf.
The input to a function is just typically called an argument
or also called a parameter.
So there are two commas, but this one is an English comma just separating hello
from the person's name.
This white comma here, color coded because the Sandbox is doing the for me
is actually separating-- excuse me-- the first argument
from the second argument.
So now, for a third time, make hello enter.
Oh my god, thank you.
Now it worked.
It still spit out this pretty long, cryptic command in white,
but that's OK.
That is, again, the automated command that Make is making possible for us.
But the fact that I see no red, no errors, just another blinking prompt
means that my program has been made.
So let me go ahead and do--
how do I run a program if it's called hello?
Yeah, dot slash hello, and we'll see why you
have the stupid dot at the beginning.
It essentially means run the program called hello
that's right here in your current folder on the server--
dot slash hello.
What is your name?
Very nice.
David, enter.
Hello, David.
Interesting.
Let's make one tweak, because I did this by accident earlier as you noted.
What if I left off for instance one of these backslash n's
that's literally now not telling the computer
to move the cursor to another line?
So let me go ahead and rerun the program.
Wait a minute.
That looks the same.
I just changed the code, but it's still behaving exactly the same.
Where's my confusion?
I didn't recompile it.
Unlike Scratch, which is amazing because you just hit the green flag
and it runs the code again, we have a second intermediate step.
I have to re-run the code.
Now how do you get out of a program?
I could just hit Enter.
You can also hit Control C for cancel, and that will just get you out
of whatever confusion you're in.
Let me go ahead and rerun, make hello--
seems to be OK--
dot slash hello, enter.
OK, this is why I've had all those backslash n's.
Let me zoom in on what's happening.
I mean, it doesn't look horrible, but frankly it kind of rubs me
the wrong way if this is what my program looks
like when I'm typing in user input.
I mean, this just looks stupid.
Minimally, I should add a space.
Maybe I can put a backslash n to move the character.
This is user interface now.
This isn't really logic.
It's just aesthetics, but I think this looks stupid.
So that's why I've had the backslash n's there all the time,
but that's why they need to be there to tell the computer to actually put
things where you want them.
Alternatively, you know what, OK, I don't like that.
Control-C for cancel.
Let me put this one back.
What happens if I get rid of this one?
And let me go ahead and recompile the code first
as you note dot slash hello enter.
OK, I've cleaned up that aesthetic headache, enter.
I mean, it's not quite the same problem, but this looks stupid too
because the dollar sign just represents my prompt where
I'm supposed to type commands and yet hello comma David prompt.
And that's just messy.
So this is why we've had all of these new lines.
Now you asked earlier, what if you put the new line elsewhere in the string.
Well, suppose I do that.
Suppose I put a couple of them.
Let me do this and no spaces whatsoever.
Now this is looking a little weird, but the computer is just going to interpret
this literally-- print H-E-L-L-O comma new line substitute in the string
for percent S then another new line.
So how many lines of output is this going to display?
I heard four.
Other values?
Let's see.
Let's go ahead and make hello and then run
dot slash hello, what is your name as before enter hello comma new line
David-- so four total lines certainly or just two lines from the computer
itself.
So just to recap then, with code like this
how many functions have I used in this particular program?
How many functions?
So it's two-- printf, which we've been using and get
string, which is the new one.
Where is string declared?
CS50 dot h, printf meanwhile is declared in standard IO.h standard input output.
Meanwhile, string, this data type also comes from CS50 itself,
and then we've used the format codes, and we've
use variables to achieve the same result.
And let's just hammer this home.
Brian and Karim, do you mind popping up for just a second?
Or who's there?
Erin, come on up.
So just to make this clear because there is now
some terminology that we want to use.
Let's see.
Do you want to be--
you'll be get string.
So we have some name tags here like you get at events.
So Erin shall be get underscore string.
If you want go ahead and put this on.
And Brian, you want to be printf.
So we won't act out all of our actual programs
because this will quickly become obvious.
So Brian is printf.
So this point though, remains in that this is nice
that I have some colleagues with whom I work here
because I don't really want to do all of the hard work of making things happen.
And so if I'm instead the programmer or the orchestrator
of a whole bunch of things happening, I can actually implement this code now
more physically.
And let's focus, though, for just a moment on what the key takeaways are.
One, functions can take input.
Those inputs are called arguments or parameters,
and functions can return things.
They can have return values.
Printf, for instance, does it take input?
What's the input to printf, for instance?
Yeah, like hello world.
Whatever it is you want to print is by definition the input to printf.
Does print return a value thus far?
It does do something on the screen certainly.
It prints stuff on the screen, but we haven't
seen it return something because we haven't seen it with equal sign
to the left.
Now it turns out printf does return things.
It's just not often that useful to use, but we've only
seen printf for the moment as taking inputs-- more on that another time.
Get string, meanwhile-- does get string take inputs?
How many inputs?
Just one, the prompt that you want the human to see.
The first prompt I used was what is your name.
I could make the prompt anything, but that's
the question that get string is asking.
Does get string return a value?
It does.
That's of course in Scratch called answer, hard coded as answer.
We can store in any variable we want.
So let me just go ahead and implement this program.
Erin, go get me a string and ask the person, what is their name.
So--
ERIN: What is your name?
AUDIENCE: Elizabeth.
DAVID: So she's writing down Elizabeth now.
But Erin has taken input from me.
Erin, go get someone's name and ask them, what is their name.
And now you've produce output for me.
Thank you.
This is the return value, storing the value Elizabeth,
and I'm going to go ahead and took it away
in a variable called name like this piece of paper here.
OK, Brian, could you go ahead and say hello Elizabeth.
So what's going on here?
I'm just doing less work.
I am writing this program--
Erin, go get someone's name, Brian, could you print this out.
That's what I've been doing, is programming,
just delegating functionality to other functions or in this case
other humans who know how to do that.
And honestly, I don't have to know how Erin got that name.
She just got it.
I don't have to know how Brian wrote in that particular kind of style
of English on the screen.
I just know that he can do it, and now my program is complete.
Thank you very much to both of these two here.
We'll continue in just a moment as follows.
So all this time, we've been taking for granted
that we have an actual computer on which we can execute code,
and I keep saying Intel inside that's the silly slogan that you see inside
of most Macs and PCs with the hardware they have.
But the CPU is just the brains of the computer.
And at the end of the day, recall that the goal
is to actually have the computer turn something like this--
source code-- into actual machine code, zeros and ones.
And that's all Clang was actually doing for us.
Of course, we've only just scratched the surface now of what we can do.
It turns out there's going to be, not just these
commands that we can run, but other features of C
and in particular the CS50 library.
We've only seen thus far how to get a string,
but you can get integers and characters and funky things
like floats and doubles, which actually open a can of worms
as to problems that can happen in a computer.
And it turns out you can store different types of variables, not just
integers and strings, but bool for Boolean and chars for characters.
And you can format those things in printf.
We've only seen percent S. I alluded to percent i earlier,
but there's a few other still.
But we've got a lot of possibilities here.
But let's go ahead and take, say, a five minute break to give everyone
bit of a respite, turn on some music, and come back in five and dive
in deeper to more sophisticated programs in C.
So recall we began by comparing some Scratch
blocks against the corresponding C code, but we didn't actually
use most of those blocks in C just yet.
So let's try out a number of examples, some of which I'll write on the fly
in typing code out on my own keyboard, some of which
we already have in the course's web sites.
So we can just open them to save some time.
But let me just draw your attention to what
CS50 Sandbox is because this was the step that I skipped over earlier.
CS50 Sandbox can be used to program in bunches of languages.
We'll initially in the semester use it for C.
But if you've written Java before or Python or any number of languages,
when you go to Sandbox.CS50.io, you can simply
choose the language you want to write in.
And then at the bottom, you'll see you can
specify the name of the file you want to precreate.
So for instance, what I did earlier was I selected C at top, and then
at the bottom I typed in Hello dot C because that
was the name of the file I wanted.
And then I clicked start.
And what that led me to was precisely the interface in which we wrote hello
dot C just a moment ago, where my code editor appears on the top here,
my terminal window appears at the bottom,
and then I'm allowed to just start writing code.
So that's how we got to where we were.
And if you want to follow along now with some of these examples,
note that on the course's website we have all of them premade.
And you can actually click the links on the course's web site
and open up your own copy of a sandbox with that code.
So if the Wi-Fi cooperates, you're welcome to tinker and play and run
the same commands.
But everything is also on the course's website after.
So you needn't type everything out.
So let's go ahead and do just a quick example.
I'm going to call this int dot C just so that we can reinforce
some of what we did just a moment ago.
Rather than get a string like we did with our hello example, let me go ahead
and just get, say, an integer, and then print it out
just as we did print a name.
So I'm going to have to go ahead and, just through muscle memory,
I remember that I need standard IO dot h of the top
and then int main void and then curly braces.
And then I can do the act of actually getting the input.
So there was a function before called get string.
It turns out there's another function called
get int if you want to get an integer.
So I can actually call get int, and I can say something
like integer is the prompt.
Like, hey, human, please give me an integer.
I need a semi-colon at the end of this line.
And then how do I actually store the return value of get int in a variable?
Just as Erin handed me a sheet of paper with a string,
I'm handed a sheet of paper with a number, how do I store it somewhere?
What's should I literally type line five here?
Int space and then number or something.
So I'm going to call it i just because it's an integer,
but I could call it number or anything else.
And then I'm going to go ahead and print this out.
So printf-- let's say something like hello i backslash n semi-colon.
Not quite correct, right?
This is going to literally print hello comma.
How do I actually substitute something in?
Well, we've only seen how to substitute in strings,
but I think I spoiled earlier the answer.
If you use percent i, that says, hey, computer, put an integer here.
Then I need a second argument to printf just
as we handed Brian an argument as well.
And I said i.
I want to say i here.
But this program isn't quite correct yet.
It's in a file called int dot C. I've included standard IO dot h.
It's in main, and so what is main?
Well, today were largely going to wave our hands at that.
But int main void is perhaps the most cryptic way
you can say the equivalent of when green flag clicked.
That's all that does, and we'll come back in the weeks
to come as to why it's int, why it's main, why it's void.
But for now, humans years ago just decided
that, when you're writing a program in C and you want to start the program off,
you literally have to type int main void with those parentheses
with those curly braces, and it's the equivalent to Scratch
is when green flag clicked.
But this program will not compile, and I don't even
want to induce the stress of seeing those errors.
How do I void it?
Yeah, I need to teach the computer that get int exists,
and I know how to do that from before by including the CS50 so-called library.
Technically, CS50 dot h is a header file.
Dot h means header, and it's just a file containing C code
in which the functions are created.
More on that another time, but that just gives us access to printf.
So if I've made no typos, I should be able to compile
this program by running what command?
Make int.
I could do Clang.
I could do Clang dash O. But for now I'm going to do it simpler with just
make int and let make automate the process of compiling this program.
No error messages is good.
Let me go ahead and zoom in--
dot slash int I think would run the program.
Integer, how about 42?
Hello 42.
And notice, I can save time now.
And if I want to run it again, I don't have to do slash int all the time.
It turns out that in this kind of Linux environment,
this operating system called Linux, you can actually go up and down
and see previous commands you've typed and some others that
happen to be system specific.
And if you just set up and enter, you can run it again, type in 50 this time,
and see another output as well.
So any questions then on just an example like that?
No?
Well, let me go ahead, and I'm going to save time in this environment.
I can actually create files in here if I want by clicking the folder icon,
clicking the plus.
And then I can actually say give me a file called float dot C.
So this is equivalent to going back to the main menu
and typing in the name of the file.
I'm just going to do it a little more quickly
now in this graphical environment.
And I want to call it float dot C.
It's A bit of a weird name because at least growing up you probably
learned maybe about integers.
You probably learned about real numbers, numbers
that can have decimal points and then things after the decimal point.
In a computer, those things with decimal points
are called floating point values, or floats.
And you can think of it as the decimal point can kind of float
to the left or the right, depending on how big or small the number is
or how precise the numbers after the decimal point are.
That's a float.
So let me go ahead and implement a very similar program--
include CS50 dot h include, standard IO h int main void--
and this is after 20 years of doing this that you can do it so quickly.
Now let me instead get a float from the user--
so a real number that may very well have a decimal point in it.
I'm going to do that a little differently.
I'll zoom in, and I'm going to say, hey, computer, give me a float,
as is the data type called--
not int, not string but float.
I'll call it f just because that sounds like float, and it's nice
and succinct-- equals get float.
And then I'm just going to say float.
That's the prompt.
I could make the prompt in green anything I want.
And now I'm going to print it--
printf hello f, but I don't want f.
I want to actually print out a placeholder and you can probably
guess by now what the pattern is--
percent f for a float new line comma f semi-colon.
So this is like the same program three times now with a string, with an int,
and a float.
But again, it's just for some muscle memory and going through the pattern,
but let's see what happens differently here.
Let me go ahead and type make float enter.
OK, good, no errors.
Let me zoom in and run this now as dot slash float.
And let me go ahead and type in a number.
I'm going to just say 42.
But the computer now has the capability of storing more precision.
Before it was just an integer by definition of int.
Now it's a float.
So even though it's pretty precise, this 42.0000,
that's indeed a real number now, storing some amount of precision there.
So it turns out though that we can do more interesting math.
Let me go ahead and just open this example in advance.
This one is going to be called int dot C.
So then I don't have to type everything out.
And in ints dot C, we're going to see some math written in code that I
pre-created just to reinforce that you can actually
do some basic arithmetic in a program.
I can make see more of the code here by just scrolling down,
and let me scroll this up so we can focus on main.
And let me zoom in on the first few lines.
On this first line, I'm just getting an int, and I'm calling it x.
We've not used a variable called x recently.
But now we are.
It's no different logically than before.
Here get me another variable.
So we can see now that you can get multiple variables from the user
just like in Scratch.
And now in these lines, in green are just some format
strings-- just what do I want printf to display?
I literally, in this highlighted line here, want printf to display x plus y
equals something.
What is that something?
Well, notice what's cool about printf is that, before it is passed in input,
you can perform simple arithmetic operations.
So if you want to add x and y together, literally do x plus y.
Then the sum of those numbers is what will get handed to printf as its input.
Just like I handed Erin's piece of paper to Brian as input,
I'm handing not x and y to Brian in this case, but x plus y
or some value, the actual sum.
Similarly, subtraction is the hyphen on your keyboard.
For multiplication, it's not an x.
That would be weird, xxy.
It's instead star, or an asterisk on your keyboard.
Division is the single slash, and then this one is a little funky,
but we'll come up with some uses for this.
You can actually do modular arithmetic or just more simply remainders.
If you do x percent y, you'll get back the remainder of dividing x by y.
And what's the remainder?
So if x is 20 and y is 10, well, 20 divided by 10 goes in twice perfectly.
So remainder is 0, for instance.
But it's been a while.
So notice, though, what's curious here.
In this context, percent is not a placeholder.
It's not percent S. It's not percent i.
It's not percent Notice it's not inside of printf's format string.
This is just literally math, a math operator
as is implied by the different color blue there.
So if I actually run this--
let's go ahead and run this program.
I'm going to go ahead and do our make ints--
plural because that's the name of the file--
enter dot slash ints.
And let me zoom in and clear the screen.
Enter.
Give me a number.
2 I heard.
And another.
10 I heard.
So FYI, 2 plus 10 is 12, 2 minus 10 is negative 8, 2 times 10 is 20,
2 divided by 10 is--
2 mod y, or 2 and then take the remainder when dividing by y
is what mod means is 2.
So I get four out of five for correctness?
What's a little funky here?
Yeah, 2 divided by 10?
Like, I'm pretty sure that's like 2/10 or maybe one fifth or 0.2.
I mean, I'll take any number of answers but not 0.
So what's going on?
Well, this is a matter of representation.
It turns out in a computer program, we decided
in advance I'm going to store ints.
An int is something that does not have a decimal point.
And yet here I am rather presumptuously trying
to do to 2, an integer, divided by 10, an integer,
and expecting something other than an integer.
No, I literally am doing integer arithmetic.
So what's the computer apparently doing just intuitively?
Why, when dividing x by y as I did in this line here--
or specifically in this example you proposed, 2 divide by 10--
where is my 2/10 going?
Yeah, it's technically what?
Supposed to be 0.2, or 0.2.
That's actually the solution because, if it's 0.2 but integers
can't store decimal points or anything after them, what do you have left?
Just the zero at the beginning.
So integer arithmetic is fine if you're working with integers,
but if you want floating point arithmetic,
you're going to need to make some changes.
And so I can fix this.
In fact, let me go ahead and write a different program here.
Let me go ahead and open up from the course's website
floats dot C. That's going to give me this example, which is implemented
using floating point values instead.
So once this loads, I'm going to see a program I wrote in advance.
It's a little shorter because now I only care about looking at one problem.
And notice now x and y are now floats and not ints,
another data type that exists.
And I'm using get float, which also comes from CS50's library.
And then this line is almost the same, but you know what?
Let me let me tweak this.
Let me just make it exactly the same.
This line now that I've highlighted is exactly the same as before.
So if I do type in the same number--
so let's go ahead and zoom in and do make floats plural and dot slash
floats.
I'll give it 2 and 10, and I should hopefully see what now?
0.2.
That's pretty good, pretty precise.
But you know what?
I hate to tell you, but let's look a little farther.
It turns out by default, when you percent
f, you only see a few decimal places, like five or so it looks, by default.
Let me see a few more so.
This was one one, two, three, four, five, six
points after the decimal point.
So you know what?
I'm going to say, hey, computer, give me decimal points.
This looks completely cryptic and you just
have to kind of remember this or look it up if you forget.
If you put a dot and a number in between the percent and the f,
that's the cryptic way of telling the computer show
me a float but with this many decimal places, please.
So that just gives me decimal places, weird as the expression looks.
Now hopefully I'm just going to see some more zeros.
So let me go ahead and make floats, and let me go ahead
and zoom in and do dot slash floats 2 10 enter.
OK, still correct.
Let me get a little curious.
Let's see a lot of zeros, like 50 of them.
Let me go down here and do make floats, because I changed the code,
dot slash floats 2 10.
Ha, your grade school teachers lied to you.
2 divided by 10 is apparently not 0.2000000 infinitely.
It's apparently 0.20000000298023223876953125 and then
all of those zeros.
What the hell is going on?
Where's the bug?
Where's my mistake?
Where's my misunderstanding?
What's the explanation for this?
Well, what if I told you that inside of your computer is stuff like this?
This is RAM or memory, and you've probably generally known this idea.
They just store files.
They store music and videos.
You need memory, some kind of space.
Hard disk space is permanent storage.
RAM, or Random Access Memory, is temporary storage.
So when your laptop is open and your desktop computers is on
or your phone is powered, you're using RAM for all of the programs
you're running at once.
If you open a file, that file is stored in RAM,
but it's permanently stored on your hard drive.
So there's different types of memory.
But notice, this is zoomed in.
In reality, this is like couple of inches wide and maybe an inch tall.
So it's pretty small, but it doesn't really matter how big it is.
It just matters that it's finite in size.
You have physical hardware on your laps or in your pockets or at home
that only are so big and therefore only have so many parts
and therefore only have so many transistors
and other pieces of hardware that's actually
doing the work of storing information.
And so if you only have a finite amount of memory, how in the world
are we going to represent an infinite number of numbers?
Because I do recall from grade school I was
taught there is an infinite number of numbers, certainly real numbers, where
the decimal point can go on forever.
That is a problem if you want to represent all possible numbers
in the universe, which is infinitely many, with a finite amount of hardware.
So at some point, the computer's gotta start cutting some corners.
And so what you're really seeing here is as close
as the computer can get to storing that fraction for you precisely,
and I got a little greedy.
I looked a little too far to the right.
And granted, these are infinitesimally small values.
It's not hugely, hugely off, but it is off
because they can't expect the computer to represent
an infinite number of values using a finite amount of memory.
It's got to round off here or there and be imprecise, so to speak.
So is this a problem?
I mean, we would never have known this if I hadn't gotten greedy
and looked at 50 decimal places instead of 7, which was already pretty precise.
Is this a problem?
Yeah, like why?
Why?
AUDIENCE: If you use the equal function, [INAUDIBLE]..
DAVID: Yeah, that's a good one.
Logically, if I start using equals equals to compare things for equality,
it's going to be really hard for me to ever compare something for 2/10
as it's value because I'm going to literally have
to remember or write down or figure out this value and compare against that
and not just compare more loosely against 0.2.
And that's true, you should actually never compare floating point values
in code for equality.
I could probably get away with less than or greater than,
but even then it's going to be a little off from what I expect.
Why else might this imprecision be worrisome?
When might you not want your computer being imprecise?
What domains?
What worlds outside of a classroom?
Yeah?
What's that?
AUDIENCE: Rocket.
DAVID: Yeah, so rockets, or anything involving math and physics and danger.
You don't want numbers to be ever so slightly off.
And if you think about it, rockets is a good example
because I don't know much about rockets, but I know they go pretty fast
and there's probably angles involved because you're
trying to keep them on a trajectory.
And that's fine.
But if your trajectory is ever so slightly off
and something's going really fast and really far,
I'm pretty sure that eventually those small imprecisions start to add up.
And indeed, there's been historical incidents
where that kind of imprecision does, in fact, add up
in the realm of militaristic operations or in financial operations.
In fact, if you've ever seen Office Space or way back when Superman 3,
this is how some people made some money because they just
kept all of the fractions of pennies that computer systems were just
ignoring.
And eventually, they start to add up.
So long story short, any time you have scientific or financial
or any sort of large data sets that involve big numbers and lots of them
and lots of time, this is a problem.
And it almost suggests you shouldn't you C or let alone computers
unless we actually address this.
Now as a spoiler, humans have chipped away at this problem,
and you can use more and more bits but not infinitely many bits.
At some point you have to draw a line, but this
is why, for instance, a stock exchange might only
represent two decimal points of precision
for dollars or maybe four decimal points to the thousandths place for dollars
and cents.
And they just have to decide, that's all the precision
we can actually store precisely.
But you've got to decide how to handle it and not just ignore the problem.
But we can do a little better.
You know what?
It turns out that in most computers a float,
it takes up, yes, a finite amount of space,
but very specifically 32 bits of space or 4 bytes.
A byte, recall, is 8 bits.
So 4 bytes is 32 bits, and that's just a very common unit of measure.
But there's another one.
It turns out, if you want twice as many bits,
you can literally use a data type called double.
And in the CS50 Library, there is a function called get double.
And if I go ahead and do it here, I can now recompile this code,
make floats, even though they're not technically float types anymore.
And let me go ahead and do dot slash floats enter,
and let me type in 2 and 10.
And now it's still imprecise.
But notice, instead of seven zeros, which I think I had before,
now I've got 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 zeros.
So I've kind of pushed the problem further out, so to speak,
so it's more precise.
But it's not perfect.
You can't get certain values perfect if you
want to be able to represent an infinite range.
Any questions then about this?
And we'll come back as to some implications.
Yeah, here.
AUDIENCE: So would it always be better if you
use doubles because it's more precise?
DAVID: Good question.
Would always be better to use doubles because they're more precise?
Short answer, yes, but we're going to see thematically in this course
and computer science more generally there's always a trade-off.
And yes, if you use a double, you will avoid this problem a bit more,
but what price will you pay, so to speak?
Maybe processing power because it's got to deal with more bits at once,
and even more literally, more space.
I mean, sure we can take your solution, but I'm
going to charge you twice as many bits.
And back in the day, decades ago, when C was first being invented
and computers were really coming into play, spending twice as many bits,
even if it's only 32 more tiny zeros and ones,
that was actually expensive literally financially, and it adds up.
And even today, if you want to spend more space,
that's fine, but you're going to spend.
More space, therefore more money, and therefore
have less space available for other things.
So it's just a trade-off.
And you have to decide, as an intelligent human,
where the right inflection point is between what's more important.
Let me open up a very different example now called parity, just as an example.
And let me ask this d how do you know if a number is even or odd?
What's the trick?
Yeah, if it's divided by 2-- so 0 and 2 and 4 and 6
are even because, if you divide by 2, you don't get a remainder.
So actually, if you just want to see a quick example of why
you might use a remainder, even though it's out of context.
Here's an example for parity.
Parity is just a term referring to even or odd in this context.
How might we use this?
Well, notice I can get an int from the user up at the top.
I can then check the parity of the integer-- is it even
or odd-- with syntax like this.
Now I'm combining some of these operators
as you might be inclined intuitively.
If n, the number user typed in, mod 2, or divided by
and then check the remainder of, but that's a mouthful equals equals 0,
you just said it's an even number--
so print even else print odd.
Because what's the possible other remainder?
If you do n or any value divided by 2, you might get a remainder of 0 or 1.
I only have to check for one of those, 0 because the else implies
the other thing.
So again, very simple example.
But honestly, all of us probably have an intuitive understanding
of what's even and odd.
A computer needs to be taught that, and so there's
a program that does exactly that.
Let me open up a larger program called conditions,
and rather than type this one out, because it's a few lines of code,
let me just open it up because it concludes
exactly the code we saw a little bit ago on the slide
when we compared it to a similar C block.
In this program, in my main function-- let me focus on the first few lines
there--
I have an int called x that I'm getting via get int,
another int called y that I'm getting via get int,
and then I'm just doing some simple comparisons.
We saw this again when we compared it to Scratch,
but this is quite simply that same code in context
rather than just seeing it statically on a slide.
So let me go ahead and compile this-- make conditions enter.
It seems to compile.
Let me zoom in and do dot slash conditions enter.
x will be, say, 2 again, y will be 10.
x is indeed less than y.
If I run it again-- and I can save time by hitting up through my history
and just hitting Enter.
Let's do 2 and 2, and indeed x is equal to y and so forth.
So again, just the exact same kind of code as before but now
in the context of a working program.
What if I actually wanted to get user input kind of like our past student did
with getting a yes or no answers to the apple and the cupcake question?
Well in answer dot C, it turns out you can actually
get textual input from the user, perhaps a simple yes or no or just y
or n for succinctness.
And in this case, if I just get back a single character,
it turns out there's a separate data type for character.
If you don't want a whole string, like a whole word
or a paragraph or sentence or whatever, you just want one character.
You can actually use what's called a char or character.
And so here I'm using one other function appropriately named called get char.
I'm storing it in a variable called C because it's nice and succinct of type
char, and then notice this.
You might not have seen this syntax before,
especially if you've never programmed before even in Scratch.
But you might have seen this block similar to this in Scratch.
What does the vertical double bar probably imply here?
Or, that's it.
So in Scratch, it's nice and user friendly.
They literally just say O-R. In programming, it's
often the case that use just more cryptic sequences of characters
and two vertical bars, which are typically
above the Enter key on a US keyboard.
If C equals equals capital y or C equals equals lowercase y--
let's assume that the user wanted to say yes and go ahead and say yes.
Else if the user typed in n in capitals or and in lowercase,
let's assume he or she meant no and say no accordingly.
And what are we going to do otherwise?
Apparently nothing, and that's fine.
You don't need to have a default case if you want the program to do nothing.
It might be a little confusing because the user can type in some random word
and get no output, but that's a design decision.
Logically this is just how we might express this.
What about actually building our own blocks?
Any questions, though, before we start to create?
So recall that in Scratch we had that cough example.
Let me go ahead and create a file here real quickly
called cough zero dot C and just kind of recreate what we did last week.
Include standard IO dot h int main void--
again, just muscle memory now--
and then printf quote unquote "cough" backslash n semi-colon.
And you know what?
Let me go ahead and cough not once, but twice, three times.
The moment you start copying and pasting,
you're probably not writing good code.
It's not very maintainable.
Now if I want to change the word or translate it to another language,
I have to change it in three places.
We already decided last week that was bad.
So what would be better in C or in Scratch or in general
than this approach?
Yeah, so a for loop.
So let me do that let me create another file.
I'm going to call this one cough one dot C, is my second version.
Let me go ahead now and just copy and paste the original code,
and let's just improve it.
Let's get rid of two of these, and let's see if we can't express the 4.
So it was 4--
let me zoom in--
int i get 0.
i is less than some number.
Before it was 50.
Now I'm going to have it be 3.
i plus plus curly braces, and now let me move the cough block inside of there
and indent it just to be pretty.
And notice stylistically, I've been doing this instinctively for some time.
Everything's nicely indented just to make it more readable,
quite like the Scratch blocks, even though again a lot of white space
doesn't matter to the computer.
So if I go ahead and run this--
let me pull up the terminal window so I can see it.
Make cough one, enter--
looks good-- dot slash cough one cough cough cough.
That's good, but recall that we actually improved this design further
by abstracting it away.
Let me go ahead and make my own function now.
Let me go ahead and open up a new file, cough 2
dot C, just like I had another scratch program.
Again, include standard IO dot h int main void, and then in here
let me go ahead and do what?
Well, for int i get 0, i less than 3, i plus plus plus curly braces.
Then let me go ahead and just call cough.
It would be nice if cough existed, but unfortunately cough does not exist.
It's not in the CS50 library even.
So that's not going to help us.
I have to make my own function.
So in Scratch, you went to the block's thing
and you make your own block and the big prompt comes up
and you make your new puzzle piece.
Here we're going to have to be a little more deliberate,
and it turns out you can do it like this.
Some of these details will be non-obvious at first,
but I'm going to go ahead and call the function cough.
And cough at the moment does not need to take any inputs.
So the key word there is void.
And we've actually seen that before.
Main also has not been taking any inputs.
That's why we had the word void, but more on that another time.
And cough is not going to return anything either.
It's going to print on the screen just like Brian did.
But Brian, recall, didn't hand me anything back physically.
So there's no return value.
So I'm going to say void to the left of cough.
So for today's purposes, this just means that cough neither takes
input nor returns a value as output.
That's it, void, void.
Now as the body of that function, so to speak,
I'm just going to go ahead and say quite simply cough backslash n semi-colon.
That's it.
So now I have a puzzle piece, if you will, whose purpose in life
is to cough, which means now I can magically just call it by its name
up here as many times as I want.
So let's go ahead and compile this.
I'm really on a good roll.
Everything's been working out great so far-- make cough 2, enter, red errors.
So this is interesting, and this kind of reminds me of the previous error.
So first of all, what line is my error on?
Seven and character nine, if you care, but it's seven, on line seven--
implicit declaration of function cough is invalid in C99.
C99 is referring to literally 1999 when this version of C was invented,
and so implicit declaration of function cough.
But it's right here.
OK, wait a minute.
Instinct, let me just move this.
Let me just put it up top.
Let's see what happens.
Make cough 2-- oh my god.
That fixed it.
Why?
Even if you've never programmed before, reason through intuitively
why this solved something.
AUDIENCE: You are holding a function that you
have had been declared previously.
So even though you are making it void, you at least have [INAUDIBLE]..
DAVID: Exactly.
Because I previously was trying to use cough early on line 7,
but I was only teaching the computer what cough
was farther down in the file.
Frankly C is kind of dumb.
It literally reads your code top to bottom left or right.
And if you try to do something before you've taught the computer how
to do that, you're going to get that kind of undeclared identifier
because it just doesn't know what the word is yet.
Now in Scratch, this isn't a big deal.
You just move the puzzle pieces anywhere you want.
Order of blocks physically on the screen does not matter.
But in C, it does.
But frankly, this seems a little annoying
that now the main program here keeps getting pushed farther and farther
down the more kind of complexity I want to add to my program.
So there's another solution.
Let me actually go ahead and put this back where
it is because I'm a little particular.
I just like by convention main to be at the top, and frankly that's good style.
If main is the most important function in your program by default--
because it is the main function and it's what gets called per earlier by default
by the computer--
why am I going to push it all the way down just
to work around this stupid detail?
Well, I just need to teach the computer what the function is,
and I can do that a little redundantly by just saying this.
This is what we're going to call the prototype for a function.
If you literally just copy the very first line
of it that has its name, its inputs if any, and its output if any,
that's a prototype semi-colon.
It's literally copy paste from the function itself,
but this is now enough of a hint to say, hey, computer, this shell exists.
This is enough information for you to then call it because the computer,
so long as ir has seen the function's name before, it's
OK if the zeros and ones, so to speak, that implement it come a little later.
And so that's the more conventional way to solve that problem.
So just intuitively then, take a guess, if it's not
too much of a indirect leap, what is in standard I/O h, what is in CS50 dot h.
Those kinds d we'll call them declarations.
So literally in standard IO dot h is a line of code that
teaches the computer what printf's inputs are
and what printf's output is if any.
In CS50 dot h, there is literally a line of code
that tells the computer what get strings input is and what its output is.
And the same for get int and get float and get char and others--
that's all that's in those header files.
The zeros and ones, so to speak, are actually
in files literally called standard IO dot C and CS50 dot C,
although that's technically source code.
The zeros and ones are in a compiled file elsewhere on the system.
But all of these things we've been taking for granted,
now hopefully it makes a little more sense
because, the fact that I'm doing the sharp
include at the top, that's just a solution to a problem.
In that file is enough information to teach the computer what's printf
or what get string and other things are so
that I don't need to bother moving things around myself
or copying and pasting whoever wrote printf, his or her code,
into my program.
Now let's do one final example with coughing
and go ahead and call this call this cough 3 dot C
and go ahead and paste my same code as a moment ago just to get us started.
And recall that the last step of our cough example
last week was to actually give cough an input.
I'd kind of like to whittle this code down
to literally cough 3 because this is a really nice abstraction.
I don't want main to have to think about how many times--
just cough three times.
That's a nice, useful human abstraction.
Now let's put the functionality down here.
So if I want cough to be able to tolerate
an input like 3, which mentions of void presumably needs to change?
The one on the left or the right?
The right, the one inside the parentheses.
And it turns out, just like you can declare variables inside of a function,
as we've done, so can you declare arguments to a function like this.
So you can call it anything you want, though the data type matters, but this
is now saying, hey, computer, cough does not return a value,
like Erin did return a piece of paper.
Hey, computer, cough does take one input.
It's an integer and just call it n.
And now that you've done this, now you can have a line of code in here
like this.
For int i get 0, i is less than n i plus plus--
and then, OK, off by keystrokes here.
Then I can move this inside here, indent it nicely.
And now notice, all of the complexity of coughing
has been factored out into a function, my own puzzle piece,
if you will, that even takes an argument so that now you can literally,
if I move this far away and out of mind, now
your program is getting pretty interesting because it really
just does what it says.
And this is a nice functional abstraction, if you will,
so that now I have a new verb, a new action, a new function called cough.
Any questions on that one?
Yeah.
Sorry, say again.
AUDIENCE: What integer would main return?
DAVID: What integer would main return?
It turns out we'll come back to this.
It's going to return 0 almost always by default,
but that leaves you with almost an infinite number of non-zero values
which represent all of the many things that can go wrong.
So more on that when we start creating more mistakes.
Let's look at one other.
Let me go ahead and open this file in advance
myself called positive dot C. Suppose that I'm not
content to just have access to get int.
I want a function called get positive int because,
for whatever reason, my program, my game,
my whatever needs to know a positive value.
Maybe I'm asking the user how many players are there,
and that shouldn't be negative.
It should be a positive integer like one or two or more.
So it turns out I could write a program if I want that looks like this.
Call on this line here a function called get positive int, pass it in a prompt,
and then store the value, still in an integer, on the left hand side,
and then just go ahead and print it out.
Get positive int has this prototype at the top of the file.
Notice this is not a function that comes with CS50s library, CS50 dot h.
The function is called get positive int.
As you would hope, it returns an int, and it takes a string
as it's prompt, whatever words you want the human to see.
Let's scroll down now, and this one looks a little more involved,
and this is not a feature that Scratch has.
But let's take a look.
The first line is identical to the prototype
because I literally copied and pasted it.
Everything between these brackets is the function itself.
And here, to answer someone's question from earlier on,
do you have to declare a variable and then use it right away?
No, and that's actually a helpful solution to a problem
that we'll see in a moment.
Notice here this new keyword-- didn't see it before--
do the following while n is less than 1.
Previously, we saw a while loop and we saw a for loop.
We did not see a do while loop.
And a do while loop, while it sounds obviously similar to a while
loop, what seems a little different?
When I had that forever block earlier translated to while true,
what was the order of operations?
Did we check the condition, the true, and then print hello world?
Or did we just print hello world and then check the condition?
Yeah, you might not recall precisely, but I did actually--
I checked is true true, and we all said yes obviously.
Printf-- is it true?
Printf-- so it checked the condition first.
You might infer then this loop is a little different.
It has another word, do.
This is literally going to do this first and then check the condition
and only do it again if the condition is true.
So it's a nice way of just flipping things around in terms of order
to do something at least once rather than potentially never at all
like was the case earlier.
So what are we doing?
Get an int, passing in this prompt, store it in n.
And if the user types in a value that's less than 1,
is this going to be true or false, if n is less than 1?
So if the human types in 0, is 0 less than 1?
True, yes, so what happens, you go back to the do and you do it again.
If the user types in negative 1, is negative 1 less than 1?
Yes or true.
So you do it again.
If he or she types in negative 2, again, again.
What if he or she types in 50?
Well, 50 is not less than one.
So this is false.
And so then you proceed to the next line of code altogether.
But what's interesting about the next line of code
is that, unlike the cough example, which had void as its return type,
get positive int by default it's supposed to return an int,
just like, again, Erin handed me a piece of paper with a string on it.
And so here, if I want my own custom function called
get positive int to return value, there's
another word in C. You literally write return and then
the name of the variable or the value that you
want to hand back on a metaphorical piece of paper to whatever code
is using this.
So what's this oddity?
Why can I not do this?
If I were to mimic the code we wrote earlier like this,
why does this line of code not work just logically using
some of the mental models that we've had thus far?
AUDIENCE: Declaring the code again.
DAVID: Say again.
AUDIENCE: Declaring again and again.
DAVID: Yeah, so declaring just means creating,
is the fancy way in programming of saying creating.
So this says, hey, computer, give me an integer, call it n,
and set it equal to the return value of get int.
So whatever the function or Erin hands me back, put it over here.
But the problem is that in C variables have scope.
Scope is a fancy way of saying they only exist in
between the curly braces between which they were declared.
So that means that this variable n literally only
exists between here and here, and then it just kind of goes away.
The computer doesn't know about it anymore.
But that's a problem because, on what line number
do we actually need to know n?
It looks like 21, and that's outside the curly braces.
So just based on that basic definition, scope
is the two curly braces between which a variable is declared.
It doesn't exist outside of them.
This code just won't work.
And I'll fix it later so that you see the correct error message.
Why does this not work?
Well, you're declaring n inside of those curly braces.
So how do you avoid this?
Well, it turns out, as someone posited earlier, just declare it by itself
without even giving it a value.
And indeed the syntax for that is just to do half of a thought--
int n semi-colon.
It has no value that we know yet.
It has a garbage value, but more on that another time.
But it does now exist.
And now notice which curly braces does it exist within--
this one and this one, which means now it's accessible everywhere.
And if you in your Scratch programs actually used variables,
you might have noticed that you had to choose.
You had to make a decision for this sprite or for all sprites.
That was an allusion to what's called in programming a local
or a global variable.
These are still local, and we'll come back to this term earlier.
But it has to do with scope because, if you had specified for this sprite only,
MIT would have only let you use that variable for that specific sprite,
that cat or sheep or whatever it was you were programming.
Just as in C, this now means n can be used here and here
but not elsewhere like higher up in my program.
That's the matter of scope.
So let's now see what can go wrong beyond that.
Let me go ahead and open up this because it turns out,
when programming, there is other issues that can happen,
not just floating point in precision, as I described it as earlier.
It turns out that there's other problems that can go wrong even with integers
that we kind of avoided altogether.
So recall that we started talking about 1, 2, and 3 and why it's 123 last week.
Well, what happens in decimal if you add 1 to 123?
What number do you get?
Obviously, 124.
If we do it again, 125, 26 27, 28, 29.
What happens in decimal if I add 1 to a 9?
Well, I should get 10, but that's not how we would write this.
You put down the 0 instead, and you carry the 1.
Remember those mental heuristics?
So that's all we did there.
And then it's 2 plus 1.
So that's why 129 plus 1 is 130 because you put the 0, you carry the 1,
and so forth.
So we just all do that intuitively now.
But this has implications for what computers do too
because suppose that we consider a bigger number like 999.
And so what do you get when you add 1 to 999?
Well, you carry the 1, you carry the 1, and you get hopefully 1,000.
But what if your computer only has space for three digits?
Or what if your phone or what if your alarm clock
or whatever the device is literally only has
room for 3 digits, what is 999 plus 1 if your hardware only has three digits?
Well, it's apparently 0.
So you get this overflow 998, 999, 0.
It overflows, so to speak.
The one kind of falls off conceptually, and you roll over to the next value,
which is 000.
So what about in binary?
What number is this in binary if you translated the decimal in your head?
And remember, it's the ones column, the twos columns, and the fours column.
So this was 7 in binary--
1, so it's 4 plus 2 plus 1, so 7 in binary.
So how do you do arithmetic with binary?
It's actually the same thing.
It's just you don't have twos or threes or nines or anything in between.
You just have ones and zeros.
So what do you get when you add 1 to 111?
Well, it's the same idea.
You put down a 0 and you carry the 1 because 1 plus 1
you want to say 2 in decimal, but there is no 2.
So it rolls over to 0.
But you carry the 1.
1 plus 1 is 2, but, OK, that's 0, carry the 1.
1 plus 1, that's 2.
But I don't have a 2.
So I go back to 0, carry the 1.
So in binary, if you only have three bytes or bits rather,
if you only have three bits, what do you get when you add 1 to 7 in binary?
You apparently get 0.
And now it's getting more real.
In my computer, in my phone, in all of your hardware
it's just a finite amount of memory, RAM, that little chip
that I showed on the screen with all the little circuits.
And that has more than 3 bits of memory certainly, but it is finite.
And if we're only using, as a matter of convention, 32 bits
to represent things or 64 bits, maybe if we use doubles or something else
called a long-- a long is a 64-bit integer, whereas an integer is
typically 32 bits.
It seems that, at some point, numbers might overflow
and we're going to actually have some, so to speak,
imprecision-- ergo, integer overflow.
So you can actually see this or defenses against this in the real world.
So this is a screenshot from a game that is common on a few different platforms,
and it's a game that allows you to accumulate coins or points really,
or little Lego pieces.
And if you accumulate these points, you'll notice that eventually,
if you have way too much free time, you can only score so high in this game.
What's the highest score apparently, according
to the screenshot from whoever took this after playing for too many hours?
Wasn't me.
4 million-- no, 4 billion, 4 billion.
Why is that?
Well, it turns out that, if numbers and computers, as I've proposed,
are generally stored using 32 bits.
That kind of invites the question, well, how high can you count with 32 bits?
Well, 32 bits means you have 32 zeros and ones.
The biggest they could be is like 11111, 32 ones.
And if you actually do the math using our little columns and so forth,
it's roughly 4 billion, a little bigger than 4 billion.
So the authors of this Lego game just decided,
you know what, let's just say that the maximum number
of points or coins you can accumulate in this Lego game is 4 billion even.
Why?
It just looks even cleaner than whatever the actual value is.
But why?
How many bits are they using to store your score in this game presumably?
32 bits or 4 bytes, and that's just convention.
Whatever language they programmed this game is,
probably has a data type called an int, and that int by convention
uses 32 bits.
So at some point, they had to decide, we can either use more memory
as you proposed earlier for doubles.
Let's use 64 bits.
Then you can have crazy numbers of hours playing the game
and getting more and more points.
Or we can just say that's enough points to accumulate in the game.
Now that's when you actually anticipate this.
This doesn't always actually happen.
If we go ahead and take a look at some example code--
let me go ahead and open up overflow dot C. In this program
here, you'll see line 8 the slash slash syntax,
and I've had a bunch of these so far.
But I haven't actually mentioned them.
It turns out in C, just in Scratch-- the odds are you didn't notice this little
feature of Scratch--
you can have what are called comments.
A comment is just a note to yourself, to your TF, to your friend,
to your colleague, with whoever whom you're writing code with.
And it's just a note to self to remind yourself of what the code does.
Without this line, I could once, I'm comfortable enough programming,
figure out what these lines of code are doing.
But frankly, that's a waste of time I wrote the code once.
And if I look at it weeks or months later or someone else wrote it,
just tell me what it does.
So a comment in a program is just like a nice summary of a few lines of code,
or it's a summary in English or whatever spoken
language that describes what otherwise a cryptic looking code
might actually be doing.
So you don't have to think too hard about it to understand a program.
So iteratively double i-- iteratively just means loopingly, again and again
and again.
This is funky.
We didn't see this, before but you might guess what it does.
What the star equals do?
It does double.
It's like plus equals adds 1, star equals
doubles if the value on the right is 2.
So this is going to start printing 1 then 2 then 4 and 8 and so forth.
And notice this function.
It's called sleep.
It literally is going to sleep for a second,
and that sleep function has a prototype that someone else wrote in a file
called uni standard dot h.
I only know that by looking it up in the documentation.
But that's a new file just for sleeping.
Make overflow, which is apt here.
And let me go ahead and make the terminal window even bigger
for this one-- dot slash overflow.
OK, it's going.
It's going.
It's going to go faster and faster, so to speak,
because we're adding more and more each time by doubling.
2000, 4000, 8000, 16,000--
it's still going-- 64,000, 65,000.
Now we're into the millions--
2 million, 4, 8, 16 million.
It's getting bigger and bigger, all of these big numbers.
Ooh, interesting.
What just happened?
So it turns out, if you double numbers big enough, you get 0 eventually,
also something you probably weren't taught.
So what actually happened?
Control-C, we'll cancel this.
What happened?
I mean, the program is trying to tell me, even though it's a little cryptic,
signed integer overflow.
Signed just means it went from positive to negative essentially.
So what happened?
What's that?
Yeah, it ran out of bits.
I'm doubling the number again and again and again.
And at some point, we carried the one so to speak and it was a 33rd 1,
therefore past the boundaries of a 32-bit value,
and it just rolled over to apparently a negative because at some point--
and we haven't talked about it--
you can use like the leftmost bit in some sense to say positive or negative.
We've just talked about positive so far.
And then at that point, frankly, the computer
just gave up not really knowing what you intended beyond that.
So if you don't write code to handle this situation
and make sure that your numbers are less than 4 billion before you roll over,
just bugs will happen.
And this might seem contrived here, but this happened not too long ago.
So 1999 was just before a lot of people thought
the world was going to end because of the so-called Y2K bug,
and it really wasn't so much a bug as it was lack of forethought or lack
of features.
What was the Y2K problem in a nutshell?
Someone want to propose?
Even in a non-technical sense, yeah.
AUDIENCE: Computers couldn't display the number 2000.
DAVID: Yeah, so let me summarize here.
So if they are only using two digits to display values,
you could confuse the year 2000 with actually the year 1900 because,
long story short, what humans did kind of reasonably decades ago was--
space was expensive.
Computers were expensive.
Memory was not as abundant as it is now with all the cloud
storage and the like.
So you know what?
If it was like 1970, do we really care about 1969, 1968, let alone 1900?
Not really let's just assume we're all in the 1900s
and never show or store one 9.
Let's just store two digits for every year.
So 70 is '70 99 is 1999.
But the problem is the humans ended up running code
that they wrote years ago, decades ago way longer than humans
thought they might why.
Well, it's expensive, it's time consuming to change code,
the code is working.
Why try to break it?
Problem is, too, as people aged in and passed away,
there's fewer and fewer people that even knew the languages in which
those programs were written in.
And so now who's going to even update the software?
So lots of problems were feared, and this really just
boils down to because 1999 might have overflowed to not
zero per se but an implicit 1900.
And indeed, this definitely happened, though not nearly
on the scale as people thought.
But it does happen in even more real terms just a few years ago.
This is a Boeing 787, an actual airplane that
had to be grounded for some amount of time
because it had a programming error.
And its summarized here in an online article.
A 787 airplane that has been powered continuously for 248 days,
it turns out was the warning, can lose all of its electrical power
due to the generator going into fail safe mode.
Why is that?
This condition is caused by a software counter
internal to the generator that will overflow
after 248 days of continuous power.
So translate that.
That just means there's software running in the Boeing's actual 787s.
They were using 32-bit integers.
They were using those integers to store hundredths of seconds.
And at some point if you leave your plane on for 248 days, each of which
has 24 hours, 60 minutes in an hour, 60 seconds in a minute,
and 100 tenths of a seconds or 100 one hundredths of a second in every second,
that product of multiplying things out gets big pretty fast.
And on day 249, planes theoretically would shut down even
in the middle of flight for very real reasons
because a really big number rolls over to zero
and that confused the generator.
And these are actual smart airplane engineers
making these kinds of mistakes because of software,
not anticipating one line of code or some number of lines of code.
Or, as you proposed, why didn't they just use more bits?
And again, these are very real concerns.
So this was thankfully addressed and solved, but not before of course there
was quite the scare there.
So it turns out, in an older game, this was the game of Civilization.
It turns out that one of the characters as whom you can play,
Gandhi, is actually not as peaceful a character in the game
is as you might think.
And let's for context just take a look here for a second.
If we actually take a look at some more binary, this in binary
is what number in decimal?
OK, 1.
And this is 8-bit.
So it's a full byte.
8 bits is a byte--
1, 2, 3, 4, 5, 6, 7, 8.
So what do you get if you do a 1 minus--
well, if you subtract 1 from this, you obviously get what?
All zeros.
So 1 minus 1 is just 0.
What if you subtract 2 from this value?
What happens?
This is actually called integer underflow, which is just the opposite,
but there's really not too many options to think about this.
If you only have zeros and ones, you can probably
imagine what the bad scenario is.
If 0000001, if you subtract 1, goes to zeros, and then you do it again,
you now underflow, which just brings you around to the opposite 11111111.
So if you have 8 ones, what value is that if you do the math?
Ones, twos, fours, eight 16s.
It turns out it's 255 if you actually do all the math.
So it turns out that this game Civilization
was using a single byte to represent every character's
level of aggressiveness in the game.
And Gandhi's was, as you would expect, by default
initialized to 1, very non-aggressive.
Unfortunately, in this game of Civilization,
when a player adopts democracy in his or her civilization,
their aggression would be automatically reduced by two.
And so if Gandhi went democratic, his aggression wouldn't go to negative 1.
It looped back around to the ludicrously high figure of 255,
making him as aggressive as a civilization could possibly be.
So less impactful, to be sure, than something like the airplane example,
but these problems are omnipresent.
And if you start to keep an eye out in the popular media
or when there are bugs or hacks or exploits,
it's so often because a programmer has made a mistake in his or her code.
They didn't anticipate a scenario or they made maybe reasonable decisions
years ago, but that eventually proved to be
naive in that we're still running the same code, numbers are getting too big,
their math is wrong.
And so very real things happen.
But what's most important for us is just understanding
how and why those things happen.
And so what will we do in the days ahead?
So the next homework assignment, as with Scratch, will be to program something
but this time in C. You will use an environment
called CS50 lab, which essentially is CS50 sandbox, with which we've
been tinkering today.
But it adds to it the instructions and the specification of the problems
that you'll want to solve.
And it'll hold your hands initially through some of these steps.
You don't need to have written everything down and memorized
everything I typed today, but do feel free in the meantime
to go to the course's website and play with any of those examples.
Among the challenges ahead will be to recreate some snippets of games
from yesteryear, thinking about how things you might have seen growing up
can be translated to actual code.
And undoubtedly, among the first things you'll experience, is frustration.
You'll forget the stupid semi-colon or where does the parentheses go?
And you'll have to look back at code.
But keep in mind, none of that stuff matters.
It's absolutely frustrating initially, but what's most important is the ideas
and, honestly, the sense of gratification
that you, like all of CS50 staff before you,
ultimately feel when actually building and creating something of your own.
Let's call it a day there, and we'll see you next time.