Assignment one questions and answers

Here are some questions and answers about assignment one. Suggestions for additions to this list are welcome (via e-mail).

New questions and answers will be added at the end. This means that the questions are not organized into topics. I hope that the list isn't long enough to make this too big a problem, and I think it's more important for people to be able to read only the new stuff, by scrolling down to the end.


Q: I uploaded my file at 11:45 last night [October 10th] and it didn't work at CDF, but it worked fine at home. May I have an extension on account of this?

A: No. It's simply not possible for us to accommodate problems with your own computer equipment. We suggest that you use the CDF computers, which are professionally managed, and which have a good C compiler which correctly implements the C programming language. Use of your own equipment is at your own risk; I can sometimes assist you with it, and I'm not opposed to it, but if problems with your own computer were allowed to cause you to have extensions, everyone would have free extensions. It's just not feasible.

At this date [October 11th] it's a bit late for this information to be of use to you for assignment one. Fortunately I have a time-warp here so I'll post this on the CSC 270 web pages retroactively on September 24th. Please be advised.


Q: How do I compile multiple files together into one program?

A: List multiple files on the command line. For example,

    gcc -Wall -ansi -pedantic testdiffeq.c diffeq.c -lm
Or just type "make" to use the supplied Makefile. (We'll discuss writing Makefiles just very briefly, later in the course, or perhaps only in tutorial. For those of you who have the King book, there is a chapter about Makefiles.)


Q: When I use any math library function, I get an error that that function name is an "undefined symbol", and something about a reference. But I am #including <math.h>!

A: math.h supplies the extern declaration for the function, like "extern double pow(double x, double y)". That is important. Equally important (arguably more so, although actually both are essential) is to supply the code for the math functions.

The situation here is similar to that involved in your call of delist() from main(). You have to declare delist() in diffeq.c (actually via #include "diffeq.h"), and you have to "link" with the definition of delist() in diffeq.c.

Similarly, you have to link with the math library explicitly, if you call any functions in it. You do this by putting "-lm" at the end of your "cc" (or "gcc") command line, e.g. "cc testeq.c diffeq.c -lm". "-lm" is short for something like "/usr/lib/libm.a". These .a files are just collections of .o files, but the special rule is that the compiler only takes out the object files from libraries which satisfy as-yet-unsatisfied references from the other files. The idea is that when you call, say, the pow() function, then obviously the code for that function has to be included in your executable; but your executable does not have to swell by the size of the entire math library, just the parts you use. Thus "-lm" has to be last (or, to be precise, it has to be after at least one file which calls each function in the math library which is called from any of your files -- easiest simply to put it last always (although we do sometimes have to worry about this sort of thing when we link with multiple libraries which reference each other)).

So why don't you need to link with the stdio library to call printf, and all sorts of other libraries for the other library functions you might be calling? Because a great many libraries are in a big conglomerate library called the "C library", and the C library is linked with by default. That is to say, "-lc" is implied at the end of your cc command line. You must specify any other libraries explicitly. Except that so many of them are rolled into the C library. The math library, however, is not part of the C library, and thus must be requested explicitly.


Q: Can I use the pow() library function?

A: Yes. But if you want the function ex, that's exp(x).

Q: Well gosh, how do I find out what a library function does? I thought that exp() was something else.

A: Every library function has a unix "man page" ("man" is short for "manual"). You can read the exp man page by typing "man exp".

A2: Look it up in the index of your C book, if you have one. Your C book might have a list of commonly-called functions (which would be more useful than a list of absolutely all library functions).


Q: I want to add a "helper" function in diffeq.c. Do I add its extern declaration into diffeq.h?

A: No, for two reasons. First of all, you do not submit diffeq.h. We will compile your program with the original diffeq.h. But most of all, diffeq.h is intended to be a list of functions which are "exported" from diffeq.c, like "public methods" in Java. If something is analogous to a "private method" (or private instance variable), in C we would not put its extern declaration in the .h file, but rather we would put it right there in the .c file so that it is only accessible to other functions in that .c file itself. In C, the file level is the closest thing we have to a class.

(Actually there is a keyword "static", which means two different things in C (they got stingy about allocating new keywords), but in the case of a function declaration it always means that it is not made available to other files. This keyword is quite underused in C and we won't expect you to use it in this course; sooner or later we'll be moving to C++ and using real classes again. However, the sample solution for assignment one will use "static" properly and you can see how it works at that point.)


Q: Do I have to limit the length of the lines to 80 characters, as I did in CSC 148?

A: Yes. The printer, my computer monitor, etc, are all of finite width. The standard terminal width is 80 characters; all you can expect from me in terms of line width, e.g. in how I format the print-outs, is that I make 80 characters or fewer look acceptably. If lines are longer than that, they will wrap around. Instead, you should wrap them around yourself, taking care to make the result tidy and readable.


Q: My program works perfectly but when compiled, there are error or warning messages. Can I leave it like this?

A: No. (Well, when the due time approaches, you should submit whatever you've got; but if you have time, you should correct these errors.)

Warning messages indicate that you are doing something improper. It may fail to work on other C compilers, for example (whether this is what's going on depends on the particular error message). In this course we are writing careful, correct, tidy, and maintainable C programs.

Last year, ajr wrote a newsgroup article about this, which the above paragraph is from.


Q: I changed the statement

        x += y;
to
        if (y == 1)
            x++;
        else
            x += y;
, but this is harder to read. Which is more important, efficiency or "style"?

A: You are mistaken about efficiency. The second version will likely run slower than the first, and it will produce a larger compiled program, and it is more likely to contain errors (bugs), and future modification to this program is more likely to introduce bugs because of its unnecessarily complex structure. The most important thing, both in this course and in "real life", is to write your program clearly and correctly.

Many times when people modify their programs in this sort of way for "efficiency" they cause harm and no good. That is, the best you can hope for is that the program works almost as well as before.

There's a saying: "The first rule of optimization is: Don't."

You will have noticed that many large software projects produce programs which are abominably slow. The solution, though, is not to perform "micro-optimizations" of this kind; they may or may not help, but any help will be imperceptible and won't fix the situation. The main way one speeds up unacceptably-slow programs to an acceptable speed is to improve the algorithms. This is much harder when "micro-optimizations" are in place.

Occasionally one does perform these sorts of micro-optimizations, when you're trying to speed up a program in every last possible way. But you do them last, and you only micro-optimize the sections of the code which profiling data has shown to be worth the cost. (Usually this is no code at all; i.e. you don't do it.) The cost is substantial: it creates difficulty reading and working with the program. The benefit of most micro-optimizations is basically zero. Zero benefit for substantial cost is not a good tradeoff.


Q: How do I check whether or not my files have been submitted properly?

A: Type the following command:

submit -l -c csc270h -a a1
That "-l" is the letter L (but lower-case), not the number 1. It is like the "-l" in "ls -l".

This command does not give you the file contents, but it gives you the file size, so you can compare to an "ls -l" of that file and verify whether or not it's the correct one, and you can see whether all your files have been submitted.

You can resubmit a file by simply submitting a file by the same name again. The last one counts.


Q: I have both a course account and a "permanent" account. Does it matter which one I submit from?

A: Two answers: "No" in that if you submit successfully, you're ok; "Yes" in that I believe that the submission system will actually let you submit from only one of the two accounts. This will probably be the course account.

If the submission works, and "submit -l -c csc270h -a a1" shows your files, then they'll get graded.


Q: What are those things like "#define TABLELINES 100" in diffeq.h?

A: This is a facility of C used for constants. It is part of the "C pre-processor", like #include. We'll be discussing the C pre-processor in more detail later in the course (briefly).

It is basically a global substitution. After "#define TABLELINES 100", every time "TABLELINES" appears, it is replaced by "100" (without the quotes).

Why not simply use "const int TABLELINES = 100;"? Because in that case, TABLELINES would not be able to be used as an array dimension in ANSI-standard C. "const"s in C are not actually what we normally think of as a "const" in a programming language. They were added by the ANSI standardization committee and they don't fit with the language too well in some ways. (C++ does not have this quirk; C++ "const"s can indeed be used as array dimensions.)

Your diffeq.c should function as appropriate when TABLELINES and/or STEPSIZE are replaced with any reasonable values. This is a way in which our test program can parameterize your assignment submission. That is, you do have to use them.

Q: So, couldn't STEPSIZE have been a const, at least?

A: Yes, it could have been. But C programmers are used to the uselessness of const and thus they tend to use #define.


Q: I get some errors when compiling with -ansi and/or -pedantic, but not when compiling only with -Wall. Do I have to fix them?

A: Yes, you have to fix them. Your program should compile with no errors or warnings when compiled with "gcc -Wall -ansi -pedantic testdiffeq.c diffeq.c", using our supplied testeq.c and our supplied diffeq.h.

(Also see the q&a above about warning messages, and the above-cited newsgroup article.)


Q: What does "ISO C89 forbids mixed declarations and code" mean?

A: It means that within a given scope, all declarations must precede all non-declaration statements. For example,

int something(int x)
{
    int y = 3;
    x *= 2;
    int z = x + y;
    ...
must be re-written as
int something(int x)
{
    int y = 3;
    int z;
    x *= 2;
    z = x + y;
    ...

Q: That rule is stupid!

A: Yes, it is. As a matter of fact, it's much less stupid than similar rules in most programming languages at the time C was originally invented, but it looks very stupid today. C++ allows the "mixing" of declarations and non-declaration statements. So does the newest C standard, but we're not using that for this course (yet). Please compile with "-ansi" to enforce adherence to the original C standard in this course, for assignments one and two. (Assignments three and four will be in C++, which, among other things, eliminates this silly restriction about declarations having to be at the beginning of a scope.)


Q: What do compiler warnings about "carriage return" mean?

A: They mean that there are spurious control-Ms in your file. Control-M in the ASCII standard is called "carriage return".

These control characters probably arose because you transferred your file incorrectly from ms-dos to unix. The ASCII standard does not specify how lines of a text file are separated. In ms-dos, the line terminator is the two characters control-M and control-J (in that order). In unix, the line terminator is the single character control-J. When you transfer text files between computers, the file transfer program should have an option to change the line terminator character appropriately.

If you transferred your file in the wrong mode, you can fix it up with the "flip" command, as described in the Student Guide to CDF, page 13 ("Removing line feeds").


Q: The examples in the King book say "main()" instead of "int main()". Which one is right? And why do both of them seem to work?

A: There's a rule in C which is mostly historical and is quite silly, which says that the default type for things is int. In particular, the code

    int gloop()
    {
	return 3;
    }
is exactly the same, by definition, as
    gloop()
    {
	return 3;
    }

Almost everyone agrees that the latter form is bad. However, some people make an exception for main() for historical reasons. I think that this exception is pointless but harmless. However, leaving off an "int" in any function declaration other than main() is certainly grounds for a complaint by the grader. And since gcc -Wall -ansi -pedantic will indeed give you an error (warning) message for leaving off the "int" in the declaration of main(), you should put the "int" in there too.

The fact that you are/were allowed to leave out the word "int" in declaring a function to have return type int has led to two quite separate uses of this laxness. For one, some C programmers used to omit the type declaration to indicate that no value was returned, especially in the very early days before the "void" type was added to the language. However, other C programmers got used to leaving off the "int" just because you could.

This means that other than in the case of main(), you really don't know what is meant by a missing type declaration these days. If you mean that the function returns int, say "int"; if you mean that the function doesn't return anything, say "void". This is why the modern version of gcc gives a warning if "return type defaults to 'int'".


Q: What is a "parse error"?

A: You may know that as a "syntax error". To anthropomorphize slightly, the text has sufficiently little resemblance to a C program that the compiler doesn't know where to begin with it.

But I can also give you a more specific answer. Many of these for assignment one are being caused by people using "//"-style comments. You should use the "/* ... */" style of comments.

People are especially experiencing this if they've developed their code on a "C compiler" at home, and it's exactly the reason we recommend against using random other C compilers out there -- they may implement "extensions" which allow you to write things which aren't standard C. If you have an "always-on" type of internet access from home, e.g. ADSL (sympatico) or cable modem, then I recommend that you use the CDF computers from home rather than a compiler on your home machine. See http://www.dgp.toronto.edu/~ajr/270/remotelogin.html for terminal program recommendations -- you don't need to install anything as complex as Cygwin or similar.

(In fact the "//" style of comments has been added in the latest C standard, but we're not using that version of C for this course (yet). You may not think that 1999 is so recent, but if you look at http://gcc.gnu.org/gcc-3.1/c99status.html you will see that GCC does not yet support the full ISO 1999 C standard, so by that measure it's still too new to use in this course.)

(There's a good chance that that's not why your home C compiler accepts "//" comments anyway. A lot of compilers accept extra things which the authors thought were cool. "//" comments may indeed be cool, but in this course we are expecting you to write programs which will run correctly anywhere because they adhere to the standard C programming language. The GCC authors are not immune to this coolness disease, but if you compile with both -ansi and -pedantic, it suppresses any unwarranted coolness.)


[main course page]