[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]
