[ Music ]
>> [Background sound effects] Noah.
Thou shalt build thyself an ark measuring 300 cubids in length.
>> [Background sound effects] 300 cubids give or take.
>> [Background sound effects] Exactly 300
and thou shalt takest two of every creature.
>> Two creatures.
>> [Background sound effects] Two of every creature.
>> Even stink beetles?
>> [Background sound effects] Especially stink beetles.
>> [Background sound effects] Whoa.
Cool. God is so in your face.
>> Yeah he's my favorite fictional character.
>> Oh, it's so late you kids have to go to bed.
>> But the flood's only knee high.
At least let us watch until the midgets drown.
>> Yeah mom come on.
You let us stay up to watch Try McLauren
and such other bible epics such as David versus
and Super Goliath and Suddenly Last Supper.
>> Go Lis.
Way to site precedent.
[Sound effects]
>> Well alright.
You can stay up late tonight
but tomorrow everyone's going to bed at 5 o'clock.
[Sound effects]
>> [Background sound effects] Go forth Noah and remember,
the key to salvation is --
>> You've seen the movie now be a real life Noah only this Noah
has been accused of killing two of every animal.
Coming up next on AM Springfield.
>> Oh, my goodness.
That was a long movie.
[ Sound effects ]
>> Lighten up Lis.
>> Finland, let's see that native dance.
[ Sound effects ]
>> I head they sent a rocket to the sun once at night
and there was that submarine with screen door.
>> No, no, no, no.
no. Young man you need to do some serious boning.
[Sound effects]
>> Oh grow up Lis.
>> Okay Libya exports.
>> Yes sir you American pig.
>> [Laughter] Nice touch.
>> [Sound effects] Let's see,
the exports of Libya are numerous in amount.
One thing they export is corn,
or as the Indians call it, maize.
Another famous Indian was Crazy Horse.
In conclusion Libya is a land of contrast.
Thank you.
>> Ow, I can't breath.
Please stop em.
>> I'd like to, but I'm afraid you need diplomatic immunity.
>> Point of order, if you want
to learn anything we must respect --
>> Point of odor, Lisa stinks.
[Laughter]
>> Leave her alone.
>> You leave her alone.
[ Sound effects ]
>> [Background sound effects] Order, order, order.
Do you kids want to be like the real UN or do you just want
to squabble and waste time?
[Music]
>> [Background music] Have a great weekend kids.
Be nice to the underprivileged countries.
>> Good luck Ralphie.
If you're nose starts bleeding,
it means you're picking it too much, or not enough.
>> Okay kids, Otto's in charge.
Remember Otto, we're trusting you
with our greatest natural resource, the school bus.
[Music]
>> Water bill, third notice.
Jury duty, third notice.
Mortgage bill, ewh, second notice.
Flant Crest Enterprises.
>> Oops, that's for me.
Flant Crest Enterprises is my home business.
>> You liar.
You don't have a home a business,
why would you make up a lie like that?
>> No it's true.
Mom and I sell religious hook rugs over the internet.
>> Internet eh?
>> Yes indeedy.
I get some good scratch too.
>> Scratch eh?
>> Yep.
>> More, eh?
>> Yep.
[ Sound effects ]
>> Homer what are ya doin?
>> No time to answer that Marge.
I'm setting up a home office for my new business enterprise.
>> What business enterprise?
>> [Background sound effects] Ever heard
of a little thing called the internet?
>> The internet, eh?
>> Oh yeah.
Everybody's making money off the internet except us.
We falling behind, way behind?
>> Is that my good butter?
>> Can't discuss that now Marge.
I have to write another delicious memo.
Memo.
[ Sound effects ]
>> [Background sound effects] This song is driving me crazy.
[Sound effects]
>> I don't know why I bought this stupid cake.
[Sound effects]
>> All right and that is the connection to CS50.
[ Sound effects ]
>> Alright, welcome back to CS50,
this is the end of week two.
So a couple of announcements -- So if you did the hacker edition
of Pset 0 and still have a sensor board, that's fine.
Make sure your name, user name and ID number are on a piece
of paper in the Ziploc bag and just hand it to one
of the teaching fellows on your way out today.
We've gotten plenty of responses regarding lunch with me and CA's
and TF's and we will follow up by email sometime tomorrow
to figure out the logistics.
And it turns out if you're nice enough to one of the houses
on campus, they invite you to dinner.
So now have a dinner with David and team next Wednesday.
It's part of their senior common room event.
Space for that is very limited.
The idea is to get together around dinner in the Mather SCR
as well as the dining hall and to chat and get to know some
of the TF's and CA's and fellow students in the class as well
as some fellow Matherites.
So if that is of interest, next Wednesday as a one-time thing,
cs50.net/dinner to RSVP.
Speaking of David there's no need certainly
for formalities in this course.
It is perfectly fine to call me David and as fact,
sweet as you are, at the end of these lectures to do this things
like this, it's really just a computer science lecture.
So there's no need for that either.
Sections have -- sectioning has happened thanks to Jansu
and Yukie [Assumed spelling]
to use their computer science skills
to take a very large dataset from FAS and also
from our own database, mash them together
and email 300 plus emails out automatically.
If you ended up by algorithmic chance
in a section you're not comfortable in,
whether it's too much or too little comfort, that's fine.
Just go ahead and email sectionCS50.net no later
than this Friday.
Or if you simply can't make your assigned section time,
email us as well.
Office hours continue to be in progress, especially now
as Friday's deadline is coming up for Pset 1.
If you're having any discomfort or you're kind of freaking
out because you really just don't know how to do C
or program, it's totally fine.
Realize that there will be plenty of one-on-one help
in the science center.
You take a look at CS50.net/officehours
for the current Google calendar and this is an opportunity to,
as you can see it all barely fits, because there's
so many people who will be there in attendance.
But for me at least ask this,
Marta this past Sunday did deliver the first walk-through
for Pset 1.
You can find the video for that or the MP3
on the problem sets page on the courses website.
So if you you're asking yourself this question,
"I have no idea where to begin.
How do I do so?"
Do at least start with that video as it's meant
to answer precisely that question.
And I realize that we go quickly in the course and that I've put
up you know a dozen or more programs in C already.
And a lot of it might very well feel like this, but honestly
if not yet sat down to problem set one and plan to tonight
or tomorrow, I think you'll find once you spend some time
with this getting your hands dirty, it will all begin to sink
in and not feel so cryptic.
Finally, it turns out it's a big mistake
to say something off the cuff to say something in lecture like,
"Gee maybe you should all check the map
to make sure you submitted problem set 0"
because this induced innumerable personal emails to me
and I then had to go through our survey data checking whether
or not everyone in fact submitted.
Or if it was a Google problem,
version one of our map had a couple of bugs,
one of which was Google induced because we tried
to hammer their servers a little too fast.
They don't like it when we send 350 plus requests within in
like five seconds for GPS coordinates.
So they essentially blacklisted us once in a while.
That meant some of you didn't make the map and so forth.
So anyhow, sat down last night and redid the whole thing
and what we now have is a full-fledged little application
here, much prettier I think than the original version,
because I also addressed some other issues.
I also realized though perfect this initial version originally
was, last night around 1:00 a.m. on like my 8-core, 3 Gigahertz,
MacPro, I then pulled out my laptop, which is far slower
and the thing sucked; like it took multiple seconds just
for the page to load.
We had this map on our home page,
didn't feel like the best idea for people's first experience
to the site to be a little spinning globe or what not
as the thing loads up.
So we re-wrote the whole thing
and now what you see are little hot spots.
One of the reasons for the speed degradation was
that when you try to put 350 of these little cartoon markers
on a map, that takes a lot of CPU cycles.
It's a lot of Java script codes to make that happen,
but now it's a little fancier.
So now you can zoom in and then as soon as you are closer
to the earth, it then shows you more granularity,
where things are.
I can keep zooming and zooming and here we can finally get
into the downtown Boston area.
And in fact John and David J. are in fact
from Boston, Massachusetts.
So this too was an interesting bug.
At first I didn't realize that if you try
to plant multiple markers, i.e. multiple students or staff,
at the exact same GPS coordinates,
Google just pretty much shows the last person you put there.
So this felt a little sad
because David J. was the last one put there.
And I realized, "Damn, I'm about to get an email from John,
quote, unquote if I leave him off the map."
So we fixed that too.
We figured out what kind of algorithm it would take,
though only a few lines of code
to make a comma separate an English list of names like John
and David J. putting the word -- the commas in at the end.
So there was actually a lot
of little bite size programming projects that arose as a result.
But do feel free to play and I think you'll find
that CS50 students do hail from all over the world.
And what you can also do now, if you don't see yourself
or if you're smack dab in the middle of the ocean
where there's in fact no land because of a typo,
click on Log-In at the top of the page.
You can then click About Me
and you can now change your own hometown and no need for all
of the emails anymore.
So, we've hopefully empowered you for that.
Any questions, logistical or otherwise?
I'll admit it's actually really kind of neat to just point
and click around and just see from how all over students
in this class actually are.
So, have fun with that if you will.
So, I thought we'd take a look at a little bite sized program
that I actually whipped up right before class
to address a questions or challenge that a number
of you have run into, and that's this problem with imprecision.
So we've been -- or you've been looking at problems that one,
or starting tonight or tomorrow will be looking
at some matters of imprecision.
And remember that that just boils down to this problem of C
and a lot of languages only using a finite number of bits
to represent some value, some number.
So if you've only got a finite number of bits,
clearly there's an upper bound on just how precise you can be,
how many numbers after the decimal point you can express.
And a really simple way of seeing this as a footnote
in problems that one says is to try to represent and a float,
a very simple value of one one-hundredth.
So .01, such a small number.
It feels like it should be represented perfectly cleanly
underneath the hood, because my God it's such a common, simple,
relatively small number.
But what you see here is that's not in fact the case.
So I wrote this really quick program.
A float F is initialized to 0.01 and realized that some
of these things are just conventions.
That's equivalent to leaving off the leading 0.
This is not equivalent obviously mathematically,
but I really wanted to see this value.
So instead of just printing the value with percent F,
I used .10 F, which even though it feels
like I just transposed 01,
it actually means something different.
What does it mean if I say percent, .10 F?
[Inaudible background discussion] Yeah,
so 10 decimal places.
So the point just means after the decimal point
in this program, show me 10 decimal places.
So what that means is I'll actually be able
to see exactly how, or more exactly,
how this program is represented underneath the hood.
So let me go ahead and run GCC
on imprecision dot C. I'm now going
to run the default name of A dot out.
So what I see is, "Ah hah."
So I the programmer have been completely clear
about what number I want to express.
C just can't quite give it to me because of the judgments it has
to make as to exactly
which numbers it can represent precisely and which it's going
to have to represent almost.
And you can see it here.
But had I done this realized, had I just printed it out,
as a percent F notice that that kind of detail is kind of lost.
So this actually looks much better by default.
If you don't specify the point,
something F you just get some number of decimal places.
It looks like the number is in fact correct,
but as some of you have realized intentionally per the problem
set you start to trip over some subtle bugs.
If you're trying to make change,
especially in problem set 1 you realize
that occasionally you're giving the wrong number of coins back
because the rounding is off.
Some of you have already had or solved this question already,
well how do you round?
Well if you can imagine the name
of a function existing it might very well exist.
In fact, so there is in fact a function called round.
So what I wanted to demonstrate here is the following.
I just want an int so I'll call it the generic I and I want
to initialize I to the result
of the mathematically rounding the process
of eps decimal point two places to the right.
And this is very similar of course
to what you're doing in the problem set.
So I have .01 I want to move the decimal point one, two positions
to the right and hopefully the answer I'm going
to get back is in fact, 1.
But let's see what happens if I do this simple way.
So let me actually undo the fix that I ultimately put in place.
So I'm going to get rid of this rounding altogether.
And I'm just going to leave it at this, so I gets F times 100.
It's so simple, just move the decimal points.
I know I'm going to lose the rest of the decimal points
because if I change from a flow to an int,
remember you passed all the way after the decimal point.
Now notice I'm using percent D, so that's in fact correct.
So let me go ahead and recompile it, rerun it and you know what,
if I take .01 and move the decimal point
on paper two places.
I'm pretty sure I don't get 0, I get 1.
But that's because notice if we move the decimal point
in reality the value I'm getting is really 000.999999998.
So if you then change that value to an int,
by throwing away everything after the decimal point,
obviously you lose all of those numbers
and all have left are the things to the left
of the decimal point, which was in fact, a zero.
So let's go ahead and fix this.
So it turns out there is a function called rounds.
I express it simply by doing this.
It's in a header --
it's declared in a header file not surprising perhaps called
math dot H. We haven't used it before
but that does in fact exist.
It doesn't matter usually what order I include these files in,
I just tend to be a little anal and do things alphabetically
so I can find things more quickly
when I get more of these things.
But it's in math dot H so it looks like I have a solution.
So GCC imprecision dot C enter, damn so close.
But even though you might not have written this code yet,
what is clearly the problem?
Yeah so I haven't linked in so to speak the library.
So even though standard IO as the name suggests is just
so standard that you don't have say something like dash L STDIO.
Because C links in the standard library automatically
but the math even thought it's not standard so to speak,
so I actually have tell GCC
where to find the header file math dot H but I also have
to tell to link in the math library.
So I'm going to go with my gut.
I'm going to say dash L math and realize there is
in fact no space after this,
and weird though it looks, hit enter.
Hmh, cannot find dash L math, but remember the RTFM proverb
from last week, let's just check the man page.
So man round.
So hopefully there's a manual, so yeah.
The round function, it's apparently
in chapter three of the manual.
Notice I got this part right just by guessing.
I see that there's new versions of round.
The one I used is called round.
You pass in a double or a float, which is not even as good.
Here's the hint, uh the manual answered this question.
So let me go ahead and fix this.
So GCC not dash L math, dash L M, okay that's pretty good.
Let me rerun the program A dot out and now I have the answer.
So we'll see another trick today about how you can round
without even knowing about this round function.
But the exercise here is that if you think
that there might be a function, a utility function of sorts,
well check the man page for the name you might think it has
and more than that, especially if you've not gone ahead
and gotten any of the recommended books,
which really aren't necessary you can go to the resources page
of the course website under C. By far one
of the best references here is this thing, C reference.
We took this from cppreference.com,
C plus plus reference, ripped out all the C plus plus stuff
and left just the C stuff and you no what,
I want some math functions.
Alright standard C math, okay interesting.
It looks like C gives me all of these things,
most of which I don't need.
Oh there's a pal function.
You might find that useful at some point
but not necessarily required anytime soon.
But I want it, interesting that round is not documented here.
Let's see display all entries.
Okay well we won't waste time on this
but somewhere it is actually embedded,
for some reason not here.
Damn, that's an interesting omission.
So for every other function except round,
turn to that documentation,
which I promise you is outstanding.
But it actually it is a good way
of learning some new tricks right.
We can only cover so much in lectures and even in sections.
And frankly you'd get bored quickly
if we spent an hour saying,
"Here are the fifteen functions provided by the math library
and here is fifteen examples of each."
And that kind of stuff you can just kind of flip
through when you care or when you need to.
And again that's all about how one bootstraps him or herself
to learning a bit more about a given language.
So, let's go ahead and learn a bit more.
So, we started last time with a bug.
Let's start this time with another but of sorts related
to this very simple idea of swapping two variables.
Out of context, really not that sexy to say I want
to take this variable and this variable and move it's value
into this and this value into this,
but it's a relatively simple exercise
that triggers some problems.
So in buggy three dot C, which is in your print out from Monday
or if you weren't here there are extra printouts probably still
outside I decided this week today
to take off the training wheels so to speak
so even though I've been very good in putting comments
as you should in problem sets in the printout of this code,
I wrote a little script that rips out all of the comments
from the code displayed on the screen, only because I realized
that if I continue asking questions
like what does this block of code do?
And the answer is they are expressed in that comment,
really not all that stimulating.
So realize you have answers in your handouts if you need
to glance or reference later, but for the sake
of engaging trying to focus up here
when interesting topics come up.
So here is a function, it's called main,
that's my default function.
This is kind of interesting.
There's something interesting and new going on up here
but more on that in a moment.
So what does main do?
Main declares two variables X and Y, gives 1 the value
of 1 and 1 the value of 2.
This program is going to printfF in each in value,
not very interesting and then it's going
to say swapping dot dot dot.
And then it does what?
Well in English what is this line of code doing?
Like how would you express now
that you're getting a little more comfortable
with programming and see, what is that line doing in English.
Okay so I'm calling a function and the function is called swap.
Presumably it's meant to swap X and Y because if you kind
of think ahead where this program is probably going,
I'm hopefully -- I'm trying to demonstrate that X and Y are 1
and 2 but then I call swap and now they are 2 and 1.
Okay so let's see if that is in fact the case.
Let me go ahead and this is buggy 3.
So make buggy 3 enter, and now notice incidentally one
of the upsides of using make even at this point instead
of running GCC manually, which is also instructive,
realize that all the stuff it spits
out automatically has among other things linker flags
like this.
So we sort of aggressively provide you with flags
like dash L M just because we figure
if you're running make you don't want to have to think
about details like that but realize
if you've been using make some of the magic has been happening
because of our automation of that here.
So now I have a program called buggy 3.
It's in my current directory.
I'm going to start getting pedantic with dot slash
to say this directory, a program called buggy 3 enter apparently
it doesn't work.
It's broken.
It's buggy.
So why is that?
So let's take a quick look.
I'm going to -- this code looks pretty good.
It's hard to find but maybe you have found it.
But it's hard to find any fault logically with the code in main.
So mainly presumably in it's this swap function.
Maybe it just doesn't do anything.
So let's look.
So if I scroll down, okay alright somewhat
of a new approach alright.
But hereto, realize even though I'm calling some
of these barriers A, B and temp, which would seem
to violate this principle of good style,
well realize there are some context like iterating in a look
or just calling the variable I, so simple.
It's very reasonable.
Calling a number a counter N, very reasonable.
Calling a three-line -- four line functions variables A and B
because that's really all they have --
the function doesn't have to do all that much.
Realize sometime that it's completely legit
to use very simply named variables.
So in this case how do I swap A and B?
Well if I've got A here and B here, I can't just move --
copy A to B. Because what happens
if I just do B equals A semicolon.
I lose B. I'm kind of doing too much at once.
So what would you do in reality?
Well you can't just move this here and then that here
because of that problem so let me just move B
into a temporary variable, a little place holder.
Then I can clobber his value --
change his value by doing A against B
and then finally I can restore B
by using per this last line here that tenth variable.
So there's a trade-off here, subtle though it is,
interesting over time but notice that I'm using 32 extra bits
to implement this particular function.
I'm taking A and B, I'm swapping them but to make
that happen I actually need
in this implementation a bit more memory,
but not such a big deal.
But apparently it's still wrong.
So why can you find logical fault with this.
Or even if you're maybe among those more comfortable,
you can express what the problem is.
Why is swap not apparently swapping?
Yeah.
>> [Inaudible background question]
>> So I'm not returning anything.
So that's an interesting point.
So swap is declared as having a return value of void,
so that's interesting because it's certainly not printing
anything and the last time we saw a function
that didn't print anything,
it really didn't do anything useful.
It didn't have any side effects.
So that could be the explanation here.
So it's not returning anything.
Certainly up here notice I'm not even assigning a variable.
The return variable of swap because it's return variable --
it's return value is nothing.
It's void.
So we could fix this that way somehow.
But what else might the problem be?
Yeah.
>> [Inaudible background response]
>> Okay so that's an interesting gotcha too.
I seem to be talking about X and Y up at the top here in main,
but then all of a sudden I start talking about A and B,
so clearly X and Y aren't getting swapped
because I'm only swapping A and B. So there's a couple
of interesting take-aways here.
So that's true in this case
and it's not fundamentally the explanation,
but it's definitely related.
So in this case, yes I have two variables in this context
of main called X and Y. I go ahead and pass them
in as what we'll start calling consistently arguments.
So arguments are inputs to functions, otherwise known
as parameters, slight difference in terminology depending
on the context but for the most part they're synonyms.
So a function can take arguments or inputs
and that obviously influences behavior.
Think back a week, printfF takes an argument.
It takes a string and maybe multiple arguments separated
by commas, the variables
that then get inserted into that string.
So we've seen this before,
so inputs to functions are called arguments or parameters.
Well it turns out the way these work is as follows.
If I have a variable X here and variable Y here notice
that in the function that I'm calling I need
to give those inputs names.
Now I could coincidently name them X and Y
but that's not strictly the case right.
Consider after all that you guys have no idea what the person
who wrote printf called those variables.
You've been passing in quote-unquotes
and then a string inside of it
and maybe comma X comma Y comma Z but hopefully that programmer
who wrote that function twenty plus years ago doesn't have
to know or care what your variables are called.
He or she can use his or her own variable names.
So that's in fact the case here.
It is completely my prerogative to call these things A and B,
Fu and bar, anything I want,
because what happens you call a function in pass
and inputs usually, a copy is made of the inputs.
So yes I have 32 bits up here called X and 32 bits
up here called Y. They're storing a value, 1 and 2.
What happens when I call swap is that a copy of X
and a copy of Y are passed in.
And now in this scope so to speak,
in this context we now have copies of X
and Y. They're called A and B. There a different 32 bits for A,
a different 32 bits for Y. Are these four lines swapping do you
think logically, A and B?
Like is the code at least correct?
So yes right.
There's no logical fault with doing this.
I have a temporary variable.
I keep A around.
I clobber A with B's value.
Then I update B's value with A's former value,
which I tucked away and tapped so logically if you think this
through and even kind of play
around with a simulation on a piece of paper.
That's correct.
But at this point in the story the very last line
of this program, what is A's value?
So what is A's value where the arrow is there.
So 2 and what is B's value, 1.
But what are X and Y's value?
They're still the opposite.
They're still the original values
because again these are copies.
So the key take away here is
that when you actually call a function you get a copy
of the variables that are being passed in.
Now we'll see in time that there's a solution to this.
The fundamental problem here are that functions
like swap have their own scope, their own context,
their own dedicated memory.
So yes you can pass inputs to a function like swap.
And yes that function can manipulate those numbers,
do some math on them, even print out things, all side effects
but it does not have the capability
to change the original variables values, at least not yet.
So we can see this in one other context here.
So let's take a look at this little snippet.
So here's a function called increment as the name implies.
It's purpose in life is just
to implement a value called X. Well they claim
that this identical in spirit to this same problem.
Let me go ahead and open buggy 4 dot C. Scroll down.
Notice that I'm even claiming a simpler program here.
X gets 1 quote-unquote.
X is now 1 presumably incrementing dot dot dot.
I call increment and now I claim it's incremented
and then okay X is now 2 hopefully.
So let's do this.
Make buggy 4 enter.
Increment that's interesting.
Error oh okay that was the bug.
Not an error.
That's intentional.
So notice what happened.
I'm going to do it more simply with GCC so GCC
of buggy 4 dot C. In function increments error X
is undeclared.
But wait a minute, I'm pretty sure I had int X
so what does this mean?
If you haven't realized it already if you get errors
from GCC they're cryptic a bit
but they also have some juicy information;
the name of the file that's got the problem colon,
the line number that GCC at least thinks the problem is on
or began on and then hopefully an instructive error message
as in this case.
And realize too especially if you're first experience
in the science center or on your laptop with CS50 Pset is
to get not three lines of errors
but like this many lines of errors.
Realize that early on a stupid
or simple little problem just trigger a whole lot
of confusion.
So again if your first reaction to your problem set is,
"Oh my God, I wrote ten lines of code
and generated a hundred lines of errors" fix the top ones first
because there's often a cascading effect.
So don't pluck off the one you understand
because it's in the middle.
Start from the top down
and you'll likely knock off multiple bugs at once.
So let's look at line 40.
So notice I'm using, well let me use nano here for a second,
so buggy 4 dot C. Notice if I scroll down,
notice that the line number is changing so I can see,
"Ah hah" line forty of forty-two.
So it's not a very long file, X plus plus.
So hereto we see the fundamental problem of scope.
Notice in the top of this program buggy 4 I declared X.
It's X. That was good.
And then I assigned it a value of 1.
But now in increments, the increment is a function.
Increments has its own scope, its own context, its own chunk
of memory to play with and guess what, X was declared
in someone else's scope, namely me.
So you can't just start talking about X in the context
of increment because who knows
where increment is being stored in memory.
Increment knows nothing about make other than what it's told
and apparently I have told increment nothing
because I didn't pass in any arguments.
So this program fundamentally doesn't work because I'm trying
to implement a variable
that just doesn't exist in that scope.
So what's a solution perhaps to this problem?
How can I at least get this program to compile?
What could I do?
So I could declare X. So I could say something like,
"Alright well the problem is that I didn't declare X."
To declare a variable means to give it name
and to give it a type.
Well let's say this int X, alright does that fix it.
>> [Group response] No.
>> No obviously not.
That does give me X but a problem in C
in many languages is if you don't initialize a variable
who knows what's inside of it right.
People have been using this computer for you.
You on your own computer have been checking email,
sending -- checking websites.
So a lot of your RAM is in use and who knows what 0's
and 1's have littered your RAM at this point in the story.
So when you just say int X,
you're just telling GCC give me 32 bits of space.
But if you don't tell GCC what to put there the compiler,
the computer is pretty much going
to hand you what is already there.
Now that's a bit of a white lie
because some operating systems do scrub the memory
so if you would actually get back in some programs is all 0's
and is better than just complete nonsense.
But the rule of thumb for today
and for a while realizes do not ever fail
to initialize your variables.
Do not assume that they will be 0
because weird bad things will happen.
So this does work in terms of compilation.
Let me go ahead and save this.
Save-modify buffer, yes, enter.
Let me go ahead and rerun GCC.
That made GCC happy, but it didn't make the logic
of my program happy because I'm incrementing --
now I'm A dot out.
No I'm incrementing some other variable that yes its 32 bits
but it's a different 32 bits.
And again I haven't really solved the problem.
So what then is another solution to this problem,
like how could I go about fixing this problem
in buggy 4 dot c correctly, quote-unquote?
>> [Inaudible background discussion]
>> Yeah so what if the problem --
so the short answer is what about global variable.
No something we've really touched on yet,
but it's a simple idea.
If the fundamental problem is that X does not exist
in the scope of increment.
It only exists in the scope of main.
Well is there some other context, some other scope
that all functions can see.
I feel like intuitively I could get away
with some trick like this.
You know what, let me say X gets one there,
but you know what let me try declaring X outside
of every function because if you think of it now as having --
being viewable by the entire file this kind of makes sense.
Now X is in scope for everyone
because it wasn't declared inside
of any particular function.
So let's see if this works.
Let me save this.
Let me run GCC on buggy 4 dot c. Okay compile, so that seems
to have been progress.
No let me go ahead and run A dot out.
Viola, so that did in fact fix the problem.
So yes global variables are a possible solution
to this problem but now what we just handed you as a solution,
we kind of need to take back.
In general using global variables, bad.
That's sort of the montra within programming
because global variables very quickly become a mess.
It becomes unclear when you start writing programs
that are this long, but this long and spread
across multiple files.
It's not clear where they were defined.
Realize that if things get more sophisticated we'll introduce
better ways of solving this problem for scope.
But in this context for such a simple problem
of incrementing a counter, which frankly seems
to have little real world value as of it,
this is an adequate solution to this problem.
So for now, the tool in ones tool kit you have this ability
to use global variables
but clearly per the previous examples do we have the ability
to pass inputs and get outputs
so in general you should take the latter approach.
So I promised to explain what this is here.
So this was buggy -- actually let's go back to buggy 4
since we're already on it.
So this is buggy 4 and notice that it to at the very top
of the page has this, which looks like a function
but it's missing what, minimally?
There's none of those curly braces.
Every time we've declared a function
so far we have open brace and then some code right.
It's missing code.
But there seems to be this coincident,
a void increment open paren clothes paren semicolon.
That looks awfully like this thing here except I got rid
of the code.
I got rid of the curly braces and I slapped on a semicolon
and also got rid of the line break between void.
Incidentally you'll see different conventions.
This is a matter of style.
A lot of books, a lot of people will write code
like this on one line.
Personally I actually tend to put the return type on one line
and the name of the function on the other
because with sophisticated editor, text editors,
word processors you can actually search your code
and say you know what, I know I want the function called
increment but I want to find it
when it's the left most character on the screen
because then I can find where I implemented it,
not where I called it.
So there's little tricks like this you pick up over time.
But it's just a matter of style.
So why do I have this seemingly redundant mention
of increments up here?
Well my program is working, right.
We've mixed it with the global barrier.
Let me go ahead and delete this for now,
the seemingly superfluous line.
Let me go ahead and run GCC of buggy 4 dot C enter, huh?
Let me redo that.
You know maybe it's not my fault.
Maybe the computer screwed up.
Hmh, probably not the computer's fault,
so I'm doing something wrong, what is it?
Fortunately again GCC is being a little helpful but it looks
like I made three mistakes, line 23, line 38, okay line 23 gain,
so that's two mistakes.
But what's the warning saying?
Implicit declaration of function increment.
So the short explanation of this is that C is kind of stupid.
It's an old language, so it's a very powerful language
but when efficiency was more important then user friendliness
certain decisions were made.
For instance the decision was made
that you cannot call a function unless you've already declared
it earlier in the file than your actual calling it.
So what does that mean?
It means if I want this line here
to call the function called increment,
well it had better have been defined somewhere previously
in that actual file.
Alright so there's clearly a fix for this.
Let's see let me just go ahead
and cut these lines using little text editor tricks
that you can just copy, paste and nano
in different ways or just retype.
Let me just go ahead and paste it here.
Alright so the problem is if the increment was defined,
was implemented after main,
well an easy fix is just define it before main.
So let me go ahead and recompile.
Let me go ahead and rerun GCC and that seems
to have fixed it A dot out enter seems to have worked.
So does this mean the simple solution is just always put your
functions above main.
So maybe but there's some push backs here.
So one when you open the file the program ultimately runs
main first.
I as the reader prefer to see what the program does first.
I don't want see increments.
I don't want to see other random functions.
I want to see the main function first.
So just in terms of friendliness and readability it feels
like a good practice to put main first.
But then you clearly run into these problems.
And if you really think this through you'll run
into scenarios where one functions call another
and then he might call that again.
You run into a problem where this guy has to go here
and this guy has to here, like you'll run
into this endless loop where you're in this catch 22.
Everyone can't go in front of everyone else.
So there is a solution to this problem.
Not only can you define a function,
to define a function is the very precise terminology
for implementing the function without actual code.
You can also declare the function by simply stating
at the very top of the file what the return type is,
what the name of the function is,
what its arguments if any are semicolon.
So at the top of most any program you write
that has multiple functions within you just have to get
into the habit of declaring your functions
at the top of the file right.
It's kind of nuisance job.
It does not have this downside.
PHP does not have this downside.
It's sort of an artifact of the fact
that when this language was really first in use it took time
for the compiler to read the whole file from top
to bottom, left to right.
So it's not going to waste cycles and waste human time
by reading it once just to figure
out what functions you wrote and then go back
with that knowledge and start compiling.
So it's that simple reason there.
So it's minorly annoying these days but very simply solved.
Well let's look at one last buggy example.
So here we have a very similar variant.
So what I initially tried to do, this program compiled
and this program has a global variable.
Look at the top of the file,
int X. Here's my function declaration.
Here's main.
Here I initialize X to 1.
What do I do down here?
You see already why this program is not in fact going
to increment and then print the value of 2.
So I didn't declare it as an int in main but that's okay
because is there an X in scope, at that point
in the story where my pointer is.
There is as I declared a global variable called X up here.
So this variable is in scope everywhere
which means it's certainly in scope here,
which means at this point
in the story I am successfully initializing X to 1.
But notice what happens if I run this thing.
So this is buggy 5 -- GCC of buggy 5 dot C. And we go ahead
and run A dot outs here, A dot out.
Apparently the code is broken, it didn't compile
but the code is printing one both times,
what is happening do you think given these concepts of today?
Yeah.
>> [Inaudible background discussion]
>> Yes, I declared X twice.
And because I declared X twice in a more recent context,
one that's actually enclosed in these curly braces,
this is the declaration of X in the bottom
of my file is quote-unquote shadowing
or shadowing the original declaration of X.
So this is completely fine.
You are welcome as a programmer to use the same variable name
in multiple context but if you pick the same name,
that's all in context, still in scope from elsewhere.
You're going to shadow it and end up incrementing X,
yes but what is the value of X at this line the file, 11.
But it's this copy of X, 32 bits that was declared inside
of increments, not the 32 bits that was declared
at the very top of this file by way of a global variable.
So again another subtlety but this is actually a good thing
because it means that C is very -- it keeps things very tight.
If you declare a variable in a function, that's the one
that you actually have access to.
But there's actually an interesting explanation
for all of this.
And this is just a teaser because we'll start
to peel back these layers in future weeks
as to what's really going on.
But for today's purposes, long story short, your computer --
nice.fas.harbor.edu it has a bunch of ram,
probably like a gig of ram to gigs,
four gigs whatever it is these days, and if you think
of your RAM, I mean physically they're these little
silicone boards.
They're these little chips so if you think of them literally
as a rectangle and inside of that rectangle are a whole bunch
of bytes, billions of bytes, you have gigabytes of RAM.
Well, what happens
when a program runs its main function first take some
of the bytes from the very bottom of your bank
of RAM, so visualized here.
So main's parameters, any inputs to main
that we'll start using today,
end up at the bottom of your RAM.
Again if you think of your RAM, you're memory
as just some big rectangle,
so when main is actually called main can have equal variables,
variables like X. Variables like those we've seen in examples,
those yet put next into your RAM.
So, from the bottom on up meanwhile if main happens
to call a function called Fu, well if Fu takes some arguments,
if Fu takes some parameters like A
and B those parameters are stored next
in your computer's ram, so above conceptually main's memory.
Meanwhile if FU itself has some local variables,
TMP that 32 bit integer, those meanwhile get put next
into your computer's memory.
So the point of this story is that when we talk about scope
or we talk about context, what we're really talking
about are conceptually these different chunks of ram
that are being allocated from your program's start to finish
as it's actually running.
Fu has it's own layer there, it's own frame
as we'll start calling it.
That's distinct from main.
That means that main does not have access to Fu's chunk
of memory because just look at it, it's in a different place
in the computer's memory.
And things called global memory are actually stored somewhere
else altogether.
This is a more complete picture of the story we're beginning
to tell and will continue to tell over time.
Our global variables are actually stored way at the top
of your computer's memory along
with what's called the text segment.
So all those 0's and 1's that you see in C outputs,
when you run a program they've got to be loaded
into RAM off of your hard drive.
They too end up at the top of the rectangle
that is your chunk of memory.
Any questions?
Okay that was a lot.
Let's take our five minute break a bit early today.
[Sound effects] Alright so we are back.
Let's solve this problem in one way to just to equip you
for one possible approach.
It was actually proposed already here in the crowd,
was to use a return value.
So again the problem was that we're running into problems
of scope that somehow relates to memory management,
which is a topic we'll revisit.
Well one approach to this problem of scope would be yes,
don't just have a local variable whose value gets incremented
and then do nothing with the result.
Return the result of your hard work,
return the result of those mathematics.
But for this to work in the context
of incrementation we're going to have to make a change.
If I want to increment X maybe I should actually provide X
as an input to the function so that
that function has access to it.
And you know what don't just let that function increment X
or A if that's what the name is that it wants to give it,
go ahead and actually have
that function turn the result of its mathematics.
But then the burden is back on me,
main to actually keep it around.
So a relatively simple logical fix to that particular problem,
but let's see what else, how else this can expressed.
So this now is slightly more compelling right.
We already have a way
of incrementing values, something plus plus.
So that's not that interesting
but you already have been inclined some of you to turn
to the math library for rounding,
so there's certainly little bite-sized problems
that would be really nice to factor out
and put inside their own method --
and put inside their own function.
Maybe another such example similar
to round is cube function.
If you want to take a number and raise it to the power
of 3 you know yes you could X times X times X all
over the place, but it feels a little cleaner, or should start
to feel a little cleaner to actually outsource
that to a dedicated function
like a function called Q. Define it
as taking one argument called X. The name I give this argument
does not matter and because this is
such a short function I'm really not going
to give it an interesting name, it's really not justified,
so return A times A times A.
So it's a slightly more useful function here.
It does in fact solve the problem because now at the top,
I'll pass in X as an argument.
It does the math and returns the result and then I keep X
around as a return value therefrom.
Alright so enough on scope for a moment; let's actually segway
to a topic that ultimately will be related.
Because it boils down to manipulation of memory,
but suppose I want to do something like this.
If I want to write a program called grades dot C
and this thing has to somehow manipulate grades for a course.
I'm going to do something like into main, into RXC, Charstar,
argv and now if I want to right a program
that manages all the grades I get in a semester.
Well I could do something like this
and for simplicity we'll say grades are numbered
from 0 to 100.
Alright, so my grade for course 1 is going
to be an int, course 1.
My grade for course 2 is going to be int.
Int course 3, int course 4.
Okay so now I need to put values in these
so I'm writing a program so that I sort of geek
in my dorm room can do things later like course 1 --
I can do something like this.
Hello me, what did you get in course 1,
question mark closed parentheses.
And now I'm going to do something like course 1 gets,
what would you propose?
Yeah so gets int for instance from the CS50 library
and immediately begs the question well how do I make
that happen.
Well I need standard IO for printf.
I need the CS50 library for get int and then okay I got
that one course, now let me do a copy paste.
So I'm just going to past this three times.
Incidentally these little keyboard tricks I'm doing,
if you again go to the course website resources,
there's little instruction sheets for nano for VIM
and also Emax which is another one.
So I know how to change things around.
I'm just going to change this to a 4 a 3 okay, so this will work.
Okay so this program works.
So arguably it's pretty clean.
It's pretty simple.
It's hard to find a huge amount of fault with this,
but I only take four courses this semester.
Next semester I'm going to another four,
and after that another four and another four,
32 or more maybe in the end.
Okay I can get a little creative here, 1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11 lines of code.
Okay so I'm going to get 12 so I get the white space.
Okay so here's fall.
There's spring.
Sophomore year, sophomore spring, junior fall,
junior spring, senior fall, senior spring, good.
Now my program's coming along.
[Background sound effects]
At this point this should be rubbing you the wrong way,
just like some of your larger scratch strips, probably started
to get out of hand after awhile, especially if you're copying
or duplicating strips or nesting things a lot.
So even if one has not taken a course in computer science,
hopefully the act of programming is not as tedious or naive
as just copying and pasting like I've been doing
in Microsoft word for years.
So there's clearly an opportunity
for a construct here called a loop, right.
A 4 loop, a Y loop but there's kind of a problem at least
for those who don't have any programming background.
Even if I have a loop, I kind of still need 32
of these things, right.
So I need a lot of these and thus far we've not seen a way
where you can create a new variable inside a loop
but create a new copy of it.
We've declared variable I inside of a loop,
but we don't get a new copy of I for every iteration.
Usually we're incrementing the same copy of I.
So we need a solution to this problem.
I need a way of representing 32 ins and I'd really
like programming not to be as awful as having
to define 32 separate integers
and then me the human remember what the name of all
of those things are called and in fact, there are.
So one of the nice things about seeing in most languages is
that they provide us with this thing called an array.
And I use this language in week 0 when we talk about scratch,
because scratch has things called lists, which is sort
of the child friendly name that they gave
to the notion of the list or array.
These things are also called vectors in some context.
Linked lists will be something related.
They are all different in certain ways.
So what we define today I actually distinct
from scratch did and even what some other languages do.
But this is a little excerpt from a really nice tutorial
on line that we also link on the courses and resources page
about what an array is.
So we've talked about memory already today.
So it turns out and let me try to make use
of this for one second.
If again your computer's RAM is just a big rectangle from byte 0
on up to byte like 4 billion, if you got 4 gigabytes of RAM.
Well what I'd really like if this represents my RAM,
if I want to have courses -- if I want to have 32 courses I feel
like I want to say something like int courses
but now I don't want to copy-paste that.
I want to say give me not one int but 32 ints all together.
Well the notation for this is to use square brackets,
say the number of ints that you want,
closed square bracket, semicolon.
What that has done is to declare
for me a variable called courses.
That variable tough is an array,
an array of what, an array of integers.
Now an array is just a contiguous block
of memory that's been divvied up into smaller pieces all
of which structurally are the same.
Put in real English an array is just 32 ints back
to back to back in memory.
What that means is if I declare a single int called X with code
like that, that would carve out my computer's RAM, 32 bits
and call it X. But if I instead do int courses 32,
what I really get then is a whole bunch of int here,
and this obviously now a picture we're drawing here
so they won't fit all in a row necessarily.
[Background sound effects] So if I just count out 32
of these things, this is all going to be part of courses
so this whole chunk of memory will have the name courses.
Now how do I access an individual course,
well what I'm going to do is this.
I'm going to go ahead and clean
up the code I started writing a moment ago.
So I'm going to delete all that junk.
I'm going to get rid of this original approach and I'm going
to say something like int courses 32, now I've got them.
How do I know start plopping grades inside of each
of these cells, each of these elements.
Well course 1 is no more.
Courses is a variable.
How do you think I might get at the first element in an array.
Yeah so 0.
We always start counting from 0
so courses bracket 0 equals get int.
And now down here this becomes courses bracket, oops,
courses bracket 1 gets get ints.
Let me do another copy-paste just for now.
Courses brackets 2 gets get int
and you now see where this can go.
We already have the ability to implement loops
in C. We have the ability to have counter-variables in C
like I and J. So do you already see in your mind how we can kind
of rip out almost all of this code and try getting rid
of a hundred lines at once.
In fact I don't really need any of these lines either.
Now this is not yet a loop but couldn't I do something
like 4 int, I gets 0, I is less than 32, I plus plus.
Give me little curly braces here,
what did you get in course 1?
I'll fix that in a moment.
Let me close my curly braces here.
There's a couple of problems.
What's one I can fix easily?
Yeah so it's not courses brackets 0.
Stop hard-coding that.
Courses bracket I and then this too is a little weird.
I can't hard-code this.
Now obviously that's not the solution there to change the 1
to an I in that context, but what could I say,
course percent D question mark close quote comma I.
So again same building set
and again already viola, you know a new idea.
We just deployed this really quick.
We said you can have multiple variables all of the same type
but give them one name and refer to them numerically in this way.
Now we have the capability of expressing what
in the beginning was a very simple problem.
I want to waive inputting all of my grades.
Well now let's actually look at a polished version of this.
Well in array 1 dot C I have this program here
and it's a little more interesting
because I didn't want to just input my data,
I wanted to just compute my average,
which is slightly more compelling.
So let's actually see the result of this first.
So GCC array 1 dot C. Uh huh,
can fix that right -- dash L CS50 good.
A dot out enter.
What were your quiz scores?
So I got lets say 100 on the first one,
then I kind of screwed up.
So you're average -- you'll remember that comment now
if you're the student that gets a 50 on the quiz right.
So alright, so 50 is good.
So 75 is my average.
So you could do this on a calculator
but if you had 32 courses, you now it's kind of nice
to let a computer do that.
You don't want to have to do it all by hand necessarily.
So how does this work?
Well notice, I'm incrementing some variable,
so we already have the building blocks in there.
I'm doing some mathematics.
It feels like I'm maybe rounding too to the nearest int.
You would notice if we were just using casting from floats
to ints in this course instead
of actually mathematically rounding grades at terms end.
So let me go back into this.
This was array 1 dot C. Well let's see what I'm doing.
Well new feature; it turns out what I started to do
on the fly there a moment ago is kind of bad practice.
I hard-coded the number 32 and not only once but twice,
that tends to be bad practice.
So that's what's known as a magic number, magic in the sense
that where the heck did I define that value all over the place?
So another feature of C, and it's a little dark,
I apologize here on this screen is this ability
to have another thing called the preprocessor directive.
We've seen the sharp sign before.
That thing sharp include is a preprocessor directed.
There's another one that's useful.
Sharp define allows you to define a constant.
It's not a variable.
It's just the symbolic representation of something,
in this case a number.
So that henceforth in my code I can use capital QUIZZES anywhere
I want and it's going to refer back to that same value.
Now just intuitively what's an advantage
to having used a constant like this instead of typing in 32?
Yeah.
>> [Inaudible background discussion]
>> Yeah, exactly.
If I'm on -- if my class has more quizzes in the future
and I need to store more grades I just change it one place,
recompile and done.
And in fact that's a bit of an annoying process.
We'll also see ways when I run the program I could just tell my
program how many quizzes we had that semester.
We don't even have to hard-code it.
Now the fact that I'm capitalizing it this is this
matter of style, convention.
Almost any time you have a constant value,
you should capitalize it entirely so that it stands
to you the reader and other readers, teaching fellows
or other programmers that in fact, it is a constant value.
So what's going on here?
Well let's see I have a float called grades bracket quizzes.
Alright so we've not quite seen this context yet in examples.
It turns out if you want to have multiple variables all
of the same type, you don't need
to put them each on their own line.
You can just bring them together with commas.
So on that first line I'm declaring an array called
grades, I have how many elements in it, how many floats,
so two as per the constant called quizzes and then
after that I have another float altogether,
a different chunk of memory called sum.
And I also apparently have the foresight
to declare a variable called average and one called I.
And I start to use those here.
Alright print.
What were your quiz scores?
Alright for I is 0, I is less than quizzes,
I is plus plus quiz number percent, alright this is easy.
I know what this is and here's the line of code
that we already did on the fly albeit
with get int grade bracket I get flow.
So realize 0 indexing is important.
When the compiler gives you memory you get 0 1 2.
If you start counting at 1 you get 1, 2, 3,
4, 5, 6, 7 that's bad.
You wanted to end at 6 so to speak.
So what do I next with this value?
Alright so now I have some.
How do you compute a student's average?
Well you take all the grades, you sum them together
and you divide them by the total number
of quizzes right, old school stuff.
So sum is initialized as 0.
So I is 0 on up to quizzes to another 4 loop,
so this is easy alright.
I'm just adding to sum inside of this loop the ith value
of grades, which is just 2,
but again realize the dynamism of this program.
Just by changing that constant I could do this
for a whole semester for four years worth of college.
So now here's an interesting trick and I'll offer this just
as a little teaser for now.
To compute a student's average is really the result
of taking the sum, dividing by the number of quizzes
but then there's this .5 trick.
For those of you who want to think this through actually
for problem set 1, this .5 trick,
this is how you can implement the notion
of mathematical rounding.
And I'll leave that as a little thought exercise,
but if you think through what might happen to your grades
if you do and do not include this .5 and then proceed to cast
to an int, casting has the effect of truncating everything
after the decimal point.
So there's actually a very clever magic that's induced
by adding .5 before you throw that stuff away.
So the person who wrote the math round function
in the math library, odds are they did something very similar
to this.
Then finally what's the average,
well I just print out the results.
Well just to show that you don't need to show that little trick,
array 2 that you have print outs of is the exact same thing
but I decided to use the round function explicitly instead
of rolling it myself.
Okay so enough about math, because we've actually dwelled
on this for some time.
Let's actually start manipulating things
that are more genuinely useful and those are strings right,
because problem set 1 even though it's largely grounded
in numbers and arithmetic,
that's really just a design of necessity.
It's actually kind of hard to do more sophisticated things
when you've not even written one 4 loop or one Y loop in C.
So it's meant as a stepping stone.
Problem set 2 though is going to introduce you
to another real-world domain of cryptography,
the art of concealing information.
Information is often expressed in English
or some other textual language and so that makes the question,
"How do I somehow manipulate actual characters,
actual strings, actual paragraphs or entire letters,
entire letters of text?"
So here's a simple example that's going to get us there.
I turns out that what we called last time a string,
we already know that a string is synonymous
with a slightly more confusing Charstar the asterisk
so again we'll tease apart what that means
but a string is a Charstar.
For today's purposes what a string really is is an --
it's an array not a int but an array of Chars,
an array of 8-bit characters.
So that kind of makes sense right?
An array of if a string is just a contiguous sequence
of letters, you know f o o or h e l l o you know it kind
of makes sense that you know what the perfect data structure
for strings if we're not talking about ints anymore
but are instead alphabetical letters why don't we call this
something like the string S
so then I can put the letter H there e-l-l-o and so forth.
It feels like it makes perfect sense to actually store a string
in an array because I actually get this built-in feature
of storing things back to back to back and not all
over the place in memory.
So this program here is called string 1 dot C. Notice
that I'm using a new library up here, string dot H
for reasons we'll see in a moment.
Now what am I doing, well I've removed the comments
for today's training wheel removal purposes but this line
of code there simply gets a string from the user,
not a flow per se but a generic string
and in fact its going to store it.
Get string is going to allocate a bunch of RAM like this
and whatever you type it's going to put the first letter here,
the next letter there, the next letter there and so forth
and then it's going to hand you back
that entire chunk of memory.
So I do need to do one sanity check
and this too is a teaser of sorts today.
It turns out that if the user is malicious or foolish
or there's just some problem
that you can't anticipate we need
to sometimes have return values that are not legit values
like the actual string, a return value that's not the actual
return value number you were expecting
but some kind of sentinel value.
So a special value that you the programmer can check for
and if you get back that sentinel value instead
of a legit value you know something went wrong
and error checking is one of the topics for Monday.
So it turns out, and you would only know this
from reading the documentation or being told it in class,
get string maybe can return a special value called NULL
in all capital letters.
So we'll use this throughout the semester.
So today we're just scratching the surface.
So this is just a special value NULL that if you check for it,
when you get it back it means that the user did something
like never typed anything or just hit enter immediately
or just tried to generally mess with you
or did something you weren't expecting.
So the very first thing I do in this program is I check.
If S does not equal NULL that's a good thing, let's proceed
to do something with it.
I now have 4-loop.
4 I gets 0.
I is less than, oh this is interesting.
Take a guess what this briefly named functions does.
>> [Inaudible background discussion]
>> String lengths.
Stir lengths, so this is common feature of C.
So why say string length when you can say stirleng.
Well how does that -- that's a function.
It exists in the string library whose hetero file is called
string dot H. Now even just a little tangent,
how would you the human implement string length.
Well, I'd probably start looking at my chunk of memory
and just start counting how many legitimate values do I
actually see.
Now it turns out there's going to be a special value
that will store at the end of a string.
Backslash 0 is literally the value
of [Sound effects] eight 0 bits in a row
so it's a special value not quote-unquote 0
which is an ASCII character but rather a special sentinel value
so stirleng as we will see eventually
in more detail actually iterates over an array
like that to get its length.
So what does this do, well notice is a Char
because I declared it up here.
S is a string because I got here from the user
and S bracket I gives me the ith character in the string
and then plops it in the variable called C.
So what's the end result, well let me go ahead and on GCC
on string 1 dot C, so undefined reference again dot LCS dash 50
okay so A dot out enter okay it's not doing anything why?
Right because I didn't say printf --
I really cut some corners here
so hello there exclamation point enter.
Okay so h e l l o comma space t h e r e exclamation point all
in a separate line, why did that happen?
Well this was string one dot C,
that's precisely what should have happened
because in this 4 loop I printed percent C
which is the new format code for just a character backslash N
and so I got everything on a separate line.
So in fact had I done something maybe a little less weird
and just complied this and rerun this,
now I have a sentence here enter, now I get it back.
Now grant it I forgot one new line altogether
but all this program demonstrates is that a string
that you can fetch from the user by way
of get string hands you effectively a chunk of memory
that you can iterate over with this bracket notation just
like you could a whole bunch of grades from your course work.
Well string 2 has a slight variant on this
so in string 2 dot C I do something more intelligent
which is good design so this speaks to this access of design.
Notice this what have I done differently here
if you can think back or on your printouts see the difference
between that line and the previous version.
[ Silence ]
>> A little louder, anyone?
>> [Inaudible background discussion]
>> Yeah, so I have two initializations.
So notice at the left I have I get 0 comma N get stirleng S.
Why did I move or add this declaration of N
and assign it the return value of stirleng
in the initialization part of the loop instead of,
I'll scroll back if you haven't the print out,
instead of putting it right here in the condition
which was really nice and clean and sensible.
>> [Inaudible background discussion]
>> Yeah, because this approach elegant though it is, it's nice
and compact, right looks like a really good piece of code,
but remember the condition is checked every iteration
which means the code inside this condition is executed every
iteration which means you're calling the function again
and again and again for as many times as this thing iterates.
No what does that mean?
You're checking the length of this string by going 1,2, 3, 4,
5, return 5 again and again.
1, 2, 3, 4, 5 return 5.
1, 2, 3, I mean this should feel stupid
because this changing length in any way will know.
So they're to is an opportunity for optimization
for a little bit more clever design and thus
in string 2 do I actually call that function once?
And I wanted to be a little elegant
so I put it in the 4 loop.
I could have just done this and just got stirleng of S here
and I didn't need to use this common notation
so again there's often multiple ways
to implement the particular goal but realize
that was a fundamental improvement
because I'm not calling the function whose value is never
going to change more times than is strictly necessary.
So let's use this same feature
to do something that's more useful.
So it's a little weird looking code
but it uses all the same building blocks
that we been using for days.
So this program is set up as follows: Get a string
from the user that's old hat now.
Now what? Iterate over the string from I up to the length,
okay so we just did that.
This code is the same.
So the only new magic here are these four lines.
Now what is the saying in English?
If the ith character in S is greater than or equal
to lower case A and the ith character in S is less than
or equal to the value of the lower case Z,
what do you think the next line of code is doing?
It's just capitalizing it.
Well mathematically and I won't dwell so much
on the arithmetic here because it's the same stuff
as a week ago but notice do you capitalize something,
well let's just do the math quickly for one example.
Little A is 97.
Right I've promised this would be useful so little A is 97.
Big A is 65 so not matter what I'm doing I'm going
to be subtracting because I gotta take big numbers
and make them smaller if I'm going to go to like 97
and above to 65 and above.
So I have the value of S bracket I here then I do subtraction.
Well what do I subtract?
Well technically I just need to subtract 65 but if I put 65
in here, kind of a bad thing.
It's a magic number like Y 65.
Well why don't we just go ahead and do this.
The difference that we want to subtract off is always going
to be this, A minus A, little A minus big A.
So let's just subtract things off a little more dynamically.
And again the astute can say why are you computing A minus A
again and again and again.
It turns out compilers can be smart
and if they realize you're doing some arithmetic that's never
going to change, sometimes the compiler can optimize
that for you, but for today we offer it just for clarity.
So if we go ahead and compile this, capitalize dot C,
damn again dash L dash CS50
but again these errors should no longer be intimidating.
Let's go ahead and run A dot out and capitalize.
Hello there exclamation point and there I preserved my space.
It preserved my exclamation point
so I actually did get this right.
So let's lay the stage now for where we're going with this.
Two quick comments- one by far if you're feeling
like you're not among those with books in hand or you just
like learning stuff on line, these are the two places
to start because it covers the stuff we've been looking at.
But let's now pull back a layer
that I've been waving my hand at for a week.
You have for any program you've been writing used int, main,
and then int argC comma Charstar argv.
Well Charstar is strength.
So that's the synonym for now.
So it appears that it may all of this time has been allowed
to take in two inputs ints and also a string.
Alright so what does that actually mean?
Well it means that just like I can run GCC
and then Fu dot C I can apparently pass input to --
you gotta say something sometimes.
I can apparently pass to programs like GCC
by just writing those arguments on the command line.
So it's not quite an argument in the sense of a function
but this is a very different context.
This is my so-called blinking prompt.
I can clearly -- been doing things like dash 0 Fu and then
down here I've been saying things like dash L CS50
so there's many different labels the world has slapped
on these kinds of words, switches, lags,
command line, arguments.
We'll typically call them command line arguments
but you've used these before any time you've typed commands.
Nano takes the command line argument.
It gives the command line argument that nano is supposed
to take, the name of the file.
So we have this ability clearly in Linux,
MAC OS and other context to.
So how do we get at that information?
Well in argv 1 see a very simple example.
Notice here that in this function I first,
in this main function I print a new line then I do this.
For I is 0 on up to argC.
So take a guess, what does argC maybe represent?
Argument count, argC it's a convention.
I could have called it X and Y but the world's kind
of standardized on these two nicknames.
ArgC I argument count.
So if I want to iterate over all of the words that the user typed
at the command prompt, I'm going to iterate from 0 up to argC.
What is inside of argv?
Argv apparently all the time has been an array
because of the bracketed notation.
What is inside that array are not just characters.
It turns out that inside an array you also put other arrays.
You can put strings themselves.
So you're really taking this -- it's like a 2-dimensional array.
So argv in this case is an array of not Chars
but of Charstars aka strings.
So what does that mean?
Well let's compile this and try to infer what's going on.
GCC argv 1 dot C okay good stuff happens.
Okay so A dot out enter okay, not such good stuff.
Alright so how about Fu bar bas.
So apparently my program has the capacity
to spit out anything I type.
Let me just get a little familiar like A dot
out Fu dot C. So let's just think of this as burning nano.
So it looks like also inside of argv is not just the words
after the program you ran but what else?
The program itself which is useful, so in short argv all
of the words the user has typed
at the command prompt including the program
or the program name itself from 0 on up.
So all this program does notice is this.
It iterates from 0 to argC okay pretty simple.
It's just integer incrementation
and then what am I printing well percent S is a new format code
to here today so this means put a string here not a decimal,
not a float put a string here.
Give me the ith word inside
of argv the ith argument, inside of argv.
We can get more creative still if I open
up argv 2 dot C this looks a little fancier
and we won't dwell so much on the syntax
because again we have seen things like this.
Here's a 4 loop iterating over I.
Here's another 4 loop iterating over J
but notice what this program does
if I just reveal the magic here.
Argv 2 dot C so RA dot out, oh interesting.
So I'm just getting a littler aesthetically interesting Fu
bar bas.
So here I'm iterating not only over each
of the words the user typed but also over each
of the characters within.
So I hinted a moment ago and we'll see this in more detail
over time but argv is just a 2-dimensional array.
An array of strings but strings are arrays of Chars
so that's an array of an array of Chars so how am I doing this?
Well I iterate over the arguments from 0 to argC
and then oh here's something familiar.
Again I've been just taking babysteps over the code today.
Here's J is 0, N is initialized
to the string length of ith argument okay.
Iterate from J to that length, oh this is interesting
if argv is in fact a 2-dimensional array,
an array of strings aka an array --
an array of Chars it turns out you can put brackets back
to back if you know it's this sort of 2-dimensional array.
So argv bracket I right here, this gives me the ith word.
What does argv bracket I bracket J give me,
the J character in the ith word.
So it's actually fairly straightforward.
Again some new syntax but some fairly basic building blocks.
So here's the canonical list for now of functions you can use
that will be used not so much for problem set 1.
For the most part you've had already the basic building
blocks for problem set 1 as of last weekend and this Monday.
But for now before we start looking
at the code here's a quick reminder
of what functions are in CS50's library.
The last one of which is this latest one get string returns
a string.
But remember a string can be manipulated
with this bracket notation as we've been doing.
Now for the astute 2 at the top I disclaim memory leaks.
So CS50's library is buggy.
It intentionally -- we allow ourselves to indulge
in what's called the memory leak whereby we are actually
allocating a whole bunch of RAM for you
and we never ask you to give it back.
So realize that we'll have a lot of interesting opportunity
to discuss that but where are we going with this
and why introduce this at all?
Well clearly we got to arrays today and that's kind
of a juicy new feature but we can do this
in a more interesting context such as cryptography.
So we introduced Monday with Ralphie.
We had that expression be sure to drink your Ovaltine,
which I is repeated here using ROT 13, rotate 13,
just rotate all the letters 13 places
and that's the nonsense you get out
but it was a specific instance
of something we called a Caesar cipher,
a cipher being an algorithm or program
that scrambles information.
So this is very similar in spirit
to some very real world things.
This is the German enigma machine.
You can read up on this on Wikipedia.
It's covered in many movies and books certain over the years.
We've seen real-world incarnations of cryptography.
This is essentially a really fancy typewriter
with really special really secret gears and levers
that when you type out a message what gets spit out is something
that looks more in spirit like this.
But the Germans were smarter
than just rotating all the letters
in the German alphabet by 13 places.
That's why the Americans and allies were so intent
on stealing boxes like this so that they could figure
out what those messages were.
But what we'll look at this coming week is this notion
of cryptography and this sort of a fancy depiction
that I'll just wave my hand at just so we can look
at this guy here, Caesar supposedly.
Naive though this algorithm may seem all these years later,
use simple cryptography to send messages to
and from his generals in the field.
And they did so by way of writing them down on a piece
of paper and then rotating all of the letters as the story goes
by some number of places, so that A became D and B became E
and so forth so he and his generals had a secret
that they whispered together before they went off
out to battle and such and he said 13 or something like that.
Right now it's a fairly simple cipher and even I have sort
of trouble imaging that there weren't still even back then
before computers, really smart people who maybe by trial
and error might have figured
out how these messages were encrypted.
But for us it offers a really interesting opportunity,
because just as I've written --
just as this figure presents these letters from left to right
in a grid, it suggests that just by using a little bit
of arithmetic can we rotate letters.
An in the event that we go too far off, if we try adding 13
to the letter Z we don't want to fall off into no-man's land.
We want to wrap around back to the letter A
and what simple building block have we seen whereby we can
wrap around.
>> [Inaudible background discussion]
>> Yeah so the modulo operator.
So that's where we're going.
Now all this time throughout today's lecture has Homer
Simpson been busy at work with his little internet company.
I thought we would conclude with this 20 second clip
of how his internet business turned out.
>> Oh they have the internet on computers now.
>> Bill Gates is here.
>> Bill Gates the millionaire computer nerd Bill Gates?
Oh my God.
Get on a site Marge.
I don't want this to look like a 2-bit operation.
[Sound effects]
>> Mr. Simpson.
>> You don't look rich.
>> Don't let the haircut fool you.
I'm exceedingly wealthy.
>> Make small chat Marge.
>> Your internet ad was brought to my attention
but I can't figure out what
if anything Compu Global Hypermagenet does.
So rather than risk competing with you,
I've decided simply to buy you out.
>> I put my heart and soul into this business
and now it's finally paying off.
We're rich.
We're richer than astronauts.
>> Homer be quiet.
You'll cramp the deal.
>> I reluctantly accept your proposal.
>> Well everyone always does.
>> Buy him out boys.
[Sound effects]
>> Hey what the hell's going on?
>> Well I could get rich by writing a lot of checks.
[Laughter]
>> Have a good weekend we'll see you Monday.