Schedule
Labs
Assignments
TA office hours
Topic videos
Some course notes
Extra problems
Lecture recordings
If you already know some C, you will still probably find about half of the following to be new information, I think.
Let us begin by examining the following example program (which you can find in a separate file on the web at https://www.teach.cs.toronto.edu/~ajr/209/notes/cintrofiles/gcd-full.c )
#include <stdio.h> int main() { int i; extern int gcd(int x, int y); for (i = 0; i < 20; i++) printf("gcd of 12 and %d is %d\n", i, gcd(12, i)); return(0); } int gcd(int x, int y) { int t; while (y) { t = x; x = y; y = t % y; } return(x); }
Notes on this file:
We would typically compile the above file with:
gcc -Wall -o gcd gcd.c
"-Wall" means to turn on "all" warning messages. Warning messages are messages which typically do indicate problems with your program, but for various reasons have been deemed by the ANSI standards committee not to be in the category of errors which should prevent the production of a machine-language program.
But in practice, you should almost always take these "warning" messages just as seriously as "error" messages. Both indicate something wrong with your program.
Your assignments in this course should compile with "-Wall" with no diagnostics of any kind. That is, after the 'gcc' command you should immediately get another shell prompt.
You might feel that the "gcd" subroutine above is more useful than the main() function which just plays with it a bit. Normally we would put these into separate files so that you could compile a different (and presumably larger) program which includes the gcd() function above, but does not include the main() function above.
You are used to dividing programs into multiple files in java. In java, every public class has to be in a separate .java file. There are no such rules in C, but we try to collect related functions and variables into a file, to present a module or "package" which has some sort of unified function. Also, it is possible to make functions and variables private to an individual .c file.
So let's put the gcd function above into a separate file, which we'll call gcd.c, and the main() above into a file which we will call "testgcd.c".
Only testgcd.c needs to #include <stdio.h>, because gcd() does not use anything from that library.
We'd also typically move that "extern int gcd(int x, int y);
"
into a separate file called gcd.h.
Then testgcd.c (and anything else which uses gcd()) can #include "gcd.h", thus
picking up the declaration. So you #include "gcd.h" and compile with (link
with) gcd.c; thus gcd.h and gcd.c comprise a package, just how we're using
stdio functions from the standard C library.
Here are example testgcd.c, gcd.h, and gcd.c files divided up in this way. Note that gcd.c also #includes gcd.h. This has an extremely useful error-checking function. It makes the C compiler verify that the argument count and types in gcd.h's declaration of gcd() match the argument count and types in gcd.c's definition of gcd(). You should try changing one of them (e.g. add a third parameter) to see what happens.
Using double-quotes instead of angle-brakcets around "gcd.h" means that the C compiler should look for this file in the same directory as the .c file being compiled, whereas angle-brackets mean that it should look in /usr/include.
We would typically compile these files with:
gcc -Wall -o testgcd testgcd.c gcd.c