So. CS225. This is probably the most important (and FUN! YAY!) class of your undergrad career. Data structures are really, really, really neat toys, and the ability to use them effectively is what separates poor to average programmers from the best. If you pay attention, go to class (and section) every day and do the MP's, it will make you into a great programmer. For those of you who were bored in CS125, this class will teach you something new.
On the other hand, if you do a really half-assed job, don't care, and try to just skate by, you will most likely fail. This class is worth 4 hours for a reason. It will require a fair amount of work. But so long as you stay current and do the MP's on time, you should be just fine.
This means I'm your friend! Yay! I will do my best to keep things interesting in here. The notes are on the web, but it's to your advantage to show up. You'll see more examples, and get to ask questions. Plus I'll show you cool tricks that Jason skips over if there's time.
The course website is http://www-courses.cs.uiuc.edu/~cs225.
Familiarize yourself with its many nooks and crannies, fill them with jelly,
and enjoy.
This class will revolve around UNIX (Specifically, Solaris).
UNIX kicks ass. If you don't already know how to use it, learn..
This semester we will be using the EWS Solaris Labs. If you compile
code elsewhere, it is your responsibility to make sure it compiles on those
systems. Information specific to EWS can be found in the
EWS Lab Manual.
The Official Editor in this class is still xemacs, and it works the same as
in the Windows labs. Just run xemacs from the prompt. If you are interested in
a more visually appealing editor and setup, consult my UNIX Beautifier Tutorial.
You are also responsible for reading the two class newsgroups,
class.cs225 and class.cs225.announce in your new favorite newsreader (kidding,
you can read the newsgroup in outlook express if you want). Jason will make
announcements about MP's and exams to the .announce group, and general
discussion about MP's will take place in the class newsgroups. Please check
there first before going to office hours to save both of us some time.
Some quick notes about Usenet Etiquette:
In short: "Think twice, post once."
The way I usually do section is that I give a quick review of what Jason
presented in Lecture, and then move to the workstation to work on some actual
code.
Feel free to interrupt me at any time in general. This is not
lecture. Also often times many other students share your question or concern,
but just don't have the guts to ask. I realize that no matter what I say you
guys are still going to be uncomfortable jumping in for a couple weeks. But at
least try to timidly raise your hands or something. No question should go
unanswered.
Also, occasionally when there's extra time or the topic warrants it, I
delve into slightly more advanced topics just to solidify understanding. You
won't be responsible for that material (I'll let you know which is which), but
it's almost always good to know.
So in this class, we will be using C++. It's a whole lot like Java, except
better. Jason's already gone through the spiel of why C++ in lecture. My
reason for liking the language is the surge of power you get from your code
running directly on the hardware, instead of in some wussy virtual machine.
Superficial differences between C++ and Java
Example: Cup.java transformed into and Cup.C with Cup.h
I/O in C++ is a bit cleaner than in Java. It is done by three predefined
objects called the Standard Input Output streams. They are cin,
cout and cerr.
Examples using cin, cout, and cerr
In order to handle include files, C++ has an extra stage to its
compilation process. Before the compiler
converts C++ code into asm, a program called the preprocessor runs through
your code and interprets the following directives, among others:
Example of the preprocessor (CC -E) in action
Pointers kick ass. Jason said that Java doesn't have pointers in lecture.
This is not entirely true. Every object variable in Java was in fact a
pointer. A limited, wussy pointer, but a pointer nonetheless. (The converse, as
we shall see, does NOT hold. A regular object variable in C++ is allocated on the
stack, without the need to call new).
Pointers allow you direct access to the computers memory. A pointer
variable holds NOTHING other than a numerical (in this case, 32 bit) value.
This number is an address in memory. Real, honest to god memory.
In fact, it helps if you actually think of pointers as integers with no type,
only an address. If you forget to assign an pointer to an address, bad things
happen. You can write to random areas of memory, and make things go crazy in a
hurry. CS just got a little more interesting.
Now it's time for some handwaving on the whiteboard to refresh your
memories of the how a compiler works with automatically allocated variables in
Java, and show the analog in C++. Recall that every variable has three things:
an address in memory, a value, and a name, and that local variables are placed
on the stack
Operators dealing with pointers:
Examples dealing with these operators.
So in Java, when you wanted memory for an array or an object, you requested
it with new. This is still the case in C++. What is NOT the case is
that this memory is automatically cleaned up for you during the program's
lifetime. For every piece of memory you allocate with new in C++, you
must keep track of it and eventually return it to the system with
delete.
Common pitfalls:
Example of new and delete.
Back in my day, they forced us all to use a system called PSP, or the
Personal Software Process. I loved it. I organized my whole life around PSP
charts. I went insane. It was great.
The PSP process divides development into 5 stages: Planning, Design, Code,
Compile, and Test. You record how much time you spend in each stage, and how
many bugs you introduce into each stage, and what these bugs were. (Bug
classes included Documentation, Syntax, Build System, Assignment, Interface,
Checking, Data, Function, System, Environment). After doing this analysis for
a while, you got really good at predicting how long something would take you,
and also which bugs you were most prone to make where.
They forced us to do it, and everyone hated it. Like I said, I followed it
religiously though, and it worked. By the end of the semester, I was writing
MP's that ran and passed all test cases on the first try. By the end of the
following summer, I was writing large software projects for the NCSA that did
the same. If you want to be a great programmer, I highly recommend this
process.
At the very least, do what Jason suggests. Before rushing off to compile
something, check it over. Keep a log of what mistakes you make, and turn that
log into a simple checklist. It takes something like 10X less time to find
bugs in code review than it does through debugging.
Sample Checklist:
More Example code can be found right here
Administrivia
Describing how to solve a problem is usually OK, as are code snippets.
But don't dump an entire file or function to the newsgroup.
Embed your responses to people's questions in the quoted
text of their message, and TRIM irrelevant sections of the message.
If you post a question and then figure it out, do NOT post a replay
saying "Nevermind, I got it." Other people may have that question too. Answer
yourself on the group. It's only fair.
Don't post simply to say "Me too!" or other one line expressions of
idiocy.
If you want to test your newsreader, post to alt.test or cmi.test.
The newsgroup is for discussion of CS225 related material only. If a
conversation develops over which brand of toilet paper (or which newsreader) is best,
resist the urge to participate.
How I like to Run Things
C++ vs Java
If you forget the semicolon at the end of a class, you will get all kinds
of odd, undecypherable errors.
Instead of having a public or private label for each function and
variable, you specify it once with a label ending in a colon, and access
remains the same until you say otherwise.
In C++, you can (and should) separate your class definition from the
implementation of the functions. Definition goes in a header (.h) file, and
implementation goes in the C++ (.C) file.
In C++, main is a function by itself, without a class. It usually goes in
it's own .C file still, but it doesn't have to.
CC is the C++ compiler, and like I said, programs run natively in the OS.
I/O
The Preprocessor
This directive allows you to enact a direct substitution for an
identifier in your program. It also lets you define pseudo-functions called
macros (but we won't worry about that right now). It is convention to write
the identifier for defined constants in all uppercase, and sometimes with two
underscores on each side. #define by itself is useful for elimination "magic numbers"
such as array sizes and such, to make the code more readable and to keep it
bug-free. It can also be used in combination with #ifdef to prevent multiple inclusions
of the same file, as we shall see.
#include stuffs the contents of its argument into the current file.
These three all check if IDENTIFIER is defined. If it is, the code inside
the body (up until #endif, or #else) gets passed to the compiler. If not, the code is tossed aside. This
is useful to prevent include files from being included twice.
These tie in with the #ifdef and #if directives, and work just like their
equivalent keywords.
ditto.
Pointers
"Every variable has an address". You've heard this hopefully over 2 dozen
times by now. Well, this is how you get that address. It is called the
"Address of" operator, and yields the address of a variable in memory.
This is the opposite operation. It is called the indirection operator.
What it does it accesses the stuff at the memory address stored in a pointer.
So *&var is just var.
These are used in pointer arithmetic. Pointer arithmetic is a special
kind of math that takes into account the size of the objects being pointed
to. More on this later.
new and delete
All this may seem simple, but things can get tricky later on, when
there aren't pointer variables for each memory location in more complicated
data structures. You have to keep the layout of things in your head (or better
yet, on paper).
delete does NOT change the value of a pointer. You
must do that yourself with NULL. If you use already freed memory, your
program will eventually crash at an unexpected location (usually an unrelated
call to new or delete).
Some C++ implementations will catch this, others will corrupt themselves
and eventually crash.
Sometimes you forget to call new. Calling delete on an unallocated
pointer causes the C++ library to write to random areas of memory, leading to
an eventual crash.
Example of new and delete with arrays
Example of pointer arithmetic
Example of new and delete gone horribly, horribly wrong.
Code Review
More Example Code