The header file stdio.h of the C Standard Library provides elementary functions for input and output. A file is here represented by a pointer to a FILE. The struct FILE is opaque (i.e. encapsulated away from us), we therefore do not know its internal structure and only use pointers to it.
fopen requires a file name and a mode, which specifies how the file is opened ("r" for reading, "w" for writing). It produces a pointer to a FILE if the file was successfully opened or NULL otherwise. For reading and writing, we often use the functions
int fscanf(FILE* f, char const* format, ...);
int fprintf(FILE* f, char const* format, ...);
The commonly used functions printf and scanf are abbreviations for these where f is set to stdin or stdout, respectively.
Subsection4.14.1Format Strings
Both, fprintf and fscanf use so-called format strings to determine how input and output is formatted. The chosen format element also describes how the corresponding argument is to be interpreted. In the following, we give a few examples of format strings and refer to the corresponding Unix manpages for a complete documentation.
char const *weekday = "Wednesday";
char const *month = "March";
int day = 11;
int hour = 10;
int min = 30;
printf("%s, %s %d, %.2d:%.2d\n",
weekday, month, day, hour, min);
We want to write a program that computes the average of all numbers from a list of files. A technique to compute the average of a list of numbers is the running average. If we know the average \(s_n\) of the first \(n\) numbers \(a_1, \dots, a_n\text{,}\) the average of the numbers \(a_1, \dots, a_{n+1}\) can be computed as:
We start with a function that computes the average of all numbers given in one file. We assume that the input files contain textual representations of floating-point numbers that are separated by whitespace characters as in this example:
We convert the textual representation to a double floating-point value using fscanf and store it into a variable val. The average and the number of the read numbers are stored in a struct:
The function running_average expects a file and a pointer to such a struct as arguments. It then reads as long as it can find numbers in the file and continues the average computation according to (4.1):
The following main function accepts a list of file names as command line parameters. It opens these files one after the other and calls the running_average function with it. Lastly, it prints the computed average. If no command line parameter is given, the standard input stdin is used as an input file.
int main(int argc, char *argv[])
{
avg_t avg;
avg.avg = 0.0;
avg.n = 0;
if (argc == 1) {
running_average(stdin, &avg);
}
else {
for (int i = 1; i < argc; i++) {
FILE* input;
if ((input = fopen(argv[i], "r")) != NULL) {
running_average(input, &avg);
fclose(input);
}
else {
fprintf(stderr, "no such file: %s\n", argv[i]);
return 1;
}
}
}
printf("%g\n", avg.avg);
return 0;
}