Assignment two last-minute notes
Here are some last-minute notes about assignment two. None
of this constitutes new information. But here are some reminders, and
clarifications of matters which really are in the course
materials but maybe you missed it.
Speaking of which, I do recommend reading the Q&A
file. There's a bunch of useful stuff in there.
Overall:
- KEEP IT SIMPLE! The more complex program has more bugs, is harder to
work with, increases the chance that you introduce bugs when modifying it.
- Similarly, try to avoid special cases. Ask yourself whether something
really is a special case, or if it's already covered by the processing of the
general case.
- Checking whether you think an operation (e.g. fopen, opendir) is going to
succeed is not a substitute for checking the return value to see whether it
actually did succeed. So, skip the pre-check and just do the operation and
check whether or not it succeeded. (And call perror() properly!)
-
Check for possible error return from all system calls, and from fopen,
opendir, etc. For any library or kernel call which can return an error
indication, you have to check it and do something appropriate — even if it's
just printing an error message and exiting.
If you think that a system call in a particular situation can't possibly
fail, you're wrong! — ask me and I can tell you a way in which it will fail.
Put these checks in place in initial development.
Many student questions have been answered by putting in the error
checks (and a proper call to perror()), after which the bug became apparent.
- Remember the software tools principle "Say what you're asked to
— no more, no less." For example, this pipeline should yield no output,
for any file "file":
./crypt -k foo file | ./crypt -d -k foo | diff - file
because you output only the encrypted or decrypted file, nothing else.
- Don't exceed array bounds.
- Don't assume anything about user input, about other files which might be
around, etc. Users do all sorts of crazy thing and your program still has to
work.
- Proper indentation is required. Make your program look nice, and
readable. In "real life", when writing a program whose source code only you
will ever see... make it look nice, and readable, because you're someone who
has to read it, too. Not only today and tomorrow, but maybe in a few years
when you've forgot about it and why you did things a certain wacky and
complicated and unreadable way.
-
Don't comment bad code, rewrite it. When you write comments explaining
your code, consider whether they indicate a defect in your code,
and if so, fix the code.
-
When calling fopen() or opendir() in a loop, you need to call fclose() or
closedir(), or you will run out of resources if given a sufficiently
large number of arguments.
-
KEEP IT SIMPLE!
Always keep in mind the possibility of reorganizing code to make it shorter
and clearer.
And, these programs are all simpler than you may think. If you're going down
some complicated route, ask me about it and I'll tell you how to keep it
simple.
Crypt:
-
You must call getopt() to do the processing of the command-line arguments and
options. See the sample getopt.c.
And be clear on what "optind" does for you — you DON'T go through all of
argv again looking for where the file names are; getopt() tells you where the
file names are.
-
If referring to the character 'a', write 'a', not 97. (etc)
Whatyear:
-
The values you have to set before calling mktime are tm_year, tm_mon, tm_mday,
tm_hour, tm_min, tm_sec, and tm_isdst. Normally we set tm_isdst to -1, which
means “you figure it out”.
Findempty:
-
You can't assume that "." and ".." are the first two entries in a directory.
Check whether or not it's "." or ".." with strcmp.
Other file names beginning with a dot are not special.
-
Don't exceed array bounds, and don't ask a string library function to exceed
array bounds. You can't call strcpy or strcat unless you have in mind basically a
mathematical proof that the resulting string will fit into the target
array. This is often accomplished by being in an 'if' which calls strlen.
-
Don't use getcwd() or realpath(). If your program is run with a relative
file path name, your output will be in terms of that relative file path name.