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