Search

7.13 — Command line arguments

As you learned in the introduction to development lesson, when you compile and link your program, the compiler produces an executable file. When a program is run, execution starts at the top of the function called main(). Up to this point, we’ve declared main like this:

Notice that this version of main() takes no parameters. However, many programs need some kind of input to work with. For example, let’s say you were writing a program called WordCount to count the number of words in a text file. What text file should be read and processed? The user has to have some way of telling the program which file to open. To do this, you might take this approach:

However, there is a major problem with this approach. Every time the program is run, the program will wait for the user to enter input. That means execution of the program can not be automated very easily. For example, if you wanted to run this program on 500 files every week, the program would stop and wait for you to enter a new filename each and every time it was run. And you’d have to do so by hand.

Command line arguments

For programs that have minimal and/or optional inputs, command line arguments offer a great way to make programs more modular. Command line arguments are optional string arguments that a user can give to a program upon execution. These arguments are passed by the operating system to the program, and the program can use them as input.

Programs are normally run by invoking them by name. On the command line, to run a program, you can simply type in its name. For example, to run the executable file “WordCount” that is located in the root directory of the C: drive on a Windows machine, you could type:

C:\>WordCount

In order to pass command line arguments to WordCount, we simply list the command line arguments after the executable name:

C:\>WordCount Myfile.txt

Now when WordCount is executed, Myfile.txt will be provided as a command line argument. A program can have multiple command line arguments, separated by spaces:

C:\>WordCount Myfile.txt Myotherfile.txt

This also works for other command line operating systems, such as Linux (though your prompt and directory structure will undoubtedly vary).

If you are running your program from an IDE, the IDE should provide a way to enter command line arguments. For example, in Microsoft Visual Studio 2005, right click on your project in the solution explorer, then choose properties. Open the “Configuration Properties” tree element, and choose “Debugging”. In the right pane, there is a line called “Command Arguments”. You can enter your command line arguments there for testing, and they will be automatically passed to your program when you run it.

Now that you know how to provide command line arguments to a program, the next step is to access them from within our C++ program. To do that, we use a different form of main() than we’ve seen before. This new form of main() takes two arguments (named argc and argv by convention) as follows:

You will sometimes also see it written as:

Even though these are essentially the same, we prefer the first representation because it’s intuitively easier to understand.

argc is an integer parameter containing a count of the number of arguments passed to the program (think: argc = argument count). argc will always be at least 1, because the first argument is always the name of the program itself! Each command line argument the user provides will cause argc to increase by 1.

argv is where the actual arguments themselves are stored. Although the declaration of argv looks intimidating, argv is really just an array of C-style strings. The length of this array is argc.

Let’s write a short program to print the value of all the command line parameters:

Now, when we invoke this program with the command line arguments “Myfile.txt” and “100”, the output will be as follows:

There are 3 arguments:
0 C:\WordCount
1 Myfile.txt
2 100

Argument 0 is always the name of the current program being run. Argument 1 and 2 in this case are the two command line parameters we passed in.

Back to our previous example, let’s go ahead and partially write WordCount so it uses command line arguments instead of asking the user for input:

Now, when WordCount is run, it will not require any user interaction. This means we can have a batch file, script, or even another program run WordCount many times in a row (with different command line arguments) in an automated manner.

Those of you studying computer science in school (or planning on taking programming classes) may find that your professors ask you to use command line arguments to provide inputs to the program rather than using cin. Running each student’s program (when there are 50 or 100 students) and having to type in the same filenames or inputs to test whether the program works makes for slow grading and is tedious to boot. By using command line arguments, professors and TAs can automate the process of running the student’s programs on a preselected set of inputs, using another program to compare whether the output matches known correct output. This can speed up the overall grading process immensely.

7.14 -- Ellipses (and why to avoid them)
Index
7.12 -- Handling errors (assert, cerr, exit, and exceptions)

