[MUSIC PLAYING]
DAVID MALAN: All right, this is CS50, and this is a very exciting day,
because today we're going to learn a new language.
And that's not something that you can say happens to you every day.
And this language is going to look a little something like this.
Today, we introduce C--
a very traditional, a very old language that's purely text-based,
but it can do everything that you can do in Scratch and even more,
but without the user friendliness that we're now
used to over the past few days.
However, even though this might look quite cryptic to you at first glance,
even though there's some English or English-like words in there,
rest assured that within a few days, certainly within a few weeks,
you'll be able to understand every character on the screen,
every line of code, and much more.
But I dare say that any course like this can be a little daunting, especially
if you have no prior experience.
But recall from last week, that is, indeed, the norm, the common case.
2/3 of CS50 students-- perhaps yourself among them--
have never taken a CS course before.
So what looks like this today, realize, will feel exactly like this ultimately.
Indeed, even though the code is going to look different-- whoops.
Even though the code is going to look different,
the ideas today are going to be absolutely
the same as this past week in Scratch.
We'll look at functions and conditions and Boolean expressions, loops,
and other features along the way.
But I'm perhaps reminded of this wonderful hack from MIT
back in 1991, an expression that MIT is that getting an education from MIT
is like taking a drink from a fire hose.
And in the spirit of MIT hacks, as they're called,
some students wired up an actual fire hose to an actual water fountain
with a sign on the wall that says exactly that.
And this is the kind of course, as with many introductory courses,
where it feels like you're really getting hit in the face with way
more information, way more ideas than you can possibly take down all at once.
But realize that you'll be able to absorb all the more material over time.
And the goal of the class, ultimately, is
to present you with as many concepts and practical skills
as might prove useful later on.
And so realize by end of semester will this feel much less like this
and much more like something you have succeeded at.
So without further ado, let's go about introducing this language called C.
So on the left here, recall that this was maybe the simplest
program we could write in Scratch.
And all this program did was compel a cat, or any sprite,
to say hello on the screen.
Today, to achieve that same result, we're
going to start writing code that looks like this, using a keyboard only--
fewer graphical user controls.
But let's see why the left is actually equivalent to the right.
So let's break it down into, say, this single puzzle piece.
This, of course, did what to the--
this represented what in the context of a Scratch program?
What was the role of this puzzle piece?
AUDIENCE: Like starting things.
DAVID MALAN: Yeah, for starting things.
So for the main part of your program to kick off,
you have to attach it to this one green flag clicked puzzle piece.
And we're going to see in C that it's not nearly as straightforward.
But it's something that you can just kind of copy/paste for now.
And within a few days will this make more sense character by character.
Int main void and then this open curly braces,
it's called followed, by this closed curly brace
suggests that all of the code that we're going to write today onward
is going to go between those two curly braces as opposed
to underneath a puzzle piece like this.
So even though this won't make perfect sense today or for a few days,
realize that it is functionally equivalent to just saying
when the green flag is clicked, here is the main part of my program.
Now, what might a program actually do for you?
Well, you might have something like say "hello world" in Scratch that just
literally prints that on the screen.
So let's consider how you would implement this in C, C
being a text-based or keyboard-based language.
Well, there isn't a verb or a function called say in C. Instead,
it's called print, or not quite print.
It's actually called printf, where the f stands for formatted
so that you can print formatted text, as we'll soon see.
Then, you go ahead and put, next to printf, two parentheses-- an
open parenthesis and a close parenthesis.
And that's kind of reminiscent of this oval shape in which we were previously
putting input into in the first place.
And the input we provided last week was to just say, hello world.
So literally, in C, you're going to write "hello world"
in between those two parentheses.
But C is a little more nit-picky.
You can't just start writing words in between parentheses.
Anytime you have characters or words or sentences or phrases,
you need to actually encapsulate that text with double quotes,
as in this case.
So you just have to surround whatever it is you want to say or print
with double quotes here.
And the last thing with C that's so easy to forget early on,
as you undoubtedly will, is that you need to finish your thought.
So just like in an English essay, you typically end a sentence with a period,
so in C do you finish your thought.
But not with a period, but with a semicolon, generally
at the end of a line of code.
But we'll see which types of lines of code require this.
So on the left, we have an idea from last week.
On the right, we have an idea from this week, as we'll soon see on my computer,
but they are functionally equivalent.
They do the same thing.
So how do we go about, then, getting from this Scratch program
to this Scratch program?
Let's go ahead and point out one last thing.
We need one last line of code, which I just
popped up on the screen, which is to include stdio.h.
Well, what does that mean?
It turns out that Scratch is super user friendly.
You've got all of those colorful categories of puzzle pieces
on the left, and they're just available to you
right from the moment you start using Scratch.
In C, when you want to use some function-- or some puzzle piece,
if you will--
you have to typically tell the computer in advance
where that function is implemented, where it was saved.
And this is going to be the admittedly cryptic syntax for saying,
hey, computer, look in a file that we're going
to start calling stdio.h, whatever that means,
in order to access this function.
So, again, that's a huge mouthful.
That's the first of the fire hoses today.
But the important line of code for today's purposes
really is going to be this one down in the middle.
So how, then, do I go about writing my very first program in C,
just as last week, we wrote our very first program in Scratch?
Well, consider that the first thing we did in Scratch
was to open up a program, a tool-- scratch.mit.edu.
You can program, actually, on your own Mac, on your own PC,
no matter what operating system you're running.
But frankly, it tends to be really annoying and very prone
to technical support headaches if all of us
try to install requisite software on all of our individual Macs and PCs.
Invariably, all of us have different versions of things,
and our computers don't quite function the same.
So in the earliest weeks of CS50, we use a cloud-based tool--
CS50 Sandbox, which lives at sandbox.cs50.io.
And you'll use this for your first problem set this coming week.
This is a programming environment similar in spirit to Scratch,
but that does not use Scratch.
It doesn't use puzzle pieces.
It instead uses C, this text-based language
that we're starting to see now.
So there's two main parts to this programming environment.
On the top here, it's just going to be where I write my actual code.
Literally, in a moment, I'm going to click that plus,
and I'm going to create a new file.
And I'm going to start writing code in that file and save it.
And then, in the bottom half of this programming environment
is what we're going to start calling a terminal window.
A terminal window is sort of an old-school interface
via which you can run commands by literally typing them at a prompt
and then hitting Enter.
So unlike in Scratch--
and frankly, unlike in Mac OS and Windows these days--
where you point and click and drag and so forth, interacting
with a graphical user interface, a lot of our programming
early on is going to involve typing commands.
So let's make this more real.
The goal at hand, again, is to, quite simply, implement a program in C
that says hello to the world, which is functionally going to be
similar to the Scratch program at left.
But we now need to implement it using the language at right.
So in this programming environment, I'm going
to go ahead and click this plus sign up top for new file or tab.
By convention, I'm going to go ahead and name my file something like hello.c.
Hello just because I want this program to say hello,
but I could call it anything I want.
And dot c because the convention, in this programming language C,
is to name your files that contain your code with literally
dot c, much like you have dot doc or dot x for Microsoft Word,
dot gif for graphical files, and the like.
So I'm going to go ahead and click Create File.
And you'll see now that I have a blinking prompt on line 1--
it's going to automatically number my lines for me-- in a tab called hello.c.
This is where I can write code.
Now, even though the code I'm about to write is, frankly, pretty cryptic--
include standard.io, int main void.
And then in here, I'm going to do printf, quote, unquote,
"hello world" semicolon.
I have just written my first program in C.
So I'm going to go ahead and zoom in at top left.
It's six lines of code total.
And you'll see that I have include stdio.h, whatever that means,
int main void, whatever that means.
And then, really, the essence of this program is on line 5--
print, or printf for formatting, "hello world."
So recall that int main void is similar in spirit to the
when green flag clicked.
And printf is similar to the say block.
And this top line of code, we just need it,
because the computer is not going to understand printf
unless I tell it to include that file.
All right, so now I claim I've written some code.
How do I go about running it?
Well, how do you run a program on your Mac or PC?
What do you typically do?
You double-click it, right?
Unfortunately, there doesn't seem to be anything obvious to double-click here.
In fact, there's no icon on my screen.
And in fact, there's no program, per se, yet.
Because computers, recall from last week, don't understand English.
They don't technically understand C, per.
Se what is the language that computers speak and understand?
AUDIENCE: Binary.
DAVID MALAN: Yeah, so binary, zeros and ones.
And yet, this clearly is not zeros and ones.
And frankly, none of us would have a good time if coding involved,
these days, literally writing zeros and ones, which, in some sense,
it did involve way back in the day.
But nowadays, it turns out there's a solution to this problem.
This, as cryptic as it looks to most of us in this room,
at least you can imagine eventually getting comfortable,
probably, with this syntax, once you learn the rules and the syntax
and so forth.
But we need to convert it somehow to zeros and ones.
And how to do that is perhaps not obvious.
So it turns out if we want to convert code like this to zeros and ones
that the computer understands, there needs to be some intermediate step.
I actually need, on my Mac or PC or this cloud-based environment,
a program that is going to take as input my source code, which
is that language called C, and is going to produce
as output what's called machine code.
So source code is something like C or Python or Java or C++ and maybe other
languages you've heard about.
It's English-like syntax in which you write programs.
Machine code is the zeros and ones that every computer actually understands.
So to get from source code to machine code,
there needs to be some kind of algorithm or, more specifically,
a piece of software that does that conversion.
And that piece of software is what we're going to start calling a compiler.
So we're going to write code literally by just typing commands at a keyboard.
We're going to save those commands in a file,
just like you saved your code in Scratch.
But before I can run my program and do the equivalent of double-clicking
on it, I need to run it through a compiler
and produce output, which is zeros and ones.
So how do I go about doing that?
This is the first of the more esoteric commands,
but it turns out it's relatively straightforward to do.
At the top of my programming environment--
again, I have my code here at top left.
And if I scroll down to the bottom, I have this, again,
so-called terminal window.
And the dollar sign is just a weird human convention.
The dollar sign just means type something here.
That's your so-called prompt, or your shell.
But the blinking cursor is just inviting me to type a command at this prompt.
The first command I'm going to type is what's called Clang for C language.
Clang is the name of a program that exists to compile code.
Someone else wrote this.
Someone else online built this program called Clang-- a whole group of people,
in fact.
Made it freely available for me and you to download onto your own Macs or PCs
or this sandbox environment.
And we can use Clang to convert source code to machine code.
So I'm going to go ahead and run Clang hello.c.
I've not hit Enter yet, but the moment I hit Enter,
we're going to see something happen.
Let me go up to this little folder icon up here,
and you can actually see all of the files in my current sandbox,
so to speak, my programming environment.
There's, of course, only one, because the only file I've created thus far
is called hello.c.
But notice what happens the moment I hit Enter,
after having typed out Clang hello.c.
So clearly something else exists now, and it's
a really stupid name and very cryptic.
It's a.out, but you can perhaps guess what's inside of that new file.
What might be inside of it?
AUDIENCE: Machine code.
DAVID MALAN: Yeah, machine code.
So it stands for assembly output, but that just means machine code.
So inside of this file are a whole bunch of zeros and ones
that correspond to this code, but in binary,
in the language the computer can understand.
So literally what I just did was this--
I took as input code that looks like this, written in C.
I ran it as input into the compiler and produced this output, zeros and ones.
And those zeros and ones were automatically
saved for me inside of a file that, by human convention, is called a.out.
All right, but someone proposed earlier, to run a program,
typically, on your Mac and PC, you just double-click it.
But there's really nothing to double-click.
And in fact, if I double-click on this, it's going to look really weird,
and the computer's not going to understand it.
Because it's zeros and ones that aren't meant to be clicked.
They're meant to be executed at this command prompt.
So let me go ahead and do this.
This, too, is cryptic.
But I'm going to go ahead and do ./a.out.
And this, weird as this may look at first glance,
is how I tell the computer, run the program a.out in my current directory.
So that period that I typed first just means it's literally right here,
in my current folder, as though you're double-clicking
on it on your Mac or PC.
And /a.out means look in this directory, and run the program in the file called
a.out.
So let me go ahead and hit Enter.
And voila, hello world.
So you were very impressed last week, as I recall, when I made the cat say,
hello world.
Here, we seem less than underwhelmed.
But hello world is now my program in C that's done exactly the same thing.
But admittedly, it looks a little stupid at the moment.
It looks a little buggy.
What rubs you the wrong way, even if you've never programmed before?
AUDIENCE: Dollar sign.
DAVID MALAN: Yeah, the dollar sign.
I didn't mean to say hello world dollar sign,
but that dollar sign is just like an artifact, right?
What is the dollar sign again?
AUDIENCE: Prompt.
DAVID MALAN: It's just that prompt.
It's waiting for another command, and that's why my cursor is blinking there.
But it just looks stupid, right?
We could argue that this was my intent, but frankly, I'd be lying.
That doesn't quite do what I want it to do.
And this is because, unlike Scratch--
which, again, is more user friendly--
C, and many languages like it, literally will only do what you tell them to do.
At no point did I tell the computer to move the cursor to a new line.
I didn't finish that thought.
I said, hello, comma, world, and that's it.
I never sent a command to the computer to actually move that cursor,
but I can.
So let me go back up to my code here.
And it turns out that in C, if you tell the computer
to print hello, comma, world, that is literally all it's
going to print for you.
If you want to print a new line, you need
to use a special command, a special character called a new line character,
which is represented by backslash n.
Now, why is that?
Well, it's really because even though you
might be inclined to hit Enter like this and just hit
Enter like you would hope the computer would do,
even if you've never programmed before, this probably
should start to rub you in the wrong way.
It just looks a little weird.
It looks a little messy, that one line is up here
and the second line is down here.
So what humans decided years ago is let's
just have a simple instruction, backslash n,
that tells the computer to move that new line down.
So let me go ahead and zoom out now.
In the sandbox, it automatically saves like Google Docs,
so you don't have to go to File, Save or anything like that.
If I go ahead now and rerun this program ./a.out Enter, it's not yet fixed.
Let me go ahead and zoom in.
Notice that the symptom is still there.
Why?
What mistake have I already made?
Yeah, I didn't recompile it.
So again, the computer is going to start taking you very, very literally
now that you're programming it to do things.
And if you want to run the new version of your code,
you are literally going to have to do something like Clang
and then hello.c, Enter.
And nothing seems to happen.
And frankly, and ironically, when you don't see any output,
that usually is a good thing.
When you do see output, it's usually a list of, like, five mistakes
that you made or error messages that we'll soon see.
But we still have a.out.
It's just a newer version thereof.
So if I go ahead and zoom in now and do this-- ./a.out, Enter--
now I have a more impressive version of hello world.
I've just cleaned it up a little bit.
All right, let me pause for just a moment
and see if there are any questions on these mechanics thus far.
Yeah?
AUDIENCE: Why is line 2 empty?
DAVID MALAN: Say it a little louder.
AUDIENCE: Why is line 2 empty?
DAVID MALAN: Why is line 2 empty?
Oh, really good question.
So line 2 is empty just because I have decided stylistically
it looks a little better.
Much like in an English essay, you might hit
Enter, Enter to just separate your paragraphs,
so will programmers often separate their code, just
to make it a little easier to digest so it doesn't
look like just one big blob of code.
But it's not necessary, and I could omit it.
Other questions?
Yeah?
AUDIENCE: Can you rename a.out so that you have more than one
file in your directory?
DAVID MALAN: Really good question.
Can you rename a.out so that you can have more than one file or program
in the same directory?
Absolutely.
So let me do that right now.
It turns out that when you run commands on a computer like Clang,
you don't have to only say the name of the program and the name of the file.
You can add additional options, otherwise known
as command-line arguments.
And here, too, it's a little arcane.
You have to know what's possible in order to type these things out.
But it turns out that with Clang--
and if you read the documentation, you would see--
you can actually say -o for output.
And then you can specify any name that you
want for the file in which your machine code is going to be saved.
So notice what happens now.
When I hit Enter now, watch the top left-hand corner,
where I have a.out and hello.c.
I now have hello, as well.
And so now I can go ahead and say ./hello instead of a.out,
and the result will now be the same.
And let me take this as an opportunity to point out one other thing.
Even though we see this graphical interface over here,
this is just convenient, because you and I
are generally familiar with that interface from our own Macs and PCs.
But I can do everything via this command prompt that I can do via my mouse.
In fact, in this programming environment,
I can type a command called ls for list.
It's shorthand notation, because years ago, humans decided, well,
why type L-I-S-T if we can just type ls, which sounds kind of the same.
And thus was born the ls command, which quite simply displays
a list of all the files in that current folder or directory.
And we see the same thing-- a.out, hello, and hello.c.
And you can perhaps infer or guess, what does the asterisk
mean after a.out and hello, perhaps?
AUDIENCE: Executable.
DAVID MALAN: It's executable, which just means
there's machine code in there that can be run by the computer,
whereas hello.c does not have that asterisk or star after it,
which just means it's source code.
So you can even visually distinguish source code from machine code
from machine code.
Now, suppose that I don't want a.out to exist anymore,
because it looks like a stupid name.
I'm never going to remember what the program is.
Well, you can type other commands, like rm, for remove, a.out.
And then hit Enter.
And it's a little arcane.
It says remove regular file a.out.
Notice the prompt is now blinking after that question mark.
I can go ahead and type Y for yes or yes for yes.
Notice that nothing seems to have happened.
But how can I check what files now exist in this folder?
Yeah, so just ls again, and now I'm down to those two files.
So it turns out there's other commands, too, that we can type.
And there's commands like ls and rm.
There's mkdir for make directory.
There's rmdir for remove directory.
And anytime you have to know or use one of these commands,
we'll make sure to tell you in the problem set.
But realize anything you can do with your mouse
and that graphical user interface, can you also do at this command line.
All right, so let's take things up a slight notch
and do something that's a little more interesting,
going back to the side by side here.
So thus far, all we've done is print out hello world.
But recall, last week, the second program we wrote
was a little more dynamic and interactive.
What did we do last week as our second program in Scratch, if you recall?
AUDIENCE: It prompted the user for their name.
DAVID MALAN: Yeah, it prompted the user for their name.
And then we said hello, David, or hello, Brian, or whoever
was actually running the program.
So that program looked a little something like this.
These two lines of code were attached to a when green flag clicked last week.
This blue block here at top was a function,
and that function returned an argument, returned a response.
It returned the answer that the user had typed in.
And that was useful, because we then used the user's answer
to join it together, or concatenate left and right, with the word hello.
And then we said the result of that.
So how do we do this in C?
Well, this is where things are going to escalate quickly.
But again, it's all going to follow certain rules and patterns that
are going to get more and more familiar over time.
In C, at least in the CS50 Sandbox, the closest equivalent
to the ask function in Scratch is going to be a C function called get_string.
A string is just a programmer's expression
for a word or phrase or a sentence.
So text as opposed to numbers or some other piece of data.
So get_string is the closest analog to the ask function there.
In between the parentheses, which imply here's
where you can provide some input, I can go ahead
and provide the prompt that the user is going to see on the screen--
for instance, what's your name, quote unquote.
Now, why the quotes?
I just claimed earlier that anytime you pass a string--
a word, a phrase, alphabetical characters--
you have to surround them with double quotes
on the left and double quotes on the right.
And to be clear, why did I have this weird incantation here, backslash n?
AUDIENCE: New line.
DAVID MALAN: Yeah, it just moves the cursor to the new line.
Why?
Just because it looks a little prettier.
I don't have to.
And indeed, a moment ago, my own computer prompted me to say yes or no,
and it did not move the cursor to the next line.
That's because that programmer decided not to bother doing that.
But I'll go ahead and keep things clean by doing this.
Now, once I ask the user for their name by way of this get_string function,
I need to do something with it.
And in C, the way you do this is you literally
give yourself a variable, which is a piece of storage for a value.
And I'm going to go ahead and call it answer, just like Scratch did.
But in C, I can call this anything I want.
I could call it xyz.
None of those are very descriptive, so I'm going to call it answer instead.
You can use any word.
But C is a little different.
C is old school, and you have to be super explicit as to what type of value
you are getting and, therefore, storing in the variable.
So to the left of the name of the variable,
I have to tell the computer the type of value I need to store
is going to be a string.
And we're going to see in a moment, there's other types of values.
There's numbers and more, but for now, we're just going to store a string.
And there's one thing missing from this line of code.
AUDIENCE: Semicolon.
DAVID MALAN: Semicolon, right?
End of thought, and that was a big thought,
but a semicolon finishes this thought.
Now, this equals sign is a little different from algebra,
if you think back to your math days, where you might say x equals y.
When x equals y, that means, literally, x is the same thing as y.
But here, the equals sign in programming languages
typically is the kind of a motion from right to left.
This equal sign doesn't technically mean equal.
It means assign, or the assignment operator.
Move from the right something to the left.
So if this get_string function, just like the ask function,
asks the user for their name and hands back a value,
you want to put that name into a variable
called answer, from right to left.
So even though we-- just as we wrote it from right to left,
so do you think about it executing from right to left.
So at this point in the story, we now have
somewhere in the computer's memory, in a so-called variable, the user's answer
to their name.
What do I want to do with it?
Well, in C, there isn't a join function, so we're
going to have to do this a little differently.
But there kind of is a say function, and what was that say function called?
AUDIENCE: Printf.
DAVID MALAN: Printf.
So printf is the go-to function any time you want to print or say something
on the screen.
So I'm going to go ahead and use printf.
And I'm going to use parentheses, because parentheses mean, here
come my inputs, otherwise known as arguments or parameters in programming.
But these are synonymous for our purposes.
And now this is a little non-obvious, right?
Because I don't want to just put, quote unquote, hello, comma, answer.
Why?
Why would it be incorrect to do quote unquote, hello, comma, answer?
What's that?
AUDIENCE: It will just print out answer.
DAVID MALAN: Right, it will literally say hello, comma, answer, right?
And that's not what we want.
We don't want to say "hello answer."
We want to say, hello, David or hello, Brian,
or whoever is playing this program.
So I somehow do need to join the word hello with the user's input.
And the way to do this in printf is a little different from Scratch.
You use what's called a placeholder.
So you literally write the sentence or phrase
that you want to say or print to the screen,
but wherever you don't yet know the value in advance,
you put a placeholder using a percent sign and then an s denoting string.
And this is because, of course, if I'm writing this program today,
I have no idea who's going to run it tomorrow.
So I want to dynamically put a placeholder
so that if someone plays this program tomorrow or the next day,
their name gets dynamically inserted.
I, of course, don't know their name today.
So quote unquote, hello, comma, percent s.
And that percent s is just a placeholder for whatever I want to plug in there.
Backslash n, of course, just means new line.
So the only new thing here is this percent s.
Now, it turns out that functions in C, just like in Scratch,
can take no arguments.
Or they can take one arguments.
Or they can take two or more arguments.
And if they take two or more, you just separate them with commas.
So the way printf works--
and you would only know this, again, by being taught it or reading
the documentation-- is that you can, yes,
provide just a single string as its input--
quote unquote, something.
But if you have some placeholders in there,
you can tell the computer what to plug in by adding a comma
and then the name of the value or variable that you want to plug in.
So now, these two lines of code are equivalent to these here.
But again, even though at first glance, it
might look especially cryptic, if you just
break it down to the individual components
from right to left and then from outside to inside,
you can generally infer even what new code that you've never seen before
is doing.
Any questions on these two lines of Scratch or C?
Yeah?
AUDIENCE: Can you add [INAUDIBLE]?
DAVID MALAN: Absolutely.
Can you add other variables?
If I had more variables in this program, thanks to more lines of code,
I could just do comma, something else, comma, something else, comma.
And I could just have one placeholder in that quoted
expression for all of those variables that I want to plug in.
And they go from left to right.
So if I had two percent s's here, the first one
would come after the first comma.
The second one would come after the second comma.
AUDIENCE: So you need a percent s [INAUDIBLE]??
DAVID MALAN: Correct.
You need a percent s for any placeholder you want to plug in if it's a string.
And we're going to see other placeholders in just a moment.
Good question.
Other questions?
No?
Oh, yeah, in back.
AUDIENCE: Is there another way to concatenate strings?
DAVID MALAN: Is there another way to concatenate strings?
Short answer-- yes, many ways, none of them easy.
So we'll build up to that, actually, in a couple of weeks' time.
Printf, for now, is by far the easiest way to do it.
Other questions?
And if I ever miss your hand, there's just lots of glare.
Do just call out.
Over here.
OK, all three of you.
Over here on the right.
AUDIENCE: [INAUDIBLE].
DAVID MALAN: Sure.
What is a string?
A string is a sequence of zero or more characters in double quotes.
So put another way, it's a word, a phrase, a sentence, a paragraph-- zero
or more characters, alphabetical letters, in double quotes.
Other questions?
Yeah?
AUDIENCE: What would happen if your backslash n was outside the quotations.
DAVID MALAN: Really good question.
What would happen if your backslash n is outside the quotations?
Well, let me go ahead and do this.
And frankly, this is the right instinct to have.
Any time, moving forward, you have those same instinctive questions,
just try it.
You can do no harm to the computer.
So let me go ahead and just accidentally, if you will,
put the backslash n outside of the quotes,
is what I think your question is.
All right, so let's see what happens.
So I'm going to go ahead now and run Clang.
I know how to make a customized name now,
so I'm going to adopt that convention. -o hello.
And now I'm going to go ahead and say hello.c,
which I think is going to be broken.
And indeed, something, indeed, has broken here.
Let's see what the error is.
So it's a little arcane, too, but hello.c, colon 5, colon 26.
What's going on there?
Well, let me zoom out.
Anytime you make a mistake in your code like this,
Clang is going to try to help you figure out where that mistake or that bug is.
So hello.c colon five means look on line 5 for your mistake.
Then, see, it says error-- expected close parentheses right around here.
So it's a little weird, because no, I don't want a close parentheses,
I think.
I want the new line.
So it's not perfectly able to tell you, hey,
that backslash n should be inside of the quotes.
But it can at least help you hone in on where the mistake is.
So it's somewhere around there, at which point
your own memory or your own googling should kick in to figure out,
oh, that's got to be inside of the quotes.
Good question.
Was there a third question back there?
Yeah?
No?
OK.
All right, so let's go ahead now and transition to a few other features
that we can do, as well--
namely, implementing the same program that I just had.
Let me go ahead and close this file and create a new one called,
say, string.c, because I'm now experimenting with strings.
And I'm going to start as before--
include stdio.h int main void.
And then I'm going to go ahead here and say string answer get get_string,
quote unquote, what's your name, question mark, backslash n, semicolon.
And as an aside, everything I type on the keyboard
today we will post on the course's website after.
So no need to type down every little character if you'd prefer not.
And then I'm going to go ahead and say printf, quote unquote, hello answer.
Not answer, because we claimed that that was bad.
That would literally say answer.
I want to do a placeholder, percent s.
And now backslash n, comma, answer, semicolon.
So I think I have transcribed the code from the slide
into my programming environment now in a file called string.c.
So let me go ahead and zoom out.
And if I want to compile this program, convert it
from source code to machine code, what command can I type down here?
So Clang.
So string.c.
But that's going to give me a program, by default, called
a.out, which is just very non-helpful.
So let me go ahead and say -o string, just so
that my program is called string.
But I could call it anything I want.
I could call it program two, if I prefer.
So let me go ahead and hit Enter.
And oh my god, there are more errors than there are lines
of code, which is a little worrisome.
And this tier two is where you should take some comfort that that just means
the computer's gotten confused, right?
You're not that bad at programming that you generate more errors than lines
of code you've written yourself.
It's just that the computer got really confused at some point,
and it kind of starts tripping over itself, so to speak, conceptually.
It doesn't know where the error is, so it starts misinterpreting correct code
as incorrect code.
So the place to start is always with the very first error message.
So you'll notice that I already scrolled all the way up to the command
that I typed, which was right here, as I've highlighted.
Focus on the first error you see, and maybe the others
are just phantom errors, confusion that arose instead.
So let me go ahead and zoom in on this part of the screen
and see if we can't diagnose this issue.
The command I ran was Clang -o string string.c.
That just means my input is my source code in string.c.
I want my output to be machine code in a file called string.
All right, string.c line 5 is where the error begins,
so that seems to be a familiar location.
Use of undeclared identifier string.
Did you mean-- anticipation-- stdin?
No, I didn't.
I meant string in this case.
So here, too, the computer's gotten confused,
and even it's green helpful message is actually not helpful.
No, I want a string.
I don't want standard n.
But the reason for this is that technically,
at least this point in the story, there is no such thing as a string,
S-T-R-I-N-G in C. That's actually a training wheel of sorts that
we're going to use for just a couple of weeks until, to your question earlier,
we're going to show what's really going on underneath the hood of the computer,
so to speak, when it comes to implementing a string.
So string is something that the CS50 course provides to you
in a file called CS50.h.
So just as there's a file called standard I/O--
where I/O just means input/output, like printing and getting input.
Just as there's a file called stdio.h, in which printf was invented,
all of these other functions that I might use in this program,
like get_string, happen to be stored in a file called CS50.h.
So my problem arose a moment ago when compiling this code,
because the computer had no idea what a string is.
And it has no idea-- we'll see what the function get_string is.
So let me go ahead and recompile this now.
I'm going to go ahead and do Clang -o string string.c and zoom in.
Here we go.
Enter.
OK, progress.
Still a bug.
There's still a mistake, because red can't possibly
mean anything good in this context.
And indeed, it's an error.
But it's many fewer errors.
So there's the last piece of commands that we need to introduce now.
Notice what the error message is saying.
So after I run Clang -o string string.c, there's
still a problem in my function main.
What is the problem?
Undefined reference to get_string.
So it turns out that when using the CS50 library, you have to do two things.
In your source code, you have to tell the computer
to include this file CS50.h, where, again,
functions like get_string and the word string
are actually implemented for you.
But when compiling your code, you need to, somewhat redundantly
but for different reasons, tell the computer to add all of the code
that the CS50 staff wrote to implement get_string and string
and other functions like this.
I'm going to go ahead and write Clang -o string string.c, just like before,
but I need to tell the computer this special instruction
to link it with CS50.
And this will make more sense in just a couple of weeks' time.
But this is just a -l for link and CS50.
And all this tells the computer is this--
the zeros and ones for my actual program are going to come from string.c right
here.
This is my source code.
But CS50 staff, years ago, also wrote code in C in order
to give you functions like get_string, in order
to give you variables like strings.
The zeros and ones from the CS50 library are stored elsewhere in the cloud.
They need to be linked in together with yours.
So just as your code is in this file, our code is in that file.
And so by telling the computer to include it in your source code
and to link it in this command is just the arcane way of saying,
combine my code with CS50's code into one program that I can actually run.
Now, all of this, frankly is very quickly
becoming very overwhelming, I think, and very unnecessarily complicated.
So there is a better way than this.
It turns out, moving forward, if you would like to compile your code,
you don't have to remember -o.
You don't have to remember -l CS50.
You don't have to remember any of those commands, hopefully just the ideas.
You can instead say, make me a program called string, and be done with it.
All this white output is just automatically generated for you
when you tell the computer, make my program.
And the program make will figure out what command-line arguments to use,
what name to give the file, what libraries
or code that other people have written to link in.
So henceforth, when you want to compile your program,
literally just say make and the name of the program.
But it's not make string.c.
It's make and the name of the program.
Make, this other program, will figure out
that you mean something called string.c.
And I can rewind and do this for hello, too.
Make hello.
Oh, I never fixed the problem from before.
So let me go into hello.c by opening that file.
Let me fix this for posterity.
Save this file, or let the file auto save.
Now do make hello.
And viola, it's done the same thing for me now.
Yeah?
AUDIENCE: Is make like a standard thing [INAUDIBLE]..
DAVID MALAN: Really good question.
Is make a standard thing or CS50 specific?
It is not a CS50 specific thing.
It is a standard tool that exists on Macs and PCs and computers
generally running Unix or Linux.
And indeed, the sandbox tool that we're using
is itself a computer in the cloud, even though it just
has these two windows, tabs up top and the terminal window down below.
When you log in to CS50 Sandbox, you have access
to your own server in the cloud running an operating system called Linux.
And Clang and make and other tools we'll see, like ls and rm,
all exist in that operating system.
They're not at all CS50 specific.
Yeah?
AUDIENCE: With that, so would hello be machine code, not [INAUDIBLE]??
DAVID MALAN: Correct.
Hello is the machine code.
Hello.c is the source code.
AUDIENCE: So [INAUDIBLE]?
DAVID MALAN: Correct.
Make is a smart program designed to make our lives easier, no pun intended,
whereby if you do make hello, it will look for a file called hello.c.
And if it finds it, it will create the program called hello
from source code to machine code, respectively.
Yeah?
AUDIENCE: [INAUDIBLE].
DAVID MALAN: Not exactly.
So make is a program that comes with an operating system called Linux,
and it also comes with Mac OS.
And these days, it also comes with Windows.
It is a program that you can run by typing its name,
not that you run by double-clicking an icon.
Good question.
Yeah?
AUDIENCE: [INAUDIBLE]?
DAVID MALAN: Good question.
So does that mean make is stored on your computer
or in the cloud-based computer?
In the cloud-based computer.
So at this point in the semester, and for the first several weeks,
everything we do will be in the cloud in a standardized environment
called CS50 Sandbox and, soon, something called CS50 Lab.
But it's designed to be representative of a standard Linux computer
and also a Mac or PC.
But the software tends to differ somewhat,
so we standardize on Linux, which is a very popular operating system
in the software development world.
All right, so let's take a look at a couple of other equivalencies and then
comparisons and start to write more interesting programs than ones
that just say hello world.
So here, again, is a summary of how you technically
should convert your source code to machine code
by using a program called Clang with a command-line argument,
a special parameter, -o hello, to name the file something else.
And honestly, no one's ever going to remember this command.
And even if you do, it's just very tedious to type.
That's why programs like make exist, which
just automate that exact same process.
But they are still doing the same thing--
compiling your source code into machine code.
And to run the program thereafter, you say
dot, which just refers to your current folder,
because we'll see that you can have multiple folders on a server, and hello
is the name of the program.
All right, let's take a look at a couple of other types of features of Scratch
and see what it's going to look like in C,
and then we'll start to implement some programs in C more manually.
So consider this example here, which was an example
of what type of feature in Scratch?
This did what for us?
AUDIENCE: Variable.
DAVID MALAN: So this was an example of a variable.
And that variable, in this case, was called counter.
And we initialized it to-- that is, we set it equal to-- zero.
In C, on the right-hand side, if we want to achieve this same result
today onward, you're literally going to say the name of the variable,
like counter, but you can call it anything you want, equals zero.
Because recall that the equal sign is the assignment operator.
So whatever is on the right is going to get
copied into whatever is on the left.
However, that's not quite sufficient, because when you declare a variable
and you say, hey, computer, I need some storage for some value,
you have to tell the computer what the type of that variable is.
We've seen strings are variables that store multiple words.
But in this case, we want to store a number.
And in C, that type of number is called an int or an integer,
but I-N-T for short.
There's one thing missing from this line of code.
AUDIENCE: Semicolon.
DAVID MALAN: Semicolon.
Just finishes the thought.
So what does this do?
Hey, computer, give me a variable whose type is integer, or int.
Call that variable counter, and store the value zero in that variable
by default. So it turns out that we can do other such operations on variables.
For instance, here we have the incrementation feature of Scratch.
Change the counter by one by adding 1 to the variable.
So how do we do this in C?
In C, you would do something like this.
And this is a little paradoxical if you're coming at this from algebra,
because how could counter possibly be equal to counter plus 1?
But it's not equality.
This is assignment from right to left.
So on the left-hand side, you're saying counter.
That's the name of your variable.
On the right-hand side, you're saying counter plus 1,
whatever that arithmetic answer is.
And you're copying counter plus 1 into counter.
I'm still missing something here, which is that semicolon.
But I do not need to say int in this example.
At this point in the story, it is assumed that counter exists
and that I've used a line of code like the previous one
somewhere else in my program.
Because that tells the computer once, give me a variable called counter,
and let me store ints in it.
This line of code assumes that counter exists,
and so we do not specify the word int again.
You specify it just once.
Now, we need the semicolon, as I proposed.
But frankly, this is such a common operation in programming,
as we'll see, to just increment a variable.
Turns out there's other ways to do this.
You can, instead, equivalently say this--
counter plus equals 1 semicolon.
It is literally the same thing.
And if that's too many keystrokes for you,
you can literally just say counter plus plus semicolon,
and that, too, does the same thing.
This is what's known in programming as syntactic sugar.
It doesn't add any functionality that you couldn't do some other way.
But it does it in a prettier, often more succinct way.
And it's just more common to write lines of code like this.
All right, let's consider another example.
This was called what in Scratch?
Yeah, a condition, a decision that you have to make.
So if something is true, then do this.
In C, we might convert it as follows.
If x less than y in parentheses--
which isn't quite the angled shape that we have here in green, but in C,
you use parentheses here.
So if x is less than y, open paren, close paren,
then go ahead and do the following.
And just as this yellow or orange puzzle piece kind of looks like it's
hugging the purple puzzle piece, so does this open curly brace
and this close curly brace, so to speak, is kind of there
ready to hug or encapsulate one or more lines of code.
What's the line of code?
It might be something like this-- printf x is less than y backslash n.
So, again, new syntax, but we've seen the curly braces before
in the context of main.
And we've seen parentheses before in the context of inputs.
So this is just kind of a pattern that we'll
start to follow in C whenever we want to do something conditionally.
OK, in Scratch, we saw something like this--
if x is less than y, then say x is less than y.
Else, conclude that x is not less than y.
In C, it almost looks the same, but you set yourself up with an else block
with two sets of curly braces, sort of two characters ready to hug
the lines of code in between them.
And we can just plug in now, literally, the translations to printf
by saying printf x is less than y or printf x is not less than y.
Now, notice, there's only two semicolons in this example.
You generally do not end things like conditions with semicolons.
You end functions or lines involving functions with semicolons.
And that's not a hard, fast rule, but you
don't want lines of code-- you don't want semicolons
after every line of code.
You generally want it after some action.
And you'll start to notice this pattern, even though it's perhaps not
obvious at first.
All right, how about this one?
If, else if, else if.
Now, notice we're just kind of reusing the if-else if block and then another
if block down here.
Turns out in C, it's almost a little easier.
You can literally just say this--
if x is less than y, do this with curly braces.
Else, if x is greater than y, do this in curly braces.
Else, if x equals equals y, do this in curly braces.
And what do you want to do in each case?
Different printf's based on the say messages that we want to display.
But there's one curiosity here.
Almost looks like a typo.
Yeah, the double equal sign.
But it's not a bug.
It's not a mistake.
Why am I perhaps using double equals here instead of a single equal sign,
like in Scratch?
Let me go over here.
Yeah?
AUDIENCE: [INAUDIBLE].
DAVID MALAN: Exactly.
I said earlier that the single equals sign is used for assignment from right
to left.
And honestly, this is just kind of a human situation, where
we painted ourselves into a corner.
We already use the equals sign for assignment.
Then, presumably, some human realized, oh, shoot, how do we ask the question,
is this equal to that?
Well, we've already used that symbol.
So humans, decades ago, decided, all right,
we'll solve that problem by just using two equals signs back to back.
So this is the so-called equality operator.
A single equals sign is just the assignment.
This is, hands down, one of the most common mistakes to make early on,
especially if you use Scratch or other languages beforehand.
And you just get to develop the muscle memory over time.
Once you make that mistake a few times, it'll go away.
All right, but it turns out that this program,
while arguably correct-- or this code, while correct,
in that it's going to do this or this or that-- and I do think those
are the three possible situations.
If you've got two integers, x and y, x is either less than y, greater than y,
or equal to y.
But one of these questions technically doesn't need to be asked.
There's technically three Boolean expressions here, right--
x less than y, x greater than y, x equals equals y.
A Boolean expression, recall, is a question
that it has a yes/no answer or a true/false answer or a 1/0 answer.
But I don't need to ask three questions here, do I?
I think I saw your hand.
Why not?
AUDIENCE: Well, because if x is less than [INAUDIBLE]..
DAVID MALAN: Exactly.
This third question, this Boolean expression, does x equal equal y,
goes without saying logically.
Because if x is not less than and it's not greater than,
if it's just [INAUDIBLE] the only other scenario I can think of
is that it equals y.
So we can actually simplify both the Scratch code and the C code
by just having this else condition down below, as well.
So we'll talk, over the next several weeks,
about different qualities of code.
Correctness, like does it do what it's supposed to do,
but also the quality of design, like did you write this code as efficiently as
possible, as quickly as possible, in a way that
uses the least amount of memory and the least amount of CPU,
the brains of the computer?
And this is just an allusion to that kind of capability.
All right, just a couple of more comparisons
before we go back to writing some code.
How about something like this?
In Scratch, we, of course, called this a loop-- a cycle that happens again
and again and again.
And a loop like this can be implemented in C not quite in the same way,
but like this.
It turns out the closest word to the word
forever in Scratch is the word while.
It kind of suggests the idea of doing something again and again.
This was the word that humans chose years ago.
But you don't just say while.
You have to say not only what you want to do forever,
but you need to answer a Boolean expression.
So in C, if you want to implement a loop,
you need to literally be able to say while something is true.
You need to ask a question to which the answer is yes or true or one.
All of those are equivalent to a programmer.
So what's an example of an expression, a Boolean expression,
that is always true, if my goal is to do something forever?
AUDIENCE: Five equals five.
DAVID MALAN: Is five equal equal to five, all right.
I could do is four equal equal to four.
I could do is two greater than one.
I could do is one less than two.
I could come up with an infinite number of Boolean expressions
that just logically are always true.
But the simplest way is just to say literally true.
So it's a little hackish, but this is perhaps
the simplest question you can ask, because true, by definition,
it turns out, is always true, just as false is always false.
And so I can literally just say while true in order
to induce a infinite loop, so to speak, that does something forever.
All right, let's try another type of looping construct.
This was a loop that did something 50 times.
This one, now we have to get a little more clever,
and we have to kind of wire things up.
So if I want to do something 50 times, here's one way.
Why don't I give myself a variable and call it counter.
But I could call it anything I want and initialize it to zero.
Then, let me go ahead-- you know what?
Counter is actually pretty verbose.
Most programmers, when they're just counting,
they, by convention, just use the letter i, i for integer.
But you can call it anything you want.
So I'm going to call it int i equals zero.
Then I'm going to go ahead and do the following.
While the following expression is true, let me just
ask a question again and again.
While i is less than 50, let me go ahead and say, hello world.
So I can just print out, hello world.
But I'm not quite done sort of building this logic.
I've initialized a variable to zero.
I'm going to, again and again, ask the question, is i less than 50?
But for this to work out logically, what other piece of logic
do I need to add to the code?
Yeah?
AUDIENCE: You have to increment i by one.
DAVID MALAN: Yeah, I have to increment i, right?
So even if you don't recall--
and that's fine-- the syntax for doing that, you do
need a line of code like this.
So that, logically, you're going to do the following-- set i equal to zero,
and then do the following while i is less than 50.
Well, is i less than 50?
Obviously, because 0 is less than 50.
So you print out, hello world.
And then, as you propose, we need to increment i.
So now i equals i plus 1.
So at this point in the story, i equals 1.
And now the way the code works, much like our pseudo code last week,
is you sort of implicitly go back to this line.
Last week, in pseudocode, I literally said, go back to line 3.
Here, it happens automatically by nature of how C interprets these lines of code
in these curly braces.
And I can actually simplify this as follows.
I can say i plus plus.
Now, it's not quite as pretty as Scratch, where you just say,
repeat the following 50 times.
But using the principles of last week now translated to C,
you can kind of wire together your own logic that
does something any number of times.
And there's one other way to do this, just so you've seen it here.
It turns out that a more common way to do something a fixed number of times
is using a different preposition-- the word for.
And a for loop looks like this.
A for loop does something, like print out hello world, again and again,
but it's even more mechanical.
But it automates into one line of code the exact same logic
we just implemented.
After the word for, you can put parentheses.
And then inside of those parentheses, you
can say something like, give me a variable called counter
and initialize it to zero.
Or that's a little wordy.
Let's just use i.
So that is identical, logically, to what we did a moment ago.
But the for loop actually takes one, two, three inputs inside
of its parentheses.
It's a little funky in terms of its syntax.
The second input to the for loop is the Boolean expression
you want to ask again and again and again, so is i less than 50?
And the last thing that you can do in a for loop
is this third input, where you can do your update of one or more variables.
So if I do i equals i plus 1 or, more succinctly, i plus equals 1,
or even more so tersely, i plus plus, I have now
whittled down to just four lines of code what I previously
did in a few more lines of code.
These are both correct.
They both do exactly the same thing.
And even though the for loop is a little non-obvious-- because this is step one,
this is step two, this is step three, then
in increments-- it achieves the same result.
And you'll play with this over time in the next couple of weeks
when doing something again and again.
But it's just a more succinct way of achieving that same goal.
Any questions, then, on while loops or for loops here?
All right, so let's look at one final set of definitions.
It turns out that in C, we have a whole list of data types
besides just strings and besides ints.
And we'll see these and use these over time.
You can have a bool, so to speak, which is literally the value true or false.
And we use that implicitly earlier when I just said while true.
You can have a char, or character, which is a single character, not two or more
or a phrase.
It's just like the letter Y or N if you're asking the question yes or no.
You can have an int, of course, which is an integer, a string, which
is one or more characters inside of double quotes.
So it's bigger than an individual char, typically.
And then there's a few other data types--
int and long.
So int is typically a certain size.
You can only count so high with an int.
Typically, you can count as high as 4 billion with an int,
and that's not big enough for certain applications.
Today's biggest companies like Facebook and Microsoft and Google
have many more pieces of data than 4 billion.
So there exist things called long, which actually use more bits.
They're wider values, so they can count even higher.
A float is a floating point value, which is
a fancy way of saying a real number, something that has a decimal point.
And a double is just a real number that can have even more digits
after the decimal point.
So we'll see those before long.
Well, what other features does the CS50 the library provide?
It gives you not only the function get_string,
we'll see a few others like get_int or get_float or get_double or get_char.
These are all functions that will prompt the human
with the blinking prompt for certain values that they might want to provide.
And then for placeholders, let's round this out.
Printf, recall, had a placeholder for percent s for a string.
Turns out there's a few other placeholders, as well.
If you want to plug in an int, we're going to start using percent i.
If you want to plug in a float-- that is, a real number--
you're going to use percent f.
And there's a couple of other format codes, as well.
But we've seen just one of those thus far.
And then in terms of arithmetic operations,
you can do a lot of mathematics very simply.
And we'll do just a couple of examples, literally just
by using the characters that you might be inclined to type on the screen.
So, in short, suppose that we want to go ahead and write one program of our own.
We can use any number of these functions-- get_int and get_float
and get_more.
But before that, let's go ahead and take a five-minute break here,
because that was quite the fire hose, indeed.
Cookies await in the lobby outside, and we'll resume in five minutes.
So we are back, and now we begin focusing not just on comparisons
of C with Scratch, but on actually writing
some code from Scratch but in C. And the goal at hand
really is to begin to develop the muscle memory via which
you can start with literally empty files and start to fill it
with C implementations of your ideas.
So rest assured that all of the examples we're about to do live
are already pre-baked online, so you'll be
able to download all of these examples from the course's website.
In Brian's super section will you be able to explore them in more detail.
And later this week will you have opportunities
hands-on to work on these same types of programs, as well.
For now, the overarching goal is exposure and concepts and the beginning
of developing that muscle memory.
So with that said, let me go ahead and create a new file called int.c,
the purpose of which is going to be to get an integer from the user,
much like a bit ago I got a string from the user.
I'm going to go ahead and, as before, I'm
going to include some familiar files.
So I'm going to go ahead and include preemptively CS50.h
so that have I access to strings and get_string
and get_int and get_float and other features, as well.
I'm going to include stdio.h so that I have access to printf
so I can actually see what we're doing.
Then I'm going to do this, which again, for today's purposes
and for a couple of weeks, is just kind of copy/paste.
This is the equivalent of when green flag clicked,
but we'll explain, in a couple of weeks, exactly why you're writing int
and why you're writing void.
In here, I'm going to do something like this.
This time, I want to get not a string but an int.
So let's do in age get get_int, what's your age?
Now, to be fair, I can probably type that pretty quickly,
because I have the muscle memory already for programming in C.
But if we look at it real methodically for a moment,
this is just another function, get_int, from the CS50 library that's
going to get an integer.
This is the prompt that the human is going
to see with their cursor moving to a new line because of the backslash n.
And whatever they type in is going to get
copied from right to left into a variable called age, the type of which,
so to speak, is int, or integer.
Now let me go ahead and compute, like, how many days old this person is.
So if I want to do that, I could do something like this.
Well, give me an integer.
Call it days.
And then just do age times 365.
I proposed a bit ago that there's a bunch
of arithmetic operators like plus and minus
and multiplication and subtraction and even the remainder operator.
So this line, 7, just says multiply age by 365.
Copy that value, from right to left, into a new variable called days.
And now I can go ahead and print this if I want.
So printf something like, you are at least percent--
not s, because it's not a string, but percent i because it's an integer now--
days old, backslash n.
But again, this is a placeholder, so I'm not done yet.
What do I need to put inside of these parentheses also on line 8?
Yeah, so comma, days, if that's the value that I want to plug in.
And I'm missing one more thing.
AUDIENCE: Semicolon.
DAVID MALAN: Semicolon at the end of the line.
Now, hopefully, I got this right.
But odds are the first time you write your programs,
you're going to see error messages.
But let's see, make int is the quickest way now to compile this code.
Enter.
All right, the big, long white command is OK.
So long as you don't see red or yellow or colored output that indicates
warnings or errors, you should be OK.
I'm going to clear my screen now so I can just now run this program, ./int.
And suppose your age is, say, 50.
Well, you are at least 18,250 days old.
But let me use this as an opportunity to not just do something correct, which
I claim this code is, but to just make it better designed.
It's fine to be storing this value, age, in a variable called age.
And it's fine to be creating a second variable called
days, in which my mathematical answer is age times 365.
But strictly speaking, I don't need that additional line of code.
I could also just do age times 365 here.
So C is nice like that.
You can compose, just like in Scratch, bigger ideas from multiple smaller
pieces.
And frankly, if I really want to get crazy,
notice I can actually highlight that whole function
call, so to speak, get rid of the age all together,
and just plug this in here times 365.
But at this point, we're starting to cross an inflection point.
Yes, this is correct, because I, strictly speaking,
don't need a variable, right?
I can pass-- we saw last week--
one function's output as another function's input
by just nesting them in this way.
But honestly, now we're at the point where this line of code
is so relatively long, it's just too hard to read.
And so this is an example where, for design's sake, you know what?
The previous version was probably a bit better,
because I can read the code more top to bottom than left to right.
But this is a design decision.
And indeed, you might agree or disagree.
You might agree or disagree with your teaching fellow, or TF, ultimately.
These are the kinds of decisions that go into writing good or bad code
or good or better code.
Much like in an English essay or in any written language,
you could argue that one person has written their document better
than another.
So we'll begin to appreciate these nuances over time.
What about float?
Well, let me go ahead and write another program real quick called float.c.
And this one is going to use floating point
values, which again, is just synonymous with real numbers with decimal points.
Let me go ahead and include CS50.h, include stdio.h.
And then int main void and then my open curly braces.
And now let's do this.
Let me get the price of something.
So int price equals get float, what's the price, for instance.
Semicolon.
And now let me do something mathematical with this.
Let me go ahead and say, your total is.
And now let me just do the total price with tax, for instance.
In Massachusetts, sales tax is 6.25%.
So let's just write a little program that does that.
Your total is-- not percent s, because it's not a string.
Not percent i, because it's not an integer.
It should be percent f for float.
And in fact, I goofed.
I actually made a mistake here accidentally.
I don't want to store the price in an int if I'm getting it as a float.
If I'm getting a real number with a decimal point,
I probably want to store it as a float, as well.
So again, different format codes, different placeholders
for different contexts.
Now let me go ahead and do this.
And if I want to plug in the price, I'm going
to do price times 1.0625, which just mathematically means add 106.25%--
or multiply, rather, the price by 106.25%
so that you actually see the total with tax.
All right, so let's go ahead and compile this.
Make float, Enter.
No error messages, so that's already promising.
./float.
And what's the price?
How about $100.
OK, that's a little excessively precise.
The total price is $106.250000.
But that's just because the computer, per last week,
is using some number of bits to store values.
And the computer happens to be capable of showing this many digits
after the decimal point.
But what if you don't want to do that?
Well, it turns out there's some pretty arcane tricks you can do.
Instead of doing percent f, I can actually
do percent dot 2f, which again, you would only
know from having heard it before looking it up in a book or reference.
That's going to show me only two digits after the decimal point.
So if I recompile this code and make float and do ./float,
now notice if the price is $100, now my total is a little more user friendly--
106.25.
So in short, this is the f in printf.
Just as you can print something to the screen,
you can format it as by telling printf to only show so many digits.
Well, let me try something else.
Let me go ahead and copy/paste the beginnings of this code,
just to speed things up.
So I can implement a program called parity.c.
So parity is a fancy way of saying is a value even or odd.
And I've gone ahead and just copied and pasted
the setup of the code, not the essence of my main function.
But let's go ahead, in this program, and ask the user for a number.
We'll call it n.
And we'll use get_int to get that value.
And we're just going to say to the human, what's the value of n?
And I'm just going to say n colon space to just prompt them for some integer.
Then I'm going to go ahead and ask a question.
I want to ultimately print out even if the number is even or odd
if the number is odd.
So you could imagine doing this the very tedious way, like if n equals equals 1,
I could go ahead and print out odd.
And then else if n equals equals 2, I could print out even.
And then after that, I could support the number three, else if n--
I mean, this is stupid, right?
I could do this forever.
But it's at least showing a pattern, right?
One and then three and then five, of course, are going to be odd,
and two and four and six are going to be even, and so forth.
Well, it turns out we can compute this mathematically.
And a very common trick might be this--
we can actually do this.
If n divided by 2 has a remainder of, for instance, 0,
then I'm going to go ahead and conclude that the number is even.
So this percent sign is a new construction.
It's not plus.
It's not minus.
It's not multiplication or division.
This is the remainder operation, or the modulo operation, so to speak.
And this just means divide n by 2, and if the answer has a remainder of 0,
you can conclude, by definition of even, that the number is even.
So I'm going to print that.
Else-- I could do else if n percent 2 equals equals 1
and has a remainder of 1, you could imagine saying odd.
But as you noted earlier, this is not necessary.
What could I instead do to make the program a little better designed,
a little more efficient?
Yeah?
AUDIENCE: You could just use else and that would be fine.
DAVID MALAN: Yeah.
So if we're talking about integers, I can just
conclude, well, if it's not even, it must be odd, by definition.
And so here, we can just do even and odd.
So this program, once run, is going to look like this.
Make parity.
Looks like it compiled OK.
So ./parity is how I run it.
Let's type the number 50.
That's even.
Let's type the number 49.
That's odd.
Proof by example.
This is not very compelling, but I bet this is going to be correct, just
based on those two examples alone.
Yeah?
AUDIENCE: [INAUDIBLE] user did not understand our comment that answer's
a float or not an integer?
DAVID MALAN: Sorry, say that again?
AUDIENCE: What if the user doesn't understand, I'm saying?
Like I just do something like 1 and 1/2 [INAUDIBLE]..
DAVID MALAN: Really good question.
One of the reasons we provide for the first few weeks of the class
a few functions in the CS50 library like get_string and get_int and get_float
is that it forces the user to behave as you expect so that your program doesn't
crash because of unexpected user input.
So to your point, suppose the user is being a little difficult and says,
my number is going to be 1.5.
Get_int is going to prompt them for the same question again and again and again
until they cooperate.
If you type in apple, it's going to prompt you again.
Only once you provide an actual integer will it cooperate.
So those are among the features you get from the CS50 library,
just so that we can focus on ideas and not
on what we would call error checking, or malicious users, in this case.
All right, so what else can we do once we
have the ability to express conditions?
Well, let me go ahead and open one that I brought with me.
So rather than type all of these from Scratch,
let me go ahead and open conditions1.c.
So this is a program that's already been written.
And it turns out, it's got some other lines in it,
these grayed-out outlines that begin with slash slash.
You might not have noticed this, but in Scratch, you
can have what are called comments.
They're like little sticky notes that you can add
that don't do anything functionally.
It's just like notes to self or notes to your friend or notes to your TF.
That's what a comment is in a programming language.
So anything starting with a slash slash is a note to self.
And it's a reminder to me what this line of code does.
It's a reminder to your colleagues in the real world
or your TF in a class to explain to them what this line of code
is supposed to be doing, even if maybe you have a bug
and it's not actually doing that.
So I've begun, in these pre-created examples, to comment my code,
but the lines are essentially the same.
Go ahead and give me access to the CS50 library.
And a library, again, is just a file of code
that someone else wrote that we're using.
And give me access to the standard I/O library, which contains
printf and some other things, as well.
Notice here, I have x equals get_int in order
to get one integer from the user called x.
Now I'm going to ask them for a second integer by just calling it y
and calling get_int again.
And now I can do things like compare these values.
So this is now a complete version of the Scratch-like program
I pulled up before that allows us to conclude is x less than y,
greater than y, or, by default, equal to y.
So the only difference is we saw these lines of code on the screen before.
Now we see, in context, that, oh, for those lines to work,
we need to get the integers from the user.
And we need to have the equivalent of when green flag clicked,
and we need the equivalent of these includes so that it's
a complete self-contained program.
And just to be clear, even though I made this
in advance, if I wanted to run this program, how could I run it?
Call conditions.c.
Yeah, so make conditions first.
Sorry.
Oh, this is actually a teachable moment.
Why did this not work?
So no rule to make target conditions stop, which is a little emphatic.
But what does that mean?
Well, in advance today, what I did was I downloaded into my sandbox
a folder called src1, S-R-C meaning "source" in programmer speak.
And I just downloaded this into the sandbox for me.
Because in that folder are all of the examples
not only that I wrote in live, but also some others that I brought with me.
Unfortunately, all of those files are in a folder called src1.
Now, on your Mac or PC, if you want to open a folder, you do what I did.
You double-double the icon, and boom, the folder is open.
But in a terminal window, a text-based environment, you can't do that.
If I type ls, we'll see all of the files that I've created today--
float and hello and int.
But notice over here, there's a folder.
And that's what the trailing slash is.
That's a forward slash that just means, hey, human,
this is a folder, just so it's obvious.
Just like the asterisk means here's a machine code that you can run.
I need to change into that directory, but I can't double-click.
Nothing's going to happen if I double-click on this text.
But I can type cd space src1.
cd means change directory.
And now I hit Enter.
And now if I hit ls, notice I see even more files,
because these are all of the files from the course's website
that I brought with me today.
And if you type a command like this, pwd,
this will reveal even more information about the system,
but more on this in the weeks to come.
You're actually inside a src1 folder that's inside of a sandbox folder
that's inside of a root folder.
Now, odds are, at some point, you'll get confused as to where you are.
When in doubt, just type cd.
That will whisk you away to the default folder where you began,
no matter where you found yourself to.
Type ls, and you're back at the beginning.
So when in doubt, just type cd and Enter,
and you'll be back at the beginning.
Well, let me go ahead and open up this program, but run this one first.
I'm going to go into a program called agree.c.
I'm going to hide the code for a moment and make agree.
I did it again, cd src1, Enter.
Now I can do make agree.
It seems to have compiled the program.
And if I do ./agree, this program seems to be asking me a question--
do you agree?
Now, it's not obvious from the program what I should type,
but my gut tells me, sure, yes.
So I'm going to go ahead and type y for yes and Enter.
And it seems to know that I've agreed.
If I rerun it again--
./agree-- and type n this time, not agreed.
But you know what?
It's actually better than that.
If I do ./agree and maybe do a capital Y, Enter, that also seems to work.
So how is this happening?
Well, let me look at the code here.
The top of the file is almost identical to everything thus far.
Include those two files, int main void.
But now I'm using get_char, and I'm storing my answer
in a variable called c, but I could store it in anything I want.
And now notice the slightly new syntax.
What's clearly new about what I'm doing here?
What symbols jump out?
Yeah, the vertical bar.
So this is a way of saying a logical or.
So in Python and a few other languages these days, you
might literally write the word "or."
That doesn't work in C. If you want to ask this question or this question
and just take either answer as a valid answer,
you just use two vertical bars, which are typically
above your Enter key on an American keyboard, at least.
So two vertical bars means or.
Two ampersands, it turns out, means and.
But this is just a way of asking two questions in the same breath
and accepting either answer as potentially true.
So if c is capital Y or c is lowercase y, assume that the human has agreed.
Else, if c equals capital N or lowercase n, assume that they've not agreed.
And suppose I type in some other letter all together,
what's the program going to do?
Say again?
AUDIENCE: Ask you again.
DAVID MALAN: It's not going to ask me again,
because there's no loop here, right?
There's no evidence of while or for loop.
And get_char is literally going to get a char, but it doesn't specify what char.
What happens if I don't type y or n, capital or lowercase?
It seems nothing.
Just nothing's going to happen, and that's OK.
Your program doesn't have to print something.
And indeed, if I run this again and ./agree x.
It doesn't do anything.
So I've neither agreed nor disagreed.
However, you could imagine writing a loop that somehow forces the human
to cooperate in some way or another.
All right, let's do a different example, this time
based on an idea from last time-- that of abstraction.
Recall that in Scratch, there was no puzzle piece for coughing,
to make the cat [COUGHS] on the screen.
And so we implemented this, really, with our own custom puzzle piece,
ultimately.
So let me create a program that's called cough0.c.
That's a generous definition of inactivity, but OK.
Let me reload the screen.
When in doubt in CS50, as in life, reload.
That will probably fix.
Unfortunately, with programming and the internet, that sometimes happens.
So in a moment, what I'm going to go ahead and do
is translate that idea from Scratch of implementing the notion of coughing.
But instead of the say block, I'm going to use the printf block, or the printf
function.
And then I'm going to go ahead and design this version of code slightly
better and slightly better each time.
So I'm going to go ahead and open up a file cough0.c.
And I'm going to go ahead and include, let's say, stdio.h.
I'm going to go ahead and do int main void, which again, is just our boiler
plate or copy/paste for today.
I'm going to go ahead, then, and say printf, quote unquote,
cough with a new line.
And recall, in Scratch I wanted this to happen three times,
so I'm going to do it like this-- cough, cough, cough.
All right, I'm going to give myself a terminal window here at the bottom
so that I can now go ahead and say make cough0, Enter.
Nothing bad seems to happen. ./cough0 and cough, cough, cough.
So last week, I claimed that, eh, you can design this better, right?
Anytime you're copying and pasting, odds are
you should start to resist that temptation,
because it's going to lead to messy code, longer code than it needs to be.
What's the solution to this problem from last week?
AUDIENCE: A loop.
DAVID MALAN: Yeah, a loop, a for loop.
So let me go ahead and do that.
Let me create another version, cough1.c.
And I'm going to copy/paste this code, just as a starting point.
But now I'm going to go ahead and clean it up.
So I'm going to go ahead and instead do a for loop.
And I don't quite remember what goes in the parentheses yet,
but we'll come back to that.
I do know that what I want to do some number of times is just cough.
So the only question at hand is, what was the syntax here?
Well, we can write this in any number of ways,
and we could even use a while loop.
But I do recall saying int and then the name of a variable.
I could say counter, or I could just say i
to keep it succinct, equals 0 by default.
I could do this so long as i is less than 3, for instance.
And then on each iteration, I can say i equals i plus 1 or, more succinctly,
i plus plus.
So, again, it's a lot of new syntax.
And there's semicolons all over the place now.
But if I go ahead now and do make cough1,
nothing bad seems to have happened.
./cough1, cough, cough, cough.
It seems to be slightly better designed.
Unfortunately, there is this paradigm in programming
where humans, programmers, tend to think or tend to count starting from zero.
However, if you don't like that, at least early on,
there's nothing stopping me from initializing i to 1
and then doing i is less than 4 or, even more explicitly,
i is less than or equal to 3.
There's no less than or equal sign on your keyboard, typically,
so you can mimic it by doing a less than and then an equal sign, two characters.
This is logically the same.
Set i equal to 1.
Then go ahead and print cough, and then make sure to increment it.
And then make sure it's still less than 3, and 2 is.
Make sure it's still less than or equal to 3, and it still is.
So that 2 is, logically, going to have the same effect.
However, in the interests of convention, this would be the more common approach.
Do this while i equals 0 and then 1 and then 2, for a total of 3 times.
All right, but recall what we did last time, too,
is that if I'm writing a lot of code, for some reason, that
involves programs coughing, it would be nice to give myself my own custom
function.
So let me go ahead and do that.
Let me go ahead and write my own first brand-new function.
And I'm going to do this as follows.
I'm going to go ahead and type void, then the name of the function I want.
Then I'm going to say void here, for reasons we'll come back to.
And then I'm going to literally just go ahead and say cough.
So there are functions we've used today-- printf, get_int, get_string,
get_float-- none of which we showed you the implementation of, because people,
years ago, both in the staff and in the real world,
implemented those functions for us.
You, too, can implement your own custom functions or, in Scratch,
those puzzle pieces that we made in those pink blocks.
So if you want to make your own function whose name is
cough, whose purpose in life is to say cough on the screen,
this is the syntax.
For today's purposes, you say void and void here, but the name of the function
is important.
I'll call it cough.
And then I can use it as follows.
I can say cough, cough, cough now in order to cough three times.
Or again, we already decided that was bad design.
For int i get 0, i less than 3, i plus plus.
I can now do something like cough.
And so now, again, out of sight, out of mind.
I don't need to know or care how the cough function is implemented.
I can care that my code just tells the computer what to do.
For i from 0 on up to 3, cough, cough, cough.
And this is an abstraction.
I don't care that cough is implemented with printf.
I just care that there's a function called cough.
So let me go ahead and run this and see what happens.
Let me scroll down to the bottom, do make cough1.
OK, amazing.
No red errors now.
So ./cough1, cough, cough, cough.
But notice that this is a little bad design, I would claim,
because you know what?
If you keep writing custom functions up here, up here, up here,
the main part of your program is going to get pushed pretty far down.
And it's a human convention to generally have the main function
at the top of your file.
Seems pretty reasonable.
So you open the file, boom, the main function's right there.
So let's keep it there.
So let me actually move the cough function down below just so
that, again, the first thing I see is indeed the main part of my program.
And wherever cough is, I don't care.
That was the whole point of implementing it.
Let me go now to my terminal window and do make cough1.
Oh my god, some red errors flew by.
What's wrong here?
So error, implicit declaration of function cough is invalid in C '99.
C '99 means the version of C invented in 1999.
What's going on?
Implicit declaration?
So this is where C differs from Scratch again.
C is old, and it's kind of dumb.
It only knows what you tell it, and it only
knows what you tell it in order top to bottom, left to right.
So in this program right now, I have included stdio.h, as before.
I've included the beginning of main.
I've started a for loop.
And then I'm using a function that's apparently called cough.
However, where is cough now actually implemented?
Way down here on line 11 onwards.
C is not that smart.
It's not going to presume to look later in your file to see,
maybe they put the function cough down below.
It's only going to do what you tell it.
So there's a fix for this.
You can either do what I did initially, which is put
all of your custom functions up top.
But that's kind of a vicious cycle, because you can't forever
put the new functions up top.
Eventually, you're going to run into some kind of constraints.
And my god, you want the main function, by convention, to be up top.
So there's another solution here.
And this is the only time where copy/paste is compelling.
You literally copy the first line of your function's code on line 11 there.
And you go ahead and paste it at the top of your file with a semicolon.
So this is a way of sort of tricking C into, oh, you have seen cough before.
You haven't seen all of it, but you've seen enough of it--
you've seen its name--
to now tolerate its appearance in my main function.
So let me go ahead and recompile this code.
I'm going to go ahead and run make cough1 enter.
OK, now it compiled.
./cough1, and viola, we're back in business there.
But let me make one refinement.
And I'm going to jump ahead to what I called in the online examples cough3.c.
It turns out your own custom functions can take input.
This word void means that it takes no input.
And this word void means it returns no value, like get_int and get_string hand
you back something.
That's not applicable now, but we'll come back
to that in a week or two's time.
Suppose that you wanted to make the cough function more versatile
such that it will cough any number of times for you.
You know what you can do, is this.
You can change the input to cough function to be some value like n,
and you can then do something like this-- for int i get 0.
i is less than n, so not hardcoded anymore. i plus plus.
And then inside of your curly braces, you can print this cough line.
So now, notice, cough has been parameterized.
It now takes input of integer called n, and it
uses that input, n, just like you could have done
in Scratch, to do something n times--
not once, not three times, but a variable number of times.
I have to change my first line here.
This is called a prototype.
This one-liner is what's called a prototype,
and it's just copy/paste from your actual function.
But now notice what I can do.
My main function, again, is the essence of my program.
It's a little convoluted right now.
Wouldn't it be nicer if I could just say cough three times?
And indeed, now I don't need to know or care how coughing is implemented.
That's a well-designed program, arguably.
It's one line of code.
It's descriptive.
It says cough.
It takes an input, which means it costs three times.
And what's down below in the file, though I could certainly bring it
back up, is just what a computer scientist
would call an implementation detail.
Someone cares how you implement coughing,
but you don't have to care how you implement coughing.
You don't have to how we get integers.
You don't have to care about how you printf.
You just care that someone else has implemented that functionality
so you can stand on their shoulders and build more interesting programs that
are actually interesting to you.
Let me go ahead and open up an example that builds on this same idea.
In, let's see, positive.c, we have this example here,
which makes this all the more clear.
So here's a program that uses our two libraries, CS50 in standard I/O.
It turns out that the CS50 library does not
come with a function called get_positive_int.
It comes with get_int.
And you could imagine programs where you really
want a positive integer from the human, because negative numbers for a game
or for some program just would make no sense.
So how can we implement that?
Well, it would be nice to create it so that you can simply
write a two-line program like this where you call
a function called get_positive_int.
And if I scroll down, notice there's actually a new feature
here that we've not seen yet, but it's an interesting example
of another feature of C. What I've highlighted here
between lines 15 and 24 is this logic.
Here's a function called get_positive_int.
It takes no inputs, so I don't have to pass anything in parentheses.
I just want to get any old positive int.
But I do want this function to hand me back something,
just like get_int handed me back a value that I could put in a variable,
just like get_string does.
So this is not void.
This is int.
So this word to the left of a function is the type of its output.
This word in parentheses is the type of its input, if any.
And if there is nothing, you just say void in either or both place.
Now, here's a curiosity--
on line 17, we've not seen this before, but this is just a hint to the computer
saying give me a variable called n.
I'm not sure what I'm going to put in it yet.
So you literally just say int n semicolon.
You don't need to assign it anything yet.
It has what we'll call a garbage value.
You have no idea what's in it, but that doesn't matter.
You'll put something in it later.
Then there's this loop, which we haven't seen yet,
but in C, it's called a do-while loop.
It literally says do the following while this Boolean expression is true.
So what do I want to do?
I want to get an int from the user, prompting
the human for a positive integer, and store it in n.
However, I want to keep doing this while n is less than 1.
Because if the human types in 0 or negative 1 or negative 50
or anything non-positive, I do want to prompt them again and again and again.
So a do-while loop is kind of neat, because it
will do this first thing at least once.
Then it will check the condition and potentially do it again
if the human has not cooperated.
A while loop, if you think back, actually checked the condition first.
It was while some Boolean expression is true, do the following.
This one gives you one such iteration, one pass for free,
and then it checks the condition.
So it's just a different way of programming,
but we could do everything we've done thus far using
while loops or even for loops, as well.
All right, well let's go ahead now and make this a little more user friendly.
Let me go ahead and pull up some examples here of some screens that
might look familiar.
So if I go ahead and open up, for instance,
this slide here, you might recall this game
from yesteryear, Super Mario Brothers 1, from the very original Nintendo.
And there's some screens in that game that look a little something like this.
For instance, these are little bricks in the air
that if Mario or Luigi hits their head up against,
like a coin or something else pops out.
But this is kind of a nice idea, because it lends itself to actually doing
something a little programmatically.
For instance, how might I go about writing a program that quite
simply prints out four question marks?
Well, let me go ahead and open up, for instance, in code,
an example called mario0.c.
And I claim that this could be one way of implementing this program.
It's very simple, and it really doesn't do justice
to the other graphics on the screen, but it does implement that one idea.
And indeed, somewhere in the code for Mario,
there was probably some line of code that
told the console game to print question mark, question mark, question
mark, question mark.
In C, we could certainly do this with four question marks.
Or how else could we do something that many times?
AUDIENCE: For loop.
DAVID MALAN: Something like a for loop.
So let me go ahead and jump ahead a couple of iterations
to an example I'll call mario2.c, which just does all of this.
So this is actually pretty involved, but notice what it's doing.
In main, I'm saying, hey, give me an integer called n.
Do the following while n is less than 1.
So this is just a way of asking, what is the width of the blocks
that you want to print?
Then, once I have that answer, I can go ahead and, just as before,
print that many question marks n times, one at a time.
And at the very end, I'll print just a new line.
So in short, if you want to create a program, albeit in text,
that does something like this, and I make mario2--
whoops.
And I make mario2, Enter, and type ./mario2,
I can do a width of four and get four question marks.
Or I can do 50 and get many more on the screen, all
by just using these basic building blocks.
But notice, because of that do-while loop, if I don't cooperate
and I do something like 0 or negative 1 or negative 50,
I just keep getting prompted again and again, because n is less than 1.
That's the kind of logic that you can impose there.
But let's go ahead and skip ahead, say, to something like this in Mario,
where you have a whole lot of bricks underground.
And this time, it's not just a column or a row of bricks.
This time, it's kind of two dimensions.
Well, this is kind of interesting, because now how do you
go about printing block, block, block, block, block, block, block, block,
block, block, block, block, and actually making
a two-dimensional structure instead?
Well, there's nothing stopping us in C, as in Scratch,
from doing something, for instance, with loops.
So let me show this example here.
So suppose that with these first lines of code,
I've asked the user for the size of this block.
So I want to create something that's square-like like this-- block,
block, block, block, block, block, block, block, block, and so forth.
Well, I can go ahead and prompt them for an int again and again
and again until I know that size.
And then notice this.
This is starting to escalate again, but consider the logic.
This now is for int i get 0, i less than n, i plus plus.
So do the following n times, right?
This is a very cryptic, C-like way of saying, do the following n times.
What about line 16?
What is line 16 saying?
Even though it's using a different variable.
I'm using j just because instead of i.
AUDIENCE: Same thing.
Do the following n times.
DAVID MALAN: Yeah, it says the exact same thing-- do the following n times.
However, it's counting using j instead of i,
just so that my math doesn't kind of commingle incorrectly.
So if you think about what this Mario block is,
this is like printing rows and columns.
Kind of like an old school typewriter that's got to move from
left to right and then top to bottom, top to bottom, left to right,
and so forth just to print different blocks on different lines.
So the effect here-- if I open up mario8--
might be this, make-- oops.
Let me go ahead and make mario8, ./mario8.
What's the size going to be?
Well, maybe three.
And now I've printed out three rows and three columns.
These essentially represent each of my rows.
I'm counting from i up to--
oh.
I'm teaching myself now only, OK.
Let's rewind.
Here is what was amazing me a moment ago.
When I was running what's the size of this program,
I saw a three-by-three grid of blocks.
And if I run it again, maybe with 10, I now
see an even bigger grid of 10-by-10 bricks.
It's a little taller than it is wide, because the hash marks are
taller than they are wide.
And you'll see that now this program is dynamic.
So how is that working?
Well, if I actually look at the code here,
notice that, effectively, what line 14 is doing
is it's doing one row at a time.
It's giving me n rows, and each of those rows I'm thinking of this is i at 0,
i1, i2, and so forth.
Meanwhile, within each row, I'm using this inner loop,
which is deliberately nested inside, to kind of do each of the characters
from left to right.
So within each row, I want hash, hash, hash, hash.
Within each row-- hash, hash, hash, hash.
So it's like implementing this two-dimensional process.
But again, using the same fundamental ideas.
Just a for loop that's very carefully counting from zero on up
to some value to do something again and again and again.
And so if you think about really any of today's games
or graphics or programs, anytime you see redundancy,
whether it's this in two dimensions-- maybe it's this vertically in one
dimension or this horizontally in another.
Odds are, there's just some repetition that's happening again and again
and again that can be reduced in C or in Scratch or some other language
to ultimately just lines of code.
And indeed, this is an allusion to one of the first things
you'll do for the first problem set, problem set 1.
You'll use CS50 Lab, which is identical to CS50 Sandbox, which
I've been using thus far, but which adds instructions,
the actual problems to solve, alongside of your sandbox.
But before we tease you with that, let's just
consider now that there are a bunch of little assumptions I've been making.
Like thus far, all of the mistakes in my code
have been my own-- some intentional, but several unintentional, as well, today.
But it turns out that computers themselves do have limitations.
Inside of your Mac or PC is generally stuff like this.
This is called memory, or RAM.
And you don't typically see it unless you
remove the cover from your phone or your laptop or desktop.
RAM is where all of your programs are stored while they're running.
RAM is where all of your programs-- where all of your files are
stored while they're open.
It's what your computer uses to do multiple things at once
and keep things in memory.
However, it is, by nature of hardware, finite.
You have maybe one gigabyte, one billion bytes, of memory.
Maybe you have four gigabytes, or four billion bytes, of memory.
You have fixed amount of memory in your computer,
which means there is some fundamental limitation on what your computer can
do.
It cannot necessarily count to infinity, because how could it count to infinity
if it can't store all possible numbers using a finite amount of space?
Indeed, there are some limits of computation
that we've only just begun to see.
In fact, let me go ahead and do this.
Let me write a program that I'm going to go ahead and call float.c.
And this is just going to be a program that gets a couple of floating point
values from the user.
Let me go ahead and include the CS50 library.
Let's go ahead and include stdio.h, int main void, as before.
And all I want to do here with this program is get a couple of floats.
So give me a float.
We'll call it x.
Get_float, and I'll prompt the human for x.
Then let me go ahead and get another.
I'll call it y.
Get_float, quote unquote y.
And recall that a float is just a number that
has a decimal point in it, a so-called real number.
Now let's just do some simple division.
I claim that computers can do addition, subtraction, and so forth.
So let's do that.
Let's just tell it that x divided by y is going to equal the following--
percent f backslash n x divided by y semicolon.
So that's just sort of a very simplistic calculator
that I've implemented that only supports division.
Let me go ahead and compile this by going and typing make floats.
And you'll see that it did compile.
So floats with dot slash.
x is going to be, say, 1.
y is going to be 10.
OK, viola.
x divided by y equals 0.10000.
That's pretty nice.
And recall, if you don't want to see all those zeros, you can just say,
show me one decimal point by adding 0.1.
Recompile and then rerun it.
And now do 1, 10.
OK, so now it's 1/10.
Or is it?
Now that I have this ability to look past the decimal point,
why don't I look not a few places or one place.
Let me go ahead and look maybe 10 places after the decimal point.
Let me rerun this as make floats, ./floats, 1, 10.
Interesting.
All right, that seems a little strange.
Maybe it was just a fluke.
Let's look out a little further.
Let's look 50 decimal places out.
Let's go ahead and recompile this.
And it turns out, there's some keyboard shortcuts.
I'm now hitting up and down on my keyboard, which
will scroll through your entire history of commands
so you don't have to remember everything.
So to save time, I'm now just going up and down.
Let me go ahead and do ./floats now, 1, 10.
Oh my god, division is a lie.
So when your grade school teachers or whatnot taught you that 1 divided by 10
is 1/10, or 0.10000 infinitely, apparently that's not true.
According to this computer, 1/10 is actually this value.
So how do we reconcile that?
Who is right, grade school math or computers?
And what might explain?
Any thoughts?
Yeah?
AUDIENCE: It only stores so much so then half of that,
you don't know what's going on over there.
DAVID MALAN: Yeah, that's a good way of putting it.
Computers can only store so much, so after a certain point,
you don't know what's going on out there.
I like that.
Because that's indeed true.
If you only have a finite amount of hardware,
like a finite amount of memory, at some point, the computer has to decide,
I can count no higher than this value.
Or I can store no more than this many numbers after the decimal point.
You might be using 32 bits, which a float is.
You could use more bits, like a double, as I described it earlier,
literally uses twice as many bits, 64 bits.
So that means we could get farther out before we see that imprecision.
But you will see it.
Computers are, indeed, not perfect in this sense.
They can only store a finite amount of information.
And so in that sense, the computer is storing the closest possible match
for 1 divided by 10 that it can.
Because you can't possibly store an infinite number of numbers 100%
precisely using a finite amount of information.
And we see this in another context, too.
Let me go ahead and write one other program here called overflow.c.
And we'll see the same issue in another context.
Let me go ahead and include stdio.h.
Let me go ahead and do int main void.
Let me go ahead and do for int i gets one.
I'm going to go ahead and just say no condition and do i times equals 2.
And let me go ahead and just do this.
Print out the value of i.
So I'm doing the super quickly, but I just have written a program here
that's going to start counting at zero.
It's going to multiply i.
Star equals just means times two again and again.
And it's going to do this forever, because I literally and deliberately
didn't ask a Boolean expression here.
I could actually just say something like true,
but I can also just leave it blank.
So this just means do this forever.
It's an infinite loop.
Well, let me go ahead and this is going to fly past the screen here.
So I'm going to also sleep for one second in between.
And indeed, there's a function in C called sleep.
But to use it, you actually have to include
another file called unistandard.h.
You would only know this from looking in the documentation,
but it's a handy function that lets me sleep one second at a time.
Let me go ahead and make overflow.
No errors.
Let me increase the size of my screen.
And let me go ahead and run overflow.
And we'll see that every one second, it prints out a value starting at one,
and then it doubles it, and then it doubles it,
and then it doubles it again.
So you might recall some of these values from last week,
where I proposed that were 1,024 pages in a phone book,
and then it just got smaller and smaller and smaller.
Now we're just doing the opposite.
We're doubling by two, by two, by two.
We're just past a million now, 2 million, 4 million, 8 million,
16 million.
So we're getting up there.
So it looks like integers are pretty big.
They're indeed using 32 bits in a computer that apparently--
what just happened?
Another lie.
If you just multiply some integer by two forever, it eventually becomes zero,
it would seem.
That, too, is not right.
But what has happened?
And there's kind of an illusion to it, both in my program's name
and in the red error.
Well, at some point, you only have so many bits
after which if you keep incrementing, incrementing, incrementing,
you don't have enough bits to sort of carry the one, so to speak,
and remember the even bigger value.
After all, if we go back to some of our discussion last week to discuss now
what's called floating point imprecision or now integer overflow,
which means floats can only be so precise
and integers can only be so big.
What you have is the following scenario.
123 in decimal, in our human world--
of course, you can just keep adding one to it.
And as soon as you hit nine, it rolls over to zero.
You then carry the one, and you have 130.
That works great.
But of course, even in decimal, if you're at 999 using only three digits
and you try to add one more, you carry the one, you carry the one,
you lose the one.
Sorry.
What happens next?
This becomes 1, 0, 0, 0.
But if you only have three digits, you lose that initial one,
and you're left with just zero.
Same thing happens in binary.
Now if you context switch--
and this is, in binary, what number?
This is the fours place, twos place, ones.
So it's seven.
4 plus 2 plus 1, this is 7.
So of course, if you add 1 to 7, you'd like
to get 8, which would give you 1, 0, 0.
But if you only have three bits, three digits,
you're going to overflow, so to speak.
You're going to lose the carried one so that the value you're actually storing
is just zero.
That's why if I count high enough with an integer in a program,
once I hit the billions, eventually that one has gotten carried too far.
It's only 32 bits large.
We can't fit a number even bigger than that.
That's what's called integer overflow.
And if you ever heard of the Y2K problem,
this was a horrible, very simple problem that humans created for themselves
back in the day when computers were invented in the mid 1900s, really.
Humans decided to save space, very reasonable, because space was expensive
early on.
So instead of storing the year as 1999 or 1970 for 1970, what did they do?
Yeah, they just stored two digits, right?
Like oh my god, we're not going to be using
these computers 50 years from now.
Let's just store two digits.
Unfortunately, that was not the case.
And there was a lot of code out there and a lot of computers out there
that were still running in 1999.
But if you're only storing two digits and you plus plus one value
to the year, what you'd like to be 2000 was
misinterpreted in lots of systems as 1900, at which point stuff broke.
And the world spent millions of dollars, presumably,
having programmers start using more memory
to fix this problem in anticipation of what was called
Y2K to get ahead of this problem.
And in the end, the world did not end in 1999, which was great.
But it was a very real and a very expensive
problem because of that lack of foresight.
It turns out that there's other examples of this, as well.
So this one, as an example, will just about end on Boeing 787.
So Boeing has not been getting great press recently.
And even a few years ago, did they have what
appeared to be a very straightforward software bug.
Pictured here is a model 787 airplane.
And the article from The New York Times explained as follows--
"A model 787 airplane that has been powered continuously for 248 days
can lose all alternating current, electrical power,
due to the generator control units simultaneously
going into failsafe mode.
This condition is caused by a software counter
internal to the counters that will overflow
after 248 days of continuous power.
Boeing, according to the statement, is in the process
of developing a software upgrade that will remedy the safe condition."
So what does this mean?
Well, if you actually dig into the numbers,
248 days is roughly the value of 2 raised to the 32nd power,
give or take, in 1/100 of a second.
Which is to say that Boeing, in some crucial piece of hardware
in their 787 actual airplanes, were using integers
that were counting so high that after the 248th day of the airplane being
powered on would actually overflow, the result of which
is that the power in the plane could cut off entirely.
And so the solution, if you read through all the technical speak and jargon
there, is they literally had to reboot their planes every 248 days
in order to reset that variable back to zero.
This happens even today in the real world with issues like that.
And so you'll begin to notice these trends anytime people talk
about hardware mistakes or software mistakes.
Quite honestly, can you typically reduce them to problems
you yourselves have run into.
And let me go ahead and tease just a couple of things, a couple of features
now ahead.
It turns out that now that we have the ability to write code,
our programs, of course, can do any number of things, saying or printing
things on the screen.
We, of course, might do something like this in a program
we might call figlet, which actually comes with some systems.
And I can say something like, this is CS50,
and actually print it out in what's called ASCII art using characters
on the screen that kind of sort of look like letters
and create fairly beautiful, if old school, art on the screen.
Of course, if you write code and you understand
not only how numbers and letters are represented, but also sounds,
per our chat last week, you can do even more powerful things,
such as this note, which we will literally end on today.
SPEAKER 2: This is CS50.
DAVID MALAN: That's it for CS50.
We will see you next week.
[APPLAUSE]