CS50 - Section 10
- Section leader- Dan Ellard.
My office phone number is 496-6246 (8am-5pm), and my home phone
number is 643-9644 (6pm-10pm). Please do not call me after 10pm,
or before 10am on weekends.
By far the best way to reach me (or anyone on the course
staff) is via email. My email address
is ellard@deas. The email address of the course
account is lib50@fas.
email is also the easiest way for me to get
information to you. Please check your mail at once a day or so.
- Section meetings- Friday 9:00am, Science Center 209.
- Office hours- Sunday 2:00-4:00 (in the Science Center terminal
room), or by arrangement. (I'm available most afternoons, but
it's a good idea to call or email me ahead of time so I'll
know to be in my office when you drop by.)
Final Project Proposals
Don't forget- your final project proposal is due next Wednesday,
11/27/96. Late days cannot be used on the final project proposal,
and late project proposals will be penalized harshly. Extensions
for the project proposal will be granted in cases of personal
emergencies, but that's the only acceptable excuse (after all, we gave
out the assignment weeks ago!).
If you don't have a clue what you want to do for your final project,
please try to get a clue soon. You should take this proposal very
seriously- as seriously as any assignment. It will have a profound
effect on how happy you are during the dark days of reading period
when you need to actually grind out the code for this thing- and it
could have a profound effect on your grade on the final project (and
hence your final grade in the course).
Don't procrastinate on this.
Command Line Arguments
Command line arguments are important to ``real'' programs. At last,
we can begin to write programs that have the UNIX look and feel- they
get their arguments from the commandline (instead of incessantly
prompting the user) and therefore can be easily hooked together with
other programs or scripts.
Note that there is somewhat exhaustive coverage of this subject in the
lecture notes and the textbook (especially K+R) so I'll just touch
upon the high points in this handout.
The True Type of main
At last, we've revealed to you the real type of the main
function, which you've been using all semester but which we never
fully explained. Here it is, in all its glory:
int main (int argc, char **argv);
(Note that on some older systems, main has a slightly
different type, which you might encounter if you look at older
code or go sightseeing in odd places. I won't say any more about
this now, to save the surprise for later.)
- main returns an int.
It really does, and in your code you should declare and define
it as such. No more "void main()", please!
- main takes two arguments.
- int argc
- The first is an int that is traditionally
called argc. argc specifies
the number of elements in the argv
array, described below.
(In your own programs, you can call it anything you
like, but if you call it anything but argc,
nobody will know what you're talking about.)
- char **argv
- The second argument is an array of strings (or char
**) that is traditionally called
argv. "argv" is short for "argument
vector" and is simply an array of strings that
represent the number of arguments (commandline options
or flags) passed to the program. The first entry
(argv ) is simply the name of the
program itself, as it appeared on the commandline.
(Once again, in your own programs you can call it
anything you like, but if you call it anything other
than argv everyone will be confused.)
- Where do the contents of argv come from?
These are created and filled in by the program that
started your program (typically the shell, in
response to some command typed by a user). You
don't have to worry about how this text gets to
your program from the commandline that the user typed (unless
you are interested in actually writing a shell, in
which case you are responsible for doing this!).
Your program can just assume that however it
gets called, these arguments will be passed in
Warning: gross generalizations ahead. When your
program is run, it doesn't really start at main-
that's just where it begins executing code that you wrote.
Before it calls your main, it actually is running
another function whose job it is to rummage through the
commandline and figure out what arguments to pass to
main. End of gross generalizations.
The getopt Function
Note the use of the getopt function (which is shown in the
lecture notes). getopt makes handling command line
arguments relatively easy, and may be useful for your final projects.
It will certainly be useful for assignment 8!
File I/O: stdio
Like command line arguments, file I/O is very important to ``real''
programs; even though we haven't done all that much with file I/O in
this course, if you're planning on doing more programming, you're
going to see this stuff again.
This subject is covered somewhat in the Roberts book, but much
more throughly in K+R and the online manual pages.
The abstraction of files provided by the standard I/O
library (stdio) is implemented in a structure called
FILE. Almost all of the stdio functions take a pointer
to one of these structures as one of their parameters
(either explicitly or implicitly). The main exception
is fopen, which is used to get one of these
pointers in the first place.
UNIX gives your programs three default FILE pointers,
just for showing up:
Here is list of some of the more popular functions:
- stdin - standard input. For interactive
programs, if you read standard input, you'll get
what the user types on the keyboard.
- stdout - standard output. For interactive
programs, if you write to standard output, then
whatever you write will appear on the users screen.
- stderr - standard error. Like stdout, but
can be treated seperately when appropriate. For example, if you want
to capture all of the error messages that your program
emits, you can redirect stderr to a file and still have
all the ordinary (stdout) message show up on your screen-
or vice versa.
- fopen and fclose
- Open or close a file.
- fgetc and fputc
- Read or write a single character.
An important note about fgetc (that pops
up in a few other places): although fgetc reads
a char, it returns an int. This
is esential for the following reason- if fgetc
just returned a char, then what value could it return
to indicate to you that something had gone wrong?
Every possible return value (any member of
the set of possible chars) would correspond to something
that might actually be in a file. Therefore, in order
to make it possible to also return error codes, fgetc
returns an int. If the value is 0..255 (for 8-bit chars)
then you know that fgetc succeeded, but if
it is outside this range, then something else happened.
For most implementations of fgetc that I am aware
of, there's only one error code, which is EOF (which is
returned when you attempt to read past the end of the file, or
some other error occurs), other functions use a similar
philosophy and return different things.
Note that there are several related functions and macros:
getchar, getc, putchar, and putc. These can be useful,
and you'll see them a lot (particularly in older code)
but fgetc and fputc are all you need.
- fgets and fputs
- Read or write a line of text. Assumes that the file is
text. (Note- fputs does not add a newline, so if
you want there to be one, you must add it yourself)
There is another function named gets which is
similar to fgets, but notoriously dangerous to use.
(It doesn't check its arguments, nor does it check that what
the user types is valid, and so can permit the user to
scribble all over memory.) I suggest that you never use it.
- fread and fwrite
- Read or write "blocks" of data. Useful for reading or writing an
entire array or structure, or any arbitrary (but specific)
amount of data.
- fscanf and fprintf
- Read or write data according to given format. fprintf
is almost exactly like printf, but prints to a file
instead of the screen.
fscanf is sort of like fprintf, only
backwards. It can be tricky to use; one simplification to
help do formatted reading is to use fgets to read a
line of text and then use sscanf (a relative of
fscanf that scans strings instead of files) instead
of using fscanf.
- fseek and ftell
- Move around in a file, or find out where you are in a file.
The rewind function is a special case of the
fseek that can be used to rewind to the beginning
of a file. (Note that some files can't be rewound- you'd need
a time machine to rewind stdin, for example!) This can be
handy on assignment 8.
- Flush changes (make them happen immediately).
- feof and ferror
- Determine if the End Of File has been reached, or some
For this assignment, you have to complete two programs:
labyrinth and 800.
labyrinth is a maze-solving program. To finish this
program, you only need to write two functions (although you may or may
not find it useful to write additional functions that you use as
helper functions for the functions that you must write):
One amusement that you can add to your program is an "animation" of
the process of your program attempting to solve each maze.
Descriptions for how to do this are given in labyrinth.txt.
It makes your program a lot of fun to watch. Remember to use the
sleep_milli function to pause after each step, however, or
else the whole thing will flash by too quickly to enjoy.
- In labyrinth.c you must complete the
parse_args function in order to allow your
labyrinth to parse commandline arguments- and since
this program has several important options, it's pretty
helpless until you write this function.
See labyrinth.c for more info; the options that you
need to recognize are documented there. When in doubt as to
what your program should do with regards to commandline
options, use sol_labyrinth as a model.
- In laby_solve.c you must complete the
laby_solve function in order for your
labyrinth program to actually do what it's supposed
to do- solve mazes.
This function returns SOLVABLE if the labyrinth can be solved
(there is a path from the start position to the finish
position) or UNSOLVABLE if no such path exists. In addition,
if there is a path, this function specifies one possible path.
I will not give you any hints about what algorithm to use to
accomplish this goal, beyond the following:
- Read labyrinth.txt. Once you get past the bad
jokes, there is actually some useful information here,
including some important and powerful hints (which I
will not reproduce here, in an effort to get you to
- Recursion is very useful, and a very elegant recursive
solution is easy to write. Just attack this problem
like any other- figure out what the base cases are,
and what values to return for each, and then figure
out what the recursive cases are.
- If this function becomes long and complicated, then
you are doing things the hard way! You may want to
rethink your algorithm.
- Do not be overly concerned with efficiency, just try to
come up with a solution. Unless you do something
silly, even a seemingly inefficient solution will be
of the same order as a good one. (Note however that
it is easy to write an infinite recursion for this
problem, and this degree of inefficiency is simply not
Also note that a bunch of the routines that implement the "graphics"
mode are provided for you to browse through and have (hopefully) been
written in a manner so that they should be relatively easy to snip out
of this code and reuse as a model for many different sorts of
text-base games or displays. See laby_win.c and
curses_utils.c for more information. Some of this info
could be quite useful on final projects.
800 is a program that reads in a sorted database of phone
numbers and then allows the user to look for entries that have
"interesting" telephone numbers (for example, telephone numbers that
spell things or consist of amusing sequences of numbers, if you are
amused by such things).
I think this program is well-described in the assignment, but here are
some details that have come up since then:
- You may assume that whatever the user types in will be shorter
than 500 characters. If they type in something longer, you
can safely ignore it, or detect the error and exit, or do
whatever you think is appropriate as long as it doesn't
violate some other rule of the program.
Note that no matter what the user types, you are really
interested in the first seven letters (or however many they
specified, if they didn't specify as many as seven). Any
additional letters cannot represent digits in a telephone
number, because the telephone numbers are only seven digits in
length (the 1-800 is not part of the listing).
- Use the "standard" mapping from letters to numbers. If you feel
like handling Q and Z, please make sure that you're doing the
appropriate thing. (I don't know what that is, since my
phones are too old to have this feature...)
- Remember that your program must be able to handle mixed-case
names, or mixtures of letters and digits.
- If the user types in something nonsensical, your program should
not respond in kind. If the user types in something bogus,
your program should respond with stony silence and not dump
core, crash, or generally act confused.
Please bring any errors or inconsistencies in this document
to the attention of the author.
Dan Ellard - (firstname.lastname@example.org)