25 comments to 7.13 — Command line arguments

  • Tom

    Do you want to include:

    #include

    in the code that people copy to their clipboard so that errors don't occur?
    E.g.
    g++ j35.cpp -g -o xxx
    j35.cpp: In function ‘int main(int, char**)’:
    j35.cpp:8: error: ‘cout’ was not declared in this scope
    j35.cpp:8: error: ‘endl’ was not declared in this scope
    j35.cpp:9: error: ‘exit’ was not declared in this scope

    That is:

    #include <iostream>
    int main(int argc, char *argv[])
    {
        using namespace std;
        // If the user didn't provide a filename command line argument,
        // print an error and exit.
        if (argc <= 1)
        {
            cout << "Usage: " << argv[0] << " <Filename>" << endl;
            exit(1);
        }
    
        char *pFilename = argv[1];
    
        // open file and process it
    }
    
    
  • dzmat

    Even when there is no command line arguments passed to program, argc=1, because argv[0] is a name of executable and is always present.

  • Kurt

    In the last example isn't there a off by 1 error?

        if (argc <= 1)
        {
            cout << "Usage: " << argv[0] << " <Filename>" << endl;
            exit(1);
        }
    

    When there is a command line argument, argc = 1 then (argc <= 1) is the same as 1 <=1 what translates to true so the program exits.
    It should be like this no?

        if (argc < 1)
    
    • Quinn

      Actually, argc always evaluates to at least one, even without any other command-line arguments. If it were just (argc < 1) then you'd end up with that if statement never evaluating to true, and the program most likely crashing due to trying to load up something that wasn't there if the user tried not giving any arguments.

  • Mohamad

    I am confused as to how to pass command line arguments to main using CODE::BLOCKS any instructions?

    • Mohamad

      Nevermind I figured it out... all I had to do was go to the command line in Vista Start mean (which looks like a search instead of the run box you get in Windows XP) and type in the path to the file and the argument. Thanks for all the good lessons.

      • Quinn

        You can set arguments automatically in Code::Blocks using the Project -> Set programs' arguments menu option. Then when you build/run or just run it the program will always run with your selected arguments.

  • Pathik

    "Each command line argument the user provides will will cause argc to increase by 1."

    There are 2 'will'.

    [ Fixed. Thanks! -Alex ]

  • isn't it easier to put inputs in a file and then read then from the file instead of using command line argumens?

    • It depends on what your program is doing and how it's run. If your program is a standalone program that does lots of text processing, then sure, a file input would be perfect for that.

      However, consider the case where you're writing a program you expect to be called by other programs. Are you going to make them all write files before they call you? What if two programs call you at the same time?

      Generally, my feeling is that you should use command line parameters if you can, and file inputs only when necessary.

  • Astro

    Should "char *pFilename = argv[1];" in the example above be "char *pFilename = &argv[1];" ????

    Am I confusing myself here?

    • argv is of type char *argv[], which is essentially a pointer to a pointer.

      When we use the array index operator [] on a pointer/array, there is an implicit dereference that happens. If argv is of type char *argv[], then argv[1] is of type char*, which is what we've declared pFilename as.

      • Ben

        "char *argv" is a pointer to a char.
        But what is "char *argv[]"? Pointer to a pointer? Or do you mean pointer to C-style string?

        I assumed that in the case of a "Command line arguments", the size of "*argv[]" was dynamically defined by the argument "argc".

        However this program compiles but crashes when executed:

        char *pchTest[4];
        for (int iii = 0; iii < 4; iii++)
        {
          char chTemp = 97 + iii;
          *pchTest[iii] = chTemp;
        }
        

        I feel I'm getting confused.

        • dogthinker

          Ben, your program is crashing when you are trying to use a non-constant variable to define the size of an array, which is not allowed.

          I think the size of the arrays here are being implicitly defined by the input (the command line parameters.) The argc parameter is simply passing us the size of the array of C-style strings - not defining them.

          If you want code to help you imagine what is happening, running a program with the following input:

          C:WordCount Myfile.txt Myotherfile.txt

          Would give us a value for *argv[] analgous to if you used the following code:

          char* argv[] = {"C:>WordCount","Myfile.txt","Myotherfile.txt"};
        • char *argv[] is indeed a pointer to a pointer. However, thinking about it like that will only lead to confusion. Instead, think of it as an array of strings.

          Now, consider what an "array of strings" really is. A string is an array of characters, so an "array of strings" is really an "array of (array of characters)". An array is really just a pointer, so an "array of (array of characters)" is really just a "pointer to a pointer to characters". And that's exactly how argv is defined.

          Now, the thing to note here is that argv comes prepopulated -- that is, each string in argv[] is already pointing to its appropriate command line argument. The size of the argv array is argc, as you state.

          Now, to your program. You declare an array of 4 strings called pchTest, which is fine. However, like all C++ basic data types, pchTest is not initialized by default. So while pchTest points to an array of 4 strings, each of the strings is pointing to garbage memory.

          This is why your program crashes when you try and write a value into them -- you're dereferencing a garbage address.

          Probably the best way to fix this is to dynamically allocate the strings when you need them:

          char *pchTest[4];
          for (int iii = 0; iii < 4; iii++)
          {
            char chTemp = 97 + iii;
            pchTest[iii] = new char[1]; // allocate string with room for 1 char
            *pchTest[iii] = chTemp;
            cout << *pchTest[iii];
            delete pchTest[iii]; // deallocate string
          }
          

          However, that said, I think you're best off avoiding trying to create your own arrays of strings using this method altogether. There are much cleaner, safer, and understandable ways of doing the same thing using classes, which will be covered shortly.

  • Doug

    You have a GREAT site! I am using Visual Studio 2008 and it has been working great up until now. If I use the built in "_tmain" declaration, I get 4 addresses printed. But when I use your declaration, it works perfect. What is the difference in the declarations?

    int _tmain(int argc, _TCHAR* argv[])
    //int main(int argc, char *argv[])   
    {   
        using namespace std;   
      
        cout << "There are " << argc << " arguments:" << endl;   
      
        // Loop through each argument and print its number and value   
        for (int nArg=0; nArg < argc; nArg++)   
            cout << nArg << " " << argv[nArg] << endl;   
      
        return 0;   
    }  
    
    • I think this has something to do with the way your program is doing character encoding. TCHAR is a macro that can resolve to either char or wchar_t depending on whether or not you are using wide characters. If you are using wide characters (wchar_t), then trying to use cout to print them will print addresses instead of values because it doesn't know how to handle them. My guess is that _tmain() is converting your command line parameters to wide character strings, but main() isn't.

    • baldo

      In Visual Studio, _tmain is a macro that expands to wmain according and _TCHAR expands to wchar_t.
      The problem is that you are using 'cout' (which works with single wide strings) with a double wide string.

      // This should work 
      wcout << argv[0] << endl; 
      
  • kingyo

    Really nice job, helped me a lot...
    Thank you!

  • programmer in training

    I though the final example is suppose to be main(int argc, char *argc) instead of just int main()??

    [ It is indeed. -Alex ]

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">