In class yesterday I made a number of modifications to the mpg.cpp program that was presented in the previous lecture notes. The changes I made will help you with the lab assignment and include:
Also note that I changed the way I handle input in the while loop. The way I did it previously, by putting the read inside the while condition, is a bit sloppy, because file I/O can fail for reasons other than end-of-file. In these other cases, we may want to skip the line of input and continue.
I have now placed a priming read before the while loop and then used the eof method to determine whether the end-of-file has been reached. The priming read initializes the input variables and the file's eof flag. If you are familiar with the phrase "priming the pump", this is the phrase from which priming read is derived. If I fail to put the priming read before the loop, then the loop will get executed once, even if the input file is empty. In that case garbage will get printed because nothing will be read into the input variables.
I have also placed a read statement at the end of the loop to get the next line of input.
#include <iostream> #include <string> #include <fstream> -- add fstream to enable file I/O #include <stdlib.h> -- stdlib.h declares the exit function using namespace std; // auto turns out to be a C++ reserved word so I substituted car instead class car { public: string name; float avg_mpg; }; // it's better to declare constants rather than hard-coding them const int NUM_DRIVERS = 3; /* in order to use command line arguments you must declare the following two arguments for main: 1) argc: the number of command line arguments. It is equal to 1 plus the number of command line arguments you provide, because the first command line argument is actually the name of the executable 2) argv: an array of character strings that contain the command line arguments. argv[0] is the name of the executable. The command line arguments provided by the user start at argv[1]. */ main(int argc, char *argv[]) { ifstream input_file; -- input_file is an (i)nput (f)ile stream car max_car; // holds the car with the best gas mileage seen thus far float avg; // average gas mileage for the current car int mpg[NUM_DRIVERS]; // gas mileage achieved by drivers for current car string model; // name of current car /* make sure that we receive exactly the number of arguments that we expect. If we receive too few, then argv[1] will be undefined and our program will crash. If we receive too many, the extra arguments will be ignored. More importantly, the user probably has a misconception about how to use our program. */ if (argc != 2) { cerr << "usage: " << argv[0] << " filename" << endl; /* exit provides us with a way to immediately exit the program and to provide the user with an error code that indicates why the program exited abnormally. There are no "standard" values for error codes. They are defined by the programmer. */ exit(1); } /* we must now open the input file and then check to ensure that it was opened correctly. We can test the stream directly, as I have done here, or you can call the stream's fail method. My method is the more commonly accepted idiom. If the open fails, it writes an error message to a protected part of memory. perror, which stands for (p)rint error, is a C++ provided function that can read this protected error message and print it to the console. You can also provide an argument to perror, in which case perror concatenates your argument to the start of the error message. Providing an argument to perror can help you locate where in the source file the error has occurred. */ input_file.open(argv[1]); if (!input_file) { perror(argv[1]); exit(1); } // initialize max_car.avg_mpg to a small value or else it might never get set max_car.avg_mpg = -1.0; /* initial priming read that initializes the input variables and sets the eof flag to true if the file is empty */ input_file >> model >> mpg[0] >> mpg[1] >> mpg[2]; /* the eof method returns true when end-of-file is reached */ while (input_file.eof() != true) { // remember to cast either the numerator or divisor to a float in order // to avoid integer arithmetic avg = (mpg[0] + mpg[1] + mpg[2]) / (float)NUM_DRIVERS; if (avg > max_car.avg_mpg) { max_car.name = model; max_car.avg_mpg = avg; } /* read the next line of input */ input_file >> model >> mpg[0] >> mpg[1] >> mpg[2]; } cout < "best car = " < max_car.name < endl; cout < "mpg = " < max_car.avg_mpg < endl; }