The argc argument represents the number of arguments on the command line. The count includes the command name itself. The argv variable is a pointer to a pointer to a char. This sounds a bit abstract, but you can treat argv as if it were an array of pointers to the command-line arguments, with argv[0] being a pointer to the first character of a string holding the command name, argv[1] being a pointer to the first character of a string holding the first command-line argument, and so on. That is, argv[0] is the first string from the command line, and so on. For example, suppose you have the following command line:
wc report1 report2 report3
In this case, argc would be 4, argv[0] would be wc, argv[1] would be report1, and so on. The following loop would print each command-line argument on a separate line:
for (int i = 1; i < argc; i++)
cout << argv[i] << endl;
Starting with i = 1 just prints the command-line arguments; starting with i = 0 would print the command name as well.
Command-line arguments, of course, go hand-in-hand with command-line operating systems such as the Windows command prompt mode, Unix, and Linux. Other setups may still allow you to use command-line arguments:
• Many Windows IDEs (Integrated Development Environments) have an option for providing command-line arguments. Typically, you have to navigate through a series of menu choices that lead to a box into which you can type the command-line arguments. The exact set of steps varies from vendor to vendor and from upgrade to upgrade, so check your documentation.
• Many Windows IDEs can produce executable files that run under in the Windows command prompt mode.
Listing 17.17 combines the command-line technique with file stream techniques to count characters in files listed on the command line.
Listing 17.17. count.cpp
// count.cpp -- counting characters in a list of files
#include
#include
#include
int main(int argc, char * argv[])
{
using namespace std;
if (argc == 1) // quit if no arguments
{
cerr << "Usage: " << argv[0] << " filename[s]\n";
exit(EXIT_FAILURE);
}
ifstream fin; // open stream
long count;
long total = 0;
char ch;
for (int file = 1; file < argc; file++)
{
fin.open(argv[file]); // connect stream to argv[file]
if (!fin.is_open())
{
cerr << "Could not open " << argv[file] << endl;
fin.clear();
continue;
}
count = 0;
while (fin.get(ch))
count++;
cout << count << " characters in " << argv[file] << endl;
total += count;
fin.clear(); // needed for some implementations
fin.close(); // disconnect file
}
cout << total << " characters in all files\n";
return 0;
}
Note
Some C++ implementations require using fin.clear() at the end of the program, and others do not. It depends on whether associating a new file with the ifstream object automatically resets the stream state. In does no harm to use fin.clear() even if it isn’t needed.
On a Linux system, for example, you could compile Listing 17.17 to an executable file called a.out. Then sample runs could look like this:
$ a.out
Usage: a.out filename[s]
$ a.out paris rome
3580 characters in paris
4886 characters in rome
8466 characters in all files
$
Note that the program uses cerr for the error message. A minor point is that the message uses argv[0] instead of a.out:
cerr << "Usage: " << argv[0] << " filename[s]\n";
This way, if you change the name of the executable file, the program will automatically use the new name.
The program uses the is_open() method to verify that it was able to open the requested file. Let’s examine that matter further.
File Modes
The file mode describes how a file is to be used: read it, write to it, append it, and so on. When you associate a stream with a file, either by initializing a file stream object with a filename or by using the open() method, you can provide a second argument that specifies the file mode:
ifstream fin("banjo", mode1); // constructor with mode argument
ofstream fout();
fout.open("harp", mode2); // open() with mode arguments
The ios_base class defines an openmode type to represent the mode; like the fmtflags and iostate types, it is a bitmask type. (In the old days, it was type int.) You can choose from several constants defined in the ios_base class to specify the mode. Table 17.7 lists the constants and their meanings. C++ file I/O has undergone several changes to make it compatible with ANSI C file I/0.
Table 17.7. File Mode Constants