Absolute Beginners C++


Lesson 11 - Command Lines

11.1 Accessing command line arguments

// ex11-1 - accessing command line arguments
#include <iostream>
#include <string>
using namespace std;
int main(int argc,char *argv[])
{
    cout << "argc=" << argc << endl;
    for (int i=1;i<argc;i++) 
        cout << "argv[" << i << "]=" 
             << argv[i] << endl;
    return(0);
}
ex11-1 hello testing one two
argc=5
argv[1]=hello
argv[2]=testing
argv[3]=one
argv[4]=two
Example ex11-1 shows how a C++ program can gain access to 'program arguments', that is any information put on the command line after the name of the program itself.  Such arguments are commonly used to specify, for example, the names of any files on which the program is to operate, or to specify any different modes of operation of the program.  Thus the command line:
XCOPY *.CPP A:\
is a MS-DOS command which executes the program XCOPY with two arguments: '*.CPP' which means 'all files with names ending in .CPP' and 'A:\' which is the name of the root directory on the diskette drive.  The program XCOPY retrieves these two arguments to work out exactly what copying function is required.
As you might expect, the command line arguments are provided as arguments to the main function.  However they are not supplied, as you could reasonably have expected, as a string variable, but as a more primitive array type of primitive 'C' string objects.  This is just a historical hang-over from how access to the program arguments was performed in the 'C' language.  Nevertheless, apart from the declaration of the main function, access to the strings is fairly straightforward.
The main function must be declared as taking two arguments, one to hold the number of strings passed to main(), and one to hold a table of string 'pointers'.  Thus the declaration
int main(int argc,char *argv[])
can be read as declaring a function called main, of type int, that takes two arguments: the first 'argc' is the argument count and is of type int, while the second 'argv' is a variable-length array '[]' of pointers '*' to arguments stored as characters 'char'.
This aside, you can see that we can access each of the arguments with the [] indexing notation we used for vectors.  Furthermore argc contains the total number of words on the command line, including the name of the program itself.  Thus the actual arguments are in indexes from 1 to argc-1.  The element argv[0] normally contains the name of the program, but this shouldn't be relied upon - anyway it is unusual for a program not to know its own name!

11.2 Accessing command line arguments as a vector

// ex11-2 - accessing command line arguments
//          as a vector
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main(int argc,char *argv[])
{
    // create an empty vector of strings
    vector<string> args;
    // copy program arguments into vector
    int i;
    for (i=1;i<argc;i++) 
        args.push_back(argv[i]);
    // sort vector
    sort(args.begin(),args.end());
    // list sorted arguments
    cout << "Sorted arguments:";
    for (i=0;i<args.size();i++) 
        cout << " " << args[i];
    cout << endl;
    return(0);
}
ex11-2 one two three four five
Sorted arguments: five four one three two
Example ex11-2 shows a simple way of copying the arguments into real C++ strings, so that we can do normal types of operations on them.  We create an empty vector of strings called 'args', then use a for loop to append the program arguments to the vector using push_back().  We can now call functions like 'sort()' if we like on the vector, or do comparisons with '<', or use substr() or find(), etc on the strings. 

11.3 Command line decoding

 // ex11-3.cpp - command line decoding
#include <iostream>
#include <string>
using namespace std;
// global program settings
int     iparam=0;     // integer parameter
double  dparam=0;     // double parameter
string  sparam="";    // string parameter
int     fparam=0;     // boolean flag
// main program
int main(int argc,char *argv[])
{
    int optind=1;
    // decode arguments
    while ((optind < argc) && (argv[optind][0]=='-')) {
        string sw = argv[optind];
        if (sw=="-i") {
            optind++;
            iparam = atoi(argv[optind]);
        }
        else if (sw=="-d") {
            optind++;
            dparam = atof(argv[optind]);
        }
        else if (sw=="-s") {
            optind++;
            sparam = argv[optind];
        }
        else if (sw=="-f")
            fparam=1;
        else
            cout << "Unknown switch: " 
                 << argv[optind] << endl;
        optind++;
    }
    // report settings
    cout << "Integer parameter = " << iparam << endl;
    cout << "Double parameter = " << dparam << endl;
    cout << "String parameter = " << sparam << endl;
    cout << "Flag parameter = " << fparam << endl;
    // report rest of command line
    cout << "Remaining arguments = ";
    for (;optind<argc;optind++) cout << argv[optind];
    cout << endl;
    return(0);
}
ex11-3 -i 10 -d 2.5 -s "hello there" -f file1 file2
Integer parameter = 10
Double parameter = 2.5
String parameter = hello there
Flag parameter = 1
Remaining arguments = file1 file2
Example ex11-3 is an extended example of command line argument processing.  In this example we accept a variable number of arguments of different types in arbitrary order.  We do this by preceding each argument with an indicator (often called a 'switch') which identifies the argument, and hence its type.  In the example the switches are
 
-i integer argument
-d double argument
-s string argument
-f flag with no argument

The program processes the switches in the order specified on the command line, irrespective of the nature of the switch. A for loop passes over the arguments, assigning each to a string variable sw so that it can be compared to each switch type in turn using '==' operators.  If a match is found, then the appropriate operation is performed, setting the values of an integer parameter iparam, a double parameter dparam, a string parameter sparam, or a flag parameter fparam, appropriately.  Notice that all parameters have been given values in their declaration: these are the values the parameters have by default: if no program argument sets them.  In the example these program parameters have been made 'global' variables, that is accessible by all program functions, by declaring them outside the main function.
To process the arguments, it is first necessary to test if they are switches by comparing the first character of each argument with the character '-'.
Since the program arguments are provided as character sequences, we need to 'convert' these to store them into integer or double variables.  The function which converts a string of alphanumeric characters to an integer value is called 'atoi()'; while the function which converts a string of alphanumeric characters into a double value is called 'atof()'.  If the program finds an argument not preceded by a known switch it stops processing arguments.  In the example, the values of the parameters are then printed, along with any unprocessed arguments.

11.4 Exercises

a. Write a program (ttable.cpp) that prints a times table for every number specified on the command line, as in:
ttable 6 10 12
 1   6  10  12
 2  12  20  24
 3  18  30  36
etc
12  72 120 144
b. Write a program (scalc.cpp) that does simple arithmetic calculations which are specified on the command line. Allow operators '+', '-', '*' and '/'. Check that any arguments provided are sensible before doing the calculation, as in:
scalc 3 + 5
3 + 5 = 8
scalc 2.5 * 1.5
2.5 * 1.5 = 3.75
scalc 5 /
Usage: scalc number operator number
scalc 5 / 0
Error: division by zero


© 1999 Mark Huckvale University College London