You’ll need to learn how to use a few library routines from the C standard library (often called libc) to implement the source code for this assignment. All C code is automatically linked with the C library, which is full of useful functions you can call to implement your program. Learn more about the C library here and perhaps here.
For this project, we recommend using the following routines to do file input and output: fopen() and fclose(). Whenever you use a new function like this, the first thing you should do is read about it – how else will you learn to use it properly?
On UNIX systems, the best way to read about such functions is to use what are called the man pages (short for manual). In our HTML/web-driven world, the man pages feel a bit antiquated, but they are useful and informative and generally quite easy to use.
To access the man page for fopen(), for example, just type the following at
your UNIX shell prompt: prompt> man fopen
Then, read! Reading man pages effectively takes practice; why not start learning now?
We will also give a simple overview here. The fopen() function “opens” a file, which is a common way in UNIX systems to begin the process of file access. In this case, opening a file just gives you back a pointer to a structure of type FILE, which can then be passed to other routines to read, write, etc.
Here is a typical usage of fopen():
FILE *fp = fopen("main.c", "r");
if (fp == NULL) {
printf("cannot open file\n");
exit(1);
}
A couple of points here. First, note that fopen() takes two arguments: the name of the file and the mode. The latter just indicates what we plan to do with the file. In this case, because we wish to read the file, we pass “r” as the second argument. Read the man pages to see what other options are available.
Second, note the critical checking of whether the fopen() actually succeeded. This is not Java where an exception will be thrown when things goes wrong; rather, it is C, and it is expected (in good programs, i.e., the only kind you’d want to write) that you always will check if the call succeeded. Reading the man page tells you the details of what is returned when an error is encountered; in this case, the macOS man page says:
Upon successful completion fopen(), fdopen(), freopen() and fmemopen()
return a FILE pointer. Otherwise, NULL is returned and the global variable
errno is set to indicate the error.
Thus, as the code above does, please check that fopen() does not return NULL before trying to use the FILE pointer it returns.
Third, note that when the error case occurs, the program prints a message and then exits with error status of 1. In UNIX systems, it is traditional to return 0 upon success, and non-zero upon failure. Here, we will use 1 to indicate failure.
Side note: if fopen() does fail, there are many reasons possible as to why. You can use the functions perror() or strerror() to print out more about why the error occurred; learn about those on your own (using … you guessed it … the man pages!).
Finally, whenever you open a file remember you need to close it! You can use the fclose()
function
to close files.
Once a file is open, there are many different ways to read from it. There are two functions that might be useful for you in the context of this assignment.
Reading/Writing a line: A number of UNIX utilities (e.g., grep, cat) read input files one line at time. There are two useful functions to read lines: fgets
which can read a fixed number of characters but stops when it reaches the end of a line, and getline
which can read entire lines into a buffer (be careful with very long lines!). You can learn more about these functions in, you guessed it, the man pages! To write a string to a file you can similarly use fputs
or the more powerful formatting capabilities in fprintf
.
Reading/Writing bytes: Another common way to read files is to read them a few bytes at a time. This is
especially handy if you need to read a fixed number of bytes (hint: think about the wis-tar format!) and you know the type of the data you will be reading.
The relevant functions to lookup for this are fread
and fwrite
.
To find the size of a file we can use the stat
function that is also part of the C library.
As you can see from the man page (you might need to run man 2 stat
),
the stat function returns a number of useful properties about a file. Among those are the size of
the file which is stored in the st_size
field. Thus you can get the file size using code that
looks like
struct stat info;
int err = stat("a.txt", &info);
// Do error checking here!
printf("size of a.txt = %ld\n", info.st_size);